@rubytech/create-maxy-code 0.1.474 → 0.1.475

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 (64) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +16 -7
  3. package/payload/platform/plugins/docs/references/google-guide.md +15 -6
  4. package/payload/platform/plugins/google/.claude-plugin/plugin.json +1 -1
  5. package/payload/platform/plugins/google/PLUGIN.md +60 -12
  6. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts +2 -0
  7. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.d.ts.map +1 -0
  8. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js +229 -0
  9. package/payload/platform/plugins/google/mcp/dist/__tests__/account-audit.test.js.map +1 -0
  10. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +9 -9
  11. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -1
  12. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts +2 -0
  13. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.d.ts.map +1 -0
  14. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js +17 -0
  15. package/payload/platform/plugins/google/mcp/dist/__tests__/consent-url-redirect.test.js.map +1 -0
  16. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts +2 -0
  17. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.d.ts.map +1 -0
  18. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js +146 -0
  19. package/payload/platform/plugins/google/mcp/dist/__tests__/loopback-listener.test.js.map +1 -0
  20. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts +2 -0
  21. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.d.ts.map +1 -0
  22. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js +19 -0
  23. package/payload/platform/plugins/google/mcp/dist/__tests__/pending-redirect.test.js.map +1 -0
  24. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts +2 -0
  25. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.d.ts.map +1 -0
  26. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js +41 -0
  27. package/payload/platform/plugins/google/mcp/dist/__tests__/register-redirect-chain.test.js.map +1 -0
  28. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts +44 -0
  29. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.d.ts.map +1 -0
  30. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js +112 -0
  31. package/payload/platform/plugins/google/mcp/dist/auth/account-audit.js.map +1 -0
  32. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts +17 -0
  33. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.d.ts.map +1 -0
  34. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js +143 -0
  35. package/payload/platform/plugins/google/mcp/dist/auth/loopback-listener.js.map +1 -0
  36. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts +9 -0
  37. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.d.ts.map +1 -1
  38. package/payload/platform/plugins/google/mcp/dist/auth/pending-store.js.map +1 -1
  39. package/payload/platform/plugins/google/mcp/dist/index.js +73 -5
  40. package/payload/platform/plugins/google/mcp/dist/index.js.map +1 -1
  41. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts +2 -0
  42. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.d.ts.map +1 -0
  43. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js +37 -0
  44. package/payload/platform/plugins/google/mcp/dist/scripts/account-audit.js.map +1 -0
  45. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +20 -4
  46. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -1
  47. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +19 -9
  48. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -1
  49. package/payload/platform/plugins/google/references/auth.md +93 -14
  50. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +21 -3
  51. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
  52. package/payload/platform/services/claude-session-manager/dist/activity-rows.js +6 -2
  53. package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
  54. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
  55. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +43 -5
  56. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
  57. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +9 -0
  58. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -1
  59. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +78 -0
  60. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -1
  61. package/payload/server/public/activity.html +1 -1
  62. package/payload/server/public/assets/activity-Mz1BhgB1.js +1 -0
  63. package/payload/server/server.js +368 -300
  64. package/payload/server/public/assets/activity-CdipMTDp.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-maxy-code",
3
- "version": "0.1.474",
3
+ "version": "0.1.475",
4
4
  "description": "Install Maxy — AI for Productive People",
