@bongos/core 1.24.4 → 1.24.6

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 (61) hide show
  1. package/.bongos-core.json +99 -59
  2. package/clients/bongos-client/README.md +1 -1
  3. package/clients/bongos-client/bongos-client.global.js +6 -0
  4. package/clients/bongos-client/index.cjs +6 -0
  5. package/clients/bongos-client/index.d.ts +7 -0
  6. package/clients/bongos-client/index.mjs +6 -0
  7. package/docs/adr/0396-google-sign-in-a-stand-in-login-and-a-browser-approved-cli-sign-in.md +8 -0
  8. package/docs/api/openapi.json +110 -5
  9. package/docs/api-reference.md +6 -3
  10. package/docs/copy-inventory.md +47 -43
  11. package/docs/copy-registry.json +81 -45
  12. package/docs/file-map.md +3 -2
  13. package/docs/module-api-changelog.md +4 -2
  14. package/docs/page-inventory.json +2 -1
  15. package/docs/page-readings.json +64 -56
  16. package/migrations/core_286_credit_log_no_spend.sql +128 -0
  17. package/modules/copy-desk/auto-close.js +51 -11
  18. package/modules/copy-desk/page-status.js +18 -6
  19. package/modules/copy-desk/tests/copy_no_cms.mjs +8 -1
  20. package/modules/copy-desk/tests/copy_page_auto_close.mjs +68 -6
  21. package/modules/copy-desk/tests/copy_page_status.mjs +5 -1
  22. package/modules/hall-ui/public/tweak-editor.js +2 -1
  23. package/modules/lifecycle/db-claims.js +2 -2
  24. package/modules/lifecycle/db-ship.js +2 -2
  25. package/modules/lifecycle/routes/claims.js +7 -1
  26. package/modules/platform-identity/account-logins.js +131 -0
  27. package/modules/platform-identity/migrations/platform_identity_035_account_login_email_idx.sql +19 -0
  28. package/modules/platform-identity/routes/profile.js +29 -1
  29. package/modules/platform-identity/routes/sso.js +25 -3
  30. package/modules/public-landing/public/account.html +114 -0
  31. package/modules/public-landing/public/account.states.json +1 -0
  32. package/modules/ui-design/kit/serve.js +24 -0
  33. package/package-lock.json +2 -2
  34. package/package.json +1 -1
  35. package/release-notes.json +39 -1
  36. package/scripts/bongos/codemod-rename-scripts-gds.js +1 -3
  37. package/scripts/bongos/dev-box-guard.js +0 -1
  38. package/scripts/bongos/publish-manifest.js +1 -1
  39. package/scripts/bongos/run-unit-tests.js +4 -0
  40. package/src/bongos/agent-standing-rules.js +44 -0
  41. package/src/bongos/auth-github.js +24 -7
  42. package/src/bongos/module-scope-map.js +3 -2
  43. package/src/bongos/routes/auth-google.js +71 -5
  44. package/src/bongos/routes/auth-link.js +132 -0
  45. package/src/bongos/routes/me.js +4 -1
  46. package/src/bongos/routes.js +2 -0
  47. package/src/bongos/sign-in-pages.js +20 -1
  48. package/src/module-api.js +1 -1
  49. package/tests/account_linking.mjs +289 -0
  50. package/tests/account_logins_db.mjs +56 -0
  51. package/tests/agent_standing_rules.mjs +142 -0
  52. package/tests/claims_batch_routes.mjs +115 -25
  53. package/tests/copy_desk_page_release.mjs +20 -0
  54. package/tests/copy_stuck_page_tweaks.mjs +5 -3
  55. package/tests/credit_log_no_spend_db.mjs +160 -0
  56. package/tests/effective_visibility_predicate.mjs +8 -0
  57. package/tests/government_laws_session.mjs +2 -1
  58. package/tests/hall_tweak_editor.mjs +11 -0
  59. package/tests/host_topology_skips.mjs +2 -0
  60. package/tests/hub_account_page.mjs +91 -5
  61. package/tests/run_node_reroute.mjs +136 -0
