@bongos/core 1.19.533 → 1.19.535
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.
- package/.bongos-core.json +121 -56
- package/clients/bongos-client/index.d.ts +1 -1
- package/config/branding.neutral.json +3 -2
- package/docs/adr/0245-the-way-back-into-an-optional-step-is-that-step-s-own-answer-route.md +144 -0
- package/docs/adr/0246-catalog-membership-is-a-projection-not-a-federation-side-effect.md +96 -0
- package/docs/adr/0247-the-join-door-is-one-composed-answer-and-dark-matter-has-no-live-verdict-yet.md +202 -0
- package/docs/adr/README.md +4 -0
- package/docs/api/openapi.json +8 -1
- package/docs/api-reference.md +1 -1
- package/docs/copy-inventory.md +162 -157
- package/docs/copy-registry.json +252 -196
- package/docs/file-map.md +1 -0
- package/docs/module-api-changelog.md +16 -0
- package/modules/hall-ui/public/hall-kit.js +93 -7
- package/modules/hall-ui/public/roadmap-timeline.js +105 -0
- package/modules/hall-ui/public/roadmap.html +7 -1
- package/modules/hall-ui/public/roadmap.js +16 -0
- package/modules/hall-ui/public/style.css +4 -2
- package/modules/hall-ui/public/watch.html +4 -0
- package/modules/hall-ui/public/watch.js +116 -0
- package/modules/onboarding/module.json +1 -1
- package/modules/onboarding/routes/access-requests.js +21 -6
- package/modules/platform-identity/module.json +1 -1
- package/modules/platform-identity/project-catalog.js +202 -0
- package/modules/platform-identity/routes/my-projects.js +7 -2
- package/modules/platform-identity/routes/projects.js +6 -0
- package/modules/platform-identity/routes/sso.js +10 -0
- package/modules/provisioning/catalog-bridge.js +105 -0
- package/modules/provisioning/provisioning.js +28 -2
- package/modules/provisioning/routes/provisioning.js +45 -11
- package/modules/provisioning/tests/provisioning.mjs +11 -8
- package/modules/public-landing/public/assets/cosmos.css +15 -0
- package/modules/public-landing/public/projects.html +162 -3
- package/modules/ui-design/kit/serve.js +1 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/fitness.js +9 -0
- package/scripts/gds/provision-net.js +7 -0
- package/scripts/hall-preview/refresh-fixtures.js +6 -0
- package/src/bongos/project-door.js +138 -0
- package/src/branding.js +8 -0
- package/src/module-api.js +12 -1
- package/tests/access_requests_invite.mjs +2 -2
- package/tests/application_lifecycle.mjs +1 -0
- package/tests/catalog_only_client.mjs +242 -0
- package/tests/currency_label.mjs +8 -5
- package/tests/hall_kit_charts.mjs +173 -0
- package/tests/hall_oversight_world.mjs +159 -0
- package/tests/hall_reading_world.mjs +153 -0
- package/tests/module_api.mjs +1 -0
- package/tests/project_catalog_bridge.mjs +355 -0
- package/tests/project_catalog_routes.mjs +213 -0
- package/tests/project_join_door.mjs +166 -0
- package/tests/project_join_door_route.mjs +206 -0
- package/tests/project_modules_ui.mjs +318 -0
- package/tests/projects_hub.mjs +6 -1
- package/tests/projects_hub_pre_uat.mjs +2 -2
- package/tests/provision_settings_apply.mjs +6 -5
- package/tests/provisioning_module_selection.mjs +164 -3
- package/tests/provisioning_settings.mjs +10 -7
- package/tests/provisioning_settings_apply.mjs +3 -3
- package/tests/provisioning_settings_env.mjs +7 -4
|
@@ -164,7 +164,7 @@ await ta('owner reads DEFAULTS (public / apply) on a row with empty settings —
|
|
|
164
164
|
reset();
|
|
165
165
|
const r = await get('/provisioning/instances/18/settings');
|
|
166
166
|
assert.equal(r.status, 200, r.raw);
|
|
167
|
-
assert.deepEqual(r.body.settings, { platform_visibility: 'public', joinability: 'apply', visibility: 'public' });
|
|
167
|
+
assert.deepEqual(r.body.settings, { platform_visibility: 'public', joinability: 'apply', visibility: 'public', join_grant: 'full' });
|
|
168
168
|
// the planet rides beside the settings (task 1003347): no default — null = the platform's own pick
|
|
169
169
|
assert.deepEqual(r.body.planet, { planet_template: null, planet_accent: null, card_backdrop: null });
|
|
170
170
|
assert.deepEqual(r.body.options, {
|
|
@@ -172,6 +172,9 @@ await ta('owner reads DEFAULTS (public / apply) on a row with empty settings —
|
|
|
172
172
|
// the join door (task 1002324, ADR 0182 D1) — the third policy axis, offered
|
|
173
173
|
// to the form the same way as its two neighbours
|
|
174
174
|
visibility: ['public', 'private', 'stealth'],
|
|
175
|
+
// what a PUBLIC join grants (task 1002331, ADR 0247) — the fourth policy
|
|
176
|
+
// axis, offered to the form the same way
|
|
177
|
+
join_grant: ['view', 'apply', 'full'],
|
|
175
178
|
planet_template: [...provisioning.PLANET_TEMPLATES], planet_accent: ['sea', 'terracotta', 'gold-soft', 'sun-lit', 'accent'],
|
|
176
179
|
// the card's backdrop (task 1003352) is the same kind of key: platform-drawn,
|
|
177
180
|
// closed list, no default, no push — so it rides the same vocab
|
|
@@ -184,14 +187,14 @@ await ta('a stored planet reads back; a name that left the vocabulary reads null
|
|
|
184
187
|
const r = await get('/provisioning/instances/18/settings');
|
|
185
188
|
assert.equal(r.status, 200, r.raw);
|
|
186
189
|
assert.deepEqual(r.body.planet, { planet_template: 'bead-obsidian-tint', planet_accent: null, card_backdrop: null });
|
|
187
|
-
assert.deepEqual(r.body.settings, { platform_visibility: 'public', joinability: 'apply', visibility: 'public' }, 'the planet is not a setting: the policy read is untouched');
|
|
190
|
+
assert.deepEqual(r.body.settings, { platform_visibility: 'public', joinability: 'apply', visibility: 'public', join_grant: 'full' }, 'the planet is not a setting: the policy read is untouched');
|
|
188
191
|
});
|
|
189
192
|
|
|
190
193
|
await ta('stored keys overlay the defaults', async () => {
|
|
191
194
|
reset({ inst: { owner_builder_id: 7, slug: 'spike', status: 'active', settings: { joinability: 'invite_only' } } });
|
|
192
195
|
const r = await get('/provisioning/instances/18/settings');
|
|
193
196
|
assert.equal(r.status, 200, r.raw);
|
|
194
|
-
assert.deepEqual(r.body.settings, { platform_visibility: 'public', joinability: 'invite_only', visibility: 'public' });
|
|
197
|
+
assert.deepEqual(r.body.settings, { platform_visibility: 'public', joinability: 'invite_only', visibility: 'public', join_grant: 'full' });
|
|
195
198
|
});
|
|
196
199
|
|
|
197
200
|
await ta('ANOTHER builder\'s GET → 404 (no existence leak)', async () => {
|
|
@@ -219,7 +222,7 @@ await ta('owner changes one key — merged, returned effective, audited api:self
|
|
|
219
222
|
reset();
|
|
220
223
|
const r = await patch('/provisioning/instances/18/settings', { joinability: 'open' });
|
|
221
224
|
assert.equal(r.status, 200, r.raw);
|
|
222
|
-
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'open', visibility: 'public' }, 'the SAVED value — the response never claims the instance runs it (task 1003140)');
|
|
225
|
+
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'open', visibility: 'public', join_grant: 'full' }, 'the SAVED value — the response never claims the instance runs it (task 1003140)');
|
|
223
226
|
assert.equal(r.body.push.queued, true, 'an active co-tenant gets the live push (task 1003140)');
|
|
224
227
|
assert.deepEqual(updateCalls, [{ id: 18, patch: { joinability: 'open' } }], 'exactly the sent key, nothing else');
|
|
225
228
|
assert.equal(events.length, 1);
|
|
@@ -232,7 +235,7 @@ await ta('owner changes both keys in one call', async () => {
|
|
|
232
235
|
reset();
|
|
233
236
|
const r = await patch('/provisioning/instances/18/settings', { platform_visibility: 'gated', joinability: 'invite_only' });
|
|
234
237
|
assert.equal(r.status, 200, r.raw);
|
|
235
|
-
assert.deepEqual(r.body.saved, { platform_visibility: 'gated', joinability: 'invite_only', visibility: 'public' });
|
|
238
|
+
assert.deepEqual(r.body.saved, { platform_visibility: 'gated', joinability: 'invite_only', visibility: 'public', join_grant: 'full' });
|
|
236
239
|
});
|
|
237
240
|
|
|
238
241
|
await ta('the OWN-SCOPE WALL: another builder\'s PATCH → 404 and the write path is never reached', async () => {
|
|
@@ -271,7 +274,7 @@ await ta('the owner sets the door to stealth — stored, echoed effective, audit
|
|
|
271
274
|
reset();
|
|
272
275
|
const r = await patch('/provisioning/instances/18/settings', { visibility: 'stealth' });
|
|
273
276
|
assert.equal(r.status, 200, r.raw);
|
|
274
|
-
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'apply', visibility: 'stealth' });
|
|
277
|
+
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'apply', visibility: 'stealth', join_grant: 'full' });
|
|
275
278
|
assert.deepEqual(updateCalls, [{ id: 18, patch: { visibility: 'stealth' } }], 'exactly the sent key, nothing else');
|
|
276
279
|
assert.equal(events[0].actor, 'api:self');
|
|
277
280
|
assert.match(events[0].detail, /visibility=stealth/);
|
|
@@ -331,7 +334,7 @@ await ta('the owner picks a planet: saved, echoed as `planet`, audited — and N
|
|
|
331
334
|
const r = await patch('/provisioning/instances/18/settings', { planet_template: 'bead-obsidian-tint', planet_accent: 'sea' });
|
|
332
335
|
assert.equal(r.status, 200, r.raw);
|
|
333
336
|
assert.deepEqual(r.body.planet, { planet_template: 'bead-obsidian-tint', planet_accent: 'sea', card_backdrop: null });
|
|
334
|
-
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'apply', visibility: 'public' }, 'the policy half is untouched');
|
|
337
|
+
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'apply', visibility: 'public', join_grant: 'full' }, 'the policy half is untouched');
|
|
335
338
|
assert.deepEqual(updateCalls, [{ id: 18, patch: { planet_template: 'bead-obsidian-tint', planet_accent: 'sea' } }]);
|
|
336
339
|
assert.equal(r.body.push.queued, false);
|
|
337
340
|
assert.equal(r.body.push.restart, false, 'an active co-tenant would get a push for a POLICY change — never for the planet');
|
|
@@ -212,7 +212,7 @@ await ta('ACTIVE standalone: the row is written FIRST, then a settings-apply int
|
|
|
212
212
|
reset();
|
|
213
213
|
const r = await patch('/provisioning/instances/18/settings', { platform_visibility: 'gated' });
|
|
214
214
|
assert.equal(r.status, 200, r.raw);
|
|
215
|
-
assert.deepEqual(r.body.saved, { platform_visibility: 'gated', joinability: 'apply', visibility: 'public' }, 'the SAVED (requested) value — never `settings`, which a form would render as live');
|
|
215
|
+
assert.deepEqual(r.body.saved, { platform_visibility: 'gated', joinability: 'apply', visibility: 'public', join_grant: 'full' }, 'the SAVED (requested) value — never `settings`, which a form would render as live');
|
|
216
216
|
assert.equal(r.body.settings, undefined);
|
|
217
217
|
assert.deepEqual(updateCalls.map((c) => c.patch), [{ platform_visibility: 'gated' }]);
|
|
218
218
|
assert.equal(updateCalls[0].enqueuedSoFar, 0, 'the runner reads the row — the write must precede the intent');
|
|
@@ -261,7 +261,7 @@ await ta('an enqueue that THROWS still answers 200 "saved" — never a 500 that
|
|
|
261
261
|
enqueueThrows = new Error('db down');
|
|
262
262
|
const r = await patch('/provisioning/instances/18/settings', { joinability: 'open' });
|
|
263
263
|
assert.equal(r.status, 200, r.raw);
|
|
264
|
-
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'open', visibility: 'public' });
|
|
264
|
+
assert.deepEqual(r.body.saved, { platform_visibility: 'public', joinability: 'open', visibility: 'public', join_grant: 'full' });
|
|
265
265
|
assert.equal(updateCalls.length, 1, 'the write landed');
|
|
266
266
|
receiptShape(r.body.push, { queued: false, restart: true, reachable: true });
|
|
267
267
|
assert.match(r.body.push.message, /Saved, but the restart could not be queued/);
|
|
@@ -274,7 +274,7 @@ await ta('same values as already stored → no write, no event, no intent, "No c
|
|
|
274
274
|
reset({ inst: { ...ACTIVE, settings: { platform_visibility: 'gated', joinability: 'open' } } });
|
|
275
275
|
const r = await patch('/provisioning/instances/18/settings', { platform_visibility: 'gated', joinability: 'open' });
|
|
276
276
|
assert.equal(r.status, 200, r.raw);
|
|
277
|
-
assert.deepEqual(r.body.saved, { platform_visibility: 'gated', joinability: 'open', visibility: 'public' });
|
|
277
|
+
assert.deepEqual(r.body.saved, { platform_visibility: 'gated', joinability: 'open', visibility: 'public', join_grant: 'full' });
|
|
278
278
|
assert.equal(updateCalls.length, 0, 'nothing written (no updated_at reshuffle)');
|
|
279
279
|
assert.equal(events.length, 0, 'no "settings changed" event for a change that is not one');
|
|
280
280
|
assert.equal(enqueueCalls.length, 0, 'a whole-form save must not bounce a live project');
|
|
@@ -57,7 +57,10 @@ t('a row with NO stored settings emits today\'s behavior EXPLICITLY, never nothi
|
|
|
57
57
|
assert.equal(v.CLOUDBONGOS_JOINABILITY, 'apply');
|
|
58
58
|
// the join door rides the same transport (task 1002324, ADR 0182 D1)
|
|
59
59
|
assert.equal(v.CLOUDBONGOS_VISIBILITY, 'public');
|
|
60
|
-
|
|
60
|
+
// what a public join grants rides it too (task 1002331, ADR 0182 D6)
|
|
61
|
+
assert.equal(v.CLOUDBONGOS_JOIN_GRANT, 'full');
|
|
62
|
+
assert.equal(linesOf(provisioning.settingsEnvLines({}, 'X')).length,
|
|
63
|
+
Object.keys(provisioning.SETTINGS_VOCAB).length, 'every policy key always present');
|
|
61
64
|
});
|
|
62
65
|
|
|
63
66
|
t('an off-vocabulary stored value falls back to the default, never reaches the instance', () => {
|
|
@@ -96,11 +99,11 @@ t('it names the live push by the intent the runner actually dispatches (task 100
|
|
|
96
99
|
});
|
|
97
100
|
|
|
98
101
|
t('settingsEnvVars is the single source both legs derive from — same keys, same values as the lines', () => {
|
|
99
|
-
const row = { settings: { platform_visibility: 'gated', joinability: 'open', visibility: 'stealth' } };
|
|
102
|
+
const row = { settings: { platform_visibility: 'gated', joinability: 'open', visibility: 'stealth', join_grant: 'view' } };
|
|
100
103
|
const vars = provisioning.settingsEnvVars(row, 'CLOUDBONGOS');
|
|
101
|
-
assert.deepEqual(vars, { CLOUDBONGOS_PLATFORM_VISIBILITY: 'gated', CLOUDBONGOS_JOINABILITY: 'open', CLOUDBONGOS_VISIBILITY: 'stealth' });
|
|
104
|
+
assert.deepEqual(vars, { CLOUDBONGOS_PLATFORM_VISIBILITY: 'gated', CLOUDBONGOS_JOINABILITY: 'open', CLOUDBONGOS_VISIBILITY: 'stealth', CLOUDBONGOS_JOIN_GRANT: 'view' });
|
|
102
105
|
assert.deepEqual(varsOf(provisioning.settingsEnvLines(row, 'CLOUDBONGOS')), vars, 'the standup lines ARE the vars');
|
|
103
|
-
assert.deepEqual(provisioning.settingsEnvVars({}, 'X'), { X_PLATFORM_VISIBILITY: 'public', X_JOINABILITY: 'apply', X_VISIBILITY: 'public' }, 'defaults, explicitly');
|
|
106
|
+
assert.deepEqual(provisioning.settingsEnvVars({}, 'X'), { X_PLATFORM_VISIBILITY: 'public', X_JOINABILITY: 'apply', X_VISIBILITY: 'public', X_JOIN_GRANT: 'full' }, 'defaults, explicitly');
|
|
104
107
|
});
|
|
105
108
|
|
|
106
109
|
console.log('\nwebEnvBody — the settings ride the real per-instance env file:');
|