@rubytech/create-maxy-code 0.1.472 → 0.1.473

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 (125) hide show
  1. package/dist/__tests__/google-client-id-env.test.js +12 -10
  2. package/dist/index.js +6 -29
  3. package/dist/port-resolution.js +5 -5
  4. package/package.json +1 -1
  5. package/payload/platform/config/brand.json +1 -0
  6. package/payload/platform/docs/superpowers/plans/2026-07-18-ledger-write-path-fix.md +109 -0
  7. package/payload/platform/lib/ledger-core/dist/reconcile.d.ts +7 -0
  8. package/payload/platform/lib/ledger-core/dist/reconcile.d.ts.map +1 -1
  9. package/payload/platform/lib/ledger-core/dist/reconcile.js +5 -2
  10. package/payload/platform/lib/ledger-core/dist/reconcile.js.map +1 -1
  11. package/payload/platform/lib/ledger-core/src/__tests__/reconcile.test.ts +20 -0
  12. package/payload/platform/lib/ledger-core/src/reconcile.ts +12 -2
  13. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +24 -5
  14. package/payload/platform/plugins/docs/references/google-guide.md +10 -3
  15. package/payload/platform/plugins/docs/references/ledger.md +9 -1
  16. package/payload/platform/plugins/docs/references/troubleshooting.md +4 -0
  17. package/payload/platform/plugins/google/.claude-plugin/plugin.json +1 -1
  18. package/payload/platform/plugins/google/PLUGIN.md +4 -1
  19. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js +79 -28
  20. package/payload/platform/plugins/google/mcp/dist/__tests__/account-register.test.js.map +1 -1
  21. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.d.ts +2 -0
  22. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.d.ts.map +1 -0
  23. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.js +54 -0
  24. package/payload/platform/plugins/google/mcp/dist/__tests__/boot.test.js.map +1 -0
  25. package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.js +26 -1
  26. package/payload/platform/plugins/google/mcp/dist/__tests__/google-client.test.js.map +1 -1
  27. package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.js +3 -2
  28. package/payload/platform/plugins/google/mcp/dist/__tests__/index-registration.test.js.map +1 -1
  29. package/payload/platform/plugins/google/mcp/dist/index.d.ts +9 -5
  30. package/payload/platform/plugins/google/mcp/dist/index.d.ts.map +1 -1
  31. package/payload/platform/plugins/google/mcp/dist/index.js +38 -37
  32. package/payload/platform/plugins/google/mcp/dist/index.js.map +1 -1
  33. package/payload/platform/plugins/google/mcp/dist/lib/google-client.d.ts +10 -7
  34. package/payload/platform/plugins/google/mcp/dist/lib/google-client.d.ts.map +1 -1
  35. package/payload/platform/plugins/google/mcp/dist/lib/google-client.js +25 -13
  36. package/payload/platform/plugins/google/mcp/dist/lib/google-client.js.map +1 -1
  37. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts +58 -17
  38. package/payload/platform/plugins/google/mcp/dist/tools/account-register.d.ts.map +1 -1
  39. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js +143 -37
  40. package/payload/platform/plugins/google/mcp/dist/tools/account-register.js.map +1 -1
  41. package/payload/platform/plugins/google/references/auth.md +91 -74
  42. package/payload/platform/plugins/ledger/PLUGIN.md +13 -1
  43. package/payload/platform/plugins/ledger/mcp/dist/index.js +23 -15
  44. package/payload/platform/plugins/ledger/mcp/dist/index.js.map +1 -1
  45. package/payload/platform/plugins/ledger/mcp/dist/lib/read.d.ts +11 -1
  46. package/payload/platform/plugins/ledger/mcp/dist/lib/read.d.ts.map +1 -1
  47. package/payload/platform/plugins/ledger/mcp/dist/lib/read.js +20 -1
  48. package/payload/platform/plugins/ledger/mcp/dist/lib/read.js.map +1 -1
  49. package/payload/platform/plugins/ledger/mcp/dist/lib/types.d.ts +14 -11
  50. package/payload/platform/plugins/ledger/mcp/dist/lib/types.d.ts.map +1 -1
  51. package/payload/platform/plugins/ledger/mcp/dist/lib/types.js.map +1 -1
  52. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.d.ts +12 -0
  53. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.d.ts.map +1 -0
  54. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.js +50 -0
  55. package/payload/platform/plugins/ledger/mcp/dist/lib/write-rejects.js.map +1 -0
  56. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.d.ts +5 -5
  57. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.d.ts.map +1 -1
  58. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.js +11 -11
  59. package/payload/platform/plugins/ledger/mcp/dist/tools/cash-record.js.map +1 -1
  60. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.d.ts +7 -2
  61. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.d.ts.map +1 -1
  62. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.js +9 -3
  63. package/payload/platform/plugins/ledger/mcp/dist/tools/invoice-record.js.map +1 -1
  64. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.d.ts +7 -0
  65. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.d.ts.map +1 -1
  66. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.js +3 -4
  67. package/payload/platform/plugins/ledger/mcp/dist/tools/payment-record.js.map +1 -1
  68. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.d.ts +1 -1
  69. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.d.ts.map +1 -1
  70. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.js +4 -1
  71. package/payload/platform/plugins/ledger/mcp/dist/tools/reconcile.js.map +1 -1
  72. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts +27 -2
  73. package/payload/platform/services/claude-session-manager/dist/activity-rows.d.ts.map +1 -1
  74. package/payload/platform/services/claude-session-manager/dist/activity-rows.js +33 -2
  75. package/payload/platform/services/claude-session-manager/dist/activity-rows.js.map +1 -1
  76. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
  77. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +1 -0
  78. package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
  79. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  80. package/payload/platform/services/claude-session-manager/dist/http-server.js +3 -0
  81. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  82. package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
  83. package/payload/server/{chunk-BSTIQX52.js → chunk-Y6V45R6M.js} +1 -12
  84. package/payload/server/maxy-edge.js +1 -1
  85. package/payload/server/public/activity.html +6 -6
  86. package/payload/server/public/assets/{AdminLoginScreens-BfamGqS7.js → AdminLoginScreens-B7TQZV8u.js} +1 -1
  87. package/payload/server/public/assets/{AdminShell-5nHOAzXO.js → AdminShell-DAuri4Yh.js} +1 -1
  88. package/payload/server/public/assets/{Checkbox-CD6aHwac.js → Checkbox-B1XhnhPk.js} +1 -1
  89. package/payload/server/public/assets/activity-kRwzxEKU.js +1 -0
  90. package/payload/server/public/assets/{admin-Cpcw_YE-.js → admin-BdcccSb5.js} +1 -1
  91. package/payload/server/public/assets/{browser-0znOwk1W.js → browser-B6woQ2qX.js} +1 -1
  92. package/payload/server/public/assets/{calendar-CykigHdg.js → calendar-CalCeg5T.js} +1 -1
  93. package/payload/server/public/assets/chat-9s2-L06v.js +1 -0
  94. package/payload/server/public/assets/chevron-left-C3ho8SnB.js +1 -0
  95. package/payload/server/public/assets/data-Cfr-7ERI.js +1 -0
  96. package/payload/server/public/assets/{graph-JV5_xF3V.js → graph-HeZaatSQ.js} +1 -1
  97. package/payload/server/public/assets/{graph-labels-DPYORjBH.js → graph-labels-4W7JuOgG.js} +1 -1
  98. package/payload/server/public/assets/{maximize-2-8vKr3h21.js → maximize-2-DKx-aTPb.js} +1 -1
  99. package/payload/server/public/assets/{operator-Liul1QEq.js → operator-DD9L2VJM.js} +1 -1
  100. package/payload/server/public/assets/{page-Cg7B1RQx.js → page-Ceado9Kr.js} +1 -1
  101. package/payload/server/public/assets/{page-CYRA87CB.js → page-tJxw0zNO.js} +1 -1
  102. package/payload/server/public/assets/{public-B4HMtpjt.js → public-BYFWxyeC.js} +1 -1
  103. package/payload/server/public/assets/{rotate-ccw-sz5IQSnr.js → rotate-ccw-DrzdV9h7.js} +1 -1
  104. package/payload/server/public/assets/{tasks-D9oYgEzs.js → tasks-DSwoxGzh.js} +1 -1
  105. package/payload/server/public/assets/{time-entry-format-CSuCexpM.js → time-entry-format-Bn79w6tq.js} +1 -1
  106. package/payload/server/public/assets/{triangle-alert-ClS81-CU.js → triangle-alert-CjDVh6r-.js} +1 -1
  107. package/payload/server/public/assets/{useCopyFeedback-Cn6YgeNx.js → useCopyFeedback-DXHkkJw-.js} +1 -1
  108. package/payload/server/public/assets/{useSelectionMode-BaD-ZZRk.js → useSelectionMode-D2H8jAhE.js} +1 -1
  109. package/payload/server/public/assets/{useSubAccountSwitcher-CNZL3PKn.css → useSubAccountSwitcher-Br7Z6Cpu.css} +1 -1
  110. package/payload/server/public/assets/{useVoiceRecorder-BOzHrDAU.js → useVoiceRecorder-zUvPe55I.js} +1 -1
  111. package/payload/server/public/browser.html +5 -5
  112. package/payload/server/public/calendar.html +6 -6
  113. package/payload/server/public/chat.html +12 -12
  114. package/payload/server/public/data.html +11 -11
  115. package/payload/server/public/graph.html +11 -11
  116. package/payload/server/public/index.html +14 -14
  117. package/payload/server/public/operator.html +14 -14
  118. package/payload/server/public/public.html +12 -12
  119. package/payload/server/public/tasks.html +5 -5
  120. package/payload/server/server.js +1414 -1324
  121. package/payload/server/public/assets/activity-Dj2nJzPw.js +0 -1
  122. package/payload/server/public/assets/chat-DIOJZ411.js +0 -1
  123. package/payload/server/public/assets/chevron-left-Cq7UvOI0.js +0 -1
  124. package/payload/server/public/assets/data-lHgqlhmu.js +0 -1
  125. /package/payload/server/public/assets/{useSubAccountSwitcher-CvjWJSGv.js → useSubAccountSwitcher-CUJpgkKI.js} +0 -0