@@ -183,6 +183,8 @@ export function createClient(opts = {}) {
183
183
  getAuthGoogleCallback: (args) => request("GET", "/auth/google/callback", { hasBody: false }, args),
184
184
  // GET /auth/google/start — rank: public — GET /auth/google/start
185
185
  getAuthGoogleStart: (args) => request("GET", "/auth/google/start", { hasBody: false }, args),
186
+ // GET /auth/link/github/start — rank: public — GET /auth/link/github/start
187
+ getAuthLinkGithubStart: (args) => request("GET", "/auth/link/github/start", { hasBody: false }, args),
186
188
  // POST /auth/logout — rank: any-builder — POST /auth/logout
187
189
  postAuthLogout: (args) => request("POST", "/auth/logout", { hasBody: true }, args),
188
190
  // POST /auth/revoke — rank: archon — POST /auth/revoke
@@ -193,6 +195,8 @@ export function createClient(opts = {}) {
193
195
  getAuthWebAdmissionStatus: (args) => request("GET", "/auth/web/admission-status", { hasBody: false }, args),
194
196
  // GET /auth/web/callback — rank: public — GET /auth/web/callback
195
197
  getAuthWebCallback: (args) => request("GET", "/auth/web/callback", { hasBody: false }, args),
198
+ // GET /auth/web/callback/link — rank: public — GET /auth/web/callback/link
199
+ getAuthWebCallbackLink: (args) => request("GET", "/auth/web/callback/link", { hasBody: false }, args),
196
200
  // GET /auth/web/handoff — rank: public — GET /auth/web/handoff
197
201
  getAuthWebHandoff: (args) => request("GET", "/auth/web/handoff", { hasBody: false }, args),
198
202
  // GET /auth/web/start — rank: public — GET /auth/web/start
@@ -851,6 +855,8 @@ export function createClient(opts = {}) {
851
855
  postMeSessionsRevokeAll: (args) => request("POST", "/me/sessions/revoke-all", { hasBody: true }, args),
852
856
  // GET /me/sign-in-methods — rank: any-builder — GET /me/sign-in-methods
853
857
  getMeSignInMethods: (args) => request("GET", "/me/sign-in-methods", { hasBody: false }, args),
858
+ // DELETE /me/sign-in-methods/{provider} — rank: any-builder — DELETE /me/sign-in-methods/:provider
859
+ deleteMeSignInMethodsProvider: (args) => request("DELETE", "/me/sign-in-methods/{provider}", { hasBody: false }, args),
854
860
  // GET /me/skill-prefs — rank: any-builder — GET /me/skill-prefs
855
861
  getMeSkillPrefs: (args) => request("GET", "/me/skill-prefs", { hasBody: false }, args),
856
862
  // PATCH /me/skill-prefs — rank: any-builder — PATCH /me/skill-prefs
@@ -50,3 +50,11 @@ Decision 8's two refusals are lifted, without ever sending a minted key to a cor
50
50
  - **People read the handle.** The hall's admission queue shows `ana`, not `~ana`.
51
51
 
52
52
  Credits, ranks and community pages needed no change: the hub's check-in and rollup already take a negative key. Still open: a hall's command-line sign-in (`/sso/device/*`) is GitHub's device flow, so a Google-only person signs in to a hall in the browser; engineering work still needs GitHub (task 1004997).
53
+
54
+ ## Amendment — linking GitHub and Google, both ways (task 1004995)
55
+
56
+ - **A link is a sign-in with the other account, made while signed in.** Link Google rides the Google sign-in with a flag in the host-only state cookie (Google matches redirect URIs exactly). Link GitHub uses its own callback, `/auth/web/callback/link`, a subdirectory of the registered GitHub callback, which GitHub accepts, so the owner's GitHub app needs no change. Both answers land on `/account#aWaysIn`.
57
+ - **Never a merge.** A way in that already reaches another person, or a GitHub account with its own builder row here, is refused and the page says so: "That GitHub account already has its own account here, so it was not linked." Both accounts may hold credits and history, and joining them is not the server's decision.
58
+ - **Removing.** Never the last way in. And never GitHub from an account born with it: that account's key is its GitHub id, so a GitHub sign-in would still reach it and the removal would be a lie. A person who joined with Google may remove a linked GitHub, and then shows their stand-in again from their next sign-in.
59
+ - **Every GitHub sign-in on the hub finds the person first** (the ADR 0393 carry-over, closed): the web and device sign-ins ask the hub who the GitHub id reaches and use that key. A project's command-line sign-in (`/sso/device/poll`) cannot tell whether the project takes a minted key, so for a GitHub account linked to someone who joined with Google it says to sign in in the browser.
60
+ - **Matching emails suggest, never join.** This amends decision 3's "emails are never looked up" in one place only: on a first Google sign-in, if another account's GitHub way in shows the address Google verified, the person is offered "Sign in with GitHub" (then link Google from the account page) or "Make a new account with Google". Only the provider's name crosses; no account is named or joined. The hub keeps the GitHub address it sees at sign-in (GitHub's public address) for this alone.
@@ -2173,6 +2173,27 @@
2173
2173
  "security": []
2174
2174
  }
2175
2175
  },
