@bongos/core 1.21.66 → 1.21.67

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 (49) hide show
  1. package/.bongos-core.json +111 -41
  2. package/docs/copy-inventory.md +414 -386
  3. package/docs/copy-registry.json +815 -537
  4. package/docs/file-map.md +1 -0
  5. package/docs/module-api-changelog.md +2 -0
  6. package/docs/page-inventory.json +45 -12
  7. package/docs/page-readings.json +959 -907
  8. package/modules/platform-identity/routes/my-projects.js +1 -1
  9. package/modules/public-landing/public/account.html +1 -1
  10. package/modules/public-landing/public/assets/cosmos.css +12 -10
  11. package/modules/public-landing/public/contact.html +1 -1
  12. package/modules/public-landing/public/guild.html +1 -1
  13. package/modules/public-landing/public/index-cli.states.json +20 -0
  14. package/modules/public-landing/public/index.html +68 -1
  15. package/modules/public-landing/public/index.states.json +4 -4
  16. package/modules/public-landing/public/invitations-empty.states.json +56 -0
  17. package/modules/public-landing/public/invitations-picker.states.json +84 -0
  18. package/modules/public-landing/public/invitations.html +956 -0
  19. package/modules/public-landing/public/invitations.probes.json +430 -0
  20. package/modules/public-landing/public/invitations.states.json +473 -0
  21. package/modules/public-landing/public/privacy.html +1 -1
  22. package/modules/public-landing/public/projects.html +18 -543
  23. package/modules/public-landing/public/projects.probes.json +0 -29
  24. package/modules/public-landing/public/projects.states.json +0 -6
  25. package/modules/public-landing/public/terms.html +1 -1
  26. package/modules/ui-design/kit/fixtures/bongos-cli-latest-sample.json +10 -0
  27. package/modules/ui-design/kit/fixtures/featured-invitations.json +183 -0
  28. package/modules/ui-design/kit/fixtures/guilds-empty.json +1 -0
  29. package/modules/ui-design/kit/fixtures/me-guild-engagements-empty.json +1 -0
  30. package/modules/ui-design/kit/fixtures/me-guild-requests-empty.json +1 -0
  31. package/modules/ui-design/kit/fixtures/my-projects-applied.json +29 -0
  32. package/modules/ui-design/kit/fixtures/my-projects-invites-empty.json +1 -0
  33. package/modules/ui-design/kit/serve.js +5 -1
  34. package/package-lock.json +2 -2
  35. package/package.json +1 -1
  36. package/release-notes.json +10 -0
  37. package/src/module-api.js +1 -1
  38. package/src/platform-server.js +11 -0
  39. package/tests/hub_account_page.mjs +1 -1
  40. package/tests/hub_engagement_cards.mjs +44 -40
  41. package/tests/hub_guild_cards.mjs +24 -22
  42. package/tests/hub_invitations_page.mjs +414 -0
  43. package/tests/join_relay_outcome.mjs +1 -1
  44. package/tests/landing_legal_pages.mjs +8 -6
  45. package/tests/landing_page.mjs +125 -3
  46. package/tests/my_projects_surface.mjs +14 -6
  47. package/tests/public_landing_projects.mjs +12 -14
  48. package/tests/render_check.mjs +3 -2
  49. package/tests/ui_design_kit.mjs +3 -3
@@ -21,9 +21,10 @@
21
21
  // audit could not confirm, so it is asserted here rather than described.
22
22
  // 3. WHAT WAS STILL MISSING. The invitations half had no caller anywhere — no
23
23
  // surface fetched the invite list, so a builder holding an invitation could
24
- // not act on it. Closed by task 1003774: the hub's /projects?view=mine now
25
- // reads GET /my-projects/invites (idea 1000903). The pin below flipped from
26
- // "no surface calls this" to "some surface does" for the same reason.
24
+ // not act on it. Closed by task 1003774, which put the list in the hub's
25
+ // /projects?view=mine (idea 1000903); task 1004276 moved it to the hub's own
26
+ // /invitations page. The pin below flipped from "no surface calls this" to
27
+ // "some surface does" for the same reason.
27
28
  //
28
29
  // Static reads only (no import of the app, no DB) → runs in the `unit` gate.
29
30
  //