5
5
  "bin": {
6
6
  "create-maxy-code": "./dist/index.js"
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: platform-architecture
3
3
  description: Use when grounding any documented-surface claim about what Maxy ships — plugins, skills, specialists, install/deploy flows, internals. This is the install catalogue, not evidence of what is enabled on the current account. For install state on this account, call `capabilities-here`; for documented surface, cite the `Source:` URL inline.
4
- content-hash: sha256:87a32054a533d5a60538763ef209f3b3e9d64d70f677d91507dbada9d1006609
4
+ content-hash: sha256:3f1095125f80c4f095ed4fbe31bf54975c3ef99332fc3958138af6ad9e82b04e
5
5
  brand: maxy-code
6
6
  product-name: Maxy
7
7
  ---
@@ -2228,14 +2228,23 @@ force Google's annual third-party security assessment. Calendar is only a
2228
2228
  `google-account-register` returns a consent URL. Relay it to the user: they open
2229
2229
  it on any device, sign in, and approve.
2230
2230
 
2231
- Their browser then lands on a page that **fails to load**. That is expected, not
2232
- a fault — the vendor app is a Desktop client, so Google redirects to a loopback
2233
- address on the user's own device where nothing is listening. The address bar
2234
- carries the code. Ask them to copy it and pass it to
2231
+ What happens next depends on where they approved.
2232
+
2233
+ **If they approved on the machine this install runs on**, the connection
2234
+ completes by itself and their browser shows a page naming the connected account.
2235
+ Nothing is pasted. That page asks them to return to the chat and say so — do
2236
+ that, then call `google-account-register-poll` to confirm.
2237
+
2238
+ **If they approved on another device**, such as a phone, their browser lands on
2239
+ a page that **fails to load**. That is expected, not a fault: the vendor app is
2240
+ a Desktop client, so Google redirects to a loopback address on the install, and
2241
+ a phone has no route to it. The address bar still carries the code. Ask them to
2242
+ copy the **whole URL** from the address bar and pass it to
2235
2243
  `google-account-register-submit`, which completes the connection.
2236
2244
 
2237
- If they paste the whole `code=...` fragment, or a value containing `%2F`, the
2238
- tool handles it. `google-account-register-poll` reports the outcome at any point.
2245
+ Paste the entire URL — the tool pulls the code out. A bare code, a `code=...`
2246
+ fragment, and a value containing `%2F` all work too.
2247
+ `google-account-register-poll` reports the outcome at any point.
2239
2248
 
2240
2249
  The register tool does not block and does not wait. A second register while one
2241
2250
  is already live is refused rather than overwriting it; that refusal names how
@@ -14,14 +14,23 @@ force Google's annual third-party security assessment. Calendar is only a
14
14
  `google-account-register` returns a consent URL. Relay it to the user: they open
15
15
  it on any device, sign in, and approve.
16
16
 
17
- Their browser then lands on a page that **fails to load**. That is expected, not
18
- a fault — the vendor app is a Desktop client, so Google redirects to a loopback
19
- address on the user's own device where nothing is listening. The address bar
20
- carries the code. Ask them to copy it and pass it to
17
+ What happens next depends on where they approved.
18
+
19
+ **If they approved on the machine this install runs on**, the connection
20
+ completes by itself and their browser shows a page naming the connected account.
21
+ Nothing is pasted. That page asks them to return to the chat and say so — do
22
+ that, then call `google-account-register-poll` to confirm.
23
+
24
+ **If they approved on another device**, such as a phone, their browser lands on
25
+ a page that **fails to load**. That is expected, not a fault: the vendor app is
26
+ a Desktop client, so Google redirects to a loopback address on the install, and
27
+ a phone has no route to it. The address bar still carries the code. Ask them to
28
+ copy the **whole URL** from the address bar and pass it to
21
29
  `google-account-register-submit`, which completes the connection.
22
30
 
23
- If they paste the whole `code=...` fragment, or a value containing `%2F`, the
24
- tool handles it. `google-account-register-poll` reports the outcome at any point.
31
+ Paste the entire URL — the tool pulls the code out. A bare code, a `code=...`
32
+ fragment, and a value containing `%2F` all work too.
33
+ `google-account-register-poll` reports the outcome at any point.
25
34
 
26
35
  The register tool does not block and does not wait. A second register while one
27
36
  is already live is refused rather than overwriting it; that refusal names how
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "google",
3
- "description": "Live Google Calendar for one account via the Google Calendar API v3 — read plus control. Per-account OAuth authorization-code + PKCE against a Desktop client whose id and secret ship in brand config; the plugin mints the consent URL and exchanges the code in-process, and nothing in platform/ui participates. One account can connect several Google accounts; every operational tool takes an optional account selector (the email address) and refuses ambiguously when two or more are connected and none is named. There is deliberately no Gmail surface — mail runs on the `email` plugin's IMAP/SMTP path, and Gmail's restricted scopes would force Google's annual third-party security assessment, whereas Calendar is only a sensitive scope. Tools — google-account-register / google-account-register-submit / google-account-register-poll: connect a Google Calendar (returns a consent URL; the user approves, lands on a page that fails to load by design, and pastes the code back to submit); google-calendar-list: events in the next rangeDays days, recurring series expanded; google-calendar-event: one event by id; google-calendar-create / google-calendar-update / google-calendar-cancel: control events, attendees notified, update changes only the fields named; google-calendar-respond: accept, decline or tentatively accept an invitation, leaving other attendees' responses untouched; google-calendar-freebusy: busy blocks for this or named calendars; google-account-info: auth state for one connected Google account; google-account-list: every connected Google account with its own status.",
3
+ "description": "Live Google Calendar for one account via the Google Calendar API v3 — read plus control. Per-account OAuth authorization-code + PKCE against a Desktop client whose id and secret ship in brand config; the plugin mints the consent URL and exchanges the code in-process, and nothing in platform/ui participates. One account can connect several Google accounts; every operational tool takes an optional account selector (the email address) and refuses ambiguously when two or more are connected and none is named. There is deliberately no Gmail surface — mail runs on the `email` plugin's IMAP/SMTP path, and Gmail's restricted scopes would force Google's annual third-party security assessment, whereas Calendar is only a sensitive scope. Tools — google-account-register / google-account-register-submit / google-account-register-poll: connect a Google Calendar (returns a consent URL; approving on the install machine completes by itself and the browser confirms it, while approving on another device lands on a page that fails to load by design and the user pastes the address-bar URL back to submit); google-calendar-list: events in the next rangeDays days, recurring series expanded; google-calendar-event: one event by id; google-calendar-create / google-calendar-update / google-calendar-cancel: control events, attendees notified, update changes only the fields named; google-calendar-respond: accept, decline or tentatively accept an invitation, leaving other attendees' responses untouched; google-calendar-freebusy: busy blocks for this or named calendars; google-account-info: auth state for one connected Google account; google-account-list: every connected Google account with its own status.",
4
4
  "version": "0.1.0",
5
5
  "author": {
6
6
  "name": "Rubytech LLC"
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: google
3
- description: Live Google Calendar for one account via the Google Calendar API v3 — read plus control. Per-account OAuth authorization-code + PKCE against a Desktop client whose id and secret ship in brand config; the plugin mints the consent URL and exchanges the code in-process, and nothing in platform/ui participates. One account can connect several Google accounts; every operational tool takes an optional account selector (the email address) and refuses ambiguously when two or more are connected and none is named. There is deliberately no Gmail surface — mail runs on the `email` plugin's IMAP/SMTP path, and Gmail's restricted scopes would force Google's annual third-party security assessment, whereas Calendar is only a sensitive scope. Tools — google-account-register / google-account-register-submit / google-account-register-poll: connect a Google Calendar (returns a consent URL; the user approves, lands on a page that fails to load by design, and pastes the code back to submit); google-calendar-list: events in the next rangeDays days, recurring series expanded; google-calendar-event: one event by id; google-calendar-create / google-calendar-update / google-calendar-cancel: control events, attendees notified, update changes only the fields named; google-calendar-respond: accept, decline or tentatively accept an invitation, leaving other attendees' responses untouched; google-calendar-freebusy: busy blocks for this or named calendars; google-account-info: auth state for one connected Google account; google-account-list: every connected Google account with its own status.
3
+ description: Live Google Calendar for one account via the Google Calendar API v3 — read plus control. Per-account OAuth authorization-code + PKCE against a Desktop client whose id and secret ship in brand config; the plugin mints the consent URL and exchanges the code in-process, and nothing in platform/ui participates. One account can connect several Google accounts; every operational tool takes an optional account selector (the email address) and refuses ambiguously when two or more are connected and none is named. There is deliberately no Gmail surface — mail runs on the `email` plugin's IMAP/SMTP path, and Gmail's restricted scopes would force Google's annual third-party security assessment, whereas Calendar is only a sensitive scope. Tools — google-account-register / google-account-register-submit / google-account-register-poll: connect a Google Calendar (returns a consent URL; approving on the install machine completes by itself and the browser confirms it, while approving on another device lands on a page that fails to load by design and the user pastes the address-bar URL back to submit); google-calendar-list: events in the next rangeDays days, recurring series expanded; google-calendar-event: one event by id; google-calendar-create / google-calendar-update / google-calendar-cancel: control events, attendees notified, update changes only the fields named; google-calendar-respond: accept, decline or tentatively accept an invitation, leaving other attendees' responses untouched; google-calendar-freebusy: busy blocks for this or named calendars; google-account-info: auth state for one connected Google account; google-account-list: every connected Google account with its own status.
4
4
  tools:
5
5
  - name: google-account-register
6
6
  publicAllowlist: false
@@ -78,19 +78,27 @@ The vendor app is a **Desktop (installed app)** client, the one type whose
78
78
  secret Google sanctions shipping in distributed software. Its id and secret come
79
79
  from `brand.json` and are stamped by the installer together or not at all.
80
80
 
81
- `google-account-register` mints the PKCE pair, persists it single-slot per
82
- account, and returns a consent URL whose redirect is the IP literal
83
- `http://127.0.0.1:8571` never `localhost`, since Google's port-agnostic
84
- loopback matching applies only to the literal. The user opens the URL on any
85
- device and approves, then lands on a page that **fails to load by design**
86
- (nothing listens there) and copies the `code` from the address bar.
87
- `google-account-register-submit` exchanges it in-process with the stored
88
- verifier, resolves the account's email from its primary calendar, and writes
89
- encrypted tokens. `google-account-register-poll` reports the outcome from local
90
- state.
81
+ `google-account-register` mints the PKCE pair, binds a single-shot listener on
82
+ `127.0.0.1` at an OS-assigned port, and returns a consent URL carrying that
83
+ port. The host is always the IP literal, never `localhost` Google's
84
+ port-agnostic loopback matching applies only to the literal.
85
+
86
+ Consent on the install's own machine reaches that listener, which verifies
87
+ `state`, completes the exchange, and renders a page naming the account. Consent
88
+ on another device cannot reach it, so the redirect fails to load and the user
89
+ pastes the address-bar URL into `google-account-register-submit`. Both paths
90
+ exchange in-process with the stored verifier, resolve the email from the primary
91
+ calendar, and write encrypted tokens. `google-account-register-poll` reports the
92
+ outcome from local state.
93
+
94
+ The pending entry stores the redirect it issued, because the port varies per
95
+ registration and Google compares the exchange's `redirect_uri` byte for byte
96
+ against the one that issued the code. A failed bind falls back to
97
+ `http://127.0.0.1:8571`, leaving the paste path exactly as it was.
91
98
 
92
99
  Token refresh also runs in-process against Google. Nothing in `platform/ui`
93
- participates in Google OAuth.
100
+ mints, exchanges or refreshes a Google credential; its only Google surface is the
101
+ standing pending audit below, which reads a file's age and never decrypts.
94
102
 
95
103
  ## Scope
96
104
 
@@ -111,6 +119,46 @@ is why they are declared in the self-named `${FOO}` form (see
111
119
  `clientSecretConfigured`; either reading `false` on a brand that ships both is
112
120
  the mis-stamp signature.
113
121
 
122
+ ## Observability
123
+
124
+ Two failures here emit no event and do not reproduce on demand: a registration
125
+ the operator abandons, and a refresh token that expires. Nothing touches either;
126
+ they simply stop being true at some future date. Two standing audits report them
127
+ without anything polling.
128
+
129
+ | Audit | Where it runs | Interval | Per-finding line | Heartbeat |
130
+ |---|---|---|---|---|
131
+ | Stranded pending registration | in-process in `platform/ui` | 5 min | `[google-oauth] op=pending-stranded account=<id> ageSec=<N>` | `[google-oauth] op=pending-audit scanned=<N> stranded=<M>` |
132
+ | Refresh-token TTL | spawned `mcp/dist/scripts/account-audit.js` | 1 hour | `[google-account-audit] account=<id> email=<addr> refreshTtlDays=<D> status=<ok\|expiring\|expired>` | `[google-account-audit] op=heartbeat accounts=<N> ok=<A> expiring=<B> expired=<C>` |
133
+
134
+ They run on different mechanisms deliberately. The pending audit needs no
135
+ decrypt — file age alone is conclusive — so it runs in-process and stays
136
+ independent of whether any spawn is healthy. The refresh audit must decrypt the
137
+ token blob with the per-account key, so it runs where `TokenStore` lives.
138
+
139
+ **The heartbeat is the point.** Each audit emits its heartbeat on every cycle,
140
+ including cycles that find nothing, because an audit that has stopped running is
141
+ otherwise indistinguishable from one reporting all-clear. The absence of a
142
+ heartbeat over more than one interval is the documented signal that the audit is
143
+ down — not silence meaning healthy. A failed pending cycle logs
144
+ `op=pending-audit-error`, deliberately a different token from the heartbeat so a
145
+ broken cycle can never be counted as a clean one.
146
+
147
+ `refreshTtlDays` is days left on Google's 180-day **inactivity** revocation
148
+ clock, measured from `lastRefresh`. Google publishes no refresh-token expiry and
149
+ the stored blob holds none, so this is the only bounded, locally-computable
150
+ clock. It does not predict the user revoking access or changing their password,
151
+ neither of which is observable from here. A connection holding no refresh token
152
+ at all reports `expired` with zero days regardless of how recently it was
153
+ written, because it dies when its access token lapses about an hour out.
154
+
155
+ Diagnostic path:
156
+
157
+ ```
158
+ ~/<brand>-code/platform/scripts/logs-read.sh --tail server 200 \
159
+ | grep -E '\[google-oauth\]|\[google-account-audit\]'
160
+ ```
161
+
114
162
  ## Out of scope
115
163
 
116
164
  Gmail (stays on IMAP/SMTP), Contacts, Drive/Docs, push notification channels,
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=account-audit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-audit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/account-audit.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Refresh-TTL audit (Task 1773).
3
+ *
4
+ * The audit exists because a 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. So every test here drives the audit ALONE. None of them call
7
+ * a register or poll path first: that is the path that already worked, and a test
8
+ * that primes it proves nothing about the audit.
9
+ */
10
+ import { strict as assert } from "node:assert";
11
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
12
+ import { tmpdir } from "node:os";
13
+ import { join } from "node:path";
14
+ import { test } from "node:test";
15
+ import { TokenStore } from "../auth/token-store.js";
16
+ import { REFRESH_EXPIRING_THRESHOLD_DAYS, REFRESH_INACTIVITY_LIMIT_DAYS, auditConnectedAccounts, classifyRefresh, runAccountAudit, } from "../auth/account-audit.js";
17
+ const DAY_MS = 86_400_000;
18
+ const ACCOUNT_A = "aaaaaaaa-1111-4111-8111-aaaaaaaaaaaa";
19
+ const ACCOUNT_B = "bbbbbbbb-2222-4222-8222-bbbbbbbbbbbb";
20
+ function freshDir() {
21
+ return mkdtempSync(join(tmpdir(), "google-audit-"));
22
+ }
23
+ /** Write a real encrypted token blob through TokenStore, then rewrite it with a
24
+ * chosen lastRefresh — the audit must read the stored value, not a live clock. */
25
+ function seedAccount(accountsDir, accountId, email, opts, nowMs) {
26
+ const store = new TokenStore(accountId, accountsDir, email);
27
+ store.writeBlobForTest({
28
+ accessToken: "at",
29
+ refreshToken: opts.refreshToken,
30
+ accessTokenExpiry: nowMs + 3_600_000,
31
+ lastRefresh: nowMs - opts.lastRefreshAgeDays * DAY_MS,
32
+ email,
33
+ scopes: ["https://www.googleapis.com/auth/calendar"],
34
+ });
35
+ }
36
+ test("classifyRefresh: a healthy recently-refreshed token is ok", () => {
37
+ const now = Date.now();
38
+ const r = classifyRefresh({
39
+ accessToken: "at",
40
+ refreshToken: "rt",
41
+ accessTokenExpiry: now,
42
+ lastRefresh: now - 3 * DAY_MS,
43
+ email: "a@example.com",
44
+ scopes: [],
45
+ }, now);
46
+ assert.equal(r.status, "ok");
47
+ assert.equal(r.refreshTtlDays, REFRESH_INACTIVITY_LIMIT_DAYS - 3);
48
+ });
49
+ test("classifyRefresh: inside the expiring threshold is expiring, not ok", () => {
50
+ const now = Date.now();
51
+ // 175 days idle leaves 5 days of the 180-day inactivity clock.
52
+ const r = classifyRefresh({
53
+ accessToken: "at",
54
+ refreshToken: "rt",
55
+ accessTokenExpiry: now,
56
+ lastRefresh: now - 175 * DAY_MS,
57
+ email: "a@example.com",
58
+ scopes: [],
59
+ }, now);
60
+ assert.equal(r.refreshTtlDays, 5);
61
+ assert.equal(r.status, "expiring");
62
+ assert.ok(r.refreshTtlDays <= REFRESH_EXPIRING_THRESHOLD_DAYS);
63
+ });
64
+ test("classifyRefresh: past the inactivity limit is expired", () => {
65
+ const now = Date.now();
66
+ const r = classifyRefresh({
67
+ accessToken: "at",
68
+ refreshToken: "rt",
69
+ accessTokenExpiry: now,
70
+ lastRefresh: now - 200 * DAY_MS,
71
+ email: "a@example.com",
72
+ scopes: [],
73
+ }, now);
74
+ assert.equal(r.status, "expired");
75
+ assert.ok(r.refreshTtlDays <= 0);
76
+ });
77
+ test("classifyRefresh: no refresh token at all is expired with zero days", () => {
78
+ const now = Date.now();
79
+ // A connection Google issued no refresh token for dies with its access token,
80
+ // about an hour out. It is not 'ok' merely because it was just written.
81
+ const r = classifyRefresh({
82
+ accessToken: "at",
83
+ refreshToken: null,
84
+ accessTokenExpiry: now,
85
+ lastRefresh: now,
86
+ email: "a@example.com",
87
+ scopes: [],
88
+ }, now);
89
+ assert.equal(r.status, "expired");
90
+ assert.equal(r.refreshTtlDays, 0);
91
+ });
92
+ test("classifyRefresh: a lastRefresh in the future never exceeds the documented limit", () => {
93
+ // A device whose clock ran ahead, or a blob restored from such a host. Without
94
+ // the clamp this reports e.g. refreshTtlDays=200, a value the module documents
95
+ // as impossible.
96
+ const now = Date.now();
97
+ const r = classifyRefresh({
98
+ accessToken: "at",
99
+ refreshToken: "rt",
100
+ accessTokenExpiry: now,
101
+ lastRefresh: now + 20 * DAY_MS,
102
+ email: "a@example.com",
103
+ scopes: [],
104
+ }, now);
105
+ assert.equal(r.refreshTtlDays, REFRESH_INACTIVITY_LIMIT_DAYS);
106
+ assert.equal(r.status, "ok");
107
+ });
108
+ test("an email carrying whitespace cannot split the audit line into bogus fields", () => {
109
+ const dir = freshDir();
110
+ const now = Date.now();
111
+ const lines = [];
112
+ try {
113
+ const store = new TokenStore(ACCOUNT_A, dir, "spacey@example.com");
114
+ store.writeBlobForTest({
115
+ accessToken: "at",
116
+ refreshToken: "rt",
117
+ accessTokenExpiry: now + 3_600_000,
118
+ lastRefresh: now,
119
+ email: "bad id@example.com",
120
+ scopes: [],
121
+ });
122
+ runAccountAudit(dir, now, (l) => lines.push(l));
123
+ const line = lines.find((l) => l.includes("refreshTtlDays="));
124
+ assert.ok(line);
125
+ // status must remain the LAST field and parse cleanly: an unescaped space
126
+ // would push `status=` out of position for any k=v reader.
127
+ const fields = Object.fromEntries(line.split(" ").slice(1).map((p) => p.split("=")));
128
+ assert.equal(fields.status, "ok");
129
+ assert.equal(fields.refreshTtlDays, String(REFRESH_INACTIVITY_LIMIT_DAYS));
130
+ assert.equal(fields.email, "bad_id@example.com");
131
+ }
132
+ finally {
133
+ rmSync(dir, { recursive: true, force: true });
134
+ }
135
+ });
136
+ test("auditConnectedAccounts reports every connected account across accounts", () => {
137
+ const dir = freshDir();
138
+ const now = Date.now();
139
+ try {
140
+ seedAccount(dir, ACCOUNT_A, "one@example.com", { lastRefreshAgeDays: 1, refreshToken: "rt" }, now);
141
+ seedAccount(dir, ACCOUNT_A, "two@example.com", { lastRefreshAgeDays: 175, refreshToken: "rt" }, now);
142
+ seedAccount(dir, ACCOUNT_B, "three@example.com", { lastRefreshAgeDays: 0, refreshToken: null }, now);
143
+ const rows = auditConnectedAccounts(dir, now);
144
+ assert.equal(rows.length, 3);
145
+ const byEmail = new Map(rows.map((r) => [r.email, r]));
146
+ assert.equal(byEmail.get("one@example.com")?.status, "ok");
147
+ assert.equal(byEmail.get("two@example.com")?.status, "expiring");
148
+ assert.equal(byEmail.get("three@example.com")?.status, "expired");
149
+ assert.equal(byEmail.get("one@example.com")?.accountId, ACCOUNT_A);
150
+ assert.equal(byEmail.get("three@example.com")?.accountId, ACCOUNT_B);
151
+ }
152
+ finally {
153
+ rmSync(dir, { recursive: true, force: true });
154
+ }
155
+ });
156
+ test("one unreadable blob does not blind the scan", () => {
157
+ const dir = freshDir();
158
+ const now = Date.now();
159
+ try {
160
+ seedAccount(dir, ACCOUNT_A, "good@example.com", { lastRefreshAgeDays: 1, refreshToken: "rt" }, now);
161
+ // Corrupt ciphertext under the same account — decrypt will throw.
162
+ const badDir = join(dir, ACCOUNT_A, "secrets", "google", "accounts", "bad@example.com");
163
+ mkdirSync(badDir, { recursive: true });
164
+ writeFileSync(join(badDir, "tokens.enc"), "not:validciphertext");
165
+ const rows = auditConnectedAccounts(dir, now);
166
+ // The healthy account still reports; the corrupt one is skipped, not fatal.
167
+ assert.ok(rows.some((r) => r.email === "good@example.com" && r.status === "ok"));
168
+ }
169
+ finally {
170
+ rmSync(dir, { recursive: true, force: true });
171
+ }
172
+ });
173
+ test("non-uuid directories under accountsDir are ignored", () => {
174
+ const dir = freshDir();
175
+ const now = Date.now();
176
+ try {
177
+ mkdirSync(join(dir, "not-an-account", "secrets", "google", "accounts", "x@example.com"), {
178
+ recursive: true,
179
+ });
180
+ assert.deepEqual(auditConnectedAccounts(dir, now), []);
181
+ }
182
+ finally {
183
+ rmSync(dir, { recursive: true, force: true });
184
+ }
185
+ });
186
+ test("a missing accounts directory yields no rows and does not throw", () => {
187
+ assert.deepEqual(auditConnectedAccounts(join(tmpdir(), "google-audit-absent-dir"), Date.now()), []);
188
+ });
189
+ test("runAccountAudit emits one line per account plus a heartbeat", () => {
190
+ const dir = freshDir();
191
+ const now = Date.now();
192
+ const lines = [];
193
+ try {
194
+ seedAccount(dir, ACCOUNT_A, "one@example.com", { lastRefreshAgeDays: 1, refreshToken: "rt" }, now);
195
+ seedAccount(dir, ACCOUNT_A, "two@example.com", { lastRefreshAgeDays: 175, refreshToken: "rt" }, now);
196
+ runAccountAudit(dir, now, (l) => lines.push(l));
197
+ const perAccount = lines.filter((l) => l.includes("account=") && !l.includes("op=heartbeat"));
198
+ assert.equal(perAccount.length, 2);
199
+ assert.ok(perAccount.some((l) => l.includes("[google-account-audit]") &&
200
+ l.includes(`account=${ACCOUNT_A}`) &&
201
+ l.includes("email=two@example.com") &&
202
+ l.includes("refreshTtlDays=5") &&
203
+ l.includes("status=expiring")), `expected an expiring line, got: ${perAccount.join(" | ")}`);
204
+ const heartbeat = lines.filter((l) => l.includes("op=heartbeat"));
205
+ assert.equal(heartbeat.length, 1);
206
+ assert.ok(heartbeat[0].includes("accounts=2"));
207
+ assert.ok(heartbeat[0].includes("ok=1"));
208
+ assert.ok(heartbeat[0].includes("expiring=1"));
209
+ assert.ok(heartbeat[0].includes("expired=0"));
210
+ }
211
+ finally {
212
+ rmSync(dir, { recursive: true, force: true });
213
+ }
214
+ });
215
+ test("the heartbeat is emitted on a cycle that finds nothing", () => {
216
+ // This is the whole point of the heartbeat: an audit that stopped running must
217
+ // not be indistinguishable from an audit reporting all-clear.
218
+ const dir = freshDir();
219
+ const lines = [];
220
+ try {
221
+ runAccountAudit(dir, Date.now(), (l) => lines.push(l));
222
+ assert.equal(lines.length, 1);
223
+ assert.ok(lines[0].includes("[google-account-audit] op=heartbeat accounts=0"));
224
+ }
225
+ finally {
226
+ rmSync(dir, { recursive: true, force: true });
227
+ }
228
+ });
229
+ //# sourceMappingURL=account-audit.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-audit.test.js","sourceRoot":"","sources":["../../src/__tests__/account-audit.test.ts"],"names":[],"mappings":"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"}
@@ -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":""}