2176
+ "/auth/link/github/start": {
2177
+ "get": {
2178
+ "operationId": "get_auth_link_github_start",
2179
+ "tags": [
2180
+ "auth"
2181
+ ],
2182
+ "summary": "GET /auth/link/github/start",
2183
+ "description": "an OAuth entry point that gates itself: with no live session it sends the person to /account, so only a signed-in person ever links (ADR 0396).\n\n**Rank:** `public` — No authentication — any caller.",
2184
+ "x-rank": "public",
2185
+ "x-source": "src/bongos/routes/auth-link.js",
2186
+ "responses": {
2187
+ "200": {
2188
+ "description": "Success."
2189
+ },
2190
+ "400": {
2191
+ "$ref": "#/components/responses/BadRequest"
2192
+ }
2193
+ },
2194
+ "security": []
2195
+ }
2196
+ },
2176
2197
  "/auth/logout": {
2177
2198
  "post": {
2178
2199
  "operationId": "post_auth_logout",
@@ -2364,6 +2385,27 @@
2364
2385
  "security": []
2365
2386
  }
2366
2387
  },
2388
+ "/auth/web/callback/link": {
2389
+ "get": {
2390
+ "operationId": "get_auth_web_callback_link",
2391
+ "tags": [
2392
+ "auth"
2393
+ ],
2394
+ "summary": "GET /auth/web/callback/link",
2395
+ "description": "the OAuth callback for linking; the state cookie + code are the bearer, and the live session cookie names the person (no session: /account).\n\n**Rank:** `public` — No authentication — any caller.",
2396
+ "x-rank": "public",
2397
+ "x-source": "src/bongos/routes/auth-link.js",
2398
+ "responses": {
2399
+ "200": {
2400
+ "description": "Success."
2401
+ },
2402
+ "400": {
2403
+ "$ref": "#/components/responses/BadRequest"
2404
+ }
2405
+ },
2406
+ "security": []
2407
+ }
2408
+ },
2367
2409
  "/auth/web/handoff": {
2368
2410
  "get": {
2369
2411
  "operationId": "get_auth_web_handoff",
@@ -4162,7 +4204,7 @@
4162
4204
  "claims"
4163
4205
  ],
4164
4206
  "summary": "POST /claims/batch",
4165
- "description": "Atomic multi-claim. Body: { task_ids: [n,n,n], worktree_name?: string }. All-or-nothing: if any single task fails (already claimed, not ready, or touches conflict with another active claim OR another task in the batch), the whole transaction rolls back and we return 409 with a structured failures[] enumerating every problem found in one pass. rank: any-builder — atomic multi-claim; same Xenos row-level filter applies. V3.R13 (task 237): same newcomer gate as POST /claims — a fresh builder can't sneak around the \"one claim at a time\" rule by batching.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
4207
+ "description": "Atomic multi-claim. Body: { task_ids: [n,n,n], worktree_name?: string }. All-or-nothing: if any single task fails (already claimed, not ready, or touches conflict with another active claim OR another task in the batch), the whole transaction rolls back and we return 409 with a structured failures[] enumerating every problem found in one pass. rank: any-builder — atomic multi-claim; same Xenos row-level filter applies. V3.R13 (task 237): same newcomer gate as POST /claims — a fresh builder can't sneak around the \"one claim at a time\" rule by batching. task 1005005: and the same gateOneActiveClaimPerSession as POST /claims, in the same order, so a session already holding a claim in this tree cannot batch more work into it. It reads the SESSION's existing active claims (the batch's own rows do not exist yet), keyed on the body's worktree_name — the caller's tree, which a batch also uses as its row-name prefix. A bind_session:false batch (the hall) has no session and passes, as on /claims.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
4166
4208
  "x-rank": "any-builder",
4167
4209
  "x-source": "modules/lifecycle/routes/claims.js",
4168
4210
  "requestBody": {
@@ -15999,7 +16041,7 @@
15999
16041
  "me"
16000
16042
  ],
16001
16043
  "summary": "GET /me/sign-in-methods",
16002
- "description": "the ways the caller's OWN account signs in (task 1004992, ADR 0393): GitHub, Google, or both, with the address each provider vouched for. Keyed on the authenticated github_id (the person key); the provider's user id never crosses. A system:* principal has no platform account: [].\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
16044
+ "description": "the ways the caller's OWN account signs in (task 1004992, ADR 0393): GitHub, Google, or both, with the address each provider vouched for. Keyed on the authenticated github_id (the person key); the provider's user id never crosses. A system:* principal has no platform account: []. Each method carries `unlink_refused` (null, 'last_way_in' or 'born_with') so the page can say why a Remove is missing (task 1004995).\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
16003
16045
  "x-rank": "any-builder",
16004
16046
  "x-source": "modules/platform-identity/routes/profile.js",
16005
16047
  "responses": {
@@ -16030,6 +16072,58 @@
16030
16072
  ]
16031
16073
  }
