openmeld 0.3.91 → 0.3.95

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.
@@ -2,9 +2,66 @@
2
2
 
3
3
  import { Nt as openMeldRootDir, _n as __exportAll } from "./base-url-Cv9x5Es9.js";
4
4
  import { t as CURRENT_DAEMON_EXECUTION_CONTRACT_EPOCH } from "./runtime-transport-J50KvRbm.js";
5
+ import { createRequire } from "node:module";
6
+ import { z } from "zod/v4";
5
7
  import { join, resolve } from "node:path";
6
8
  import { createHash, randomUUID } from "node:crypto";
7
- import { mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
9
+ import { chmod, mkdir, open, readFile, rename, rm, writeFile } from "node:fs/promises";
10
+ import { spawn } from "node:child_process";
11
+ import { fileURLToPath } from "node:url";
12
+ //#region ../../packages/schemas/dist/schemas/local-machine/macos-keychain-helper.js
13
+ const macOsKeychainServiceSchema = z.string().trim().min(1).max(512);
14
+ const macOsKeychainAccountSchema = z.string().trim().min(1).max(512);
15
+ const macOsKeychainAccessTokenSchema = z.string().min(1).max(65536);
16
+ const macOsKeychainHelperOperationSchema = z.enum([
17
+ "store",
18
+ "read",
19
+ "delete"
20
+ ]);
21
+ const macOsKeychainHelperRequestSchema = z.discriminatedUnion("operation", [
22
+ z.strictObject({
23
+ schemaVersion: z.literal(1),
24
+ operation: z.literal("store"),
25
+ service: macOsKeychainServiceSchema,
26
+ account: macOsKeychainAccountSchema,
27
+ accessToken: macOsKeychainAccessTokenSchema
28
+ }),
29
+ z.strictObject({
30
+ schemaVersion: z.literal(1),
31
+ operation: z.literal("read"),
32
+ service: macOsKeychainServiceSchema,
33
+ account: macOsKeychainAccountSchema
34
+ }),
35
+ z.strictObject({
36
+ schemaVersion: z.literal(1),
37
+ operation: z.literal("delete"),
38
+ service: macOsKeychainServiceSchema,
39
+ account: macOsKeychainAccountSchema
40
+ })
41
+ ]);
42
+ const macOsKeychainHelperMutationSuccessSchema = z.strictObject({
43
+ schemaVersion: z.literal(1),
44
+ ok: z.literal(true),
45
+ operation: z.enum(["store", "delete"])
46
+ });
47
+ const macOsKeychainHelperReadSuccessSchema = z.strictObject({
48
+ schemaVersion: z.literal(1),
49
+ ok: z.literal(true),
50
+ operation: z.literal("read"),
51
+ accessToken: z.union([macOsKeychainAccessTokenSchema, z.null()])
52
+ });
53
+ const macOsKeychainHelperErrorSchema = z.strictObject({
54
+ schemaVersion: z.literal(1),
55
+ ok: z.literal(false),
56
+ operation: macOsKeychainHelperOperationSchema,
57
+ errorMessage: z.string().trim().min(1).max(2048)
58
+ });
59
+ const macOsKeychainHelperResponseSchema = z.union([
60
+ macOsKeychainHelperMutationSuccessSchema,
61
+ macOsKeychainHelperReadSuccessSchema,
62
+ macOsKeychainHelperErrorSchema
63
+ ]);
64
+ //#endregion
8
65
  //#region src/strategy-constants.ts
9
66
  const DEFAULT_GATEWAY_CHAIN_TIMEOUT_MS = 3e4;
10
67
  const DEFAULT_REMOTE_SESSION_TIMEOUT_MS = 8e3;
@@ -31,6 +88,234 @@ const HEARTBEAT_RESPONSE_TIMEOUT_MS = 15e3;
31
88
  const DAEMON_RUNTIME_CONTRACT_EPOCH = CURRENT_DAEMON_EXECUTION_CONTRACT_EPOCH;
32
89
  const OPENCLAW_CLI_TIMEOUT_MS = 3e4;
33
90
  //#endregion
91
+ //#region src/runtime/distribution.ts
92
+ const BINARY_DISTRIBUTION = "binary";
93
+ const NPM_DISTRIBUTION = "npm";
94
+ /**
95
+ * The distribution form this CLI build was compiled for. Falls back to `npm`
96
+ * when the marker is absent (e.g. under Vitest, where no build-time define
97
+ * runs), which keeps the safe, path-independent default.
98
+ */
99
+ function resolveOpenMeldDistribution() {
100
+ return NPM_DISTRIBUTION;
101
+ }
102
+ function isBinaryDistribution() {
103
+ return resolveOpenMeldDistribution() === BINARY_DISTRIBUTION;
104
+ }
105
+ //#endregion
106
+ //#region src/config/macos-native-keychain.ts
107
+ const MAC_OS_KEYCHAIN_HELPER_ARG = "__openmeld_macos_keychain_helper";
108
+ const HELPER_OUTPUT_MAX_BYTES = 128 * 1024;
109
+ let loadedAddon = null;
110
+ let unresponsiveKeychainError = null;
111
+ async function storeMacOsNativeKeychainToken(input) {
112
+ if (isBinaryDistribution()) {
113
+ await runBoundedMacOsNativeKeychainRequest({
114
+ operation: "store",
115
+ service: input.service,
116
+ account: input.account,
117
+ accessToken: input.accessToken
118
+ });
119
+ return;
120
+ }
121
+ (await loadAddon()).store(input.service, input.account, input.accessToken);
122
+ }
123
+ async function readMacOsNativeKeychainToken(input) {
124
+ if (isBinaryDistribution()) return await runBoundedMacOsNativeKeychainRequest({
125
+ operation: "read",
126
+ service: input.service,
127
+ account: input.account
128
+ });
129
+ return (await loadAddon()).read(input.service, input.account);
130
+ }
131
+ async function deleteMacOsNativeKeychainToken(input) {
132
+ if (isBinaryDistribution()) {
133
+ await runBoundedMacOsNativeKeychainRequest({
134
+ operation: "delete",
135
+ service: input.service,
136
+ account: input.account
137
+ });
138
+ return;
139
+ }
140
+ (await loadAddon()).remove(input.service, input.account);
141
+ }
142
+ async function runMacOsNativeKeychainRequestInChild(input, options = {}) {
143
+ const request = macOsKeychainHelperRequestSchema.parse({
144
+ schemaVersion: 1,
145
+ ...input
146
+ });
147
+ const timeoutMs = options.timeoutMs ?? 5e3;
148
+ if (!(Number.isSafeInteger(timeoutMs) && timeoutMs > 0)) throw new Error("macOS Keychain helper timeout must be a positive integer");
149
+ return await new Promise((resolve, reject) => {
150
+ const child = spawn(process.execPath, [MAC_OS_KEYCHAIN_HELPER_ARG], {
151
+ env: process.env,
152
+ shell: false,
153
+ stdio: [
154
+ "pipe",
155
+ "pipe",
156
+ "pipe"
157
+ ],
158
+ windowsHide: true
159
+ });
160
+ let settled = false;
161
+ let stdout = "";
162
+ let stderr = "";
163
+ const clearDeadline = () => {
164
+ clearTimeout(deadline);
165
+ };
166
+ const rejectOnce = (error) => {
167
+ if (settled) return;
168
+ settled = true;
169
+ clearDeadline();
170
+ reject(error);
171
+ };
172
+ const deadline = setTimeout(() => {
173
+ if (settled) return;
174
+ settled = true;
175
+ child.kill("SIGKILL");
176
+ reject(new MacOsNativeKeychainTimeoutError(`macOS Keychain did not respond within ${formatTimeout(timeoutMs)}`));
177
+ }, timeoutMs);
178
+ child.stdout.setEncoding("utf8");
179
+ child.stderr.setEncoding("utf8");
180
+ child.stdout.on("data", (chunk) => {
181
+ stdout += String(chunk);
182
+ if (Buffer.byteLength(stdout, "utf8") > HELPER_OUTPUT_MAX_BYTES) {
183
+ child.kill("SIGKILL");
184
+ rejectOnce(/* @__PURE__ */ new Error("macOS Keychain helper output was too large"));
185
+ }
186
+ });
187
+ child.stderr.on("data", (chunk) => {
188
+ stderr += String(chunk);
189
+ if (Buffer.byteLength(stderr, "utf8") > HELPER_OUTPUT_MAX_BYTES) stderr = stderr.slice(-131072);
190
+ });
191
+ child.once("error", (error) => {
192
+ rejectOnce(/* @__PURE__ */ new Error(`macOS Keychain helper could not start: ${toErrorMessage$1(error)}`));
193
+ });
194
+ child.stdin.once("error", (error) => {
195
+ rejectOnce(/* @__PURE__ */ new Error(`macOS Keychain helper input failed: ${toErrorMessage$1(error)}`));
196
+ });
197
+ child.once("close", (code) => {
198
+ if (settled) return;
199
+ clearDeadline();
200
+ settled = true;
201
+ try {
202
+ resolve(parseMacOsKeychainHelperResult({
203
+ code,
204
+ operation: request.operation,
205
+ stderr,
206
+ stdout
207
+ }));
208
+ } catch (error) {
209
+ reject(toError(error));
210
+ }
211
+ });
212
+ child.stdin.end(JSON.stringify(request), "utf8");
213
+ });
214
+ }
215
+ async function runMacOsNativeKeychainHelperIfRequested(argv = process.argv) {
216
+ if (!argv.includes(MAC_OS_KEYCHAIN_HELPER_ARG)) return false;
217
+ if (!(isBinaryDistribution() && process.platform === "darwin")) throw new Error("the internal macOS Keychain helper is only available in the macOS binary");
218
+ const rawRequest = await readHelperStdin();
219
+ let json;
220
+ try {
221
+ json = JSON.parse(rawRequest);
222
+ } catch {
223
+ throw new Error("invalid macOS Keychain helper request");
224
+ }
225
+ const request = macOsKeychainHelperRequestSchema.safeParse(json);
226
+ if (!request.success) throw new Error("invalid macOS Keychain helper request");
227
+ const response = await executeHelperRequest(request.data).catch((error) => ({
228
+ schemaVersion: 1,
229
+ ok: false,
230
+ operation: request.data.operation,
231
+ errorMessage: truncateErrorMessage(toErrorMessage$1(error))
232
+ }));
233
+ process.stdout.write(JSON.stringify(response));
234
+ return true;
235
+ }
236
+ async function runBoundedMacOsNativeKeychainRequest(input) {
237
+ if (unresponsiveKeychainError) throw unresponsiveKeychainError;
238
+ try {
239
+ if (input.operation === "read") return await runMacOsNativeKeychainRequestInChild(input);
240
+ await runMacOsNativeKeychainRequestInChild(input);
241
+ } catch (error) {
242
+ if (error instanceof MacOsNativeKeychainTimeoutError) unresponsiveKeychainError = error;
243
+ throw error;
244
+ }
245
+ }
246
+ function parseMacOsKeychainHelperResult(input) {
247
+ if (input.code !== 0) throw new Error(`macOS Keychain helper exited with code ${input.code ?? "unknown"}${input.stderr.trim() ? `: ${input.stderr.trim()}` : ""}`);
248
+ let rawResponse;
249
+ try {
250
+ rawResponse = JSON.parse(input.stdout);
251
+ } catch {
252
+ throw new Error("macOS Keychain helper returned an invalid response");
253
+ }
254
+ const parsed = macOsKeychainHelperResponseSchema.safeParse(rawResponse);
255
+ if (!(parsed.success && parsed.data.operation === input.operation)) throw new Error("macOS Keychain helper returned an invalid response");
256
+ if (!parsed.data.ok) throw new Error(parsed.data.errorMessage);
257
+ return parsed.data.operation === "read" ? parsed.data.accessToken : void 0;
258
+ }
259
+ async function executeHelperRequest(input) {
260
+ const addon = await loadAddon();
261
+ if (input.operation === "store") {
262
+ addon.store(input.service, input.account, input.accessToken);
263
+ return {
264
+ schemaVersion: 1,
265
+ ok: true,
266
+ operation: "store"
267
+ };
268
+ }
269
+ if (input.operation === "delete") {
270
+ addon.remove(input.service, input.account);
271
+ return {
272
+ schemaVersion: 1,
273
+ ok: true,
274
+ operation: "delete"
275
+ };
276
+ }
277
+ return {
278
+ schemaVersion: 1,
279
+ ok: true,
280
+ operation: "read",
281
+ accessToken: addon.read(input.service, input.account)
282
+ };
283
+ }
284
+ async function readHelperStdin() {
285
+ let raw = "";
286
+ process.stdin.setEncoding("utf8");
287
+ for await (const chunk of process.stdin) {
288
+ raw += String(chunk);
289
+ if (Buffer.byteLength(raw, "utf8") > HELPER_OUTPUT_MAX_BYTES) throw new Error("macOS Keychain helper request was too large");
290
+ }
291
+ return raw;
292
+ }
293
+ function truncateErrorMessage(message) {
294
+ return (message.trim() || "macOS Keychain operation failed").slice(0, 2048);
295
+ }
296
+ function formatTimeout(timeoutMs) {
297
+ return timeoutMs % 1e3 === 0 ? `${timeoutMs / 1e3} seconds` : `${timeoutMs} ms`;
298
+ }
299
+ function toErrorMessage$1(error) {
300
+ return error instanceof Error ? error.message : String(error);
301
+ }
302
+ function toError(error) {
303
+ return error instanceof Error ? error : new Error(String(error));
304
+ }
305
+ var MacOsNativeKeychainTimeoutError = class extends Error {
306
+ name = "MacOsNativeKeychainTimeoutError";
307
+ };
308
+ async function loadAddon() {
309
+ if (loadedAddon) return loadedAddon;
310
+ if (process.platform !== "darwin") throw new Error("macOS Keychain is only available on macOS");
311
+ if (isBinaryDistribution()) {
312
+ loadedAddon = (await import("./config/macos-native-keychain-embedded")).loadEmbeddedMacOsKeychainAddon();
313
+ return loadedAddon;
314
+ }
315
+ loadedAddon = createRequire(import.meta.url)(fileURLToPath(new URL("./native/openmeld-keychain.node", import.meta.url)));
316
+ return loadedAddon;
317
+ }
318
+ //#endregion
34
319
  //#region src/config/token-store.ts
35
320
  const TOKEN_STORE_KEYCHAIN_SERVICE = "sh.openmeld.auth.token";
36
321
  const INSECURE_FALLBACK_ENV_KEY = "OPENMELD_AUTH_ALLOW_INSECURE_FILE_TOKEN";
@@ -44,6 +329,7 @@ const EXEC_FILE_BASE_OPTIONS = {
44
329
  timeout: COMMAND_TIMEOUT_MS
45
330
  };
46
331
  let insecureFallbackWarningShown = false;
332
+ let macOsPrivateStorageWarningShown = false;
47
333
  async function storeAccessToken(input) {
48
334
  const key = buildTokenKey({
49
335
  authBaseUrl: input.authBaseUrl,
@@ -60,8 +346,13 @@ async function storeAccessToken(input) {
60
346
  };
61
347
  }
62
348
  if (process.platform === "darwin") try {
63
- const account = buildMacOsAccount(key);
64
- await setMacOsKeychainToken({
349
+ const account = buildUniqueMacOsAccount(key);
350
+ if (shouldUseNativeMacOsKeychain()) await storeMacOsNativeKeychainToken({
351
+ account,
352
+ service: TOKEN_STORE_KEYCHAIN_SERVICE,
353
+ accessToken: input.accessToken
354
+ });
355
+ else await setMacOsKeychainToken({
65
356
  service: TOKEN_STORE_KEYCHAIN_SERVICE,
66
357
  account,
67
358
  accessToken: input.accessToken
@@ -82,7 +373,16 @@ async function storeAccessToken(input) {
82
373
  key
83
374
  };
84
375
  }
85
- throw new Error(`failed to store access token in macOS Keychain: ${toErrorMessage(error)}`);
376
+ const privateKey = buildUniqueTokenFileKey(key);
377
+ await setInsecureFileToken({
378
+ key: privateKey,
379
+ accessToken: input.accessToken
380
+ });
381
+ warnMacOsPrivateStorageFallback(error);
382
+ return {
383
+ provider: "insecure-file",
384
+ key: privateKey
385
+ };
86
386
  }
87
387
  if (process.platform === "win32") try {
88
388
  await setWindowsDpapiToken({
@@ -120,7 +420,7 @@ async function storeAccessToken(input) {
120
420
  }
121
421
  async function readAccessToken(ref) {
122
422
  try {
123
- if (ref.provider === "macos-keychain") return toAccessTokenReadResult(await getMacOsKeychainToken(ref));
423
+ if (ref.provider === "macos-keychain") return toAccessTokenReadResult(shouldUseNativeMacOsKeychain() ? await readMacOsNativeKeychainToken(ref) : await getMacOsKeychainToken(ref));
124
424
  if (ref.provider === "windows-dpapi") return toAccessTokenReadResult(await getWindowsDpapiToken(ref));
125
425
  if (ref.provider === "insecure-file") return toAccessTokenReadResult(await getInsecureFileToken(ref));
126
426
  return { status: "missing" };
@@ -133,7 +433,7 @@ async function readAccessToken(ref) {
133
433
  }
134
434
  async function deleteAccessToken(ref) {
135
435
  if (ref.provider === "macos-keychain") {
136
- await deleteMacOsKeychainToken(ref).catch(() => void 0);
436
+ await (shouldUseNativeMacOsKeychain() ? deleteMacOsNativeKeychainToken(ref) : deleteMacOsKeychainToken(ref)).catch(() => void 0);
137
437
  return;
138
438
  }
139
439
  if (ref.provider === "windows-dpapi") {
@@ -146,7 +446,7 @@ function isStoredTokenRef(value) {
146
446
  if (!(value && typeof value === "object")) return false;
147
447
  const record = value;
148
448
  const provider = normalizeString(record.provider);
149
- if (provider === "macos-keychain") return Boolean(normalizeString(record.service) && normalizeString(record.account));
449
+ if (provider === "macos-keychain") return Boolean(normalizeString(record.service) && normalizeString(record.account) && record.accessGroup === void 0);
150
450
  if (provider === "windows-dpapi" || provider === "insecure-file") return normalizeTokenFileKey(record.key) !== null;
151
451
  return false;
152
452
  }
@@ -154,8 +454,14 @@ function buildTokenKey(input) {
154
454
  const rootDir = resolve(openMeldRootDir());
155
455
  return createHash("sha256").update(`${input.clientId}\n${input.authBaseUrl}\n${rootDir}`).digest("hex");
156
456
  }
157
- function buildMacOsAccount(key) {
158
- return `openmeld-auth-${key}`;
457
+ function buildUniqueMacOsAccount(key) {
458
+ return `openmeld-auth-${key}-${randomUUID()}`;
459
+ }
460
+ function buildUniqueTokenFileKey(key) {
461
+ return createHash("sha256").update(`${key}\n${randomUUID()}`).digest("hex");
462
+ }
463
+ function shouldUseNativeMacOsKeychain() {
464
+ return isBinaryDistribution();
159
465
  }
160
466
  async function setMacOsKeychainToken(input) {
161
467
  await runCommand("security", [
@@ -218,11 +524,13 @@ async function deleteWindowsDpapiToken(input) {
218
524
  await rm(windowsDpapiTokenPath(input.key), { force: true });
219
525
  }
220
526
  async function setInsecureFileToken(input) {
221
- await mkdir(tokenDirectoryPath(), { recursive: true });
222
- await writeFile(insecureTokenPath(input.key), `${input.accessToken}\n`, {
527
+ await ensurePrivateTokenDirectory();
528
+ const path = insecureTokenPath(input.key);
529
+ await writeFile(path, `${input.accessToken}\n`, {
223
530
  encoding: "utf8",
224
531
  mode: 384
225
532
  });
533
+ if (process.platform !== "win32") await chmod(path, 384);
226
534
  }
227
535
  async function getInsecureFileToken(input) {
228
536
  const raw = await readFile(insecureTokenPath(input.key), "utf8").catch((error) => {
@@ -252,6 +560,11 @@ function allowInsecureFallback() {
252
560
  if (fallbackEnabled) warnInsecureFallback("platform");
253
561
  return fallbackEnabled;
254
562
  }
563
+ function warnMacOsPrivateStorageFallback(error) {
564
+ if (macOsPrivateStorageWarningShown) return;
565
+ macOsPrivateStorageWarningShown = true;
566
+ console.warn(`[openmeld auth] macOS Keychain is unavailable. OpenMeld saved this session in a private file protected for your macOS user account, so setup can continue. A future successful setup or login will move the session back to Keychain. Details: ${toErrorMessage(error)}`);
567
+ }
255
568
  function warnInsecureFallback(reason) {
256
569
  if (insecureFallbackWarningShown) return;
257
570
  insecureFallbackWarningShown = true;
@@ -264,6 +577,14 @@ function shouldForceInsecureStore() {
264
577
  function isNativeSecureStorePlatform() {
265
578
  return process.platform === "darwin" || process.platform === "win32";
266
579
  }
580
+ async function ensurePrivateTokenDirectory() {
581
+ const directory = tokenDirectoryPath();
582
+ await mkdir(directory, {
583
+ recursive: true,
584
+ mode: 448
585
+ });
586
+ if (process.platform !== "win32") await chmod(directory, 448);
587
+ }
267
588
  async function runPowerShellScript(script, token, entropy) {
268
589
  const payload = JSON.stringify({
269
590
  token,
@@ -415,6 +736,7 @@ var auth_session_exports = /* @__PURE__ */ __exportAll({
415
736
  updateAuthSessionActiveOrganization: () => updateAuthSessionActiveOrganization
416
737
  });
417
738
  const TRAILING_SLASHES_RE = /\/+$/u;
739
+ let cachedAuthSession = null;
418
740
  async function getAuthSessionState(options = {}) {
419
741
  const localState = await getLocalAuthSessionState();
420
742
  switch (localState.state) {
@@ -445,6 +767,7 @@ async function setAuthSession(input) {
445
767
  if (!authBaseUrl) throw new Error("auth base URL is required");
446
768
  const clientId = String(input.clientId ?? "").trim();
447
769
  if (!clientId) throw new Error("client_id is required");
770
+ const previousTokenRef = normalizeTokenRef((await readSessionPayload())?.tokenRef);
448
771
  const tokenRef = await storeAccessToken({
449
772
  accessToken,
450
773
  authBaseUrl,
@@ -465,11 +788,23 @@ async function setAuthSession(input) {
465
788
  const path = authSessionPath();
466
789
  await mkdir(join(openMeldRootDir(), "auth"), { recursive: true });
467
790
  try {
791
+ await assertStoredAccessTokenReloads({
792
+ accessToken,
793
+ tokenRef
794
+ });
468
795
  await writeSessionPayloadAtomically(path, payload);
469
796
  } catch (error) {
470
797
  await deleteAccessToken(tokenRef).catch(() => void 0);
471
798
  throw error;
472
799
  }
800
+ cacheAuthSession({
801
+ payload,
802
+ session: buildStoredAuthSession({
803
+ accessToken,
804
+ payload
805
+ })
806
+ });
807
+ if (previousTokenRef && !areStoredTokenRefsEqual(previousTokenRef, tokenRef)) await deleteAccessToken(previousTokenRef).catch(() => void 0);
473
808
  }
474
809
  async function getAuthSession() {
475
810
  const localState = await getLocalAuthSessionState();
@@ -515,8 +850,17 @@ async function updateAuthSessionActiveOrganization(activeOrganization) {
515
850
  ...buildActiveOrganizationPayload(activeOrganization)
516
851
  };
517
852
  await writeSessionPayloadAtomically(authSessionPath(), nextPayload);
853
+ const currentCachedSession = readCachedAuthSession(payload);
854
+ if (currentCachedSession) cacheAuthSession({
855
+ payload: nextPayload,
856
+ session: buildStoredAuthSession({
857
+ accessToken: currentCachedSession.accessToken,
858
+ payload: nextPayload
859
+ })
860
+ });
518
861
  }
519
862
  async function clearAuthSession() {
863
+ cachedAuthSession = null;
520
864
  const payload = await readSessionPayload();
521
865
  if (payload?.v === 1 && isStoredTokenRef(payload.tokenRef)) await deleteAccessToken(payload.tokenRef).catch(() => void 0);
522
866
  await removeSessionFileBestEffort();
@@ -543,30 +887,37 @@ async function getLocalAuthSessionState() {
543
887
  state: "invalid",
544
888
  session: null
545
889
  };
546
- const accessToken = await readAccessToken(tokenRef);
547
- if (accessToken.status === "missing") return {
548
- reasonCode: "session_token_missing",
549
- state: "invalid",
550
- session: null
551
- };
552
- if (accessToken.status === "unavailable") return {
553
- errorMessage: accessToken.errorMessage,
554
- reasonCode: "session_token_unavailable",
555
- state: "invalid",
556
- session: null
557
- };
558
- const session = {
559
- v: 1,
560
- accessToken: accessToken.accessToken,
561
- tokenType,
562
- authBaseUrl,
563
- clientId,
564
- createdAt,
565
- ...typeof payload.expiresAt === "string" && payload.expiresAt.trim() ? { expiresAt: payload.expiresAt.trim() } : {},
566
- ...typeof payload.scope === "string" && payload.scope.trim() ? { scope: payload.scope.trim() } : {},
567
- ...buildAuthUserPayload(payload.user),
568
- ...buildActiveOrganizationPayload(payload.activeOrganization)
569
- };
890
+ let session = readCachedAuthSession(payload);
891
+ if (!session) {
892
+ const accessToken = await readAccessToken(tokenRef);
893
+ if (accessToken.status === "missing") return {
894
+ reasonCode: "session_token_missing",
895
+ state: "invalid",
896
+ session: null
897
+ };
898
+ if (accessToken.status === "unavailable") return {
899
+ errorMessage: accessToken.errorMessage,
900
+ reasonCode: "session_token_unavailable",
901
+ state: "invalid",
902
+ session: null
903
+ };
904
+ session = buildStoredAuthSession({
905
+ accessToken: accessToken.accessToken,
906
+ payload: {
907
+ ...payload,
908
+ v: 1,
909
+ tokenRef,
910
+ tokenType,
911
+ authBaseUrl,
912
+ clientId,
913
+ createdAt
914
+ }
915
+ });
916
+ cacheAuthSession({
917
+ payload,
918
+ session
919
+ });
920
+ }
570
921
  if (isExpired(session.expiresAt)) return {
571
922
  reasonCode: "session_expired",
572
923
  state: "expired",
@@ -577,6 +928,42 @@ async function getLocalAuthSessionState() {
577
928
  session
578
929
  };
579
930
  }
931
+ async function assertStoredAccessTokenReloads(input) {
932
+ const reloaded = await readAccessToken(input.tokenRef);
933
+ if (reloaded.status === "found" && reloaded.accessToken === input.accessToken) return;
934
+ if (reloaded.status === "unavailable") throw new Error(`stored access token could not be reloaded: ${reloaded.errorMessage}`);
935
+ throw new Error("stored access token could not be reloaded");
936
+ }
937
+ function buildStoredAuthSession(input) {
938
+ return {
939
+ v: 1,
940
+ accessToken: input.accessToken,
941
+ tokenType: input.payload.tokenType,
942
+ authBaseUrl: input.payload.authBaseUrl,
943
+ clientId: input.payload.clientId,
944
+ createdAt: input.payload.createdAt,
945
+ ...typeof input.payload.expiresAt === "string" && input.payload.expiresAt.trim() ? { expiresAt: input.payload.expiresAt.trim() } : {},
946
+ ...typeof input.payload.scope === "string" && input.payload.scope.trim() ? { scope: input.payload.scope.trim() } : {},
947
+ ...buildAuthUserPayload(input.payload.user),
948
+ ...buildActiveOrganizationPayload(input.payload.activeOrganization)
949
+ };
950
+ }
951
+ function cacheAuthSession(input) {
952
+ cachedAuthSession = {
953
+ payloadKey: buildAuthSessionPayloadKey(input.payload),
954
+ session: input.session
955
+ };
956
+ }
957
+ function readCachedAuthSession(payload) {
958
+ const payloadKey = buildAuthSessionPayloadKey(payload);
959
+ return cachedAuthSession?.payloadKey === payloadKey ? cachedAuthSession.session : null;
960
+ }
961
+ function buildAuthSessionPayloadKey(payload) {
962
+ return `${authSessionPath()}\n${JSON.stringify(payload)}`;
963
+ }
964
+ function areStoredTokenRefsEqual(left, right) {
965
+ return JSON.stringify(left) === JSON.stringify(right);
966
+ }
580
967
  function normalizeTokenRef(input) {
581
968
  if (!isStoredTokenRef(input)) return null;
582
969
  return input;
@@ -741,6 +1128,6 @@ async function removeSessionFileBestEffort() {
741
1128
  await rm(authSessionPath(), { force: true }).catch(() => void 0);
742
1129
  }
743
1130
  //#endregion
744
- export { RUNTIME_AGENT_CONTROLLER_REPORT_SYNC_RETRY_INTERVAL_MS as A, MIN_SPACE_REQUEST_TIMEOUT_MS as C, REGISTER_RESPONSE_TIMEOUT_MS as D, PROVIDER_CONVERSATION_PROOF_SYNC_RETRY_INTERVAL_MS as E, ROUTE_CATALOG_LOAD_TIMEOUT_MS as O, MIN_HEARTBEAT_INTERVAL_MS as S, PROVIDER_CONVERSATION_PROOF_SYNC_INTERVAL_MS as T, DEFAULT_HEARTBEAT_INTERVAL_MS as _, getAuthSessionState as a, MAX_HEARTBEAT_INTERVAL_MS as b, setAuthSession as c, CATALOG_SYNC_SIGNAL_POLL_INTERVAL_MS as d, DAEMON_RUNTIME_CONTRACT_EPOCH as f, DEFAULT_GATEWAY_CHAIN_TIMEOUT_MS as g, DAEMON_STREAM_KEEPALIVE_PONG_TIMEOUT_MS as h, getAuthSessionMetadata as i, RUNTIME_STATE_PERSIST_MIN_INTERVAL_MS as j, RUNTIME_AGENT_CONTROLLER_REPORT_SYNC_INTERVAL_MS as k, updateAuthSessionActiveOrganization as l, DAEMON_STREAM_KEEPALIVE_INTERVAL_MS as m, clearAuthSession as n, getCurrentAuthOwnerUserId as o, DAEMON_STREAM_CONNECT_TIMEOUT_MS as p, getAuthSession as r, normalizeStoredActiveOrganization as s, auth_session_exports as t, CATALOG_SYNC_RETRY_INTERVAL_MS as u, DEFAULT_SPACE_REQUEST_TIMEOUT_MS as v, OPENCLAW_CLI_TIMEOUT_MS as w, MAX_SPACE_REQUEST_TIMEOUT_MS as x, HEARTBEAT_RESPONSE_TIMEOUT_MS as y };
1131
+ export { REGISTER_RESPONSE_TIMEOUT_MS as A, MAX_HEARTBEAT_INTERVAL_MS as C, OPENCLAW_CLI_TIMEOUT_MS as D, MIN_SPACE_REQUEST_TIMEOUT_MS as E, RUNTIME_AGENT_CONTROLLER_REPORT_SYNC_INTERVAL_MS as M, RUNTIME_AGENT_CONTROLLER_REPORT_SYNC_RETRY_INTERVAL_MS as N, PROVIDER_CONVERSATION_PROOF_SYNC_INTERVAL_MS as O, RUNTIME_STATE_PERSIST_MIN_INTERVAL_MS as P, HEARTBEAT_RESPONSE_TIMEOUT_MS as S, MIN_HEARTBEAT_INTERVAL_MS as T, DAEMON_STREAM_KEEPALIVE_INTERVAL_MS as _, getAuthSessionState as a, DEFAULT_HEARTBEAT_INTERVAL_MS as b, setAuthSession as c, isBinaryDistribution as d, resolveOpenMeldDistribution as f, DAEMON_STREAM_CONNECT_TIMEOUT_MS as g, DAEMON_RUNTIME_CONTRACT_EPOCH as h, getAuthSessionMetadata as i, ROUTE_CATALOG_LOAD_TIMEOUT_MS as j, PROVIDER_CONVERSATION_PROOF_SYNC_RETRY_INTERVAL_MS as k, updateAuthSessionActiveOrganization as l, CATALOG_SYNC_SIGNAL_POLL_INTERVAL_MS as m, clearAuthSession as n, getCurrentAuthOwnerUserId as o, CATALOG_SYNC_RETRY_INTERVAL_MS as p, getAuthSession as r, normalizeStoredActiveOrganization as s, auth_session_exports as t, runMacOsNativeKeychainHelperIfRequested as u, DAEMON_STREAM_KEEPALIVE_PONG_TIMEOUT_MS as v, MAX_SPACE_REQUEST_TIMEOUT_MS as w, DEFAULT_SPACE_REQUEST_TIMEOUT_MS as x, DEFAULT_GATEWAY_CHAIN_TIMEOUT_MS as y };
745
1132
 
746
- //# sourceMappingURL=auth-session-73FalW41.js.map
1133
+ //# sourceMappingURL=auth-session-yymO5FGR.js.map