@@ -116,10 +117,17 @@ test('an invitations surface exists — the hub reads GET /my-projects/invites (
116
117
  // dead end the moment a caller exists to press it. Each invite renders as a
117
118
  // way IN (a link to the project) instead — signing in there is the acceptance
118
119
  // act (task 1002969).
120
+ // Both hub pages: /invitations holds the invite list now (task 1004276), and
121
+ // /projects is where it lived and where a regression could put a caller back.
122
+ const HUB_PAGES = ['modules/public-landing/public/invitations.html', 'modules/public-landing/public/projects.html'];
119
123
  test('the hub never calls the accept route — ADR 0335 retired that flip', () => {
120
- const html = read('modules/public-landing/public/projects.html');
121
- assert.doesNotMatch(html, /invites\/[^'"]*\/accept/,
122
- 'a hub caller of the accept route reopens the dead end ADR 0335 closed — render the invite as a link into the project instead');
124
+ for (const rel of HUB_PAGES) {
125
+ assert.doesNotMatch(read(rel), /invites\/[^'"]*\/accept/,
126
+ `${rel}: a hub caller of the accept route reopens the dead end ADR 0335 closed — render the invite as a link into the project instead`);
127
+ }
128
+ // the guard is only meaningful where the invite list is: it must be on one of these pages
129
+ assert.ok(HUB_PAGES.some((rel) => read(rel).includes("'/my-projects/invites'")),
130
+ 'the invite list moved off both hub pages — point this guard at wherever it went');
123
131
  });
124
132
 
125
133
  // Task 1002818 (ADR 0353) finished the retirement on the server: the route is gone,
@@ -521,28 +521,26 @@ test('a stamped asset still serves — the query string is not part of the filen
521
521
  // nowhere to live until now. loadMemberships() already fetched GET /my-projects
522
522
  // for the map's Apply button (R10, task 1002286) — this just renders the rest
523
523
  // of what that same read carries, plus the separate invites list.
524
- test('#view-mine reads the invitations list, alongside the building-on and join surfaces', async () => {
524
+ // The invitations and the join-by-address field moved to their own page with task
525
+ // 1004276 (the owner's call, ADR 0337 D5); tests/hub_invitations_page.mjs holds that
526
+ // page as served. What stays here: building-on with Leave, and a door to the page.
527
+ test('#view-mine keeps building-on with Leave, and points at /invitations for the invitations and the join field', async () => {
525
528
  const { body } = await request('/projects', 'game.test.local');
526
- assert.match(body, /\/my-projects\/invites/, 'GET /my-projects/invites must be called');
527
- assert.match(body, /id="invitesList"/);
528
529
  assert.match(body, /id="buildingList"/);
529
- assert.match(body, /\/my-projects\/join/, 'the join-by-URL field must post to /my-projects/join');
530
- assert.match(body, /id="joinOrigin"/);
531
- assert.match(body, /id="joinNote"/, 'the applicant note (task 1002330) rides along, and stays optional');
532
530
  assert.match(body, /\/my-projects\/'\s*\+\s*encodeURIComponent/, 'Leave must address the project by its own client id');
533
- assert.match(body, /origin = 'https:\/\/' \+ origin/,
534
- 'a bare host ("grove.cloudbongos.com") must be assumed https:// rather than sent as-is — the server\'s origin lookup is an exact match');
531
+ for (const gone of ['invitesList', 'guildInviteList', 'engageList', 'guildRequestList', 'joinOrigin', 'joinNote', 'joinBtn', 'mineInvites']) {
532
+ assert.doesNotMatch(body, new RegExp(`id="${gone}"`), `#${gone} moved to /invitations`);
533
+ }
534
+ assert.doesNotMatch(body, /\/my-projects\/invites/, 'the invitations are read on their own page now');
535
+ assert.match(body, /<h2 id="mineToInvitesH">Invitations<\/h2>\s*<p class="lede">[^<]*<a href="\/invitations">Open your invitations<\/a><\/p>/, 'the mine view says where they went');
536
+ assert.match(body, /\/my-projects\/join/, 'the map card’s Apply to join still posts the join relay');
535
537
  });
536
538
 
537
- test('an invite renders as a way INTO the project, never the retired accept flip (ADR 0335)', async () => {
539
+ test('the hub never calls the retired accept flip (ADR 0335)', async () => {
538
540
  const { body } = await request('/projects', 'game.test.local');
539
541
  // the hub-only accept flip never admits anyone to the project's own instance
540
- // (ADR 0335) — a caller of it here would reopen the exact dead end that ADR
541
- // retired, so the invite's action is an outbound link instead
542
+ // (ADR 0335) — a caller of it here would reopen the exact dead end that ADR retired
542
543
  assert.doesNotMatch(body, /invites\/[^'"]*\/accept/, 'no caller of the retired hub accept route');
543
- assert.match(body, /Open project/, 'the invite links into the project — signing in there is the acceptance act');
544
- assert.match(body, /'\/my-projects\/invites\/' \+ encodeURIComponent\([^)]+\) \+ '\/decline'/,
545
- 'decline still works: it only clears the hub\'s own pending row');
546
544
  });
547
545
 
548
546
  test('the map card\'s Apply button reads as truly inert once applied, with a live status region (R10 fixups)', async () => {
@@ -24,8 +24,9 @@ test('a shared asset reaches every page in its dir whose HTML names it', () => {
24
24
  // sky-data.js is shared by the two doors of one page (task 1004232): /thinking and /goal-map.
25
25
  assert.deepEqual(names(['modules/hall-ui/public/sky-data.js']), ['goal-map.states.json', 'thinking.states.json']);
26
26
  assert.deepEqual(names(['modules/hall-ui/public/text-fit.js']), ['goals.states.json']);
27
- // the account page links the hub's sheet too since task 1004259, and the guild page since task 1002301
28
- assert.deepEqual(names(['modules/public-landing/public/assets/cosmos.css']), ['account.states.json', 'guild.states.json', 'projects.states.json']);
27
+ // the account page links the hub's sheet too since task 1004259, the guild page since task 1002301,
28
+ // and the invitations page since task 1004276
29
+ assert.deepEqual(names(['modules/public-landing/public/assets/cosmos.css']), ['account.states.json', 'guild.states.json', 'invitations.states.json', 'projects.states.json']);
29
30
  });
30
31
 
31
32
  test('the page a builder changed comes before the pages a shared file reaches, so the render cap never drops it', () => {
@@ -34,7 +34,7 @@ test('the platform floors are a pinned list — a floor cannot vanish quietly',
34
34
  });
35
35
 
36
36
  test('the shipped states files validate and sit beside the page they name', () => {
37
- for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/projects-empty.states.json', 'modules/public-landing/public/projects-dns-pending.states.json', 'modules/public-landing/public/projects-hall-live.states.json','modules/public-landing/public/index.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/account-private.states.json', 'modules/public-landing/public/guild.states.json', 'modules/hall-ui/public/ranks.states.json']) {
37
+ for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/projects-empty.states.json', 'modules/public-landing/public/projects-dns-pending.states.json', 'modules/public-landing/public/projects-hall-live.states.json','modules/public-landing/public/index.states.json', 'modules/public-landing/public/index-cli.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/account-private.states.json', 'modules/public-landing/public/guild.states.json', 'modules/public-landing/public/invitations.states.json', 'modules/public-landing/public/invitations-empty.states.json', 'modules/public-landing/public/invitations-picker.states.json', 'modules/hall-ui/public/ranks.states.json']) {
38
38
  const json = readJson(rel);
39
39
  const v = lib.validateStatesFile(json);
40
40
  assert.deepEqual(v.errors, [], `${rel}: ${v.errors.join('; ')}`);
@@ -43,14 +43,14 @@ test('the shipped states files validate and sit beside the page they name', () =
43
43
  }
44
44
  // the apex is dark only (task 1003336): its states files name the one mode, and
45
45
  // render.js reads it as the default so a plain `--page /` never renders light
46
- for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/index.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/guild.states.json']) {
46
+ for (const rel of ['modules/public-landing/public/projects.states.json', 'modules/public-landing/public/index.states.json', 'modules/public-landing/public/account.states.json', 'modules/public-landing/public/guild.states.json', 'modules/public-landing/public/invitations.states.json']) {
47
47
  assert.deepEqual(readJson(rel).modes, ['dark'], `${rel}: the apex renders dark only`);
48
48
  assert.equal(readJson(rel).modeQuery, false, `${rel}: no query walks a second mode`);
49
49
  }
50
50
  });
51
51
 
52
52
  test('the shipped probes files validate', () => {
53
- for (const rel of ['modules/public-landing/public/projects.probes.json', 'modules/public-landing/public/index.probes.json', 'modules/public-landing/public/account.probes.json', 'modules/public-landing/public/guild.probes.json']) {
53
+ for (const rel of ['modules/public-landing/public/projects.probes.json', 'modules/public-landing/public/index.probes.json', 'modules/public-landing/public/account.probes.json', 'modules/public-landing/public/guild.probes.json', 'modules/public-landing/public/invitations.probes.json']) {
54
54
  const v = lib.validateProbesFile(readJson(rel));
55
55
  assert.deepEqual(v.errors, [], `${rel}: ${v.errors.join('; ')}`);
56
56
  }