@bongos/core 1.19.803 → 1.19.805

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 (235) hide show
  1. package/.bongos-core.json +261 -236
  2. package/.claude/skills/ask-for-help/SKILL.md +6 -6
  3. package/.claude/skills/backlog-review/SKILL.md +1 -1
  4. package/.claude/skills/blocker-review/SKILL.md +7 -7
  5. package/.claude/skills/blocker-solve/SKILL.md +5 -5
  6. package/.claude/skills/bug-triage/SKILL.md +7 -7
  7. package/.claude/skills/builder-claim/SKILL.md +3 -3
  8. package/.claude/skills/builder-cost/SKILL.md +2 -2
  9. package/.claude/skills/builder-end/SKILL.md +2 -2
  10. package/.claude/skills/builder-exit/SKILL.md +7 -7
  11. package/.claude/skills/builder-key/SKILL.md +2 -2
  12. package/.claude/skills/builder-reauth/SKILL.md +2 -2
  13. package/.claude/skills/builder-redteam/SKILL.md +7 -7
  14. package/.claude/skills/builder-release/SKILL.md +2 -2
  15. package/.claude/skills/builder-sequence/SKILL.md +1 -1
  16. package/.claude/skills/builder-setup/SKILL.md +3 -3
  17. package/.claude/skills/builder-ship/SKILL.md +1 -1
  18. package/.claude/skills/builder-stage/SKILL.md +1 -1
  19. package/.claude/skills/builder-start/SKILL.md +1 -1
  20. package/.claude/skills/fix-task/SKILL.md +4 -4
  21. package/.claude/skills/goal-create/SKILL.md +18 -18
  22. package/.claude/skills/goal-review/SKILL.md +7 -7
  23. package/.claude/skills/grade-audit/SKILL.md +5 -5
  24. package/.claude/skills/grade-recover/SKILL.md +4 -4
  25. package/.claude/skills/grader-health/SKILL.md +6 -6
  26. package/.claude/skills/idea-triage/SKILL.md +14 -14
  27. package/.claude/skills/merge-mode/SKILL.md +3 -3
  28. package/.claude/skills/planning-session/SKILL.md +20 -20
  29. package/.claude/skills/priority-session/SKILL.md +10 -10
  30. package/.claude/skills/recall/SKILL.md +1 -1
  31. package/.claude/skills/scan-before-install/SKILL.md +3 -3
  32. package/.claude/skills/status/SKILL.md +2 -2
  33. package/.claude/skills/strand-fix/SKILL.md +2 -2
  34. package/clients/bongos-client/README.md +1 -1
  35. package/clients/bongos-client/bongos-client.global.js +2 -0
  36. package/clients/bongos-client/index.cjs +2 -0
  37. package/clients/bongos-client/index.d.ts +2 -0
  38. package/clients/bongos-client/index.mjs +2 -0
  39. package/docs/api/openapi.json +45 -11
  40. package/docs/api-reference.md +11 -10
  41. package/docs/module-api-changelog.md +4 -0
  42. package/modules/builder-settings/profile-nudge-prefs.js +1 -1
  43. package/modules/builder-settings/render-prefs.js +1 -1
  44. package/modules/dev-box/app/README.md +1 -1
  45. package/modules/dev-box/app/src/gds-client.js +11 -9
  46. package/modules/dev-box/app/src/vendor/bongos-client.cjs +2 -0
  47. package/modules/dev-box/app/test/unit.mjs +13 -13
  48. package/modules/dev-box/box-access.js +3 -3
  49. package/modules/dev-box/box-onboard.js +7 -7
  50. package/modules/discord/bug-attachments.js +1 -1
  51. package/modules/economy/cost-classify.js +6 -6
  52. package/modules/grading/grader-rubric.json +1 -1
  53. package/modules/grading/grader-score.js +1 -1
  54. package/modules/hall-ui/module.json +1 -1
  55. package/modules/hall-ui/public/drachmae.js +3 -3
  56. package/modules/hall-ui/public/idea.js +1 -1
  57. package/modules/hall-ui/public/md-reader.js +1 -1
  58. package/modules/hall-ui/public/people.html +5 -1
  59. package/modules/hall-ui/public/people.js +44 -5
  60. package/modules/hall-ui/public/primer.js +4 -4
  61. package/modules/hall-ui/public/roster.js +1 -1
  62. package/modules/hall-ui/public/shell.js +1 -1
  63. package/modules/hall-ui/public/task.js +1 -1
  64. package/modules/ideas/inbox.js +2 -2
  65. package/modules/lifecycle/db-analytics.js +1 -1
  66. package/modules/lifecycle/done-when.js +4 -4
  67. package/modules/lifecycle/version-close.js +1 -1
  68. package/modules/memory/learnings.js +2 -2
  69. package/modules/memory/memory.js +1 -1
  70. package/modules/onboarding/onboarding.js +1 -1
  71. package/modules/platform-identity/routes/my-projects.js +1 -1
  72. package/modules/platform-identity/routes/sso.js +2 -2
  73. package/modules/public-landing/public/index.html +2 -2
  74. package/modules/public-landing/public/projects-floor.states.json +1 -1
  75. package/modules/public-landing/public/projects.html +1 -1
  76. package/modules/public-landing/public/projects.states.json +1 -1
  77. package/modules/sessions/db.js +120 -0
  78. package/modules/sessions/module.json +2 -2
  79. package/modules/sessions/pollers/session-upload-health.js +111 -0
  80. package/modules/sessions/pulse.js +2 -2
  81. package/modules/sessions/routes/sessions.js +46 -0
  82. package/modules/sessions/upload-health.js +197 -0
  83. package/modules/status-ui/module.json +1 -1
  84. package/modules/status-ui/public/explore.js +1 -1
  85. package/package-lock.json +2 -2
  86. package/package.json +1 -1
  87. package/scripts/gds/agent-invoke.js +3 -3
  88. package/scripts/gds/api.js +4 -4
  89. package/scripts/gds/api.sh +1 -1
  90. package/scripts/gds/architect-audit.js +1 -1
  91. package/scripts/gds/artifact-audit.js +2 -2
  92. package/scripts/gds/audit-ships.js +2 -2
  93. package/scripts/gds/backfill-cost.js +1 -1
  94. package/scripts/gds/backfill-sessions.js +1 -1
  95. package/scripts/gds/backfill-subagent-rewards.js +1 -1
  96. package/scripts/gds/backfill-task-rewards.js +2 -2
  97. package/scripts/gds/box-auth-check.js +1 -1
  98. package/scripts/gds/box-sync.js +3 -3
  99. package/scripts/gds/box.js +10 -10
  100. package/scripts/gds/build-cli-package.js +3 -3
  101. package/scripts/gds/capture.js +2 -2
  102. package/scripts/gds/ci-grade.js +1 -1
  103. package/scripts/gds/claim-recall.js +2 -2
  104. package/scripts/gds/cli-lib.js +3 -3
  105. package/scripts/gds/context-pack.js +1 -1
  106. package/scripts/gds/copy-apply.js +2 -2
  107. package/scripts/gds/dev-lib.js +2 -2
  108. package/scripts/gds/fetch-art-key.js +2 -2
  109. package/scripts/gds/fetch-sound-prefs.js +3 -3
  110. package/scripts/gds/grade-smoke.js +1 -1
  111. package/scripts/gds/hooks/pre-push.js +1 -1
  112. package/scripts/gds/init.js +9 -9
  113. package/scripts/gds/key-card.js +1 -1
  114. package/scripts/gds/learning-capture.js +2 -2
  115. package/scripts/gds/linkify-refs.js +2 -2
  116. package/scripts/gds/local-preview-lib.js +1 -1
  117. package/scripts/gds/login.js +11 -10
  118. package/scripts/gds/main-audit.js +1 -1
  119. package/scripts/gds/newcomer-floor.config.json +1 -1
  120. package/scripts/gds/newcomer-floor.js +2 -2
  121. package/scripts/gds/newcomer-floor.templates.json +2 -2
  122. package/scripts/gds/onboarding-ship.js +1 -1
  123. package/scripts/gds/paste-token.js +3 -3
  124. package/scripts/gds/portability-smoke-memory.sh +5 -5
  125. package/scripts/gds/prove-strict-versioning.js +2 -2
  126. package/scripts/gds/provision-net.js +2 -2
  127. package/scripts/gds/provision-units.js +3 -3
  128. package/scripts/gds/pulse.js +2 -2
  129. package/scripts/gds/push-path-brief.js +2 -2
  130. package/scripts/gds/reauth.js +1 -1
  131. package/scripts/gds/recall.js +1 -1
  132. package/scripts/gds/redteam-patrol.js +3 -3
  133. package/scripts/gds/render-ideas.js +5 -5
  134. package/scripts/gds/repo-metrics.js +1 -1
  135. package/scripts/gds/sandbox-stage.js +3 -3
  136. package/scripts/gds/seed-adopt-tasks.js +3 -3
  137. package/scripts/gds/seed-board-room-tasks.js +1 -1
  138. package/scripts/gds/seed-bongos-app-tasks.js +2 -2
  139. package/scripts/gds/seed-bongos-coreB-tranche1-tasks.js +3 -3
  140. package/scripts/gds/seed-bongos-coreB-tranche2-tasks.js +4 -4
  141. package/scripts/gds/seed-bongos-tasks.js +5 -5
  142. package/scripts/gds/seed-bongos-v1-idea-routing-tasks.js +1 -1
  143. package/scripts/gds/seed-bongos-v1-seo-tasks.js +1 -1
  144. package/scripts/gds/seed-bv1-community-tasks.js +1 -1
  145. package/scripts/gds/seed-bv1-privacy-invites-tasks.js +1 -1
  146. package/scripts/gds/seed-bv1-profile-page-tasks.js +1 -1
  147. package/scripts/gds/seed-bv1-profiles-tasks.js +1 -1
  148. package/scripts/gds/seed-bv1-r01-delta-tasks.js +1 -1
  149. package/scripts/gds/seed-gds-v4-tasks.js +3 -3
  150. package/scripts/gds/seed-medusa-tasks.js +1 -1
  151. package/scripts/gds/seed-productization-tasks.js +1 -1
  152. package/scripts/gds/seed-project-admin-console-tasks.js +1 -1
  153. package/scripts/gds/seed-provisioning-tasks.js +2 -2
  154. package/scripts/gds/seed-strict-versioning-tasks.js +3 -3
  155. package/scripts/gds/seed-v2-world-tasks.js +2 -2
  156. package/scripts/gds/seed-verify-criteria.js +1 -1
  157. package/scripts/gds/session-digest.js +1 -1
  158. package/scripts/gds/session.js +2 -2
  159. package/scripts/gds/setup.js +7 -7
  160. package/scripts/gds/ship-flow.js +3 -3
  161. package/scripts/gds/ship-grade-steps.js +3 -3
  162. package/scripts/gds/ship-memory-sync.js +1 -1
  163. package/scripts/gds/ship-session-upload.js +3 -3
  164. package/scripts/gds/smoke-batch-claim.sh +10 -10
  165. package/scripts/gds/smoke-batch-release.sh +14 -14
  166. package/scripts/gds/smoke-claim-consistency.sh +19 -19
  167. package/scripts/gds/smoke-dependencies.sh +9 -9
  168. package/scripts/gds/smoke-write.sh +11 -11
  169. package/scripts/gds/start.js +1 -1
  170. package/scripts/gds/status.js +2 -2
  171. package/scripts/gds/strand-watch.js +1 -1
  172. package/scripts/gds/triage.js +4 -4
  173. package/scripts/gds/version-close.js +2 -2
  174. package/scripts/hall-preview/README.md +1 -1
  175. package/scripts/hall-preview/server.js +1 -1
  176. package/src/bongos/auth-admission.js +3 -3
  177. package/src/bongos/auth-idp.js +2 -2
  178. package/src/bongos/auth.js +3 -3
  179. package/src/bongos/db.js +2 -2
  180. package/src/bongos/llm-cache.js +2 -2
  181. package/src/bongos/metrics.js +1 -1
  182. package/src/bongos/middleware/audit.js +3 -3
  183. package/src/bongos/middleware/rate-limit.js +1 -1
  184. package/src/bongos/platform-visibility-gate.js +2 -2
  185. package/src/bongos/routes/_helpers.js +1 -1
  186. package/src/bongos/routes/audit-log.js +1 -1
  187. package/src/bongos/routes/auth.js +5 -5
  188. package/src/bongos/routes/backup.js +1 -1
  189. package/src/bongos/routes/builders.js +1 -1
  190. package/src/bongos/routes/instance.js +1 -1
  191. package/src/bongos/routes/live.js +1 -1
  192. package/src/bongos/routes/me.js +2 -2
  193. package/src/bongos/routes/modules.js +2 -2
  194. package/src/bongos/routes/public.js +1 -1
  195. package/src/bongos/routes/security.js +4 -4
  196. package/src/bongos/routes.js +1 -1
  197. package/src/bongos/serve-internal.js +6 -6
  198. package/src/branding.js +1 -1
  199. package/src/module-api.js +1 -1
  200. package/src/module-seams.js +2 -2
  201. package/src/platform-server.js +2 -2
  202. package/tests/api_alias_exceptions.mjs +67 -0
  203. package/tests/application_echo.mjs +12 -12
  204. package/tests/artifact_audit.mjs +1 -1
  205. package/tests/auth_page_gate.mjs +4 -4
  206. package/tests/auth_web_recovery.mjs +11 -11
  207. package/tests/bongos_login.mjs +7 -4
  208. package/tests/box_env.mjs +6 -6
  209. package/tests/bug_attachments.mjs +1 -1
  210. package/tests/cli_sessions.mjs +1 -1
  211. package/tests/dev_lib.mjs +1 -1
  212. package/tests/discord_bugs.mjs +2 -2
  213. package/tests/discord_inbound.mjs +2 -2
  214. package/tests/explore_visible_states.mjs +1 -1
  215. package/tests/government_page_gates.mjs +1 -1
  216. package/tests/hall_reference_world.mjs +1 -1
  217. package/tests/idea_ideate_full.mjs +1 -1
  218. package/tests/idp_federation.mjs +2 -2
  219. package/tests/llm-cache.mjs +1 -1
  220. package/tests/manage_manifest_shared_read.mjs +3 -3
  221. package/tests/people_directory_clip.mjs +219 -0
  222. package/tests/planning_session_skill.mjs +1 -1
  223. package/tests/platform_visibility_gate.mjs +15 -15
  224. package/tests/profile_route.mjs +37 -26
  225. package/tests/projects_hub.mjs +2 -2
  226. package/tests/provision.mjs +2 -2
  227. package/tests/provision_settings_apply.mjs +4 -4
  228. package/tests/sandbox_stage.mjs +8 -8
  229. package/tests/scouting_owner_access_and_reach.mjs +3 -3
  230. package/tests/session_upload_health.mjs +329 -0
  231. package/tests/setup_device_flow_fallback.mjs +1 -1
  232. package/tests/skill_ask_for_help.mjs +3 -3
  233. package/tests/skill_grade_audit.mjs +2 -2
  234. package/tests/skill_grader_health.mjs +3 -3
  235. package/tests/smoke_write_contract.mjs +1 -1
