@rubytech/create-maxy-code 0.1.474 → 0.1.476

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 (138) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
  3. package/payload/platform/lib/storage-broker/dist/cf-exec.js +3 -2
  4. package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
  5. package/payload/platform/lib/storage-broker/src/cf-exec.ts +3 -2
  6. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +18 -9
  7. package/payload/platform/plugins/cloudflare/skills/calendar-site/template/schema.sql +13 -3
  8. package/payload/platform/plugins/docs/references/calendar-booking.md +2 -2
  9. package/payload/platform/plugins/docs/references/google-guide.md +15 -6
  10. package/payload/platform/plugins/google/.claude-plugin/plugin.json +1 -1
  11. package/payload/platform/plugins/google/PLUGIN.md +60 -12
  12. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts +2 -0
  13. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts.map +1 -0
  14. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js +229 -0
  15. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js.map +1 -0
  16. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +9 -9
  17. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -1
  18. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts +2 -0
  19. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts.map +1 -0
  20. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js +17 -0
  21. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js.map +1 -0
  22. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts +2 -0
  23. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts.map +1 -0
  24. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js +146 -0
  25. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js.map +1 -0
  26. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts +2 -0
  27. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts.map +1 -0
  28. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js +19 -0
  29. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js.map +1 -0
  30. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts +2 -0
  31. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts.map +1 -0
  32. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js +41 -0
  33. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js.map +1 -0
  34. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts +44 -0
  35. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts.map +1 -0
  36. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js +112 -0
  37. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js.map +1 -0
  38. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts +17 -0
  39. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts.map +1 -0
  40. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js +143 -0
  41. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js.map +1 -0
  42. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts +9 -0
  43. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts.map +1 -1
  44. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.js.map +1 -1
  45. package/payload/platform/plugins/google/mcp/dist/index.js +73 -5
  46. package/payload/platform/plugins/google/mcp/dist/index.js.map +1 -1
  47. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts +2 -0
  48. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts.map +1 -0
  49. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js +37 -0
  50. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js.map +1 -0
  51. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +20 -4
  52. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -1
  53. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +19 -9
  54. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -1
  55. package/payload/platform/plugins/google/references/auth.md +93 -14
  56. package/payload/platform/plugins/scheduling/PLUGIN.md +2 -2
  57. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js +158 -23
  58. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-reconcile.test.js.map +1 -1
  59. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.d.ts +2 -0
  60. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.d.ts.map +1 -0
  61. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.js +200 -0
  62. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/booking-schema-migration.test.js.map +1 -0
  63. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.d.ts +2 -0
  64. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.d.ts.map +1 -0
  65. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js +309 -0
  66. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/connector-sync-provision.test.js.map +1 -0
  67. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js +219 -19
  68. package/payload/platform/plugins/scheduling/mcp/dist/lib/__tests__/d1-command.test.js.map +1 -1
  69. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts +94 -11
  70. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.d.ts.map +1 -1
  71. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js +106 -22
  72. package/payload/platform/plugins/scheduling/mcp/dist/lib/booking-reconcile.js.map +1 -1
  73. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.d.ts +109 -0
  74. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.d.ts.map +1 -0
  75. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js +213 -0
  76. package/payload/platform/plugins/scheduling/mcp/dist/lib/connector-sync-provision.js.map +1 -0
  77. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts +80 -8
  78. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.d.ts.map +1 -1
  79. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js +202 -8
  80. package/payload/platform/plugins/scheduling/mcp/dist/lib/d1-command.js.map +1 -1
  81. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts +6 -4
  82. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.d.ts.map +1 -1
  83. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js +334 -142
  84. package/payload/platform/plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js.map +1 -1
  85. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +21 -3
  86. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
  87. package/payload/platform/services/claude-session-manager/dist/activity-rows.js +6 -2
  88. package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
  89. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
  90. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +43 -5
  91. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
  92. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +9 -0
  93. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -1
  94. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +78 -0
  95. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -1
  96. package/payload/server/{chunk-Y6V45R6M.js → chunk-LBCMFD4O.js} +173 -29
  97. package/payload/server/maxy-edge.js +1 -1
  98. package/payload/server/public/activity.html +6 -6
  99. package/payload/server/public/assets/{AdminLoginScreens-B44KbEuC.js → AdminLoginScreens-DximwPlS.js} +1 -1
  100. package/payload/server/public/assets/{AdminShell-BjxV2qkb.js → AdminShell-BehbH-Oa.js} +1 -1
  101. package/payload/server/public/assets/{Checkbox-DSeZNGNA.js → Checkbox-DM-eHqOS.js} +1 -1
  102. package/payload/server/public/assets/activity-hDwUeQd6.js +1 -0
  103. package/payload/server/public/assets/{admin-B4LpTCur.js → admin-CAkDnGdk.js} +1 -1
  104. package/payload/server/public/assets/{browser-CEFvaWwI.js → browser-DXl8hOoi.js} +1 -1
  105. package/payload/server/public/assets/{calendar-B3zo6V34.js → calendar-DP6hn4-6.js} +1 -1
  106. package/payload/server/public/assets/chat-DhOfVGYM.js +1 -0
  107. package/payload/server/public/assets/chevron-left-DYNBoLii.js +1 -0
  108. package/payload/server/public/assets/data-bq8fTo_s.js +1 -0
  109. package/payload/server/public/assets/{graph-RaOrnSf2.js → graph-CHcYoEJ5.js} +1 -1
  110. package/payload/server/public/assets/{graph-labels-GlTEIYJj.js → graph-labels-CZykslZM.js} +1 -1
  111. package/payload/server/public/assets/{maximize-2-CHDa8p5h.js → maximize-2-31AZEcMS.js} +1 -1
  112. package/payload/server/public/assets/{operator-DtqHY4jV.js → operator-BGGpdsO_.js} +1 -1
  113. package/payload/server/public/assets/{page-CkhFj8GQ.js → page-BloC6ygA.js} +1 -1
  114. package/payload/server/public/assets/{page-DxnWgPtd.js → page-DOeiiqbR.js} +1 -1
  115. package/payload/server/public/assets/{public-D5TUfQ3I.js → public-CGgO6IZv.js} +1 -1
  116. package/payload/server/public/assets/{rotate-ccw-BJjVAQQY.js → rotate-ccw-BlAi6iFg.js} +1 -1
  117. package/payload/server/public/assets/{tasks-CM9pYYG1.js → tasks-C1giFRRL.js} +1 -1
  118. package/payload/server/public/assets/{time-entry-format-C5RYEYjM.js → time-entry-format-CiUUQdq7.js} +1 -1
  119. package/payload/server/public/assets/{triangle-alert-DLfIsuo_.js → triangle-alert-CVqKuLoa.js} +1 -1
  120. package/payload/server/public/assets/{useCopyFeedback-7yKeiAzV.js → useCopyFeedback-ksyUe_g1.js} +1 -1
  121. package/payload/server/public/assets/{useSelectionMode-CWlh6AEq.js → useSelectionMode-BPrBkdTd.js} +1 -1
  122. package/payload/server/public/assets/{useSubAccountSwitcher-B2n9QPVI.css → useSubAccountSwitcher-K4kYeN6i.css} +1 -1
  123. package/payload/server/public/assets/{useVoiceRecorder-j3ZArZ2H.js → useVoiceRecorder-CTXP8oTW.js} +1 -1
  124. package/payload/server/public/browser.html +5 -5
  125. package/payload/server/public/calendar.html +6 -6
  126. package/payload/server/public/chat.html +12 -12
  127. package/payload/server/public/data.html +11 -11
  128. package/payload/server/public/graph.html +11 -11
  129. package/payload/server/public/index.html +14 -14
  130. package/payload/server/public/operator.html +14 -14
  131. package/payload/server/public/public.html +12 -12
  132. package/payload/server/public/tasks.html +5 -5
  133. package/payload/server/server.js +547 -423
  134. package/payload/server/public/assets/activity-CdipMTDp.js +0 -1
  135. package/payload/server/public/assets/chat-5tJdo9i_.js +0 -1
  136. package/payload/server/public/assets/chevron-left-BJllrPBj.js +0 -1
  137. package/payload/server/public/assets/data-Du79EgR-.js +0 -1
  138. /package/payload/server/public/assets/{useSubAccountSwitcher-CBlKgwms.js → useSubAccountSwitcher-DzgzTRRn.js} +0 -0
