@hellolynk-ai/codex-plugin 0.0.0-stage → 0.2.100

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.
Files changed (123) hide show
  1. package/.agents/plugins/marketplace.json +20 -0
  2. package/LICENSE +92 -0
  3. package/README.md +101 -2
  4. package/bin/hellolynk-client-setup.mjs +2748 -0
  5. package/bin/hellolynk-mcp-config-shape.mjs +23 -0
  6. package/hellolynk-client-pack-manifest.json +619 -0
  7. package/hellolynk-client-pack-pin.json +4 -0
  8. package/package.json +58 -4
  9. package/plugins/hellolynk-codex/.app.json +3 -0
  10. package/plugins/hellolynk-codex/.codex-plugin/plugin.json +38 -0
  11. package/plugins/hellolynk-codex/.mcp.json +19 -0
  12. package/plugins/hellolynk-codex/assets/hellolynk-mark.png +0 -0
  13. package/plugins/hellolynk-codex/package.json +11 -0
  14. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-account.mjs +180 -0
  15. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-core.mjs +770 -0
  16. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-client-profile.mjs +191 -0
  17. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-host-auth.mjs +347 -0
  18. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-host-protected-store.mjs +2721 -0
  19. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-local-process-lock.mjs +157 -0
  20. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-neutral-host-installation-store.mjs +765 -0
  21. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-platform-credential-store.mjs +773 -0
  22. package/plugins/hellolynk-codex/runtime/bootstrap/core/hellolynk-runtime-safety.cjs +471 -0
  23. package/plugins/hellolynk-codex/runtime/bootstrap/platform/windows/hellolynk-host-protected-store.ps1 +2866 -0
  24. package/plugins/hellolynk-codex/runtime/connect-activate.mjs +837 -0
  25. package/plugins/hellolynk-codex/runtime/core/hellolynk-agent-configurator.mjs +701 -0
  26. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-account.mjs +180 -0
  27. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-core.mjs +770 -0
  28. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-profile.mjs +191 -0
  29. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update-entry.mjs +31 -0
  30. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update-runtime.mjs +600 -0
  31. package/plugins/hellolynk-codex/runtime/core/hellolynk-client-update.mjs +453 -0
  32. package/plugins/hellolynk-codex/runtime/core/hellolynk-contact-request-e2ee.mjs +867 -0
  33. package/plugins/hellolynk-codex/runtime/core/hellolynk-device-enrollment.mjs +435 -0
  34. package/plugins/hellolynk-codex/runtime/core/hellolynk-direct-text-e2ee-client.mjs +1964 -0
  35. package/plugins/hellolynk-codex/runtime/core/hellolynk-direct-text-e2ee.mjs +1207 -0
  36. package/plugins/hellolynk-codex/runtime/core/hellolynk-host-auth.mjs +347 -0
  37. package/plugins/hellolynk-codex/runtime/core/hellolynk-host-protected-store.mjs +2721 -0
  38. package/plugins/hellolynk-codex/runtime/core/hellolynk-host-transport-client.mjs +946 -0
  39. package/plugins/hellolynk-codex/runtime/core/hellolynk-host.mjs +2374 -0
  40. package/plugins/hellolynk-codex/runtime/core/hellolynk-human-confirmation-ledger.mjs +256 -0
  41. package/plugins/hellolynk-codex/runtime/core/hellolynk-human-relationship-controller.mjs +1234 -0
  42. package/plugins/hellolynk-codex/runtime/core/hellolynk-inbox-read-state.mjs +11 -0
  43. package/plugins/hellolynk-codex/runtime/core/hellolynk-indexed-message-store.mjs +1558 -0
  44. package/plugins/hellolynk-codex/runtime/core/hellolynk-instance-conversation.mjs +185 -0
  45. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-contact-requests.mjs +1733 -0
  46. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-contacts.mjs +1228 -0
  47. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-data-migration.mjs +766 -0
  48. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-data-protection.mjs +747 -0
  49. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-identity-trust.mjs +274 -0
  50. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-messaging.mjs +3043 -0
  51. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-peer-transport.mjs +103 -0
  52. package/plugins/hellolynk-codex/runtime/core/hellolynk-local-process-lock.mjs +157 -0
  53. package/plugins/hellolynk-codex/runtime/core/hellolynk-model-inbox.mjs +230 -0
  54. package/plugins/hellolynk-codex/runtime/core/hellolynk-model-notices.cjs +60 -0
  55. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-addressing-tools.cjs +231 -0
  56. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-conversations.mjs +280 -0
  57. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-human-confirmation-broker.mjs +1036 -0
  58. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-inbox-runtime.mjs +553 -0
  59. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-notice.mjs +50 -0
  60. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-reply-routes.mjs +96 -0
  61. package/plugins/hellolynk-codex/runtime/core/hellolynk-native-worker-lease.mjs +84 -0
  62. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-assembly.mjs +955 -0
  63. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-installation-store.mjs +765 -0
  64. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-launcher.mjs +665 -0
  65. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-process.mjs +4374 -0
  66. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-store-adapters.mjs +548 -0
  67. package/plugins/hellolynk-codex/runtime/core/hellolynk-neutral-host-workbench-read-model.mjs +1365 -0
  68. package/plugins/hellolynk-codex/runtime/core/hellolynk-platform-credential-store.mjs +773 -0
  69. package/plugins/hellolynk-codex/runtime/core/hellolynk-relay-client-cli.mjs +232 -0
  70. package/plugins/hellolynk-codex/runtime/core/hellolynk-release-retention.mjs +277 -0
  71. package/plugins/hellolynk-codex/runtime/core/hellolynk-runtime-safety.cjs +471 -0
  72. package/plugins/hellolynk-codex/runtime/core/hellolynk-workbench-action-grants.mjs +457 -0
  73. package/plugins/hellolynk-codex/runtime/core/hellolynk-workbench-connection.mjs +234 -0
  74. package/plugins/hellolynk-codex/runtime/neutral-host-bootstrap.mjs +64 -0
  75. package/plugins/hellolynk-codex/runtime/neutral-host-release-entry.mjs +70 -0
  76. package/plugins/hellolynk-codex/runtime/neutral-host-release-loader.mjs +156 -0
  77. package/plugins/hellolynk-codex/runtime/neutral-host-release-manifest.json +358 -0
  78. package/plugins/hellolynk-codex/runtime/neutral-host-release-pin.json +4 -0
  79. package/plugins/hellolynk-codex/runtime/platform/windows/configure-agent.ps1 +281 -0
  80. package/plugins/hellolynk-codex/runtime/platform/windows/credential-store.ps1 +844 -0
  81. package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-host-protected-store.ps1 +2866 -0
  82. package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-human-confirmation-ledger.ps1 +155 -0
  83. package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-local-data-key.ps1 +300 -0
  84. package/plugins/hellolynk-codex/runtime/platform/windows/hellolynk-native-human-confirmation-broker.ps1 +216 -0
  85. package/plugins/hellolynk-codex/runtime/workbench/candidate-bootstrap.mjs +54 -0
  86. package/plugins/hellolynk-codex/runtime/workbench/contract.mjs +1314 -0
  87. package/plugins/hellolynk-codex/runtime/workbench/hellolynk-workbench-build.json +215 -0
  88. package/plugins/hellolynk-codex/runtime/workbench/host-capabilities.mjs +80 -0
  89. package/plugins/hellolynk-codex/runtime/workbench/i18n.mjs +1127 -0
  90. package/plugins/hellolynk-codex/runtime/workbench/loopback-surface.mjs +740 -0
  91. package/plugins/hellolynk-codex/runtime/workbench/mcp-app-bundle.mjs +97 -0
  92. package/plugins/hellolynk-codex/runtime/workbench/service.mjs +485 -0
  93. package/plugins/hellolynk-codex/runtime/workbench/state.mjs +421 -0
  94. package/plugins/hellolynk-codex/runtime/workbench/transports.mjs +171 -0
  95. package/plugins/hellolynk-codex/runtime/workbench/ui/app.mjs +6120 -0
  96. package/plugins/hellolynk-codex/runtime/workbench/ui/connection-form.mjs +155 -0
  97. package/plugins/hellolynk-codex/runtime/workbench/ui/hellolynk-mark.png +0 -0
  98. package/plugins/hellolynk-codex/runtime/workbench/ui/http-transport.mjs +247 -0
  99. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/arrow-left.svg +3 -0
  100. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/close.svg +3 -0
  101. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/contacts.svg +3 -0
  102. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/inbox.svg +3 -0
  103. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/refresh.svg +3 -0
  104. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/search.svg +3 -0
  105. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/security.svg +3 -0
  106. package/plugins/hellolynk-codex/runtime/workbench/ui/icons/settings.svg +3 -0
  107. package/plugins/hellolynk-codex/runtime/workbench/ui/index.html +139 -0
  108. package/plugins/hellolynk-codex/runtime/workbench/ui/loopback-entry.mjs +26 -0
  109. package/plugins/hellolynk-codex/runtime/workbench/ui/mcp-app-client.mjs +151 -0
  110. package/plugins/hellolynk-codex/runtime/workbench/ui/mcp-app-entry.mjs +452 -0
  111. package/plugins/hellolynk-codex/runtime/workbench/ui/styles.css +686 -0
  112. package/plugins/hellolynk-codex/server/codex-neutral-production.mjs +520 -0
  113. package/plugins/hellolynk-codex/server/mcp-proxy.mjs +306 -0
  114. package/plugins/hellolynk-codex/server/mcp-server.mjs +1193 -0
  115. package/plugins/hellolynk-codex/server/native-conversation-directory.mjs +33 -0
  116. package/plugins/hellolynk-codex/server/native-reply-routes.mjs +32 -0
  117. package/plugins/hellolynk-codex/server/native-task-client.mjs +382 -0
  118. package/plugins/hellolynk-codex/server/native-task-runtime.mjs +8 -0
  119. package/plugins/hellolynk-codex/server/neutral-host-adapter.mjs +649 -0
  120. package/plugins/hellolynk-codex/server/workbench-runtime.mjs +180 -0
  121. package/plugins/hellolynk-codex/skills/hellolynk-open/SKILL.md +11 -0
  122. package/plugins/hellolynk-codex/skills/hellolynk-open/agents/openai.yaml +4 -0
  123. package/tools/hellolynk-activate-neutral-host-clients.mjs +837 -0