16032
16074
  },
16075
+ "/me/sign-in-methods/{provider}": {
16076
+ "delete": {
16077
+ "operationId": "delete_me_sign_in_methods_provider",
16078
+ "tags": [
16079
+ "me"
16080
+ ],
16081
+ "summary": "DELETE /me/sign-in-methods/:provider",
16082
+ "description": "remove one way in from the caller's OWN account (task 1004995), keyed on the authenticated person key. Never the last way in, and never GitHub from an account born with it (its key is its GitHub id). Adding a way in is a sign-in, so it lives with the sign-in routes, not here.\n\n**Rank:** `any-builder` — Any authenticated builder (row-level ownership enforced in-handler).",
16083
+ "x-rank": "any-builder",
16084
+ "x-source": "modules/platform-identity/routes/profile.js",
16085
+ "parameters": [
16086
+ {
16087
+ "name": "provider",
16088
+ "in": "path",
16089
+ "required": true,
16090
+ "schema": {
16091
+ "type": "string"
16092
+ },
16093
+ "description": "Path parameter `provider`."
16094
+ }
16095
+ ],
16096
+ "responses": {
16097
+ "200": {
16098
+ "description": "Success.",
16099
+ "content": {
16100
+ "application/json": {
16101
+ "schema": {
16102
+ "$ref": "#/components/schemas/DeleteMeSignInMethodsProviderResponse"
16103
+ }
16104
+ }
16105
+ }
16106
+ },
16107
+ "400": {
16108
+ "$ref": "#/components/responses/BadRequest"
16109
+ },
16110
+ "401": {
16111
+ "$ref": "#/components/responses/Unauthorized"
16112
+ },
16113
+ "403": {
16114
+ "$ref": "#/components/responses/Forbidden"
16115
+ },
16116
+ "404": {
16117
+ "$ref": "#/components/responses/NotFound"
16118
+ }
16119
+ },
16120
+ "security": [
16121
+ {
16122
+ "builderSession": []
16123
+ }
16124
+ ]
16125
+ }
16126
+ },
16033
16127
  "/me/skill-prefs": {
16034
16128
  "get": {
16035
16129
  "operationId": "get_me_skill_prefs",
@@ -29998,6 +30092,17 @@
29998
30092
  "views"
29999
30093
  ]
30000
30094
  },
30095
+ "DeleteMeSignInMethodsProviderResponse": {
30096
+ "type": "object",
30097
+ "properties": {
30098
+ "ok": {
30099
+ "type": "boolean"
30100
+ }
30101
+ },
30102
+ "required": [
30103
+ "ok"
30104
+ ]
30105
+ },
30001
30106
  "DeleteMemoryFileResponse": {
30002
30107
  "type": "object",
30003
30108
  "properties": {
@@ -40436,9 +40541,9 @@
40436
40541
  "description": "A required dependency/feature is not configured or is temporarily down."
40437
40542
  }
40438
40543
  },
40439
- "x-endpoint-count": 636,
40440
- "x-schema-count": 686,
40544
+ "x-endpoint-count": 639,
40545
+ "x-schema-count": 687,
40441
40546
  "x-undocumented-bodies": 12,
40442
- "x-response-schemas": 441,
40547
+ "x-response-schemas": 442,
40443
40548
  "x-generated-by": "scripts/bongos/gen-api-docs.js"
40444
40549
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  # Bongos API reference
4
4
 
5
- > **Generated from the live route files** — the route file is authoritative. 636 endpoints across 105 route files.
5
+ > **Generated from the live route files** — the route file is authoritative. 639 endpoints across 106 route files.
6
6
  > Machine-readable spec: [`docs/api/openapi.json`](api/openapi.json) (OpenAPI 3.1). Rendered docs site: **`/docs`** (e.g. `cloudbongos.com/docs`).
7
7
 