@@ -4,7 +4,7 @@ import { createHash } from "node:crypto";
4
4
  import { mkdtempSync } from "node:fs";
5
5
  import { tmpdir } from "node:os";
6
6
  import { join } from "node:path";
7
- import { newPkce, buildConsentUrl, runAccountRegisterStart, runAccountRegisterPoll, listConnected, CALENDAR_SCOPE, LOOPBACK_REDIRECT_URI, normalisePastedCode, runAccountRegisterSubmit, } from "../tools/account-register.js";
7
+ import { newPkce, newState, buildConsentUrl, runAccountRegisterStart, runAccountRegisterPoll, listConnected, CALENDAR_SCOPE, LOOPBACK_REDIRECT_URI, normalisePastedCode, runAccountRegisterSubmit, } from "../tools/account-register.js";
8
8
  import { TokenStore } from "../auth/token-store.js";
9
9
  import { PendingStore } from "../auth/pending-store.js";
10
10
  function newDir() {
@@ -20,7 +20,7 @@ test("consent URL carries offline access, forced consent, and the calendar scope
20
20
  clientId: "cid",
21
21
  state: "st",
22
22
  challenge: "ch",
23
- accountId: "acct1",
23
+ redirectUri: LOOPBACK_REDIRECT_URI,
24
24
  }));
