@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,471 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const HELLOLYNK_CLIENT_PROFILE_CONTRACT = "hellolynk-client-profile-v1";
|
|
4
|
+
const HELLOLYNK_CONTACTS_CONTRACT = "hellolynk-local-contacts-v1";
|
|
5
|
+
const HELLOLYNK_MINIMUM_CLIENT_NODE = "22.16.0";
|
|
6
|
+
const CURRENT_PRINCIPAL_ID_COLUMN = "hellolynk_id";
|
|
7
|
+
const CURRENT_STABLE_ID = /^hellolynk:(intl|cn):([a-z0-9][a-z0-9._-]{2,179})$/;
|
|
8
|
+
const SENSITIVE_ENVIRONMENT_KEY = /(?:^|_)(?:api_?key|authorization|bearer|cookie|credential|database_url|password|passwd|private_?key|secret|token)(?:_|$)/i;
|
|
9
|
+
const BRANDED_SENSITIVE_ENVIRONMENT_KEY = /^(?:hellolynk|lynk)(?:_|$).*(?:authorization|cookie|credential|key|password|secret|token)(?:_|$)/i;
|
|
10
|
+
const AMBIENT_CAPABILITY_ENVIRONMENT_KEY = /^(?:AWS_ACCESS_KEY_ID|AWS_SHARED_CREDENTIALS_FILE|AWS_CONFIG_FILE|AWS_WEB_IDENTITY_TOKEN_FILE|GOOGLE_APPLICATION_CREDENTIALS|AZURE_CLIENT_CERTIFICATE_PATH|SSH_AUTH_SOCK|SSH_AGENT_PID|GIT_ASKPASS|SSH_ASKPASS|NPM_CONFIG_USERCONFIG|NODE_OPTIONS|NODE_PATH|DOCKER_CONFIG|KUBECONFIG|NETRC)$/i;
|
|
11
|
+
const BRANDED_RAW_CREDENTIAL = /(?:hellolynk|lynk)_(?:account|account_session|bind|dev_enroll|device|host_transport)_v\d+_[A-Za-z0-9_-]+\.[A-Za-z0-9_-]{16,}/i;
|
|
12
|
+
const BRANDED_RAW_HOST_CAPABILITY = /(?:hellolynk|lynk)_host_v\d+_[A-Za-z0-9_-]{43}(?![A-Za-z0-9_-])/i;
|
|
13
|
+
const PROFILE_FIELDS = Object.freeze([
|
|
14
|
+
"schemaVersion", "profileId", "baseUrl", "allowLoopbackHttp", "deviceId",
|
|
15
|
+
"credentialId", "principalId", "hellolynkId", "agentId", "delegateId",
|
|
16
|
+
"region", "allowedScopes", "platform", "contract",
|
|
17
|
+
]);
|
|
18
|
+
const ROUTED_PROFILE_FIELDS = Object.freeze([...PROFILE_FIELDS, "hostId", "authorizationVersion"]);
|
|
19
|
+
const CONTACT_CONTAINER_FIELDS = Object.freeze(["schemaVersion", "contractId", "profileId", "contacts"]);
|
|
20
|
+
const CONTACT_CONTAINER_FIELDS_V3 = Object.freeze([...CONTACT_CONTAINER_FIELDS, "contactRequestReadDelegateIds"]);
|
|
21
|
+
const CONTACT_CONTAINER_FIELDS_V4 = Object.freeze([...CONTACT_CONTAINER_FIELDS_V3, "relationshipSync"]);
|
|
22
|
+
const CONTACT_FIELDS = Object.freeze([
|
|
23
|
+
"contactId", "hellolynkId", "displayName", "safetyCode",
|
|
24
|
+
"autonomousSendDelegateIds", "createdAt", "updatedAt",
|
|
25
|
+
]);
|
|
26
|
+
const CONTACT_FIELDS_WITH_SAFETY_VERIFICATION = Object.freeze([
|
|
27
|
+
...CONTACT_FIELDS,
|
|
28
|
+
"safetyCodeVerificationState",
|
|
29
|
+
]);
|
|
30
|
+
const CONTACT_FIELDS_V3 = Object.freeze([
|
|
31
|
+
"contactId", "hellolynkId", "displayName", "principalId", "instances", "safetyCode",
|
|
32
|
+
"safetyCodeVerificationState", "autonomousSendDelegateIds", "continuousReadDelegateIds",
|
|
33
|
+
"createdAt", "updatedAt",
|
|
34
|
+
]);
|
|
35
|
+
const CONTACT_INSTANCE_FIELDS_V3 = Object.freeze([
|
|
36
|
+
"delegateId", "clientType", "displayName", "createdAt", "updatedAt",
|
|
37
|
+
"autonomousSendDelegateIds", "continuousReadDelegateIds",
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
function isHelloLynkSensitiveEnvironmentKey(value) {
|
|
41
|
+
const key = String(value || "");
|
|
42
|
+
return SENSITIVE_ENVIRONMENT_KEY.test(key)
|
|
43
|
+
|| BRANDED_SENSITIVE_ENVIRONMENT_KEY.test(key)
|
|
44
|
+
|| AMBIENT_CAPABILITY_ENVIRONMENT_KEY.test(key);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function sanitizeHelloLynkChildEnvironment(source = {}, overrides = {}) {
|
|
48
|
+
const environment = { ...(source || {}), ...(overrides || {}) };
|
|
49
|
+
for (const key of Object.keys(environment)) {
|
|
50
|
+
if (isHelloLynkSensitiveEnvironmentKey(key)) delete environment[key];
|
|
51
|
+
}
|
|
52
|
+
return environment;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function standaloneHelloLynkNodeEnvironment(source = {}) {
|
|
56
|
+
const environment = sanitizeHelloLynkChildEnvironment(source);
|
|
57
|
+
for (const key of Object.keys(environment)) {
|
|
58
|
+
if (/^ELECTRON_(?:RUN_AS_NODE|NO_ASAR)$/i.test(key)) delete environment[key];
|
|
59
|
+
}
|
|
60
|
+
// Node versions supporting these opt-ins consume them at startup. Unknown
|
|
61
|
+
// environment variables are harmless on older supported Node releases.
|
|
62
|
+
environment.NODE_USE_ENV_PROXY = "1";
|
|
63
|
+
environment.NODE_USE_SYSTEM_CA = "1";
|
|
64
|
+
const bypass = environment.no_proxy ?? environment.NO_PROXY ?? "";
|
|
65
|
+
environment.NO_PROXY = environment.no_proxy = [bypass, "localhost", "127.0.0.1", "::1"].filter(Boolean).join(",");
|
|
66
|
+
return environment;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function helloLynkNetworkErrorCode(error, fallback = "network_request_failed") {
|
|
70
|
+
// Only classify known codes, never expose proxy URLs, credentials or native
|
|
71
|
+
// error messages. This is diagnostic information, not permission to resend.
|
|
72
|
+
const causes = Array.isArray(error?.cause?.errors) ? error.cause.errors : [];
|
|
73
|
+
const codes = [error?.code, error?.cause?.code, ...causes.map((item) => item?.code)];
|
|
74
|
+
if (codes.some((code) => ["CERT_HAS_EXPIRED", "CERT_NOT_YET_VALID", "DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
75
|
+
"SELF_SIGNED_CERT_IN_CHAIN", "UNABLE_TO_VERIFY_LEAF_SIGNATURE", "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
76
|
+
"ERR_TLS_CERT_ALTNAME_INVALID"].includes(code))) return "network_certificate_untrusted";
|
|
77
|
+
if (codes.some((code) => ["ENOTFOUND", "EAI_AGAIN"].includes(code))) return "network_name_resolution_failed";
|
|
78
|
+
if (codes.some((code) => ["ECONNREFUSED", "UND_ERR_PRX_TLS", "UND_ERR_PROXY"].includes(code))) return "network_connection_refused";
|
|
79
|
+
for (const code of ["network_proxy_runtime_unsupported", "network_proxy_configuration_invalid", "network_system_proxy_unavailable"]) {
|
|
80
|
+
if (codes.includes(code)) return code;
|
|
81
|
+
}
|
|
82
|
+
return fallback;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function readHelloLynkWindowsProxy(baseUrl, env) {
|
|
86
|
+
const { execFile } = require("node:child_process");
|
|
87
|
+
const script = "$ErrorActionPreference='Stop'; $u=[Uri]$env:HELLOLYNK_PROXY_DESTINATION; "
|
|
88
|
+
+ "$p=[System.Net.Http.HttpClient]::DefaultProxy; "
|
|
89
|
+
+ "if(-not $p.IsBypassed($u)){ $v=$p.GetProxy($u); if($v -ne $u){[Console]::Out.Write($v.AbsoluteUri)} }";
|
|
90
|
+
return new Promise((resolve, reject) => {
|
|
91
|
+
execFile("pwsh.exe", ["-NoLogo", "-NoProfile", "-NonInteractive", "-Command", script], {
|
|
92
|
+
windowsHide: true, shell: false, timeout: 8_000, maxBuffer: 8192, encoding: "utf8",
|
|
93
|
+
env: sanitizeHelloLynkChildEnvironment(env, { HELLOLYNK_PROXY_DESTINATION: new URL(baseUrl).origin }),
|
|
94
|
+
}, (error, stdout) => error ? reject(codedError("network_system_proxy_unavailable")) : resolve(stdout.trim()));
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async function prepareHelloLynkNetwork(baseUrl, options = {}) {
|
|
99
|
+
const env = options.env || process.env;
|
|
100
|
+
const http = options.http || require("node:http");
|
|
101
|
+
const tls = options.tls || require("node:tls");
|
|
102
|
+
const platform = options.platform || process.platform;
|
|
103
|
+
const url = new URL(baseUrl);
|
|
104
|
+
// Local IPC never needs system proxy discovery or extra trust roots.
|
|
105
|
+
if (["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)) return;
|
|
106
|
+
if (typeof tls.getCACertificates === "function" && typeof tls.setDefaultCACertificates === "function") {
|
|
107
|
+
tls.setDefaultCACertificates([...new Set([...tls.getCACertificates("default"), ...tls.getCACertificates("system")])]);
|
|
108
|
+
}
|
|
109
|
+
const proxyEnv = { ...env };
|
|
110
|
+
let systemProxy = false;
|
|
111
|
+
const explicitProxy = env.https_proxy || env.HTTPS_PROXY || env.http_proxy || env.HTTP_PROXY || env.all_proxy || env.ALL_PROXY;
|
|
112
|
+
if (!explicitProxy && platform === "win32") {
|
|
113
|
+
const proxy = await (options.resolveSystemProxy || readHelloLynkWindowsProxy)(baseUrl, env);
|
|
114
|
+
if (proxy) { proxyEnv.HTTPS_PROXY = proxyEnv.HTTP_PROXY = proxy; systemProxy = true; }
|
|
115
|
+
}
|
|
116
|
+
const allProxy = env.all_proxy || env.ALL_PROXY;
|
|
117
|
+
if (allProxy) {
|
|
118
|
+
proxyEnv.HTTP_PROXY = env.http_proxy || env.HTTP_PROXY || allProxy;
|
|
119
|
+
proxyEnv.HTTPS_PROXY = env.https_proxy || env.HTTPS_PROXY || allProxy;
|
|
120
|
+
}
|
|
121
|
+
const proxies = [proxyEnv.https_proxy || proxyEnv.HTTPS_PROXY, proxyEnv.http_proxy || proxyEnv.HTTP_PROXY].filter(Boolean);
|
|
122
|
+
for (const proxy of proxies) {
|
|
123
|
+
try { if (!["http:", "https:"].includes(new URL(proxy).protocol)) throw new Error(); }
|
|
124
|
+
catch { throw codedError("network_proxy_configuration_invalid"); }
|
|
125
|
+
}
|
|
126
|
+
if (!proxies.length) return;
|
|
127
|
+
proxyEnv.NO_PROXY = proxyEnv.no_proxy = [env.no_proxy ?? env.NO_PROXY ?? "", "localhost", "127.0.0.1", "::1"].filter(Boolean).join(",");
|
|
128
|
+
if (typeof http.setGlobalProxyFromEnv === "function") {
|
|
129
|
+
http.setGlobalProxyFromEnv(proxyEnv);
|
|
130
|
+
} else {
|
|
131
|
+
const [major, minor] = String(options.nodeVersion || process.versions.node).split(".").map(Number);
|
|
132
|
+
const startupSupported = major >= 25 || (major === 24 && minor >= 5) || (major === 22 && minor >= 21);
|
|
133
|
+
// Older Node can honor explicit proxy environment at process startup, but
|
|
134
|
+
// cannot apply a discovered Windows proxy without replacing its dispatcher.
|
|
135
|
+
if (systemProxy || allProxy || !startupSupported || env.NODE_USE_ENV_PROXY !== "1") {
|
|
136
|
+
throw codedError("network_proxy_runtime_unsupported");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
let networkPreparation;
|
|
142
|
+
async function helloLynkNetworkFetch(url, options) {
|
|
143
|
+
// These requests run in HelloLynk's standalone CLI/Host. Never replace an
|
|
144
|
+
// Electron client's shared dispatcher if it imports the core for local use.
|
|
145
|
+
if (!process.versions.electron && !["localhost", "127.0.0.1", "[::1]"].includes(new URL(url).hostname)) {
|
|
146
|
+
networkPreparation ??= prepareHelloLynkNetwork(url).catch((error) => { networkPreparation = null; throw error; });
|
|
147
|
+
await networkPreparation;
|
|
148
|
+
}
|
|
149
|
+
options?.signal?.throwIfAborted();
|
|
150
|
+
return globalThis.fetch(url, options);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
let standaloneNodeSelection = null;
|
|
154
|
+
|
|
155
|
+
// A shared Host can outlive the client that started it. Running it with an
|
|
156
|
+
// Electron executable would keep that client's installation in use after quit.
|
|
157
|
+
// Resolve the existing standalone Node; never fall back to the client binary.
|
|
158
|
+
async function resolveHelloLynkStandaloneNode(options = {}) {
|
|
159
|
+
const path = require("node:path");
|
|
160
|
+
const fs = require("node:fs/promises");
|
|
161
|
+
const { execFile } = require("node:child_process");
|
|
162
|
+
const runtime = options.runtime || process;
|
|
163
|
+
const platform = runtime.platform || process.platform;
|
|
164
|
+
const paths = platform === "win32" ? path.win32 : path.posix;
|
|
165
|
+
const canonical = (value) => platform === "win32" ? value.toLowerCase() : value;
|
|
166
|
+
const realpath = options.realpath || fs.realpath;
|
|
167
|
+
const env = standaloneHelloLynkNodeEnvironment(options.env || process.env);
|
|
168
|
+
const environmentValue = (name) => Object.entries(env).find(([key]) => key.toLowerCase() === name)?.[1];
|
|
169
|
+
const cacheKey = !options.runtime && !options.probe && !options.realpath
|
|
170
|
+
? JSON.stringify([runtime.execPath, runtime.versions?.electron, runtime.versions?.bun, options.preferredExecutable, environmentValue("path"),
|
|
171
|
+
environmentValue("programfiles"), environmentValue("programw6432"), environmentValue("localappdata")]) : null;
|
|
172
|
+
if (cacheKey && standaloneNodeSelection?.key === cacheKey) {
|
|
173
|
+
try {
|
|
174
|
+
if (await realpath(standaloneNodeSelection.executable) === standaloneNodeSelection.executable) return standaloneNodeSelection.executable;
|
|
175
|
+
} catch {}
|
|
176
|
+
standaloneNodeSelection = null;
|
|
177
|
+
}
|
|
178
|
+
const selected = (executable) => {
|
|
179
|
+
if (cacheKey) standaloneNodeSelection = { key: cacheKey, executable };
|
|
180
|
+
return executable;
|
|
181
|
+
};
|
|
182
|
+
const candidates = [];
|
|
183
|
+
const add = (value) => {
|
|
184
|
+
if (typeof value === "string" && paths.isAbsolute(value) && !/[\r\n\0]/.test(value)) candidates.push(value);
|
|
185
|
+
};
|
|
186
|
+
let current = null, clientDirectory = null;
|
|
187
|
+
try { current = await realpath(runtime.execPath); } catch {}
|
|
188
|
+
if (current && runtime.versions?.electron) {
|
|
189
|
+
clientDirectory = paths.dirname(current);
|
|
190
|
+
if (platform === "darwin" && paths.basename(clientDirectory) === "MacOS") clientDirectory = paths.dirname(clientDirectory);
|
|
191
|
+
}
|
|
192
|
+
add(options.preferredExecutable);
|
|
193
|
+
if (!runtime.versions?.electron && !runtime.versions?.bun) add(current);
|
|
194
|
+
const searchPath = environmentValue("path");
|
|
195
|
+
for (const directory of String(searchPath || "").split(paths.delimiter)) {
|
|
196
|
+
const clean = directory.trim().replace(/^"(.*)"$/, "$1");
|
|
197
|
+
if (paths.isAbsolute(clean)) add(paths.join(clean, platform === "win32" ? "node.exe" : "node"));
|
|
198
|
+
}
|
|
199
|
+
if (platform === "win32") {
|
|
200
|
+
for (const variable of ["programw6432", "programfiles"]) {
|
|
201
|
+
const directory = environmentValue(variable);
|
|
202
|
+
if (typeof directory === "string" && paths.isAbsolute(directory)) add(paths.join(directory, "nodejs", "node.exe"));
|
|
203
|
+
}
|
|
204
|
+
const local = environmentValue("localappdata");
|
|
205
|
+
if (typeof local === "string" && paths.isAbsolute(local)) add(paths.join(local, "Programs", "nodejs", "node.exe"));
|
|
206
|
+
}
|
|
207
|
+
const probe = options.probe || ((executable) => new Promise((resolve, reject) => {
|
|
208
|
+
execFile(executable, ["--eval", "process.stdout.write(JSON.stringify({execPath:process.execPath,node:process.versions.node,electron:process.versions.electron,bun:process.versions.bun,release:process.release.name}))"], {
|
|
209
|
+
env, windowsHide: true, shell: false, encoding: "utf8", timeout: 5_000, maxBuffer: 4 * 1024,
|
|
210
|
+
}, (error, stdout) => {
|
|
211
|
+
if (error) return reject(error);
|
|
212
|
+
try { resolve(JSON.parse(stdout)); } catch (error) { reject(error); }
|
|
213
|
+
});
|
|
214
|
+
}));
|
|
215
|
+
const seen = new Set();
|
|
216
|
+
const outsideClient = (file) => !clientDirectory || (canonical(file) !== canonical(current)
|
|
217
|
+
&& !canonical(file).startsWith(canonical(clientDirectory + paths.sep)));
|
|
218
|
+
const clientRuntime = async (file) => {
|
|
219
|
+
// A separate node.exe inside a client's runtime cache is still owned by
|
|
220
|
+
// that client's updater. Electron's resources may contain such a binary.
|
|
221
|
+
if (/[\\/]\.cache[\\/]codex-runtimes[\\/]|[\\/]OpenAI[\\/]Codex[\\/]runtimes[\\/]/i.test(file)) return true;
|
|
222
|
+
const resources = /[\\/]resources[\\/]/ig;
|
|
223
|
+
for (const match of file.matchAll(resources)) {
|
|
224
|
+
const root = file.slice(0, match.index + match[0].length);
|
|
225
|
+
for (const marker of ["app.asar", paths.join("app", "package.json")]) {
|
|
226
|
+
if (await fs.stat(paths.join(root, marker)).then(stat => stat.isFile(), () => false)) return true;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return false;
|
|
230
|
+
};
|
|
231
|
+
for (const candidate of candidates) {
|
|
232
|
+
try {
|
|
233
|
+
const executable = await realpath(candidate);
|
|
234
|
+
if (seen.has(canonical(executable))) continue;
|
|
235
|
+
seen.add(canonical(executable));
|
|
236
|
+
if (!outsideClient(executable) || !/^node(?:\.exe)?$/i.test(paths.basename(executable)) || await clientRuntime(executable)) continue;
|
|
237
|
+
if (current && canonical(executable) === canonical(current)
|
|
238
|
+
&& !runtime.versions?.electron && !runtime.versions?.bun && runtime.release?.name === "node") {
|
|
239
|
+
assertHelloLynkClientNodeVersion(runtime.versions.node);
|
|
240
|
+
return selected(executable);
|
|
241
|
+
}
|
|
242
|
+
const result = await probe(executable, env);
|
|
243
|
+
if (result?.electron || result?.bun || result?.release !== "node") continue;
|
|
244
|
+
assertHelloLynkClientNodeVersion(result.node);
|
|
245
|
+
const actual = await realpath(result.execPath);
|
|
246
|
+
if (!outsideClient(actual) || !/^node(?:\.exe)?$/i.test(paths.basename(actual)) || await clientRuntime(actual)) continue;
|
|
247
|
+
return selected(actual);
|
|
248
|
+
} catch { /* Missing, outdated or embedded runtimes cannot host this background. */ }
|
|
249
|
+
}
|
|
250
|
+
const error = codedError("hellolynk_node_22_16_required");
|
|
251
|
+
error.message = `HelloLynk 后台需要本机独立安装的 Node.js ${HELLOLYNK_MINIMUM_CLIENT_NODE} 或更高版本`;
|
|
252
|
+
throw error;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function containsHelloLynkCredentialMaterial(value) {
|
|
256
|
+
const text = String(value || "");
|
|
257
|
+
return BRANDED_RAW_CREDENTIAL.test(text) || BRANDED_RAW_HOST_CAPABILITY.test(text);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function classifyHelloLynkStableId(value) {
|
|
261
|
+
const text = String(value || "");
|
|
262
|
+
const current = CURRENT_STABLE_ID.exec(text);
|
|
263
|
+
if (!current) return null;
|
|
264
|
+
return Object.freeze({
|
|
265
|
+
kind: "current",
|
|
266
|
+
value: text,
|
|
267
|
+
region: current[1],
|
|
268
|
+
localPart: current[2],
|
|
269
|
+
aliasKey: `${current[1]}:${current[2]}`,
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function helloLynkStableIdMatchesRegion(identityOrValue, regionValue) {
|
|
274
|
+
const identity = typeof identityOrValue === "string"
|
|
275
|
+
? classifyHelloLynkStableId(identityOrValue)
|
|
276
|
+
: identityOrValue;
|
|
277
|
+
if (!identity) return false;
|
|
278
|
+
const region = String(regionValue || "").trim().toLowerCase();
|
|
279
|
+
const canonicalRegion = region === "international" || region === "intl" ? "intl" : region;
|
|
280
|
+
return canonicalRegion === identity.region;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function isHelloLynkStableIdReservedText(value) {
|
|
284
|
+
return String(value ?? "").normalize("NFKC").trim().toLowerCase().startsWith("hellolynk:");
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function normalizeHelloLynkClientProfileContainer(value) {
|
|
288
|
+
if (!isPlainObject(value)) throw codedError("client_profile_invalid");
|
|
289
|
+
const schemaVersion = Number(value.schemaVersion);
|
|
290
|
+
if (![1, 2].includes(schemaVersion)) throw codedError("client_profile_schema_unsupported");
|
|
291
|
+
if (value.contract !== HELLOLYNK_CLIENT_PROFILE_CONTRACT || !Object.hasOwn(value, "hellolynkId")) {
|
|
292
|
+
throw codedError("client_profile_contract_invalid");
|
|
293
|
+
}
|
|
294
|
+
if (schemaVersion === 2 && ["delegateId", "hostId", "authorizationVersion"].some(
|
|
295
|
+
(field) => !Object.hasOwn(value, field),
|
|
296
|
+
)) throw codedError("client_profile_route_binding_invalid");
|
|
297
|
+
assertExactFields(value, schemaVersion === 2 ? ROUTED_PROFILE_FIELDS : PROFILE_FIELDS);
|
|
298
|
+
return Object.freeze({ value: { ...value }, migrated: false });
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function normalizeHelloLynkContactsContainer(value, expectedProfileId) {
|
|
302
|
+
if (!isPlainObject(value)) throw codedError("contact_store_invalid");
|
|
303
|
+
const schemaVersion = Number(value.schemaVersion);
|
|
304
|
+
if (![2, 3, 4].includes(schemaVersion)) throw codedError("contact_store_invalid");
|
|
305
|
+
assertExactFields(value, schemaVersion === 4 ? CONTACT_CONTAINER_FIELDS_V4
|
|
306
|
+
: schemaVersion === 3 ? CONTACT_CONTAINER_FIELDS_V3 : CONTACT_CONTAINER_FIELDS,
|
|
307
|
+
"contact_store_invalid");
|
|
308
|
+
if (schemaVersion === 4) normalizeHelloLynkRelationshipSync(value.relationshipSync);
|
|
309
|
+
if (value.contractId !== HELLOLYNK_CONTACTS_CONTRACT
|
|
310
|
+
|| value.profileId !== expectedProfileId || !Array.isArray(value.contacts)) {
|
|
311
|
+
throw codedError("contact_store_invalid");
|
|
312
|
+
}
|
|
313
|
+
for (const contact of value.contacts) {
|
|
314
|
+
if (!isPlainObject(contact)) throw codedError("contact_store_invalid");
|
|
315
|
+
if (schemaVersion >= 3) {
|
|
316
|
+
assertExactFields(contact, CONTACT_FIELDS_V3, "contact_store_invalid");
|
|
317
|
+
if (!Array.isArray(contact.instances)) throw codedError("contact_store_invalid");
|
|
318
|
+
for (const instance of contact.instances) {
|
|
319
|
+
if (!isPlainObject(instance)) throw codedError("contact_store_invalid");
|
|
320
|
+
assertExactFields(instance, [...CONTACT_INSTANCE_FIELDS_V3,
|
|
321
|
+
...(Object.hasOwn(instance, "continuousReadAfterSeq") ? ["continuousReadAfterSeq"] : [])], "contact_store_invalid");
|
|
322
|
+
if (Object.hasOwn(instance, "continuousReadAfterSeq")) {
|
|
323
|
+
if (!Array.isArray(instance.continuousReadAfterSeq) || instance.continuousReadAfterSeq.length > 32) {
|
|
324
|
+
throw codedError("contact_store_invalid");
|
|
325
|
+
}
|
|
326
|
+
const seen = new Set();
|
|
327
|
+
for (const entry of instance.continuousReadAfterSeq) {
|
|
328
|
+
assertExactFields(entry, ["delegateId", "afterSeq"], "contact_store_invalid");
|
|
329
|
+
if (typeof entry.delegateId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9_.:-]{2,198}$/.test(entry.delegateId)
|
|
330
|
+
|| seen.has(entry.delegateId) || !instance.continuousReadDelegateIds?.includes(entry.delegateId)
|
|
331
|
+
|| (entry.afterSeq !== null && (!Number.isSafeInteger(entry.afterSeq) || entry.afterSeq < 0))) {
|
|
332
|
+
throw codedError("contact_store_invalid");
|
|
333
|
+
}
|
|
334
|
+
seen.add(entry.delegateId);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
assertExactFields(
|
|
340
|
+
contact,
|
|
341
|
+
Object.hasOwn(contact, "safetyCodeVerificationState")
|
|
342
|
+
? CONTACT_FIELDS_WITH_SAFETY_VERIFICATION
|
|
343
|
+
: CONTACT_FIELDS,
|
|
344
|
+
"contact_store_invalid",
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return Object.freeze({ value, migrated: false, source: "current" });
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function normalizeHelloLynkRelationshipSync(value) {
|
|
352
|
+
const invalid = () => { throw codedError("contact_store_invalid"); };
|
|
353
|
+
if (!isPlainObject(value)) invalid();
|
|
354
|
+
assertExactFields(value, ["owner", "generations", "pendingDeletedHelloLynkIds"], "contact_store_invalid");
|
|
355
|
+
if (!Array.isArray(value.generations) || !Array.isArray(value.pendingDeletedHelloLynkIds)
|
|
356
|
+
|| value.generations.length + value.pendingDeletedHelloLynkIds.length > 2000) invalid();
|
|
357
|
+
let owner = null;
|
|
358
|
+
if (value.owner !== null) {
|
|
359
|
+
if (!isPlainObject(value.owner)) invalid();
|
|
360
|
+
assertExactFields(value.owner, ["principalId", "hellolynkId"], "contact_store_invalid");
|
|
361
|
+
if (typeof value.owner.principalId !== "string"
|
|
362
|
+
|| !/^[A-Za-z0-9][A-Za-z0-9_.:-]{2,198}$/.test(value.owner.principalId)) invalid();
|
|
363
|
+
owner = classifyHelloLynkStableId(value.owner.hellolynkId);
|
|
364
|
+
if (!owner) invalid();
|
|
365
|
+
} else if (value.generations.length) invalid();
|
|
366
|
+
const validatePeer = (peerId) => {
|
|
367
|
+
if (typeof peerId !== "string") invalid();
|
|
368
|
+
const peer = classifyHelloLynkStableId(peerId);
|
|
369
|
+
if (!peer || (owner && (peer.region !== owner.region || peer.aliasKey === owner.aliasKey))) invalid();
|
|
370
|
+
};
|
|
371
|
+
const relationshipIds = new Set();
|
|
372
|
+
const generationPeers = new Set();
|
|
373
|
+
for (const generation of value.generations) {
|
|
374
|
+
if (!isPlainObject(generation)) invalid();
|
|
375
|
+
assertExactFields(generation, ["relationshipId", "hellolynkId", "suppressed"], "contact_store_invalid");
|
|
376
|
+
if (typeof generation.relationshipId !== "string"
|
|
377
|
+
|| !/^[A-Za-z0-9][A-Za-z0-9_.:-]{2,240}$/.test(generation.relationshipId)
|
|
378
|
+
|| typeof generation.suppressed !== "boolean" || relationshipIds.has(generation.relationshipId)) invalid();
|
|
379
|
+
validatePeer(generation.hellolynkId);
|
|
380
|
+
relationshipIds.add(generation.relationshipId);
|
|
381
|
+
generationPeers.add(generation.hellolynkId);
|
|
382
|
+
}
|
|
383
|
+
const pending = new Set();
|
|
384
|
+
for (const peer of value.pendingDeletedHelloLynkIds) {
|
|
385
|
+
validatePeer(peer);
|
|
386
|
+
if (pending.has(peer) || generationPeers.has(peer)) invalid();
|
|
387
|
+
pending.add(peer);
|
|
388
|
+
}
|
|
389
|
+
return value;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
function assertExactFields(value, fields, code = "client_profile_fields_invalid") {
|
|
393
|
+
const expected = [...fields].sort();
|
|
394
|
+
const actual = Object.keys(value).sort();
|
|
395
|
+
if (actual.length !== expected.length || actual.some((field, index) => field !== expected[index])) {
|
|
396
|
+
throw codedError(code);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function isPlainObject(value) {
|
|
401
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
402
|
+
const prototype = Object.getPrototypeOf(value);
|
|
403
|
+
return prototype === Object.prototype || prototype === null;
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function codedError(code) {
|
|
407
|
+
const error = new Error(code);
|
|
408
|
+
error.code = code;
|
|
409
|
+
return error;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function assertHelloLynkClientNodeVersion(version = process.versions.node) {
|
|
413
|
+
const parts = /^(\d+)\.(\d+)\.(\d+)$/.exec(String(version || ""));
|
|
414
|
+
const supported = parts && (Number(parts[1]) > 22
|
|
415
|
+
|| (Number(parts[1]) === 22 && Number(parts[2]) >= 16));
|
|
416
|
+
if (!supported) {
|
|
417
|
+
const error = codedError("hellolynk_node_22_16_required");
|
|
418
|
+
error.message = `HelloLynk 本地客户端需要 Node.js ${HELLOLYNK_MINIMUM_CLIENT_NODE} 或更高版本(当前 ${String(version || "unknown")})`;
|
|
419
|
+
throw error;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// A clean Windows 11 ships Windows PowerShell 5.1 only; the protected stores, the Host launch and the
|
|
424
|
+
// human confirmation window need PowerShell 7 (pwsh). Probe it once per process and report a stable code
|
|
425
|
+
// instead of letting a missing pwsh surface later as an unrelated Host bootstrap failure.
|
|
426
|
+
let powerShell7Verdict;
|
|
427
|
+
|
|
428
|
+
function probePowerShell7() {
|
|
429
|
+
const { spawnSync } = require("node:child_process");
|
|
430
|
+
const result = spawnSync("pwsh.exe", ["-NoProfile", "-Command", "$PSVersionTable.PSVersion.Major"],
|
|
431
|
+
{ encoding: "utf8", windowsHide: true, shell: false, timeout: 5000 });
|
|
432
|
+
if (result.error?.code === "ENOENT") return "missing";
|
|
433
|
+
// A slow or odd answer does not prove pwsh is absent; the real call will report its own error.
|
|
434
|
+
if (result.error || result.status !== 0) return "unknown";
|
|
435
|
+
const major = Number.parseInt(String(result.stdout || "").trim(), 10);
|
|
436
|
+
return Number.isSafeInteger(major) && major >= 7 ? "ok" : "missing";
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function assertHelloLynkPowerShell7(options = {}) {
|
|
440
|
+
if ((options.platform ?? process.platform) !== "win32") return;
|
|
441
|
+
const injected = typeof options.probe === "function";
|
|
442
|
+
const verdict = injected ? options.probe() : (powerShell7Verdict ??= probePowerShell7());
|
|
443
|
+
if (verdict === "missing") {
|
|
444
|
+
const error = codedError("powershell7_missing");
|
|
445
|
+
error.message = "这台电脑没有 PowerShell 7(pwsh),HelloLynk 需要它。请安装 PowerShell 7 后重新打开客户端。";
|
|
446
|
+
throw error;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
module.exports = Object.freeze({
|
|
451
|
+
HELLOLYNK_MINIMUM_CLIENT_NODE,
|
|
452
|
+
assertHelloLynkClientNodeVersion,
|
|
453
|
+
assertHelloLynkPowerShell7,
|
|
454
|
+
CURRENT_PRINCIPAL_ID_COLUMN,
|
|
455
|
+
HELLOLYNK_CLIENT_PROFILE_CONTRACT,
|
|
456
|
+
HELLOLYNK_CONTACTS_CONTRACT,
|
|
457
|
+
classifyHelloLynkStableId,
|
|
458
|
+
helloLynkStableIdMatchesRegion,
|
|
459
|
+
containsHelloLynkCredentialMaterial,
|
|
460
|
+
isHelloLynkStableIdReservedText,
|
|
461
|
+
isHelloLynkSensitiveEnvironmentKey,
|
|
462
|
+
normalizeHelloLynkClientProfileContainer,
|
|
463
|
+
normalizeHelloLynkContactsContainer,
|
|
464
|
+
normalizeHelloLynkRelationshipSync,
|
|
465
|
+
sanitizeHelloLynkChildEnvironment,
|
|
466
|
+
standaloneHelloLynkNodeEnvironment,
|
|
467
|
+
helloLynkNetworkFetch,
|
|
468
|
+
helloLynkNetworkErrorCode,
|
|
469
|
+
prepareHelloLynkNetwork,
|
|
470
|
+
resolveHelloLynkStandaloneNode,
|
|
471
|
+
});
|