8
8
  Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust-boundary-server-enforced-permissions.md)): `public` < `any-builder` < `metic+archon` < `archon`.
@@ -78,7 +78,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
78
78
  |---|---|---|---|---|
79
79
  | GET | `/api/bongos/audit-log` | `metic+archon` | — | GET /api/bongos/audit-log?limit=&offset=&builder_id=&method= Paginated, newest-first. |
80
80
 
81
- ## `auth` (19)
81
+ ## `auth` (21)
82
82
 
83
83
  | Method | Path | Rank | Body | Description |
84
84
  |---|---|---|---|---|
@@ -94,11 +94,13 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
94
94
  | POST | `/api/bongos/auth/discord/unlink` | `any-builder` | — | unlink your OWN Discord. |
95
95
  | GET | `/api/bongos/auth/google/callback` | `public` | — | OAuth callback; the state cookie + code are the bearer. |
96
96
  | GET | `/api/bongos/auth/google/start` | `public` | — | entry into the Google OAuth handshake; identity establishment only. |
97
+ | GET | `/api/bongos/auth/link/github/start` | `public` | — | an OAuth entry point that gates itself: with no live session it sends the person to /account, so only a signed-in person ever links (ADR … |
97
98
  | POST | `/api/bongos/auth/logout` | `any-builder` | — | own session, no rank gate (a Xenos can log themselves out). |
98
99
  | POST | `/api/bongos/auth/revoke` | `archon` | `session_id` | POST /auth/revoke — V3.R38 / task 259. |
99
100
  | POST | `/api/bongos/auth/revoke-all` | `archon` | `builder_id` | POST /auth/revoke-all — V3.R38 / task 259. |
100
101
  | GET | `/api/bongos/auth/web/admission-status` | `public` | — | GET /auth/web/admission-status?login=X — the probe renderAccessPendingPage polls (task 1002097). |
101
102
  | GET | `/api/bongos/auth/web/callback` | `public` | — | OAuth callback; the state cookie + code are the bearer. |
103
+ | GET | `/api/bongos/auth/web/callback/link` | `public` | — | the OAuth callback for linking; the state cookie + code are the bearer, and the live session cookie names the person (no session: <redacted> |
102
104
  | GET | `/api/bongos/auth/web/handoff` | `public` | — | GET /auth/web/handoff?code=&return= — the far side of the one-time session handoff (task 1004357). |
103
105
  | GET | `/api/bongos/auth/web/start` | `public` | — | /auth/web — browser flow (used by the /builders page). |
104
106
 
@@ -525,7 +527,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
525
527
  | GET | `/api/bongos/market-watch/ask` | `any-builder` | — | every member reads their own card; nobody else's (isMember in gate()). |
526
528
  | POST | `/api/bongos/market-watch/ask/answer` | `any-builder` | `week_of`, `picks`, `names`, `nothing`, `builder_id` | a member answers for themselves only (isMember in gate()). |
527
529
 
528
- ## `me` (54)
530
+ ## `me` (55)
529
531
 
530
532
  | Method | Path | Rank | Body | Description |
531
533
  |---|---|---|---|---|
@@ -576,6 +578,7 @@ Base path: `/api/bongos`. Ranks (enforced server-side, [ADR 0016](adr/0016-trust
576
578
  | POST | `/api/bongos/me/sessions/revoke` | `any-builder` | `session_id` | POST /api/bongos/me/sessions/revoke — kill ONE of the caller's own sessions. |
577
579
  | POST | `/api/bongos/me/sessions/revoke-all` | `any-builder` | validated | POST /api/bongos/me/sessions/revoke-all — sign out everywhere. |
578
580
  | GET | `/api/bongos/me/sign-in-methods` | `any-builder` | — | the ways the caller's OWN account signs in (task 1004992, ADR 0393): GitHub, Google, or both, with the address each provider vouched for. |
581
+ | DELETE | `/api/bongos/me/sign-in-methods/:provider` | `any-builder` | — | remove one way in from the caller's OWN account (task 1004995), keyed on the authenticated person key. |
579
582
  | GET | `/api/bongos/me/skill-prefs` | `any-builder` | — | Per-builder skill model preferences (V3.R85 / task 304, migration 037). |
580
583
  | PATCH | `/api/bongos/me/skill-prefs` | `any-builder` | _undocumented_ | PATCH a partial set of skill overrides. |
581
584
  | GET | `/api/bongos/me/sound-prefs` | `any-builder` | — | Per-builder per-sound on/off preferences (V3.R91 / task 786, migration 075). |