25
25
  assert.equal(url.searchParams.get("access_type"), "offline");
26
26
  assert.equal(url.searchParams.get("prompt"), "consent");
@@ -37,7 +37,7 @@ test("redirect_uri carries no query string at all", () => {
37
37
  clientId: "cid",
38
38
  state: "nonce",
39
39
  challenge: "ch",
40
- accountId: "acct1",
40
+ redirectUri: LOOPBACK_REDIRECT_URI,
41
41
  }));
42
42
  const redirect = url.searchParams.get("redirect_uri");
43
43
  assert.ok(!redirect.includes("?"), `redirect_uri must have no query: ${redirect}`);
@@ -45,7 +45,7 @@ test("redirect_uri carries no query string at all", () => {
45
45
  });
46
46
  test("register stores the same opaque state it sends, and no account id", async () => {
47
47
  const dir = newDir();
48
- const res = await runAccountRegisterStart({ accountId: "acct1", accountsDir: dir, clientId: "cid" });
48
+ const res = await runAccountRegisterStart({ accountId: "acct1", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
49
49
  const sent = new URL(res.consentUrl).searchParams.get("state");
50
50
  const { PendingStore: PS } = await import("../auth/pending-store.js");
51
51
  assert.equal(new PS("acct1", dir).read()?.state, sent, "pending must hold exactly what was sent");
@@ -53,7 +53,7 @@ test("register stores the same opaque state it sends, and no account id", async
53
53
  });
54
54
  test("a second register while one is live is refused as in-progress", async () => {
55
55
  const dir = newDir();
56
- const args = { accountId: "acct1", accountsDir: dir, clientId: "cid" };
56
+ const args = { accountId: "acct1", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI };
57
57
  const first = await runAccountRegisterStart(args);
58
58
  assert.equal(first.status, "pending");
59
59
  assert.ok(first.consentUrl);
@@ -67,7 +67,7 @@ test("poll reports none with nothing connected and nothing pending", async () =>
67
67
  });
68
68
  test("poll reports pending while a fresh registration is live", async () => {
69
69
  const dir = newDir();
70
- await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "c" });
70
+ await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "c", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
71
71
  const res = await runAccountRegisterPoll({ accountId: "a", accountsDir: dir });
72
72
  assert.equal(res.status, "pending");
73
73
  });
@@ -80,7 +80,7 @@ test("listConnected reports a stored account by email", () => {
80
80
  assert.equal(connected[0].status, "ok");
81
81
  });
82
82
  test("consent redirect is the loopback IP literal, never localhost or https", () => {
83
- const url = new URL(buildConsentUrl({ clientId: "cid", state: "nonce", challenge: "ch", accountId: "a" }));
83
+ const url = new URL(buildConsentUrl({ clientId: "cid", state: "nonce", challenge: "ch", redirectUri: LOOPBACK_REDIRECT_URI }));
84
84
  const r = url.searchParams.get("redirect_uri");
85
85
  assert.equal(r, LOOPBACK_REDIRECT_URI);
86
86
  assert.equal(r, "http://127.0.0.1:8571");
@@ -116,7 +116,7 @@ test("normalisePastedCode never throws on a malformed percent escape", () => {
116
116
  });
117
117
  test("submit exchanges with the identical loopback redirect and stores the email", async () => {
118
118
  const dir = newDir();
119
- await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid" });
119
+ await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
120
120
  const calls = [];
121
121
  const fake = (async (url, init = {}) => {
122
122
  calls.push({ url: String(url), body: String(init.body ?? "") });
@@ -141,7 +141,7 @@ test("submit refuses when no registration is pending", async () => {
141
141
  });
142
142
  test("submit preserves the Google error body on a failed exchange", async () => {
143
143
  const dir = newDir();
144
- await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid" });
144
+ await runAccountRegisterStart({ accountId: "a", accountsDir: dir, clientId: "cid", state: newState(), redirectUri: LOOPBACK_REDIRECT_URI });
145
145
  const fake = (async () => new Response('{"error":"invalid_grant"}', { status: 400 }));
146
146
  await assert.rejects(() => runAccountRegisterSubmit({
147
147
  accountId: "a", accountsDir: dir, clientId: "c", clientSecret: "s", code: "4/0x", fetchImpl: fake,
@@ -1 +1 @@
1
- {"version":3,"file":"account-register.test.js","sourceRoot":"","sources":["../../src/__tests__/account-register.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-register.test.js","sourceRoot":"","sources":["../../src/__tests__/account-register.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=consent-url-redirect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-url-redirect.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/consent-url-redirect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { buildConsentUrl } from "../tools/account-register.js";
4
+ test("the consent URL carries the redirect it was given", () => {
5
+ const u = new URL(buildConsentUrl({ clientId: "cid", state: "s", challenge: "c", redirectUri: "http://127.0.0.1:54321" }));
6
+ assert.equal(u.searchParams.get("redirect_uri"), "http://127.0.0.1:54321");
7
+ });
8
+ test("the consent URL never uses the localhost hostname", () => {
9
+ const u = buildConsentUrl({
10
+ clientId: "cid",
11
+ state: "s",
12
+ challenge: "c",
13
+ redirectUri: "http://127.0.0.1:8571",
14
+ });
15
+ assert.ok(!u.includes("localhost"));
16
+ });
17
+ //# sourceMappingURL=consent-url-redirect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent-url-redirect.test.js","sourceRoot":"","sources":["../../src/__tests__/consent-url-redirect.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,MAAM,CAAC,GAAG,IAAI,GAAG,CACf,eAAe,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC,CACxG,CAAC;IACF,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,EAAE,wBAAwB,CAAC,CAAC;AAC7E,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,MAAM,CAAC,GAAG,eAAe,CAAC;QACxB,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,GAAG;QACV,SAAS,EAAE,GAAG;QACd,WAAW,EAAE,uBAAuB;KACrC,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC;AACtC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=loopback-listener.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback-listener.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/loopback-listener.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,146 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { createServer } from "node:http";
4
+ import { startLoopbackListener } from "../auth/loopback-listener.js";
5
+ async function get(url) {
6
+ const res = await fetch(url);
7
+ return { status: res.status, body: await res.text() };
8
+ }
9
+ /** A port is only proven released by rebinding it. A boolean the code under
10
+ * test sets would prove the code ran, not that the socket closed. */
11
+ async function isFree(port) {
12
+ return await new Promise((resolve) => {
13
+ const s = createServer();
14
+ s.once("error", () => resolve(false));
15
+ s.listen(port, "127.0.0.1", () => s.close(() => resolve(true)));
16
+ });
17
+ }
18
+ test("a matching state completes and the page names the account", async () => {
19
+ let seen = "";
20
+ const l = await startLoopbackListener({
21
+ accountId: "a",
22
+ state: "st-1",
23
+ onCode: async (code) => {
24
+ seen = code;
25
+ return { email: "kit@example.com" };
26
+ },
27
+ });
28
+ assert.ok(l);
29
+ const r = await get(`${l.redirectUri}/?state=st-1&code=xyz`);
30
+ assert.equal(r.status, 200);
31
+ assert.equal(seen, "xyz");
32
+ assert.match(r.body, /kit@example\.com/);
33
+ await l.close("test");
34
+ });
35
+ test("a mismatched state is refused and onCode never runs", async () => {
36
+ let ran = false;
37
+ const l = await startLoopbackListener({
38
+ accountId: "a",
39
+ state: "st-2",
40
+ onCode: async () => {
41
+ ran = true;
42
+ return { email: "x@y.z" };
43
+ },
44
+ });
45
+ assert.ok(l);
46
+ const r = await get(`${l.redirectUri}/?state=WRONG&code=xyz`);
47
+ assert.equal(r.status, 400);
48
+ assert.equal(ran, false);
49
+ await l.close("test");
50
+ });
51
+ test("an onCode failure renders Google's error rather than claiming success", async () => {
52
+ const l = await startLoopbackListener({
53
+ accountId: "a",
54
+ state: "st-3",
55
+ onCode: async () => {
56
+ throw new Error("token exchange failed (400): invalid_grant");
57
+ },
58
+ });
59
+ assert.ok(l);
60
+ const r = await get(`${l.redirectUri}/?state=st-3&code=xyz`);
61
+ assert.equal(r.status, 400);
62
+ assert.match(r.body, /invalid_grant/);
63
+ await l.close("test");
64
+ });
65
+ test("close releases the port", async () => {
66
+ const l = await startLoopbackListener({
67
+ accountId: "a",
68
+ state: "st-4",
69
+ onCode: async () => ({ email: "x@y.z" }),
70
+ });
71
+ assert.ok(l);
72
+ const port = l.port;
73
+ await l.close("test");
74
+ assert.equal(await isFree(port), true);
75
+ });
76
+ test("a completed exchange releases the port without an explicit close", async () => {
77
+ const l = await startLoopbackListener({
78
+ accountId: "a",
79
+ state: "st-5",
80
+ onCode: async () => ({ email: "x@y.z" }),
81
+ });
82
+ assert.ok(l);
83
+ const port = l.port;
84
+ await get(`${l.redirectUri}/?state=st-5&code=xyz`);
85
+ await new Promise((r) => setTimeout(r, 50));
86
+ assert.equal(await isFree(port), true);
87
+ });
88
+ test("a reload during the exchange does not run onCode twice", async () => {
89
+ let calls = 0;
90
+ const l = await startLoopbackListener({
91
+ accountId: "a",
92
+ state: "st-7",
93
+ onCode: async () => {
94
+ calls += 1;
95
+ await new Promise((r) => setTimeout(r, 80));
96
+ return { email: "x@y.z" };
97
+ },
98
+ });
99
+ assert.ok(l);
100
+ const first = get(`${l.redirectUri}/?state=st-7&code=xyz`);
101
+ await new Promise((r) => setTimeout(r, 20));
102
+ const second = await get(`${l.redirectUri}/?state=st-7&code=xyz`);
103
+ await first;
104
+ assert.equal(calls, 1, "the second request must not re-exchange the code");
105
+ assert.equal(second.status, 409);
106
+ });
107
+ test("a denied consent says so rather than blaming the link", async () => {
108
+ let ran = false;
109
+ const l = await startLoopbackListener({
110
+ accountId: "a",
111
+ state: "st-8",
112
+ onCode: async () => {
113
+ ran = true;
114
+ return { email: "x@y.z" };
115
+ },
116
+ });
117
+ assert.ok(l);
118
+ const r = await get(`${l.redirectUri}/?state=st-8&error=access_denied`);
119
+ assert.equal(r.status, 400);
120
+ assert.match(r.body, /access_denied/);
121
+ assert.doesNotMatch(r.body, /did not match/);
122
+ assert.equal(ran, false);
123
+ });
124
+ test("responses keep the code out of caches and referrers", async () => {
125
+ const l = await startLoopbackListener({
126
+ accountId: "a",
127
+ state: "st-9",
128
+ onCode: async () => ({ email: "x@y.z" }),
129
+ });
130
+ assert.ok(l);
131
+ const res = await fetch(`${l.redirectUri}/?state=st-9&code=xyz`);
132
+ assert.equal(res.headers.get("cache-control"), "no-store");
133
+ assert.equal(res.headers.get("referrer-policy"), "no-referrer");
134
+ await l.close("test");
135
+ });
136
+ test("the listener binds the loopback literal, never localhost", async () => {
137
+ const l = await startLoopbackListener({
138
+ accountId: "a",
139
+ state: "st-6",
140
+ onCode: async () => ({ email: "x@y.z" }),
141
+ });
142
+ assert.ok(l);
143
+ assert.match(l.redirectUri, /^http:\/\/127\.0\.0\.1:\d+$/);
144
+ await l.close("test");
145
+ });
146
+ //# sourceMappingURL=loopback-listener.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback-listener.test.js","sourceRoot":"","sources":["../../src/__tests__/loopback-listener.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=pending-redirect.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-redirect.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/pending-redirect.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { PendingStore } from "../auth/pending-store.js";
7
+ test("a pending entry round-trips its redirectUri", () => {
8
+ const dir = mkdtempSync(join(tmpdir(), "g-"));
9
+ const p = new PendingStore("acct-1", dir);
10
+ p.write({ state: "s1", verifier: "v1", createdAt: Date.now(), redirectUri: "http://127.0.0.1:54321" });
11
+ assert.equal(p.read()?.redirectUri, "http://127.0.0.1:54321");
12
+ });
13
+ test("a legacy pending entry with no redirectUri still reads", () => {
14
+ const dir = mkdtempSync(join(tmpdir(), "g-"));
15
+ const p = new PendingStore("acct-2", dir);
16
+ p.write({ state: "s2", verifier: "v2", createdAt: Date.now() });
17
+ assert.equal(p.read()?.redirectUri, undefined);
18
+ });
19
+ //# sourceMappingURL=pending-redirect.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending-redirect.test.js","sourceRoot":"","sources":["../../src/__tests__/pending-redirect.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD,IAAI,CAAC,6CAA6C,EAAE,GAAG,EAAE;IACvD,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,WAAW,EAAE,wBAAwB,EAAE,CAAC,CAAC;IACvG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,wBAAwB,CAAC,CAAC;AAChE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wDAAwD,EAAE,GAAG,EAAE;IAClE,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,IAAI,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAChE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,EAAE,SAAS,CAAC,CAAC;AACjD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=register-redirect-chain.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-redirect-chain.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/register-redirect-chain.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,41 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtempSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { newState, runAccountRegisterStart } from "../tools/account-register.js";
7
+ import { PendingStore } from "../auth/pending-store.js";
8
+ /** The consent URL, the pending entry and therefore the exchange must all
9
+ * carry one redirect. Google compares the exchange's value byte-for-byte
10
+ * against the one that issued the code, so a divergence here is the
11
+ * redirect_uri_mismatch that reads like a wrong client type. */
12
+ test("the consent URL and the pending entry carry the same redirect", async () => {
13
+ const dir = mkdtempSync(join(tmpdir(), "g-"));
14
+ const r = await runAccountRegisterStart({
15
+ accountId: "acct",
16
+ accountsDir: dir,
17
+ clientId: "cid",
18
+ state: newState(),
19
+ redirectUri: "http://127.0.0.1:54321",
20
+ });
21
+ assert.equal(r.status, "pending");
22
+ const inUrl = new URL(r.consentUrl).searchParams.get("redirect_uri");
23
+ const inPending = new PendingStore("acct", dir).read()?.redirectUri;
24
+ assert.equal(inUrl, "http://127.0.0.1:54321");
25
+ assert.equal(inPending, "http://127.0.0.1:54321");
26
+ assert.equal(inUrl, inPending);
27
+ });
28
+ test("the state minted by the caller is the state persisted and sent", async () => {
29
+ const dir = mkdtempSync(join(tmpdir(), "g-"));
30
+ const state = newState();
31
+ const r = await runAccountRegisterStart({
32
+ accountId: "acct",
33
+ accountsDir: dir,
34
+ clientId: "cid",
35
+ state,
36
+ redirectUri: "http://127.0.0.1:1234",
37
+ });
38
+ assert.equal(new URL(r.consentUrl).searchParams.get("state"), state);
39
+ assert.equal(new PendingStore("acct", dir).read()?.state, state);
40
+ });
41
+ //# sourceMappingURL=register-redirect-chain.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-redirect-chain.test.js","sourceRoot":"","sources":["../../src/__tests__/register-redirect-chain.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAExD;;;iEAGiE;AACjE,IAAI,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;IAC/E,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,MAAM,uBAAuB,CAAC;QACtC,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,GAAG;QAChB,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE,QAAQ,EAAE;QACjB,WAAW,EAAE,wBAAwB;KACtC,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,CAAC,UAAW,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;IACtE,MAAM,SAAS,GAAG,IAAI,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC;IACpE,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,wBAAwB,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,SAAS,EAAE,wBAAwB,CAAC,CAAC;IAClD,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;AACjC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,gEAAgE,EAAE,KAAK,IAAI,EAAE;IAChF,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,QAAQ,EAAE,CAAC;IACzB,MAAM,CAAC,GAAG,MAAM,uBAAuB,CAAC;QACtC,SAAS,EAAE,MAAM;QACjB,WAAW,EAAE,GAAG;QAChB,QAAQ,EAAE,KAAK;QACf,KAAK;QACL,WAAW,EAAE,uBAAuB;KACrC,CAAC,CAAC;IACH,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,UAAW,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;IACtE,MAAM,CAAC,KAAK,CAAC,IAAI,YAAY,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AACnE,CAAC,CAAC,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { type TokenBlob } from "./token-store.js";
2
+ /** Google revokes a refresh token after six months without use. */
3
+ export declare const REFRESH_INACTIVITY_LIMIT_DAYS = 180;
4
+ /** How much of the inactivity clock must remain before an account is merely
5
+ * `ok`. Thirty days is the window in which an operator can still act. */
6
+ export declare const REFRESH_EXPIRING_THRESHOLD_DAYS = 30;
7
+ export type RefreshStatus = "ok" | "expiring" | "expired";
8
+ export interface AccountAuditRow {
9
+ accountId: string;
10
+ email: string;
11
+ refreshTtlDays: number;
12
+ status: RefreshStatus;
13
+ }
14
+ /**
15
+ * Classify one token blob against the inactivity clock.
16
+ *
17
+ * A blob holding NO refresh token is `expired` with zero days regardless of how
18
+ * recently it was written: it works until the access token lapses, about an hour
19
+ * out, and then dies. Reporting it as `ok` because `lastRefresh` is recent would
20
+ * be precisely the false all-clear this audit exists to prevent.
21
+ */
22
+ export declare function classifyRefresh(blob: TokenBlob, nowMs: number): {
23
+ refreshTtlDays: number;
24
+ status: RefreshStatus;
25
+ };
26
+ /**
27
+ * Every connected Google account under every account, classified.
28
+ *
29
+ * An unreadable blob is skipped rather than thrown: one corrupt store must never
30
+ * blind the audit to every other account. It is not reported as a row because it
31
+ * has no TTL to report — `google-account-list` is the surface that already
32
+ * distinguishes `unreadable` from healthy.
33
+ */
34
+ export declare function auditConnectedAccounts(accountsDir: string, nowMs: number): AccountAuditRow[];
35
+ /**
36
+ * One audit cycle: a line per connected account, then a heartbeat.
37
+ *
38
+ * The heartbeat fires on EVERY cycle, including cycles that find nothing. An
39
+ * audit that has stopped running would otherwise be indistinguishable from an
40
+ * audit reporting all-clear, and the standing absence of this line over more
41
+ * than one interval is the documented signal that the audit is not running.
42
+ */
43
+ export declare function runAccountAudit(accountsDir: string, nowMs: number, emit: (line: string) => void): AccountAuditRow[];
44
+ //# sourceMappingURL=account-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-audit.d.ts","sourceRoot":"","sources":["../../src/auth/account-audit.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE9D,mEAAmE;AACnE,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD;0EAC0E;AAC1E,eAAO,MAAM,+BAA+B,KAAK,CAAC;AAMlD,MAAM,MAAM,aAAa,GAAG,IAAI,GAAG,UAAU,GAAG,SAAS,CAAC;AAW1D,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,aAAa,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,SAAS,EACf,KAAK,EAAE,MAAM,GACZ;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAWnD;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE,CAkB5F;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAC3B,eAAe,EAAE,CAYnB"}
@@ -0,0 +1,112 @@
1
+ /**
2
+ * Standing refresh-token audit (Task 1773).
3
+ *
4
+ * A connected account's refresh token expiring emits no event and does not
5
+ * reproduce on demand: nothing touches the account, it simply stops working at
6
+ * some future date. Without a periodic reconciliation, "which connected accounts
7
+ * are close to falling off?" is unanswerable without reading every token store by
8
+ * hand. This module is that reconciliation.
9
+ *
10
+ * WHAT `refreshTtlDays` MEANS. Google issues no expiry for a refresh token and
11
+ * the stored blob holds none — `TokenBlob` carries `accessTokenExpiry` and
12
+ * `lastRefresh`, nothing more. The one bounded, locally-computable clock is
13
+ * Google's six-month INACTIVITY revocation: a refresh token unused for 180 days
14
+ * is revoked. So `refreshTtlDays` is days remaining on that inactivity clock,
15
+ * measured from `lastRefresh`. It is NOT a expiry Google published, and it does
16
+ * not predict the other revocation causes (the user revoking access, a password
17
+ * change, or the app being unpublished), none of which are locally observable.
18
+ *
19
+ * Runs against local stores only — no network. It reads what is on disk and
20
+ * classifies it, so it cannot itself break a working connection.
21
+ */
22
+ import { existsSync, readdirSync } from "node:fs";
23
+ import { join } from "node:path";
24
+ import { TokenStore } from "./token-store.js";
25
+ /** Google revokes a refresh token after six months without use. */
26
+ export const REFRESH_INACTIVITY_LIMIT_DAYS = 180;
27
+ /** How much of the inactivity clock must remain before an account is merely
28
+ * `ok`. Thirty days is the window in which an operator can still act. */
29
+ export const REFRESH_EXPIRING_THRESHOLD_DAYS = 30;
30
+ const DAY_MS = 86_400_000;
31
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
32
+ /** The audit line is space-delimited `k=v`, so a value carrying whitespace would
33
+ * split into bogus fields and a reader would mis-parse the record for exactly
34
+ * the account most likely to need attention. The directory name is already
35
+ * folded by `sanitizeAccountKey`, but `blob.email` comes from Google's
36
+ * primary-calendar id and is never sanitized on the way in. */
37
+ function logSafe(value) {
38
+ return value.replace(/\s+/g, "_");
39
+ }
40
+ /**
41
+ * Classify one token blob against the inactivity clock.
42
+ *
43
+ * A blob holding NO refresh token is `expired` with zero days regardless of how
44
+ * recently it was written: it works until the access token lapses, about an hour
45
+ * out, and then dies. Reporting it as `ok` because `lastRefresh` is recent would
46
+ * be precisely the false all-clear this audit exists to prevent.
47
+ */
48
+ export function classifyRefresh(blob, nowMs) {
49
+ if (blob.refreshToken === null)
50
+ return { refreshTtlDays: 0, status: "expired" };
51
+ // Clamp idleDays at 0 so a lastRefresh in the future — a device whose clock ran
52
+ // ahead, or a blob restored from a host whose clock did — cannot report more
53
+ // days remaining than the limit this module documents as the maximum.
54
+ // `PendingStore.ageSec` clamps its analogous value for the same reason.
55
+ const idleDays = Math.max(0, Math.floor((nowMs - blob.lastRefresh) / DAY_MS));
56
+ const refreshTtlDays = REFRESH_INACTIVITY_LIMIT_DAYS - idleDays;
57
+ if (refreshTtlDays <= 0)
58
+ return { refreshTtlDays, status: "expired" };
59
+ if (refreshTtlDays <= REFRESH_EXPIRING_THRESHOLD_DAYS)
60
+ return { refreshTtlDays, status: "expiring" };
61
+ return { refreshTtlDays, status: "ok" };
62
+ }
63
+ /**
64
+ * Every connected Google account under every account, classified.
65
+ *
66
+ * An unreadable blob is skipped rather than thrown: one corrupt store must never
67
+ * blind the audit to every other account. It is not reported as a row because it
68
+ * has no TTL to report — `google-account-list` is the surface that already
69
+ * distinguishes `unreadable` from healthy.
70
+ */
71
+ export function auditConnectedAccounts(accountsDir, nowMs) {
72
+ if (!existsSync(accountsDir))
73
+ return [];
74
+ const rows = [];
75
+ for (const accountId of readdirSync(accountsDir)) {
76
+ if (!UUID_RE.test(accountId))
77
+ continue;
78
+ const connectedDir = join(accountsDir, accountId, "secrets", "google", "accounts");
79
+ if (!existsSync(connectedDir))
80
+ continue;
81
+ for (const key of readdirSync(connectedDir)) {
82
+ try {
83
+ const blob = new TokenStore(accountId, accountsDir, key).read();
84
+ if (!blob)
85
+ continue;
86
+ rows.push({ accountId, email: logSafe(blob.email ?? key), ...classifyRefresh(blob, nowMs) });
87
+ }
88
+ catch {
89
+ /* unreadable store — skip, never blind the whole scan */
90
+ }
91
+ }
92
+ }
93
+ return rows;
94
+ }
95
+ /**
96
+ * One audit cycle: a line per connected account, then a heartbeat.
97
+ *
98
+ * The heartbeat fires on EVERY cycle, including cycles that find nothing. An
99
+ * audit that has stopped running would otherwise be indistinguishable from an
100
+ * audit reporting all-clear, and the standing absence of this line over more
101
+ * than one interval is the documented signal that the audit is not running.
102
+ */
103
+ export function runAccountAudit(accountsDir, nowMs, emit) {
104
+ const rows = auditConnectedAccounts(accountsDir, nowMs);
105
+ for (const r of rows) {
106
+ emit(`[google-account-audit] account=${r.accountId} email=${r.email} refreshTtlDays=${r.refreshTtlDays} status=${r.status}`);
107
+ }
108
+ const count = (s) => rows.filter((r) => r.status === s).length;
109
+ emit(`[google-account-audit] op=heartbeat accounts=${rows.length} ok=${count("ok")} expiring=${count("expiring")} expired=${count("expired")}`);
110
+ return rows;
111
+ }
112
+ //# sourceMappingURL=account-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-audit.js","sourceRoot":"","sources":["../../src/auth/account-audit.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ export interface LoopbackListener {
2
+ readonly redirectUri: string;
3
+ readonly port: number;
4
+ close(reason: string): Promise<void>;
5
+ }
6
+ /** Resolves null when the bind fails, so the caller falls back to the fixed
7
+ * redirect and the paste path still completes the registration. A refusal
8
+ * here would turn an optimisation into a regression on any install that
9
+ * cannot bind. */
10
+ export declare function startLoopbackListener(args: {
11
+ accountId: string;
12
+ state: string;
13
+ onCode: (code: string) => Promise<{
14
+ email: string;
15
+ }>;
16
+ }): Promise<LoopbackListener | null>;
17
+ //# sourceMappingURL=loopback-listener.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loopback-listener.d.ts","sourceRoot":"","sources":["../../src/auth/loopback-listener.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtC;AA0BD;;;mBAGmB;AACnB,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACtD,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CA6HnC"}