@@ -1,26 +1,29 @@
1
1
  /**
2
2
  * Authenticated access to Google Calendar API v3.
3
3
  *
4
- * Refresh is delegated to platform/ui rather than performed here. A
5
- * Web-application OAuth client must present its client_secret at Google's
6
- * token endpoint, and that secret is house-only (${PLATFORM_ROOT}/config/
7
- * google-house.env) it must never reach a per-account MCP spawn. The server
8
- * holds it and exposes POST /api/google/oauth/refresh for this purpose.
4
+ * Refresh happens HERE, direct to Google. The vendor app is a Desktop
5
+ * (installed app) client, whose secret ships in brand config — Google states an
6
+ * installed-app secret "is obviously not treated as a secret" — so there is no
7
+ * server-side holder to delegate to and no reason to route through one.
9
8
  */
10
9
  import { TokenStore, type TokenBlob } from "../auth/token-store.js";
11
10
  export interface GoogleConfig {
12
11
  accountId: string;
13
12
  clientId: string;
13
+ /** Ships in brand config alongside the client id. Sanctioned for installed
14
+ * apps; PKCE remains the protection against an intercepted code. */
15
+ clientSecret: string;
14
16
  store: TokenStore;
15
- /** Loopback URL of the platform/ui route that holds the client secret. */
16
- refreshEndpoint: string;
17
17
  }