@@ -105,7 +105,7 @@ function streamLive(req, res, deps = {}) {
105
105
  function buildLiveRouter() {
106
106
  const router = express.Router();
107
107
 
108
- // GET /api/gds/live — SSE stream of Bongos state-change nudges for the hall.
108
+ // GET /api/bongos/live — SSE stream of Bongos state-change nudges for the hall.
109
109
  // rank: any-builder — requireBuilder gates anonymous/abuse traffic (defense
110
110
  // in depth; the payload leaks nothing). Mirrors the room's #983 signed-in
111
111
  // gate. EventSource carries the gds_session cookie on this same-origin GET, so
@@ -157,7 +157,7 @@ module.exports = function buildMeRouter() {
157
157
  // V3.R24 (#244): the `builder` payload now carries `karma` (migration 040
158
158
  // added the column + karma_log table). The field is surfaced by
159
159
  // db.getBuilderById() — no shape change here, just documenting that the
160
- // /api/gds/me response is the canonical place clients read karma from.
160
+ // /api/bongos/me response is the canonical place clients read karma from.
161
161
  //
162
162
  // rank: any-builder — own identity + own contributions; preserved per CRITICAL §4.
163
163
  router.get('/me', auth.requireBuilder, async (req, res) => {
@@ -621,7 +621,7 @@ module.exports = function buildMeRouter() {
621
621
  // The five per-builder PREFERENCE routes — /me/skill-prefs, /me/sound-prefs,
622
622
  // /me/event-sound-prefs, /me/wandering, /me/render (GET + PATCH each) — moved to
623
623
  // modules/builder-settings/routes/settings.js (BV1.R80 / ADR 0093 §1). They keep
624
- // their exact /me/* paths (the loader mounts that router on this same /api/gds
624
+ // their exact /me/* paths (the loader mounts that router on this same /api/bongos
625
625
  // router, before the public catch-all), so the API is byte-identical. The GET
626
626
  // /me aggregator above stays here as a thin facade resolving the
627
627
  // `builder-settings` port for its wandering/render/needs slices (02-module-map §2).
@@ -148,7 +148,7 @@ module.exports = function buildModulesRouter() {
148
148
  res.json({ ok: true, key, enabled, note: 'Live on this box now. Persisting past the next deploy needs config/modules.json committed.' });
149
149
  }));
150
150
 
151
- // POST /api/gds/modules/:key/submit — ADR 0107 §1 upstreaming submission.
151
+ // POST /api/bongos/modules/:key/submit — ADR 0107 §1 upstreaming submission.
152
152
  //
153
153
  // task 1770. Body: { signed_by?: "Name <email>" }. Re-runs the §4
154
154
  // AGPL/publish pre-check + requires a DCO-style sign-off against THIS box's
@@ -213,7 +213,7 @@ module.exports = function buildModulesRouter() {
213
213
  res.status(201).json({ ok: true, submission });
214
214
  }));
215
215
 
216
- // GET /api/gds/modules/submissions?status=&module_key= — the upstreaming
216
+ // GET /api/bongos/modules/submissions?status=&module_key= — the upstreaming
217
217
  // review queue (task 1771 reads this). Metadata only — no file contents (a
218
218
  // future GET .../:id can add a with-files fetch if the review UI needs it).
219
219
  //
@@ -115,7 +115,7 @@ module.exports = function buildPublicRouter() {
115
115
  // CORS for the public surface (ADR 0029 / #566): the off-box status page reads
116
116
  // these cross-origin. Read-only, no-auth, no-secret routes, so a static '*' is
117
117
  // safe; scoped to '/public' so it can't leak onto the authenticated routes on
118
- // the same /api/gds base. No Vary:Origin — the ACAO never varies by origin.
118
+ // the same /api/bongos base. No Vary:Origin — the ACAO never varies by origin.
119
119
  // Shared middleware: corsPublicGet (_helpers.js) — byte-identical to analytics.js.
120
120
  router.use('/public', corsPublicGet('/public'));
121
121
 
@@ -74,7 +74,7 @@ async function readFullAdr() {
74
74
  module.exports = function buildSecurityRouter() {
75
75
  const router = express.Router();
76
76
 
77
- // GET /api/gds/security/adr
77
+ // GET /api/bongos/security/adr
78
78
  //
79
79
  // Metic+ only. Returns the full security ADR as { adr_md, source,
80
80
  // fetched_at } when the file is provisioned; otherwise 404 with a
@@ -125,7 +125,7 @@ module.exports = function buildSecurityRouter() {
125
125
  // now `permission_forbidden`, not `rank_forbidden`.
126
126
  // -----------------------------------------------------------------------
127
127
 
128
- // GET /api/gds/security/docs — list doc METADATA (no content).
128
+ // GET /api/bongos/security/docs — list doc METADATA (no content).
129
129
  //
130
130
  // rank: archon — index of exploit-detail engagement reports. Gate:
131
131
  // requirePermission('security.report.adjudicate') — BV1.R104.
@@ -144,7 +144,7 @@ module.exports = function buildSecurityRouter() {
144
144
  }
145
145
  );
146
146
 
147
- // GET /api/gds/security/docs/:slug — one doc WITH content, or 404.
147
+ // GET /api/bongos/security/docs/:slug — one doc WITH content, or 404.
148
148
  //
149
149
  // rank: archon — reads the full exploit-detail report body. Gate:
150
150
  // requirePermission('security.report.adjudicate') — BV1.R104.
@@ -177,7 +177,7 @@ module.exports = function buildSecurityRouter() {
177
177
  }
178
178
  );
179
179
 
180
- // POST /api/gds/security/docs — upsert a doc by slug. The director uploads
180
+ // POST /api/bongos/security/docs — upsert a doc by slug. The director uploads
181
181
  // each dated engagement report here after deploy.
182
182
  //
183
183
  // Body: { slug, title, content_md }. content_md uses a large explicit cap
@@ -108,7 +108,7 @@ function buildGdsRouter() {
108
108
  });
109
109
 
110
110
  // Audit middleware (V3.R35 #256) — attaches a res 'finish' hook so every
111
- // authenticated POST/PATCH/PUT/DELETE under /api/gds is recorded in
111
+ // authenticated POST/PATCH/PUT/DELETE under /api/bongos is recorded in
112
112
  // audit_log AFTER the response is sent. It cannot fail the request: throws
113
113
  // are caught, DB errors are swallowed, and it never mutates req/res in a
114
114
  // way downstream handlers can see. Mounted BEFORE the feature routers so
@@ -2,7 +2,7 @@
2
2
  //
3
3
  // Mounts every non-game surface the platform serves onto an Express app:
4
4
  // * /healthz + /version — liveness + deployed-build info
5
- // * /api/gds/* — the GDS API (buildGdsRouter)
5
+ // * /api/bongos/* — the GDS API (buildGdsRouter)
6
6
  // * /downloads/devbox/* — Dev Box installer redirect surface (#904)
7
7
  // * generic module web-surface — each enabled module's contributes.webSurfaces
8
8
  // hosts served on its Host prefix by ONE generic static
@@ -179,7 +179,7 @@ function jsonForScript(value) {
179
179
  // the pack wins. Applied to the boot-time stamped HTML maps (the pack is a
180
180
  // boot-time singleton, computed once). Off-box surfaces that can't be
181
181
  // server-injected (the GitHub-Pages status page) read the same projection from
182
- // GET /api/gds/public/branding. Pure + exported for the unit test.
182
+ // GET /api/bongos/public/branding. Pure + exported for the unit test.
183
183
  function injectBrandingGlobal(html, brand = clientBranding(), mods = clientModules()) {
184
184
  // window.__MODULES__ — the enabled feature-module set (R54 task 1193, ADR 0062
185
185
  // §4), injected the same way as __BRANDING__ so hall/status scripts can hide
@@ -456,7 +456,7 @@ function injectModuleHallWidgets(html, scripts = hallWidgetScripts({ isEnabled:
456
456
  // builders.<apex> gets the builder surface (served by the hall-ui MODULE's web
457
457
  // surface, BV1.R85 — its DEDICATED block below); the apex host gets the game
458
458
  // (server.js) or — on a game-less instance — a plain 404 (platform-server.js). All
459
- // share the same process + the same /api/gds/* surface (mounted host-agnostically
459
+ // share the same process + the same /api/bongos/* surface (mounted host-agnostically
460
460
  // below). The prefix checks are apex-agnostic (any domain), so no brand string lives
461
461
  // here. isStatusHost + isBuildersHost stay the literal "status."/"builders."
462
462
  // predicates the entrypoints (server.js/platform-server.js) use to keep their apex
@@ -830,7 +830,7 @@ function mountInternalSurfaces(app) {
830
830
  // clean path so the address bar never shows ".../builders". PAGE paths only —
831
831
  // the slug is [a-z0-9-]+ with no dot, so asset URLs the pages emit
832
832
  // (/builders/style.css, /builders/*.js, /builders/diagrams/*.png) and the API
833
- // (/api/gds/builders/*) never match and pass through to the shim below.
833
+ // (/api/bongos/builders/*) never match and pass through to the shim below.
834
834
  const BUILDERS_CANONICAL_RE = /^\/builders(?:\/([a-z0-9-]+))?\/?$/i;
835
835
  app.use((req, res, next) => {
836
836
  if (!isBuildersHost(req)) return next();
@@ -1056,8 +1056,8 @@ function mountInternalSurfaces(app) {
1056
1056
  // read from BUILDERS_DIR. The module key is NOT named — the path is the
1057
1057
  // hall-ui module's public dir, resolved once here.
1058
1058
  //
1059
- // Auth is handled client-side: the page calls /api/gds/me; on 401 it redirects
1060
- // the browser to /api/gds/auth/web/start, which (per src/bongos/routes/auth.js)
1059
+ // Auth is handled client-side: the page calls /api/bongos/me; on 401 it redirects
1060
+ // the browser to /api/bongos/auth/web/start, which (per src/bongos/routes/auth.js)
1061
1061
  // loops back to /builders with a gds_session cookie set.
1062
1062
  const BUILDERS_DIR = path.join(ROOT, 'modules', 'hall-ui', 'public');
1063
1063
  const buildersStatic = express.static(BUILDERS_DIR, {
package/src/branding.js CHANGED
@@ -206,7 +206,7 @@ function userAgent() {
206
206
  }
207
207
 
208
208
  // The CLIENT-SAFE projection of the resolved pack — the subset the browser is
209
- // allowed to see, served by GET /api/gds/public/branding and consumed by the
209
+ // allowed to see, served by GET /api/bongos/public/branding and consumed by the
210
210
  // hall + status front-ends. Deliberately a small allow-list, NOT the whole pack:
211
211
  // origins, repo binding, db name, and env prefix are server-only and must never
212
212
  // reach the client. R56 (task 1195) seeded it with the configurable currency
package/src/module-api.js CHANGED
@@ -71,7 +71,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
71
71
  // there. scripts/gds/bump-version.js still rewrites the literal below; it appends
72
72
  // the entry to that file. Look for a version's history there, not here.
73
73
  // ---------------------------------------------------------------------------
74
- const CORE_VERSION = '1.19.803'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
74
+ const CORE_VERSION = '1.19.805'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
75
75
 
76
76
  // A namespaced logger so a module's log lines are attributable + consistent.
77
77
  // Usage: const log = api.logger('dev-box'); log.info('mounted');
@@ -188,7 +188,7 @@ function listEvents() {
188
188
  //
189
189
  // Canonical extension points (the names core consumes):
190
190
  // • 'profile.fields' — server-side: each contributor is `async (ctx) => ({…slice})`;
191
- // the slices merge into the GET /api/gds/me payload.
191
+ // the slices merge into the GET /api/bongos/me payload.
192
192
  // (The client settings-panel seam is its browser twin,
193
193
  // window.OTB.contributeSettingsPanel in dom-utils.js.)
194
194
 
@@ -240,7 +240,7 @@ async function collectContributions(point, ctx) {
240
240
  // a module's contribution can't clobber a core field). Mutates + returns `base`,
241
241
  // and reports any collided keys so the caller can surface them — that signals a
242
242
  // move task took over a core key without first removing the core copy. Used by
243
- // GET /api/gds/me to fold 'profile.fields' slices into the profile payload.
243
+ // GET /api/bongos/me to fold 'profile.fields' slices into the profile payload.
244
244
  function mergeContributions(base, slices) {
245
245
  const collisions = [];
246
246
  for (const slice of slices || []) {
@@ -7,7 +7,7 @@
7
7
  // WHAT IT SERVES — the entire internal surface, via the shared mount that
8
8
  // server.js also uses (so the two entrypoints never drift, ADR 0052):
9
9
  // * /healthz + /version
10
- // * /api/gds/* — the full GDS API (buildGdsRouter)
10
+ // * /api/bongos/* — the full GDS API (buildGdsRouter)
11
11
  // * the status dashboard host — modules/status-ui/public/ (the status-ui module's
12
12
  // web surface, BV1.R84 — served by the loader seam)
13
13
  // * the builders' hall host — modules/hall-ui/public/ (the hall-ui module's
@@ -269,7 +269,7 @@ function buildPlatformApp() {
269
269
  });
270
270
  }
271
271
 
272
- // Non-game tail. Anything that did not resolve to /api/gds, the status host,
272
+ // Non-game tail. Anything that did not resolve to /api/bongos, the status host,
273
273
  // or the builders' hall lands here. There is NO game to fall through to, so:
274
274
  // * an API-shaped path gets a self-describing JSON 404 (never HTML), the
275
275
  // same contract server.js gives so a mis-prefixed CLI call is legible;
@@ -0,0 +1,67 @@
1
+ // tests/api_alias_exceptions.mjs — the callers task 1003707 deliberately LEFT on
2
+ // the permanent /api/gds alias, and the reason each one stays.
3
+ //
4
+ // WHY THIS FILE EXISTS. C3e moved every in-repo caller onto the canonical
5
+ // /api/bongos. A handful were held back on purpose, and "on purpose" is the kind
6
+ // of fact that survives exactly one sweep: the next agent greps for the old
7
+ // spelling, sees four stragglers, tidies them, and discovers what they were for
8
+ // when sign-in breaks. Each case below names its reason, so a future move has to
9
+ // argue with the reason rather than with a leftover.
10
+ //
11
+ // The mount itself is asserted by tests/rename_history_restraint.mjs (structure)
12
+ // and tests/api_path_404.mjs (dispatch — the alias is a live mount, so it gets no
13
+ // corrective 404 hint). Only the ONE line that makes the alias permanent is
14
+ // re-asserted here, because these exceptions are worthless without it.
15
+ import assert from 'node:assert/strict';
16
+ import { test } from 'node:test';
17
+ import fs from 'node:fs';
18
+ import path from 'node:path';
19
+ import { createRequire } from 'node:module';
20
+ import { fileURLToPath } from 'node:url';
21
+
22
+ const require = createRequire(import.meta.url);
23
+ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
24
+ const read = (rel) => fs.readFileSync(path.join(ROOT, rel), 'utf8');
25
+ const ALIAS = '/api/gds';
26
+
27
+ test('the alias is still mounted — everything below depends on it', () => {
28
+ const { API_PREFIX, LEGACY_API_PREFIXES, ALL_API_PREFIXES } = require(path.join(ROOT, 'src', 'bongos', 'api-prefix.js'));
29
+ assert.equal(API_PREFIX, '/api/bongos', 'the canonical prefix is what in-repo callers now ask for');
30
+ assert.ok(LEGACY_API_PREFIXES.includes(ALIAS), 'shipped Dev Box binaries and live dev boxes call the alias');
31
+ assert.ok(ALL_API_PREFIXES.includes(ALIAS), 'and the router still mounts it');
32
+ });
33
+
34
+ test('the OAuth callbacks stay on the alias — they are registered outside this repo', () => {
35
+ const auth = read('src/bongos/routes/auth.js');
36
+ // Changing either of these needs a matching edit in the GitHub / Discord app
37
+ // settings; a repo-only change silently breaks sign-in. Pin the lines that BUILD
38
+ // the redirect_uri, not a mention of the path — auth.js also names it in an error
39
+ // message, and matching that would keep this green with both builders rewritten.
40
+ const webBuilders = auth.split(`\${WEB_REDIRECT_ORIGIN}${ALIAS}/auth/web/callback`).length - 1;
41
+ assert.equal(webBuilders, 2, 'both GitHub redirect_uri builders stay on the alias (auth.js WEB_REDIRECT_ORIGIN)');
42
+ assert.ok(auth.includes(`\${DISCORD_REDIRECT_ORIGIN}${ALIAS}/auth/discord/callback`),
43
+ 'Discord OAuth app callback (DISCORD_REDIRECT_URI)');
44
+ // The instance provisioner registers the same pinned path for every new instance.
45
+ assert.ok(read('modules/provisioning/provisioning.js').includes(`${ALIAS}/auth/web/callback`),
46
+ 'a provisioned instance registers the pinned callback, not the canonical one');
47
+ });
48
+
49
+ test('the sign-in START href moved, and that is safe because the cookie is path-scoped to /', () => {
50
+ const auth = read('src/bongos/routes/auth.js');
51
+ assert.ok(auth.includes('/api/bongos/auth/web/start'), 'the start link asks for the canonical path');
52
+ assert.ok(/path: '\/'/.test(auth), 'the session cookie is set at path / — it reaches BOTH prefixes');
53
+ });
54
+
55
+ test('the uptime poller stays on the alias so production keeps exercising it', () => {
56
+ // If nothing in production ever calls the alias, its eventual breakage is
57
+ // discovered by a user rather than by us.
58
+ assert.ok(read('src/bongos/uptime-poller.js').includes(`${ALIAS}/healthz`),
59
+ 'the poller is the one live caller that proves the alias answers');
60
+ });
61
+
62
+ test('a pasted API base is stripped whichever spelling it carries', () => {
63
+ const { normalizeInstanceBase } = require(path.join(ROOT, 'scripts', 'gds', 'login.js'));
64
+ for (const suffix of ['/api/bongos', '/api/bongos/v1', '/api/gds', '/api/gds/']) {
65
+ assert.equal(normalizeInstanceBase(`https://example.com${suffix}`), 'https://example.com', suffix);
66
+ }
67
+ });
@@ -274,7 +274,7 @@ const { attachFail } = require('../src/bongos/middleware/error-envelope.js');
274
274
  let relay = { status: 201, body: { ok: true } };
275
275
  const realFetch = globalThis.fetch;
276
276
  globalThis.fetch = async (url) => {
277
- if (String(url).endsWith('/api/gds/access-requests')) {
277
+ if (String(url).endsWith('/api/bongos/access-requests')) {
278
278
  if (relay === null) throw new Error('connection refused');
279
279
  return { status: relay.status, json: async () => relay.body };
280
280
  }
@@ -285,7 +285,7 @@ after(() => { globalThis.fetch = realFetch; });
285
285
  const app = express();
286
286
  app.use(express.json());
287
287
  app.use(attachFail);
288
- app.use('/api/gds', myProjectsRoutes());
288
+ app.use('/api/bongos', myProjectsRoutes());
289
289
 
290
290
  let server, port;
291
291
  before(async () => {
@@ -314,7 +314,7 @@ function call(method, pathname, body) {
314
314
  req.end(payload);
315
315
  });
316
316
  }
317
- const join = (note) => call('POST', '/api/gds/my-projects/join', { origin: 'https://target.example', note });
317
+ const join = (note) => call('POST', '/api/bongos/my-projects/join', { origin: 'https://target.example', note });
318
318
 
319
319
  test('the interpreter refuses a predicate it cannot read — parameterised or not', () => {
320
320
  assert.throws(() => predicateFor('github_id = $1::bigint AND something = $2', [1, 2]), /unread predicate on \$2/);
@@ -391,7 +391,7 @@ test('a failed echo write never turns a filed application into a reported failur
391
391
  test('GET /my-projects reports what was applied to and when — and no status', async () => {
392
392
  seed();
393
393
  relay = { status: 201, body: { ok: true } };
394
- const r = await call('GET', '/api/gds/my-projects');
394
+ const r = await call('GET', '/api/bongos/my-projects');
395
395
  assert.equal(r.status, 200);
396
396
  const applied = r.json.applied;
397
397
  assert.deepEqual(applied.map((a) => a.client_id), ['proj-open', 'proj-invited'],
@@ -405,7 +405,7 @@ test('GET /my-projects reports what was applied to and when — and no status',
405
405
 
406
406
  test('a project the applicant now BUILDS on drops out of applied — membership is the approval signal', async () => {
407
407
  seed();
408
- const r = await call('GET', '/api/gds/my-projects');
408
+ const r = await call('GET', '/api/bongos/my-projects');
409
409
  assert.deepEqual(r.json.building.map((b) => b.client_id), ['proj-joined']);
410
410
  assert.ok(!r.json.applied.some((a) => a.client_id === 'proj-joined'),
411
411
  'an approval becomes visible by the card flipping to member, never by the echo claiming it');
@@ -421,7 +421,7 @@ test('a project the applicant now BUILDS on drops out of applied — membership
421
421
 
422
422
  test('an echo older than the window is invisible, not deleted', async () => {
423
423
  seed();
424
- const r = await call('GET', '/api/gds/my-projects');
424
+ const r = await call('GET', '/api/bongos/my-projects');
425
425
  assert.ok(!r.json.applied.some((a) => a.client_id === 'proj-stale'),
426
426
  'a declined application must not read as "applied" forever');
427
427
  assert.ok(echoes.some((e) => e.client_id === 'proj-stale'), 'and the row is still there — the window is read-time');
@@ -429,7 +429,7 @@ test('an echo older than the window is invisible, not deleted', async () => {
429
429
 
430
430
  test('the echo read is own-scope: another account’s row is never reachable', async () => {
431
431
  seed();
432
- const r = await call('GET', '/api/gds/my-projects');
432
+ const r = await call('GET', '/api/bongos/my-projects');
433
433
  assert.ok(!r.json.applied.some((a) => a.client_id === 'proj-someone-elses'));
434
434
  const echoRead = statements.find((s) => /FROM platform_identity_application_echoes/.test(s.sql));
435
435
  assert.match(echoRead.sql, /WHERE e\.github_id = \$1::bigint/, 'keyed on the session, never on anything from the request');
@@ -444,12 +444,12 @@ test('the echo read is own-scope: another account’s row is never reachable', a
444
444
  test('leaving a project forgets the application that got you in', async () => {
445
445
  seed();
446
446
  assert.ok(echo('proj-joined'), 'precondition: the echo from the original application is still on file');
447
- const left = await call('POST', '/api/gds/my-projects/proj-joined/leave');
447
+ const left = await call('POST', '/api/bongos/my-projects/proj-joined/leave');
448
448
  assert.equal(left.status, 200);
449
449
  assert.equal(left.json.left, true);
450
450
  assert.equal(echo('proj-joined'), undefined, 'the echo goes with the membership');
451
451
 
452
- const after = await call('GET', '/api/gds/my-projects');
452
+ const after = await call('GET', '/api/bongos/my-projects');
453
453
  assert.ok(!after.json.building.some((b) => b.client_id === 'proj-joined'));
454
454
  assert.ok(!after.json.applied.some((a) => a.client_id === 'proj-joined'),
455
455
  'and it does NOT come back as "applied" now that the membership no longer hides it');
@@ -457,7 +457,7 @@ test('leaving a project forgets the application that got you in', async () => {
457
457
 
458
458
  test('leaving forgets only the leaver’s own echo, for only that project', async () => {
459
459
  seed();
460
- await call('POST', '/api/gds/my-projects/proj-joined/leave');
460
+ await call('POST', '/api/bongos/my-projects/proj-joined/leave');
461
461
  assert.ok(echo('proj-open'), 'a different project of mine is untouched');
462
462
  assert.ok(echoes.some((e) => e.client_id === 'proj-someone-elses'), 'and so is another account’s row');
463
463
  });
@@ -465,7 +465,7 @@ test('leaving forgets only the leaver’s own echo, for only that project', asyn
465
465
  test('a failed echo cleanup does not fail a leave that already happened', async () => {
466
466
  seed();
467
467
  echoFails = true;
468
- const left = await call('POST', '/api/gds/my-projects/proj-joined/leave');
468
+ const left = await call('POST', '/api/bongos/my-projects/proj-joined/leave');
469
469
  assert.equal(left.status, 200, 'the membership is already gone — the echo is a convenience, not the act');
470
470
  assert.equal(left.json.left, true);
471
471
  });
@@ -473,7 +473,7 @@ test('a failed echo cleanup does not fail a leave that already happened', async
473
473
  test('a failed echo read costs the applied list and nothing else', async () => {
474
474
  seed();
475
475
  echoFails = true;
476
- const r = await call('GET', '/api/gds/my-projects');
476
+ const r = await call('GET', '/api/bongos/my-projects');
477
477
  assert.equal(r.status, 200);
478
478
  assert.deepEqual(r.json.applied, []);
479
479
  assert.deepEqual(r.json.building.map((b) => b.client_id), ['proj-joined'], 'the memberships listing still lands');
@@ -171,7 +171,7 @@ await t('a finding is filed to the blocker surface, not only printed', async ()
171
171
  const call = async (method, path, body) => { sent.push({ method, path, body }); return { ok: true, status: 201, data: { blocker: { id: 42 } } }; };
172
172
  const r = await fileBlocker([{ id: '1003188', status: 'shipped', shipped_at: '2026-08-23', title: 'Go-live', touches: ['package.json'] }], { call });
173
173
  assert.equal(r.filed, true);
174
- assert.equal(sent[0].path, '/api/gds/blockers');
174
+ assert.equal(sent[0].path, '/api/bongos/blockers');
175
175
  assert.equal(sent[0].body.source, 'artifact-audit');
176
176
  assert.match(sent[0].body.body_md, /task 1003188/);
177
177
  });
@@ -74,7 +74,7 @@ await t('unauthenticated request → 302 to sign-in, next() NOT called', async (
74
74
  assert.equal(nexted, false, 'next() must not run for an unauthenticated request');
75
75
  assert.ok(res._redirect, 'a redirect must be issued');
76
76
  assert.equal(res._redirect.code, 302);
77
- assert.equal(res._redirect.loc, '/api/gds/auth/web/start');
77
+ assert.equal(res._redirect.loc, '/api/bongos/auth/web/start');
78
78
  });
79
79
 
80
80
  await t('authenticated request → next() called, no redirect', async () => {
@@ -95,7 +95,7 @@ await t('session lookup error → fails CLOSED (redirect, next() NOT called)', a
95
95
  let nexted = false;
96
96
  await auth.requireBuilderPage(req, res, () => { nexted = true; });
97
97
  assert.equal(nexted, false, 'must not serve the page when the lookup errors');
98
- assert.ok(res._redirect && res._redirect.loc === '/api/gds/auth/web/start',
98
+ assert.ok(res._redirect && res._redirect.loc === '/api/bongos/auth/web/start',
99
99
  'must redirect to sign-in on a lookup error (fail closed)');
100
100
  });
101
101
 
@@ -118,7 +118,7 @@ await t('box-scoped session → 302 to sign-in even though its builder holds the
118
118
  let nexted = false;
119
119
  await auth.requireBuilderPage(req, res, () => { nexted = true; });
120
120
  assert.equal(nexted, false, 'a box session must not be served a gated page shell');
121
- assert.ok(res._redirect && res._redirect.loc === '/api/gds/auth/web/start',
121
+ assert.ok(res._redirect && res._redirect.loc === '/api/bongos/auth/web/start',
122
122
  'the remedy is a different session (/builder-reauth), so sign-in — not deniedTo');
123
123
  });
124
124
 
@@ -129,7 +129,7 @@ await t('a source the registry does not declare → denied, never treated as uns
129
129
  let nexted = false;
130
130
  await auth.requireBuilderPage(req, res, () => { nexted = true; });
131
131
  assert.equal(nexted, false, 'an unrecognised scope must fail closed, exactly as requireBuilder does');
132
- assert.ok(res._redirect && res._redirect.loc === '/api/gds/auth/web/start');
132
+ assert.ok(res._redirect && res._redirect.loc === '/api/bongos/auth/web/start');
133
133
  });
134
134
 
135
135
  await t('cli and web sessions are untouched by the scope check', async () => {
@@ -21,22 +21,22 @@ const req = (cookie) => ({ headers: cookie ? { cookie } : {} });
21
21
 
22
22
  test('the retry door carries the wizard return and the repo-scope opt-in while their cookies are valid', () => {
23
23
  assert.equal(recoveryStartHref(req('gds_return=%2Fprojects%3Fview%3Dnew; gds_oauth_repos=1')),
24
- '/api/gds/auth/web/start?return=%2Fprojects%3Fview%3Dnew&repos=1');
24
+ '/api/bongos/auth/web/start?return=%2Fprojects%3Fview%3Dnew&repos=1');
25
25
  assert.equal(recoveryStartHref(req('gds_return=%2Fprojects%3Fview%3Dnew')),
26
- '/api/gds/auth/web/start?return=%2Fprojects%3Fview%3Dnew', 'a hall sign-in never asks for repos');
27
- assert.equal(recoveryStartHref(req('gds_oauth_repos=1')), '/api/gds/auth/web/start?repos=1');
26
+ '/api/bongos/auth/web/start?return=%2Fprojects%3Fview%3Dnew', 'a hall sign-in never asks for repos');
27
+ assert.equal(recoveryStartHref(req('gds_oauth_repos=1')), '/api/bongos/auth/web/start?repos=1');
28
28
  });
29
29
 
30
30
  test('with nothing left to rebuild from, the door is the bare start — never a guess', () => {
31
- assert.equal(recoveryStartHref(req('')), '/api/gds/auth/web/start');
32
- assert.equal(recoveryStartHref(req('gds_session=abc')), '/api/gds/auth/web/start');
33
- assert.equal(recoveryStartHref(req('gds_oauth_repos=0')), '/api/gds/auth/web/start', 'only the literal opt-in counts');
31
+ assert.equal(recoveryStartHref(req('')), '/api/bongos/auth/web/start');
32
+ assert.equal(recoveryStartHref(req('gds_session=abc')), '/api/bongos/auth/web/start');
33
+ assert.equal(recoveryStartHref(req('gds_oauth_repos=0')), '/api/bongos/auth/web/start', 'only the literal opt-in counts');
34
34
  });
35
35
 
36
36
  test('the door is under the same open-redirect allowlist as the callback', () => {
37
- assert.equal(recoveryStartHref(req('gds_return=https%3A%2F%2Fevil.example%2Fx')), '/api/gds/auth/web/start');
38
- assert.equal(recoveryStartHref(req('gds_return=%2F%2Fevil.example')), '/api/gds/auth/web/start');
39
- assert.equal(recoveryStartHref(req('gds_return=javascript%3Aalert(1)')), '/api/gds/auth/web/start');
37
+ assert.equal(recoveryStartHref(req('gds_return=https%3A%2F%2Fevil.example%2Fx')), '/api/bongos/auth/web/start');
38
+ assert.equal(recoveryStartHref(req('gds_return=%2F%2Fevil.example')), '/api/bongos/auth/web/start');
39
+ assert.equal(recoveryStartHref(req('gds_return=javascript%3Aalert(1)')), '/api/bongos/auth/web/start');
40
40
  });
41
41
 
42
42
  test('every OAuth error page and the pending page rebuild their door from the cookies', () => {
@@ -47,8 +47,8 @@ test('every OAuth error page and the pending page rebuild their door from the co
47
47
  'GitHub refused · State mismatch · handshake threw — three pages, three doors');
48
48
  assert.match(callback, /renderAccessPendingPage\(err\.login, recoveryStartHref\(req\)\)/, 'the auto-walk-in lands where the founder was going');
49
49
  assert.match(callback, /const onWayToProject = founderReturn\.startsWith\('\/projects'\);/, 'the founder-shaped NOT_APPROVED note');
50
- assert.match(SRC, /const cta = opts\.cta \|\| \{ href: opts\.startHref \|\| '\/api\/gds\/auth\/web\/start', label: copy\.ctaLabel \};/);
51
- assert.match(SRC, /data-start="\$\{escapeHtml\(startHref \|\| '\/api\/gds\/auth\/web\/start'\)\}"/, 'the pending page reads its start from a data attribute, never string-built into script');
50
+ assert.match(SRC, /const cta = opts\.cta \|\| \{ href: opts\.startHref \|\| '\/api\/bongos\/auth\/web\/start', label: copy\.ctaLabel \};/);
51
+ assert.match(SRC, /data-start="\$\{escapeHtml\(startHref \|\| '\/api\/bongos\/auth\/web\/start'\)\}"/, 'the pending page reads its start from a data attribute, never string-built into script');
52
52
  assert.match(SRC, /function land\(\) \{ window\.location\.href = start; \}/);
53
53
  });
54
54
 
@@ -16,12 +16,15 @@ const require = createRequire(import.meta.url);
16
16
  const { normalizeInstanceBase, pollDecision } = require('../scripts/gds/login.js');
17
17
  const LOGIN_JS = path.join(path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'), 'scripts', 'gds', 'login.js');
18
18
 
19
- test('normalizeInstanceBase adds https, strips trailing slashes + a pasted /api/gds', () => {
19
+ test('normalizeInstanceBase adds https, strips trailing slashes + a pasted /api/bongos', () => {
20
20
  assert.equal(normalizeInstanceBase('example.com'), 'https://example.com');
21
21
  assert.equal(normalizeInstanceBase('https://example.com/'), 'https://example.com');
22
22
  assert.equal(normalizeInstanceBase('https://example.com///'), 'https://example.com');
23
+ assert.equal(normalizeInstanceBase('https://example.com/api/bongos'), 'https://example.com');
24
+ assert.equal(normalizeInstanceBase('https://example.com/api/bongos/'), 'https://example.com');
25
+ assert.equal(normalizeInstanceBase('https://example.com/api/bongos/v1'), 'https://example.com');
26
+ // the permanent alias is still a legal paste — task 1003707 moved the callers, not the door
23
27
  assert.equal(normalizeInstanceBase('https://example.com/api/gds'), 'https://example.com');
24
- assert.equal(normalizeInstanceBase('https://example.com/api/gds/'), 'https://example.com');
25
28
  assert.equal(normalizeInstanceBase('http://localhost:3000'), 'http://localhost:3000');
26
29
  });
27
30
 
@@ -58,10 +61,10 @@ test('login on a Device-Flow-disabled instance explains the cause and the cure',
58
61
  res.writeHead(code, { 'Content-Type': 'application/json' });
59
62
  res.end(JSON.stringify(body));
60
63
  };
61
- if (req.url.endsWith('/api/gds/instance')) {
64
+ if (req.url.endsWith('/api/bongos/instance')) {
62
65
  return send(200, { schema: 'instance-manifest/v1', name: 'Stub', admission: { policy: 'invite-only' } });
63
66
  }
64
- if (req.url.endsWith('/api/gds/auth/device/start')) {
67
+ if (req.url.endsWith('/api/bongos/auth/device/start')) {
65
68
  // Byte-for-byte what a real instance returned when its App had the box unticked.
66
69
  return send(424, { error: { code: 'device_start_failed', message: 'device/code failed (400): {"error":"device_flow_disabled","error_description":"Device Flow must be explicitly enabled for this App"}' } });
67
70
  }
package/tests/box_env.mjs CHANGED
@@ -20,15 +20,15 @@ const box = require('../scripts/gds/box.js');
20
20
 
21
21
  const { test, summary } = makeRunner();
22
22
 
23
- await test('bakes GDS_BASE as the FULL api base (origin + /api/gds) — matches box-report-*.sh, not box-heartbeat.sh\'s bare-origin BASE', () => {
23
+ await test('bakes GDS_BASE as the FULL api base (origin + /api/bongos) — matches box-report-*.sh, not box-heartbeat.sh\'s bare-origin BASE', () => {
24
24
  const env = box.buildBoxEnv({ apiOrigin: 'https://cloudbongos.com' });
25
- assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/gds$/m);
25
+ assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/bongos$/m);
26
26
  });
27
27
 
28
- await test('strips a trailing slash off the origin before appending /api/gds', () => {
28
+ await test('strips a trailing slash off the origin before appending /api/bongos', () => {
29
29
  const env = box.buildBoxEnv({ apiOrigin: 'https://cloudbongos.com/' });
30
- assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/gds$/m);
31
- assert.ok(!env.includes('//api/gds'), 'must not double the slash');
30
+ assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/bongos$/m);
31
+ assert.ok(!env.includes('//api/bongos'), 'must not double the slash');
32
32
  });
33
33
 
34
34
  await test('no named tunnel: box.env carries GDS_BASE and nothing else', () => {
@@ -44,7 +44,7 @@ await test('named tunnel: box.env carries GDS_BASE AND all four tunnel vars', ()
44
44
  credential: 'cred456', previewHostname: 'sandbox-alice.example.com',
45
45
  },
46
46
  });
47
- assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/gds$/m);
47
+ assert.match(env, /^GDS_BASE=https:\/\/cloudbongos\.com\/api\/bongos$/m);
48
48
  assert.match(env, /^BOX_TUNNEL_TOKEN=tok123$/m);
49
49
  assert.match(env, /^BOX_TERMINAL_HOSTNAME=term-alice\.example\.com$/m);
50
50
  assert.match(env, /^BOX_TERMINAL_CREDENTIAL=cred456$/m);
@@ -101,7 +101,7 @@ await t('persistImageFromUrl: content-type says png but bytes are not → sniff_
101
101
  await t('persistImageFromUrl: valid PNG → written to disk, returns durable url', async () => {
102
102
  const r = await at.persistImageFromUrl('https://cdn.discordapp.com/a.png', { messageId: 'm42', fetchImpl: fakeFetch(PNG), dir: TMP });
103
103
  assert.equal(r.ok, true);
104
- assert.match(r.url, /^\/api\/gds\/bug-attachments\/bug-m42-[0-9a-f]{16}\.png$/);
104
+ assert.match(r.url, /^\/api\/bongos\/bug-attachments\/bug-m42-[0-9a-f]{16}\.png$/);
105
105
  assert.equal(at.isSafeName(r.file), true);
106
106
  const onDisk = await fs.readFile(path.join(TMP, r.file));
107
107
  assert.equal(onDisk.length, PNG.length);
@@ -259,7 +259,7 @@ test('login VERIFIES a stored token before trusting it, and can be forced past',
259
259
  // A stored token may be expired or revoked. Reinstating one unchecked would leave the builder
260
260
  // "signed in" to a session every later command then fails on.
261
261
  assert.match(src, /loadStoredSession\(base\)/);
262
- assert.match(src, /\/api\/gds\/me`, \{ headers: \{ Authorization/);
262
+ assert.match(src, /\/api\/bongos\/me`, \{ headers: \{ Authorization/);
263
263
  assert.match(src, /if \(me\.ok && me\.data && me\.data\.builder\)/);
264
264
  assert.match(src, /--force/, 'there must be a way to sign in as somebody else');
265
265
  });
package/tests/dev_lib.mjs CHANGED
@@ -211,7 +211,7 @@ t('stop: kills a live pid, reports not-running otherwise', () => {
211
211
  await ta('health: up + authConfigured parsed from the two healthz routes', async () => {
212
212
  const params = { port: 3006 };
213
213
  const deps = { fetchImpl: async (url) => {
214
- if (url.endsWith('/api/gds/healthz')) return { status: 200, json: async () => ({ ok: true, auth_configured: true }) };
214
+ if (url.endsWith('/api/bongos/healthz')) return { status: 200, json: async () => ({ ok: true, auth_configured: true }) };
215
215
  if (url.endsWith('/healthz')) return { status: 200 };
216
216
  return { status: 404 };
217
217
  } };
@@ -99,7 +99,7 @@ function makeDeps(over = {}) {
99
99
  calls.persist.push({ urls, opts });
100
100
  if (over.persistThrows) throw new Error('persist boom');
101
101
  // default: echo each url back as a stored ref unless overridden
102
- return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/gds/bug-attachments/bug-x-${i}.png` }));
102
+ return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/bongos/bug-attachments/bug-x-${i}.png` }));
103
103
  },
104
104
  };
105
105
  return { deps, calls };
@@ -282,7 +282,7 @@ await t('recordInboundBug: text + images → persists images + embeds durable li
282
282
  assert.equal(calls.persist.length, 1);
283
283
  assert.deepEqual(calls.persist[0].urls, ['https://cdn.discordapp.com/a.png']);
284
284
  assert.match(calls.create[0].bodyMd, /Attachments \(1\)/);
285
- assert.match(calls.create[0].bodyMd, /!\[attachment 1\]\(\/api\/gds\/bug-attachments\//);
285
+ assert.match(calls.create[0].bodyMd, /!\[attachment 1\]\(\/api\/bongos\/bug-attachments\//);
286
286
  });
287
287
 
288
288
  await t('recordInboundBug: image-only (empty text) → filed with screenshot title', async () => {
@@ -71,7 +71,7 @@ function makeDeps(over = {}) {
71
71
  persistImages: async (urls, opts) => {
72
72
  calls.persist.push({ urls, opts });
73
73
  if (over.persistThrows) throw new Error('persist boom');
74
- return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/gds/bug-attachments/bug-x-${i}.png` }));
74
+ return over.stored ?? urls.map((u, i) => ({ file: `bug-x-${i}.png`, url: `/api/bongos/bug-attachments/bug-x-${i}.png` }));
75
75
  },
76
76
  };
77
77
  return { deps, calls };
@@ -224,7 +224,7 @@ await t('recordInboundIdea: text + images → persists + embeds durable links',
224
224
  assert.equal(r.images, 1);
225
225
  assert.equal(calls.persist.length, 1);
226
226
  assert.match(calls.capture[0].bodyMd, /Attachments \(1\)/);
227
- assert.match(calls.capture[0].bodyMd, /!\[attachment 1\]\(\/api\/gds\/bug-attachments\//);
227
+ assert.match(calls.capture[0].bodyMd, /!\[attachment 1\]\(\/api\/bongos\/bug-attachments\//);
228
228
  });
229
229
 
230
230
  await t('recordInboundIdea: UNLINKED author with image → still re-hosted (guards, not identity)', async () => {
@@ -280,6 +280,6 @@ test('the page reads the public feed and asks for JSON', async () => {
280
280
  const r = render([]);
281
281
  await settle();
282
282
  assert.equal(r.requests.length, 1);
283
- assert.equal(r.requests[0].url, '/api/gds/projects/featured');
283
+ assert.equal(r.requests[0].url, '/api/bongos/projects/featured');
284
284
  assert.equal(r.requests[0].opts.headers.Accept, 'application/json');
285
285
  });