@@ -0,0 +1,347 @@
1
+ import crypto from "node:crypto";
2
+
3
+ export const HELLOLYNK_HOST_REQUEST_AUTH_DOMAIN = "hellolynk-host-request-v1";
4
+ export const HELLOLYNK_HOST_REQUEST_MAX_SKEW_MS = 30_000;
5
+ export const HELLOLYNK_HOST_NONCE_TTL_MS = 90_000;
6
+ export const HELLOLYNK_HOST_NONCE_CACHE_MAX_ENTRIES = 4_096;
7
+ // One installed capability is shared by every open conversation, receiver and
8
+ // card. Its replay history may use the existing Host-wide budget; a smaller
9
+ // default quota throttles ordinary reads and then rejects unrelated new sends.
10
+ export const HELLOLYNK_HOST_NONCE_CACHE_MAX_ENTRIES_PER_CAPABILITY = HELLOLYNK_HOST_NONCE_CACHE_MAX_ENTRIES;
11
+ export const HELLOLYNK_HOST_CAPABILITY_CONTRACT = "hellolynk-host-capability-v1";
12
+
13
+ export const HELLOLYNK_HOST_AUTH_HEADERS = Object.freeze({
14
+ capabilityId: "x-hellolynk-host-capability-id",
15
+ adapterId: "x-hellolynk-host-adapter-id",
16
+ hostGeneration: "x-hellolynk-host-generation",
17
+ timestampMs: "x-hellolynk-host-timestamp",
18
+ nonce: "x-hellolynk-host-nonce",
19
+ proof: "x-hellolynk-host-proof",
20
+ });
21
+
22
+ const IDENTIFIER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._:-]{0,126}[A-Za-z0-9])?$/;
23
+ const GENERATION_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9_-]{0,126}[A-Za-z0-9])?$/;
24
+ const NONCE_PATTERN = /^[A-Za-z0-9_-]{22,128}$/;
25
+ const PROOF_PATTERN = /^[a-f0-9]{64}$/;
26
+
27
+ export function sha256RawBody(rawBody) {
28
+ return crypto.createHash("sha256").update(asRawBody(rawBody)).digest("hex");
29
+ }
30
+
31
+ export function createHostRequestAuth(input) {
32
+ const normalized = normalizeRequestAuthInput(input);
33
+ const proof = crypto
34
+ .createHmac("sha256", normalized.secretBuffer)
35
+ .update(normalized.message, "utf8")
36
+ .digest("hex");
37
+ return {
38
+ capabilityId: normalized.capabilityId,
39
+ adapterId: normalized.adapterId,
40
+ hostGeneration: normalized.hostGeneration,
41
+ timestampMs: normalized.timestampMs,
42
+ nonce: normalized.nonce,
43
+ bodySha256: normalized.bodySha256,
44
+ proof,
45
+ headers: {
46
+ [HELLOLYNK_HOST_AUTH_HEADERS.capabilityId]: normalized.capabilityId,
47
+ [HELLOLYNK_HOST_AUTH_HEADERS.adapterId]: normalized.adapterId,
48
+ [HELLOLYNK_HOST_AUTH_HEADERS.hostGeneration]: normalized.hostGeneration,
49
+ [HELLOLYNK_HOST_AUTH_HEADERS.timestampMs]: String(normalized.timestampMs),
50
+ [HELLOLYNK_HOST_AUTH_HEADERS.nonce]: normalized.nonce,
51
+ [HELLOLYNK_HOST_AUTH_HEADERS.proof]: proof,
52
+ },
53
+ };
54
+ }
55
+
56
+ export function hostRequestAuthMatches(input) {
57
+ try {
58
+ const expected = createHostRequestAuth(input).proof;
59
+ const candidate = String(input?.proof || "").toLowerCase();
60
+ if (!PROOF_PATTERN.test(candidate)) return false;
61
+ return crypto.timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(candidate, "hex"));
62
+ } catch {
63
+ return false;
64
+ }
65
+ }
66
+
67
+ export function canonicalHostRequestMessage(input) {
68
+ return normalizeRequestAuthInput(input).message;
69
+ }
70
+
71
+ export function createHostNonce(bytes = 24) {
72
+ if (!Number.isSafeInteger(bytes) || bytes < 16 || bytes > 64) {
73
+ throw codeError("host_nonce_size_invalid");
74
+ }
75
+ return crypto.randomBytes(bytes).toString("base64url");
76
+ }
77
+
78
+ export function createNonceReplayGuard(options = {}) {
79
+ const now = normalizeNow(options.clock);
80
+ const ttlMs = normalizePositiveInteger(options.ttlMs, HELLOLYNK_HOST_NONCE_TTL_MS, 1_000, 1_800_001);
81
+ const maxEntries = normalizePositiveInteger(
82
+ options.maxEntries,
83
+ HELLOLYNK_HOST_NONCE_CACHE_MAX_ENTRIES,
84
+ 1,
85
+ 65_536,
86
+ );
87
+ const maxEntriesPerCapability = normalizePositiveInteger(
88
+ options.maxEntriesPerCapability,
89
+ Math.min(HELLOLYNK_HOST_NONCE_CACHE_MAX_ENTRIES_PER_CAPABILITY, maxEntries),
90
+ 1,
91
+ maxEntries,
92
+ );
93
+ const entries = new Map();
94
+ const capabilityEntryCounts = new Map();
95
+
96
+ function consume(capabilityId, nonce, timestampMs) {
97
+ const normalizedCapabilityId = assertIdentifier(capabilityId, "host_capability_id_invalid");
98
+ const normalizedNonce = assertNonce(nonce);
99
+ const normalizedTimestamp = assertTimestamp(timestampMs);
100
+ const current = assertTimestamp(now());
101
+ prune(current);
102
+ const key = `${normalizedCapabilityId}\0${normalizedNonce}`;
103
+ if (entries.has(key)) return false;
104
+ const capabilityEntryCount = capabilityEntryCounts.get(normalizedCapabilityId) || 0;
105
+ if (capabilityEntryCount >= maxEntriesPerCapability) {
106
+ throw codeError("host_nonce_capability_cache_full");
107
+ }
108
+ if (entries.size >= maxEntries) throw codeError("host_nonce_cache_full");
109
+ entries.set(key, {
110
+ capabilityId: normalizedCapabilityId,
111
+ expiresAt: Math.max(current, normalizedTimestamp) + ttlMs,
112
+ });
113
+ capabilityEntryCounts.set(normalizedCapabilityId, capabilityEntryCount + 1);
114
+ return true;
115
+ }
116
+
117
+ function prune(current = assertTimestamp(now())) {
118
+ for (const [key, entry] of entries) {
119
+ if (entry.expiresAt <= current) {
120
+ entries.delete(key);
121
+ const count = capabilityEntryCounts.get(entry.capabilityId) || 0;
122
+ if (count <= 1) capabilityEntryCounts.delete(entry.capabilityId);
123
+ else capabilityEntryCounts.set(entry.capabilityId, count - 1);
124
+ }
125
+ }
126
+ }
127
+
128
+ return {
129
+ consume,
130
+ prune,
131
+ get size() {
132
+ prune();
133
+ return entries.size;
134
+ },
135
+ sizeForCapability(capabilityId) {
136
+ prune();
137
+ return capabilityEntryCounts.get(assertIdentifier(capabilityId, "host_capability_id_invalid")) || 0;
138
+ },
139
+ };
140
+ }
141
+
142
+ export function assertRequestFresh(timestampMs, nowMs, maxSkewMs = HELLOLYNK_HOST_REQUEST_MAX_SKEW_MS) {
143
+ const timestamp = assertTimestamp(timestampMs);
144
+ const current = assertTimestamp(nowMs);
145
+ const allowedSkew = normalizePositiveInteger(maxSkewMs, HELLOLYNK_HOST_REQUEST_MAX_SKEW_MS, 1, 300_000);
146
+ if (Math.abs(current - timestamp) > allowedSkew) throw codeError("host_request_stale");
147
+ return timestamp;
148
+ }
149
+
150
+ export function assertCapabilityRecord(value) {
151
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
152
+ throw codeError("host_capability_invalid");
153
+ }
154
+ const expectedKeys = [
155
+ "adapterId",
156
+ "capabilityId",
157
+ "contract",
158
+ "delegateId",
159
+ "hostInstallationId",
160
+ "issuedAt",
161
+ "principalId",
162
+ "region",
163
+ "revokedAt",
164
+ "scopes",
165
+ "secretBuffer",
166
+ "state",
167
+ "version",
168
+ ];
169
+ const actualKeys = Object.keys(value).sort();
170
+ if (
171
+ actualKeys.length !== expectedKeys.length
172
+ || actualKeys.some((key, index) => key !== expectedKeys[index])
173
+ ) {
174
+ throw codeError("host_capability_fields_invalid");
175
+ }
176
+ if (value.contract !== HELLOLYNK_HOST_CAPABILITY_CONTRACT) {
177
+ throw codeError("host_capability_contract_invalid");
178
+ }
179
+ const capabilityId = assertIdentifier(value.capabilityId, "host_capability_id_invalid");
180
+ const region = assertIdentifier(value.region, "host_capability_region_invalid");
181
+ const principalId = assertIdentifier(value.principalId, "host_principal_id_invalid");
182
+ const adapterId = assertIdentifier(value.adapterId, "host_adapter_id_invalid");
183
+ const delegateId = assertIdentifier(value.delegateId, "host_delegate_id_invalid");
184
+ const hostInstallationId = assertIdentifier(
185
+ value.hostInstallationId,
186
+ "host_installation_id_invalid",
187
+ );
188
+ const version = Number(value.version);
189
+ if (!Number.isSafeInteger(version) || version < 1) throw codeError("host_capability_version_invalid");
190
+ if (value.state !== "active") throw codeError("host_capability_inactive");
191
+ const issuedAt = assertTimestamp(value.issuedAt);
192
+ if (value.revokedAt !== null) throw codeError("host_capability_revoked_at_invalid");
193
+ if (!Array.isArray(value.scopes) || value.scopes.length > 64) {
194
+ throw codeError("host_capability_scopes_invalid");
195
+ }
196
+ const scopes = value.scopes.map((scope) => (
197
+ assertIdentifier(scope, "host_capability_scope_invalid")
198
+ ));
199
+ const canonicalScopes = [...new Set(scopes)].sort();
200
+ if (
201
+ canonicalScopes.length !== scopes.length
202
+ || canonicalScopes.some((scope, index) => scope !== scopes[index])
203
+ ) {
204
+ throw codeError("host_capability_scopes_noncanonical");
205
+ }
206
+ const secretBuffer = assertSecretBuffer(value.secretBuffer);
207
+ return Object.freeze({
208
+ contract: HELLOLYNK_HOST_CAPABILITY_CONTRACT,
209
+ capabilityId,
210
+ region,
211
+ principalId,
212
+ delegateId,
213
+ hostInstallationId,
214
+ adapterId,
215
+ version,
216
+ state: "active",
217
+ scopes: Object.freeze(scopes),
218
+ issuedAt,
219
+ revokedAt: null,
220
+ secretBuffer,
221
+ });
222
+ }
223
+
224
+ export function assertIdentifier(value, errorCode = "host_identifier_invalid") {
225
+ const identifier = String(value || "");
226
+ if (!IDENTIFIER_PATTERN.test(identifier)) throw codeError(errorCode);
227
+ return identifier;
228
+ }
229
+
230
+ export function assertHostGeneration(value) {
231
+ const generation = String(value || "");
232
+ if (!GENERATION_PATTERN.test(generation)) throw codeError("host_generation_invalid");
233
+ return generation;
234
+ }
235
+
236
+ export function assertNonce(value) {
237
+ const nonce = String(value || "");
238
+ if (!NONCE_PATTERN.test(nonce)) throw codeError("host_nonce_invalid");
239
+ return nonce;
240
+ }
241
+
242
+ export function assertPathname(value) {
243
+ const pathname = String(value || "");
244
+ if (
245
+ !pathname.startsWith("/")
246
+ || pathname.length > 512
247
+ || pathname.includes("?")
248
+ || pathname.includes("#")
249
+ || pathname.includes("\r")
250
+ || pathname.includes("\n")
251
+ || pathname.includes("\\")
252
+ ) {
253
+ throw codeError("host_pathname_invalid");
254
+ }
255
+ return pathname;
256
+ }
257
+
258
+ export function assertMethod(value) {
259
+ const method = String(value || "");
260
+ if (!/^[A-Z]{3,12}$/.test(method)) throw codeError("host_method_invalid");
261
+ return method;
262
+ }
263
+
264
+ export function asRawBody(value) {
265
+ if (Buffer.isBuffer(value)) return value;
266
+ if (value instanceof Uint8Array) return Buffer.from(value.buffer, value.byteOffset, value.byteLength);
267
+ if (typeof value === "string") return Buffer.from(value, "utf8");
268
+ if (value == null) return Buffer.alloc(0);
269
+ throw codeError("host_raw_body_invalid");
270
+ }
271
+
272
+ function normalizeRequestAuthInput(input = {}) {
273
+ const capabilityId = assertIdentifier(input.capabilityId, "host_capability_id_invalid");
274
+ const adapterId = assertIdentifier(input.adapterId, "host_adapter_id_invalid");
275
+ const method = assertMethod(input.method);
276
+ const pathname = assertPathname(input.pathname);
277
+ const hostGeneration = assertHostGeneration(input.hostGeneration);
278
+ const timestampMs = assertTimestamp(input.timestampMs);
279
+ const nonce = assertNonce(input.nonce);
280
+ const secretBuffer = assertSecretBuffer(input.secretBuffer);
281
+ const bodySha256 = sha256RawBody(input.rawBody);
282
+ const message = [
283
+ HELLOLYNK_HOST_REQUEST_AUTH_DOMAIN,
284
+ capabilityId,
285
+ adapterId,
286
+ method,
287
+ pathname,
288
+ hostGeneration,
289
+ String(timestampMs),
290
+ nonce,
291
+ bodySha256,
292
+ ].join("\n");
293
+ return {
294
+ capabilityId,
295
+ adapterId,
296
+ method,
297
+ pathname,
298
+ hostGeneration,
299
+ timestampMs,
300
+ nonce,
301
+ secretBuffer,
302
+ bodySha256,
303
+ message,
304
+ };
305
+ }
306
+
307
+ function assertSecretBuffer(value) {
308
+ const secret = Buffer.isBuffer(value)
309
+ ? Buffer.from(value)
310
+ : value instanceof Uint8Array
311
+ ? Buffer.from(value.buffer, value.byteOffset, value.byteLength)
312
+ : null;
313
+ if (!secret || secret.length < 32 || secret.length > 128) {
314
+ throw codeError("host_capability_secret_invalid");
315
+ }
316
+ return secret;
317
+ }
318
+
319
+ function assertTimestamp(value) {
320
+ if (typeof value !== "number" && !/^(?:0|[1-9][0-9]{0,15})$/.test(String(value || ""))) {
321
+ throw codeError("host_timestamp_invalid");
322
+ }
323
+ const timestamp = typeof value === "number" ? value : Number(value);
324
+ if (!Number.isSafeInteger(timestamp) || timestamp < 0) throw codeError("host_timestamp_invalid");
325
+ return timestamp;
326
+ }
327
+
328
+ function normalizeNow(clock) {
329
+ if (clock == null) return () => Date.now();
330
+ if (typeof clock === "function") return clock;
331
+ if (typeof clock?.now === "function") return () => clock.now();
332
+ throw codeError("host_clock_invalid");
333
+ }
334
+
335
+ function normalizePositiveInteger(value, fallback, minimum, maximum) {
336
+ const normalized = Number(value ?? fallback);
337
+ if (!Number.isSafeInteger(normalized) || normalized < minimum || normalized > maximum) {
338
+ throw codeError("host_limit_invalid");
339
+ }
340
+ return normalized;
341
+ }
342
+
343
+ function codeError(code) {
344
+ const error = new Error(code);
345
+ error.code = code;
346
+ return error;
347
+ }