18
18
  export declare function buildQuery(q: Record<string, string | number | undefined>): string;
19
19
  export declare function isExpiring(blob: TokenBlob): boolean;
20
+ /** Test seam. Production callers reach this through callCalendar. */
21
+ export declare function accessTokenForTest(config: GoogleConfig, doFetch: typeof fetch): Promise<string>;
20
22
  export declare function callCalendar<T>(config: GoogleConfig, path: string, init?: {
21
23
  method?: string;
22
24
  body?: unknown;
23
25
  query?: Record<string, string | number | undefined>;
26
+ fetchImpl?: typeof fetch;
24
27
  }): Promise<T>;
25
28
  /** The primary calendar's id IS the account's email address. Used instead of a
26
29
  * userinfo call, because the identity scopes are deliberately not requested. */
@@ -1 +1 @@
1
- {"version":3,"file":"google-client.d.ts","sourceRoot":"","sources":["../../src/lib/google-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,UAAU,EAAwB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAK1F,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,UAAU,CAAC;IAClB,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAOjF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAEnD;AA6CD,wBAAsB,YAAY,CAAC,CAAC,EAClC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IACJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;CAChD,GACL,OAAO,CAAC,CAAC,CAAC,CA8BZ;AAED;iFACiF;AACjF,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/E"}
1
+ {"version":3,"file":"google-client.d.ts","sourceRoot":"","sources":["../../src/lib/google-client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAwB,KAAK,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAM1F,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB;yEACqE;IACrE,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,UAAU,CAAC;CACnB;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,GAAG,MAAM,CAOjF;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,SAAS,GAAG,OAAO,CAEnD;AAwDD,qEAAqE;AACrE,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,OAAO,KAAK,GACpB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,wBAAsB,YAAY,CAAC,CAAC,EAClC,MAAM,EAAE,YAAY,EACpB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IACJ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;IACpD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CACrB,GACL,OAAO,CAAC,CAAC,CAAC,CA+BZ;AAED;iFACiF;AACjF,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/E"}
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Authenticated access to Google Calendar API v3.
3
3
  *
4
- * Refresh is delegated to platform/ui rather than performed here. A
5
- * Web-application OAuth client must present its client_secret at Google's
6
- * token endpoint, and that secret is house-only (${PLATFORM_ROOT}/config/
7
- * google-house.env) it must never reach a per-account MCP spawn. The server
8
- * holds it and exposes POST /api/google/oauth/refresh for this purpose.
4
+ * Refresh happens HERE, direct to Google. The vendor app is a Desktop
5
+ * (installed app) client, whose secret ships in brand config — Google states an
6
+ * installed-app secret "is obviously not treated as a secret" — so there is no
7
+ * server-side holder to delegate to and no reason to route through one.
9
8
  */
10
9
  import { REFRESH_THRESHOLD_MS } from "../auth/token-store.js";
11
10
  import { log } from "./log.js";
12
11
  const CALENDAR_BASE = "https://www.googleapis.com/calendar/v3";
12
+ const TOKEN_URL = "https://oauth2.googleapis.com/token";
13
13
  export function buildQuery(q) {
14
14
  const parts = [];
15
15
  for (const [k, v] of Object.entries(q)) {
@@ -28,14 +28,19 @@ export function isExpiring(blob) {
28
28
  * cannot cost the account its credentials (Task 1601's lesson applied to the
29
29
  * refresh path rather than the write path).
30
30
  */
31
- async function refresh(config, blob) {
31
+ async function refresh(config, blob, doFetch) {
32
32
  if (!blob.refreshToken) {
33
33
  throw new Error("no refresh token held for this Google account; run google-account-register");
34
34
  }
35
- const res = await fetch(config.refreshEndpoint, {
35
+ const res = await doFetch(TOKEN_URL, {
36
36
  method: "POST",
37
- headers: { "content-type": "application/json" },
38
- body: JSON.stringify({ accountId: config.accountId, refreshToken: blob.refreshToken }),
37
+ headers: { "content-type": "application/x-www-form-urlencoded" },
38
+ body: new URLSearchParams({
39
+ client_id: config.clientId,
40
+ client_secret: config.clientSecret,
41
+ refresh_token: blob.refreshToken,
42
+ grant_type: "refresh_token",
43
+ }),
39
44
  });
40
45
  const text = await res.text();
41
46
  if (!res.ok) {
@@ -46,6 +51,8 @@ async function refresh(config, blob) {
46
51
  status: res.status,
47
52
  body: text.slice(0, 300),
48
53
  });
54
+ // Throwing leaves the store untouched, so a transient outage never costs
55
+ // the account its credentials.
49
56
  throw new Error(`token refresh failed (${res.status}): ${text.slice(0, 300)}`);
50
57
  }
51
58
  const json = JSON.parse(text);
@@ -55,19 +62,24 @@ async function refresh(config, blob) {
55
62
  log({ tag: "[google-mcp]", op: "refresh-ok", account: config.accountId, ttlSec: json.expires_in });
56
63
  return next;
57
64
  }
58
- async function accessToken(config) {
65
+ async function accessToken(config, doFetch) {
59
66
  const blob = config.store.read();
60
67
  if (!blob) {
61
68
  throw new Error("no Google account connected for this account; run google-account-register");
62
69
  }
63
70
  if (!isExpiring(blob))
64
71
  return blob.accessToken;
65
- return (await refresh(config, blob)).accessToken;
72
+ return (await refresh(config, blob, doFetch)).accessToken;
73
+ }
74
+ /** Test seam. Production callers reach this through callCalendar. */
75
+ export async function accessTokenForTest(config, doFetch) {
76
+ return accessToken(config, doFetch);
66
77
  }
67
78
  export async function callCalendar(config, path, init = {}) {
68
- const token = await accessToken(config);
79
+ const doFetch = init.fetchImpl ?? fetch;
80
+ const token = await accessToken(config, doFetch);
69
81
  const url = `${CALENDAR_BASE}${path}${buildQuery(init.query ?? {})}`;
70
- const res = await fetch(url, {
82
+ const res = await doFetch(url, {
71
83
  method: init.method ?? "GET",
72
84
  headers: {
73
85
  authorization: `Bearer ${token}`,
@@ -1 +1 @@
1
- {"version":3,"file":"google-client.js","sourceRoot":"","sources":["../../src/lib/google-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"google-client.js","sourceRoot":"","sources":["../../src/lib/google-client.ts"],"names":[],"mappings":"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"}
@@ -6,26 +6,32 @@ export declare function newPkce(): {
6
6
  verifier: string;
7
7
  challenge: string;
8
8
  };
9
- /** The `state` value carries BOTH the account id and the nonce, as
10
- * `<accountId>.<nonce>`.
9
+ /** Desktop (installed app) clients permit ONLY loopback redirects. https is
10
+ * rejected outright and custom URI schemes are withdrawn, so this is the whole
11
+ * option space.
11
12
  *
12
- * It cannot ride on the redirect_uri: Google requires redirect_uri to match a
13
- * registered value EXACTLY, so a per-request query parameter makes every
14
- * authorization request fail with redirect_uri_mismatch. Google's own guidance
15
- * names `state` as the mechanism for per-request application state.
13
+ * The IP literal is mandatory. RFC 8252 s7.3 makes the port irrelevant when
14
+ * matching a loopback redirect, but only for `127.0.0.1` / `::1` — NOT for the
15
+ * hostname `localhost`, which strict servers match literally.
16
16
  *
17
- * Putting the account id in an attacker-visible field is safe because it is
18
- * routing information, not authorisation: the callback still requires the
19
- * nonce half to equal the one stored in that account's pending entry, and an
20
- * attacker cannot produce a valid nonce for an account they do not control. */
21
- export declare function encodeState(accountId: string, nonce: string): string;
22
- export declare function decodeState(state: string): {
23
- accountId: string;
24
- nonce: string;
25
- } | null;
17
+ * Nothing listens on this port, by design: the consenting browser is on the
18
+ * user's own phone, so the redirect fails to load and the user copies the code
19
+ * out of the address bar. The value is fixed so the consent URL is
20
+ * deterministic and one register's logs compare against another's. */
21
+ export declare const LOOPBACK_REDIRECT_URI = "http://127.0.0.1:8571";
22
+ /** `state` is an opaque CSRF nonce and nothing more.
23
+ *
24
+ * It deliberately does NOT carry the account id. Under the Desktop flow the
25
+ * pending entry is keyed on the spawn's own ACCOUNT_ID, so submit can only ever
26
+ * read its own account's pending, and PKCE binds the code to that entry's
27
+ * verifier. Routing information in `state` would therefore buy nothing, while
28
+ * putting an account uuid into a URL opened on a personal phone, stored in
29
+ * browser history and Google's logs, and pasted back through chat.
30
+ *
31
+ * (Task 1761 encoded `<accountId>.<nonce>` because a shared hosted callback had
32
+ * to route an inbound request to an account. That callback is gone.) */
26
33
  export declare function buildConsentUrl(args: {
27
34
  clientId: string;
28
- redirectUri: string;
29
35
  state: string;
30
36
  challenge: string;
31
37
  accountId: string;
@@ -42,7 +48,6 @@ export declare function runAccountRegisterStart(args: {
42
48
  accountId: string;
43
49
  accountsDir: string;
44
50
  clientId: string;
45
- publicBase: string;
46
51
  }): Promise<{
47
52
  status: "pending" | "in-progress";
48
53
  consentUrl?: string;
@@ -56,4 +61,40 @@ export declare function runAccountRegisterPoll(args: {
56
61
  accounts: ConnectedAccount[];
57
62
  ageSec?: number;
58
63
  }>;
64
+ /** Users paste what they can see, and what they can see is Google's loopback
65
+ * redirect — which ALWAYS carries `scope` alongside `code`, and often
66
+ * `authuser` and `prompt` too. So the realistic pastes are a whole URL or a
67
+ * `code=…&scope=…` fragment, not a bare value.
68
+ *
69
+ * Extracting `code` properly matters because a mangled value reaches Google as
70
+ * an opaque string and comes back `invalid_grant`, which reads to the user as
71
+ * "your code expired" and sends them round the consent loop again. It never
72
+ * says the paste was the problem.
73
+ *
74
+ * A malformed percent escape must not throw either: `decodeURIComponent` raises
75
+ * URIError on a stray `%`, and surfacing that instead of Google's own error
76
+ * would be our parser blaming the user for a value Google would have explained.
77
+ */
78
+ export declare function normalisePastedCode(raw: string): string;
79
+ /**
80
+ * Finish a registration from the code the user pasted back.
81
+ *
82
+ * The exchange happens HERE, in the plugin, because a Desktop client's secret
83
+ * ships in brand config — there is no server-side holder to delegate to. The
84
+ * redirect_uri sent here is the same constant the consent URL carried; Google
85
+ * compares them byte for byte.
86
+ */
87
+ export declare function runAccountRegisterSubmit(args: {
88
+ accountId: string;
89
+ accountsDir: string;
90
+ clientId: string;
91
+ clientSecret: string;
92
+ code: string;
93
+ fetchImpl?: typeof fetch;
94
+ }): Promise<{
95
+ status: "registered";
96
+ email: string;
97
+ refreshTokenIssued: boolean;
98
+ warning?: string;
99
+ }>;
59
100
  //# sourceMappingURL=account-register.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-register.d.ts","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"AAgBA,eAAO,MAAM,cAAc,6CAA6C,CAAC;AAGzE;qDACqD;AACrD,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,wBAAgB,OAAO,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAGjE;AAED;;;;;;;;;;;gFAWgF;AAChF,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAItF;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAeT;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,GAAG,YAAY,CAAC;CAC7B;AAED;;6DAE6D;AAC7D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAaxF;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAgCvF;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,CAUD"}
1
+ {"version":3,"file":"account-register.d.ts","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,cAAc,6CAA6C,CAAC;AAKzE;qDACqD;AACrD,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAExC,wBAAgB,OAAO,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAGjE;AAED;;;;;;;;;;;uEAWuE;AACvE,eAAO,MAAM,qBAAqB,0BAA0B,CAAC;AAE7D;;;;;;;;;;yEAUyE;AACzE,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB,GAAG,MAAM,CAaT;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,IAAI,GAAG,YAAY,CAAC;CAC7B;AAED;;6DAE6D;AAC7D,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAaxF;AAED,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,SAAS,GAAG,aAAa,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0BvF;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IACtD,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC,CAUD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAoBvD;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,IAAI,EAAE;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,kBAAkB,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0ElG"}
@@ -2,10 +2,11 @@
2
2
  * Register flow: authorization-code + PKCE.
3
3
  *
4
4
  * `runAccountRegisterStart` mints the PKCE pair and `state`, persists them, and
5
- * returns a consent URL the operator opens on any device. Google redirects to
6
- * platform/ui's /api/google/oauth/callback, which holds the client secret,
7
- * exchanges the code, and writes tokens. `runAccountRegisterPoll` then reports
8
- * the outcome from local state only — no network.
5
+ * returns a consent URL the user opens on any device. Google redirects to a
6
+ * loopback address nothing listens on, so the page fails to load and the user
7
+ * copies the code from the address bar; `runAccountRegisterSubmit` exchanges it
8
+ * here, in-process, using the brand-config client secret.
9
+ * `runAccountRegisterPoll` reports the outcome from local state only.
9
10
  */
10
11
  import { createHash, randomBytes } from "node:crypto";
11
12
  import { existsSync, readdirSync } from "node:fs";
@@ -15,6 +16,8 @@ import { TokenStore } from "../auth/token-store.js";
15
16
  import { log } from "../lib/log.js";
16
17
  export const CALENDAR_SCOPE = "https://www.googleapis.com/auth/calendar";
17
18
  const AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth";
19
+ const TOKEN_URL = "https://oauth2.googleapis.com/token";
20
+ const PRIMARY_CALENDAR_URL = "https://www.googleapis.com/calendar/v3/calendars/primary";
18
21
  /** Google refuses an authorization code older than roughly ten minutes; a
19
22
  * pending entry past that is stranded, not live. */
20
23
  export const PENDING_LIFETIME_SEC = 600;
@@ -22,33 +25,34 @@ export function newPkce() {
22
25
  const verifier = randomBytes(48).toString("base64url");
23
26
  return { verifier, challenge: createHash("sha256").update(verifier).digest("base64url") };
24
27
  }
25
- /** The `state` value carries BOTH the account id and the nonce, as
26
- * `<accountId>.<nonce>`.
28
+ /** Desktop (installed app) clients permit ONLY loopback redirects. https is
29
+ * rejected outright and custom URI schemes are withdrawn, so this is the whole
30
+ * option space.
27
31
  *
28
- * It cannot ride on the redirect_uri: Google requires redirect_uri to match a
29
- * registered value EXACTLY, so a per-request query parameter makes every
30
- * authorization request fail with redirect_uri_mismatch. Google's own guidance
31
- * names `state` as the mechanism for per-request application state.
32
+ * The IP literal is mandatory. RFC 8252 s7.3 makes the port irrelevant when
33
+ * matching a loopback redirect, but only for `127.0.0.1` / `::1` — NOT for the
34
+ * hostname `localhost`, which strict servers match literally.
32
35
  *
33
- * Putting the account id in an attacker-visible field is safe because it is
34
- * routing information, not authorisation: the callback still requires the
35
- * nonce half to equal the one stored in that account's pending entry, and an
36
- * attacker cannot produce a valid nonce for an account they do not control. */
37
- export function encodeState(accountId, nonce) {
38
- return `${accountId}.${nonce}`;
39
- }
40
- export function decodeState(state) {
41
- const idx = state.lastIndexOf(".");
42
- if (idx <= 0 || idx === state.length - 1)
43
- return null;
44
- return { accountId: state.slice(0, idx), nonce: state.slice(idx + 1) };
45
- }
36
+ * Nothing listens on this port, by design: the consenting browser is on the
37
+ * user's own phone, so the redirect fails to load and the user copies the code
38
+ * out of the address bar. The value is fixed so the consent URL is
39
+ * deterministic and one register's logs compare against another's. */
40
+ export const LOOPBACK_REDIRECT_URI = "http://127.0.0.1:8571";
41
+ /** `state` is an opaque CSRF nonce and nothing more.
42
+ *
43
+ * It deliberately does NOT carry the account id. Under the Desktop flow the
44
+ * pending entry is keyed on the spawn's own ACCOUNT_ID, so submit can only ever
45
+ * read its own account's pending, and PKCE binds the code to that entry's
46
+ * verifier. Routing information in `state` would therefore buy nothing, while
47
+ * putting an account uuid into a URL opened on a personal phone, stored in
48
+ * browser history and Google's logs, and pasted back through chat.
49
+ *
50
+ * (Task 1761 encoded `<accountId>.<nonce>` because a shared hosted callback had
51
+ * to route an inbound request to an account. That callback is gone.) */
46
52
  export function buildConsentUrl(args) {
47
- // redirect_uri is sent VERBATIM — no query string. See encodeState above.
48
- const redirect = args.redirectUri;
49
53
  const q = new URLSearchParams({
50
54
  client_id: args.clientId,
51
- redirect_uri: redirect,
55
+ redirect_uri: LOOPBACK_REDIRECT_URI,
52
56
  response_type: "code",
53
57
  scope: CALENDAR_SCOPE,
54
58
  access_type: "offline",
@@ -91,24 +95,18 @@ export async function runAccountRegisterStart(args) {
91
95
  });
92
96
  return { status: "in-progress", ageSec: age };
93
97
  }
94
- const nonce = randomBytes(16).toString("hex");
95
- const state = encodeState(args.accountId, nonce);
98
+ const state = randomBytes(16).toString("hex");
96
99
  const { verifier, challenge } = newPkce();
97
- log({ tag: "[google-oauth]", op: "register", account: args.accountId, reg: nonce });
98
- // The pending entry stores the NONCE, not the composed state: the account is
99
- // already implied by which account's store this is, and comparing the nonce
100
- // alone keeps the check independent of the encoding.
101
- pending.write({ state: nonce, verifier, createdAt: Date.now() });
102
- log({ tag: "[google-oauth]", op: "pending-write", reg: nonce, account: args.accountId });
103
- const redirectUri = `${args.publicBase}/api/google/oauth/callback`;
100
+ log({ tag: "[google-oauth]", op: "register", account: args.accountId, reg: state });
101
+ pending.write({ state, verifier, createdAt: Date.now() });
102
+ log({ tag: "[google-oauth]", op: "pending-write", reg: state, account: args.accountId });
104
103
  const consentUrl = buildConsentUrl({
105
104
  clientId: args.clientId,
106
- redirectUri,
107
105
  state,
108
106
  challenge,
109
107
  accountId: args.accountId,
110
108
  });
111
- log({ tag: "[google-oauth]", op: "consent-url", reg: nonce, scopes: CALENDAR_SCOPE, redirect: redirectUri });
109
+ log({ tag: "[google-oauth]", op: "consent-url", reg: state, scopes: CALENDAR_SCOPE, redirect: LOOPBACK_REDIRECT_URI });
112
110
  return { status: "pending", consentUrl };
113
111
  }
114
112
  export async function runAccountRegisterPoll(args) {
@@ -123,4 +121,112 @@ export async function runAccountRegisterPoll(args) {
123
121
  }
124
122
  return { status: "pending", accounts, ageSec: age };
125
123
  }
124
+ /** Users paste what they can see, and what they can see is Google's loopback
125
+ * redirect — which ALWAYS carries `scope` alongside `code`, and often
126
+ * `authuser` and `prompt` too. So the realistic pastes are a whole URL or a
127
+ * `code=…&scope=…` fragment, not a bare value.
128
+ *
129
+ * Extracting `code` properly matters because a mangled value reaches Google as
130
+ * an opaque string and comes back `invalid_grant`, which reads to the user as
131
+ * "your code expired" and sends them round the consent loop again. It never
132
+ * says the paste was the problem.
133
+ *
134
+ * A malformed percent escape must not throw either: `decodeURIComponent` raises
135
+ * URIError on a stray `%`, and surfacing that instead of Google's own error
136
+ * would be our parser blaming the user for a value Google would have explained.
137
+ */
138
+ export function normalisePastedCode(raw) {
139
+ const s = raw.trim();
140
+ // A full URL, or a query fragment carrying more than one parameter.
141
+ if (s.includes("://") || s.startsWith("?") || s.includes("&")) {
142
+ const query = s.slice(s.indexOf("?") >= 0 ? s.indexOf("?") + 1 : 0);
143
+ const fromQuery = new URLSearchParams(query).get("code");
144
+ if (fromQuery)
145
+ return fromQuery.trim();
146
+ }
147
+ let out = s;
148
+ if (out.startsWith("code="))
149
+ out = out.slice("code=".length);
150
+ if (out.includes("%")) {
151
+ try {
152
+ out = decodeURIComponent(out);
153
+ }
154
+ catch {
155
+ // Leave it as pasted; Google's error is more useful than ours.
156
+ }
157
+ }
158
+ return out.trim();
159
+ }
160
+ /**
161
+ * Finish a registration from the code the user pasted back.
162
+ *
163
+ * The exchange happens HERE, in the plugin, because a Desktop client's secret
164
+ * ships in brand config — there is no server-side holder to delegate to. The
165
+ * redirect_uri sent here is the same constant the consent URL carried; Google
166
+ * compares them byte for byte.
167
+ */
168
+ export async function runAccountRegisterSubmit(args) {
169
+ const doFetch = args.fetchImpl ?? fetch;
170
+ const pending = new PendingStore(args.accountId, args.accountsDir);
171
+ const held = pending.read();
172
+ if (!held) {
173
+ throw new Error("no registration in progress; run google-account-register first");
174
+ }
175
+ const code = normalisePastedCode(args.code);
176
+ log({ tag: "[google-oauth]", op: "submit", account: args.accountId, reg: held.state });
177
+ const res = await doFetch(TOKEN_URL, {
178
+ method: "POST",
179
+ headers: { "content-type": "application/x-www-form-urlencoded" },
180
+ body: new URLSearchParams({
181
+ code,
182
+ client_id: args.clientId,
183
+ client_secret: args.clientSecret,
184
+ redirect_uri: LOOPBACK_REDIRECT_URI,
185
+ grant_type: "authorization_code",
186
+ code_verifier: held.verifier,
187
+ }),
188
+ });
189
+ const text = await res.text();
190
+ if (!res.ok) {
191
+ // Never discard the body: invalid_grant means expired or already used,
192
+ // redirect_uri_mismatch means the sent and registered redirects diverged.
193
+ log({
194
+ tag: "[google-oauth]", op: "submit", reg: held.state,
195
+ outcome: "error", status: res.status, body: text.slice(0, 300),
196
+ });
197
+ throw new Error(`token exchange failed (${res.status}): ${text.slice(0, 300)}`);
198
+ }
199
+ const tok = JSON.parse(text);
200
+ // Identity comes from the primary calendar's id, which IS the address, so the
201
+ // identity scopes are never requested.
202
+ const calRes = await doFetch(PRIMARY_CALENDAR_URL, {
203
+ headers: { authorization: `Bearer ${tok.access_token}` },
204
+ });
205
+ const calText = await calRes.text();
206
+ if (!calRes.ok) {
207
+ throw new Error(`identity lookup failed (${calRes.status}): ${calText.slice(0, 200)}`);
208
+ }
209
+ const email = JSON.parse(calText).id;
210
+ const stored = new TokenStore(args.accountId, args.accountsDir, email).store(tok.access_token, tok.refresh_token ?? null, tok.expires_in, { email, scopes: tok.scope ? tok.scope.split(" ") : [] });
211
+ log({
212
+ tag: "[google-oauth]", op: "tokens-write", reg: held.state,
213
+ account: args.accountId, refreshIssued: tok.refresh_token ? "true" : "false",
214
+ });
215
+ pending.clear();
216
+ log({ tag: "[google-oauth]", op: "registered", reg: held.state, account: args.accountId, email });
217
+ // A connection with no refresh token works for about an hour and then dies.
218
+ // Reporting only in the log would tell the operator "connected" and leave the
219
+ // failure to surface later as an unexplained loss of access.
220
+ const refreshTokenIssued = Boolean(stored.refreshToken);
221
+ return {
222
+ status: "registered",
223
+ email,
224
+ refreshTokenIssued,
225
+ ...(refreshTokenIssued
226
+ ? {}
227
+ : {
228
+ warning: "Google returned no refresh token, so this connection will stop working when the access token expires in about an hour. Re-run google-account-register to reconnect.",
229
+ }),
230
+ };
231
+ }
126
232
  //# sourceMappingURL=account-register.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"account-register.js","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"account-register.js","sourceRoot":"","sources":["../../src/tools/account-register.ts"],"names":[],"mappings":"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"}