@bongos/core 1.25.12 → 1.25.14

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 (55) hide show
  1. package/.bongos-core.json +106 -51
  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 +13 -4
  6. package/clients/bongos-client/index.mjs +6 -0
  7. package/docs/adr/0328-a-hosted-projects-authority-is-its-membership-row-not-its-owner-column.md +1 -1
  8. package/docs/adr/0407-a-project-grant-is-made-by-the-owner-not-witnessed-at-sign-in.md +124 -0
  9. package/docs/adr/README.md +1 -0
  10. package/docs/api/openapi.json +198 -11
  11. package/docs/api-reference.md +7 -4
  12. package/docs/copy-inventory.md +28 -34
  13. package/docs/copy-registry.json +41 -125
  14. package/docs/file-map.md +1 -1
  15. package/docs/module-api-changelog.md +4 -0
  16. package/docs/page-inventory.json +1 -0
  17. package/docs/page-readings.json +3 -3
  18. package/modules/front-door-guide/claude.js +11 -7
  19. package/modules/front-door-guide/context.js +54 -0
  20. package/modules/front-door-guide/db.js +79 -6
  21. package/modules/front-door-guide/guide.js +18 -3
  22. package/modules/front-door-guide/migrations/front_door_guide_002_plan_and_account.sql +37 -0
  23. package/modules/front-door-guide/migrations/front_door_guide_003_starting_point.sql +12 -0
  24. package/modules/front-door-guide/module.json +7 -3
  25. package/modules/front-door-guide/plan.js +102 -0
  26. package/modules/front-door-guide/pollers/retention-sweep.js +67 -0
  27. package/modules/front-door-guide/routes/front-door-guide-plan.js +145 -0
  28. package/modules/front-door-guide/routes/front-door-guide.js +36 -33
  29. package/modules/front-door-guide/settings.js +4 -0
  30. package/modules/front-door-guide/starting-point.js +55 -0
  31. package/modules/hall-ui/public/genesis-home.js +29 -2
  32. package/modules/hall-ui/public/goals-page.js +3 -29
  33. package/modules/hall-ui/public/index.html +2 -1
  34. package/modules/hall-ui/public/task-lib.js +45 -0
  35. package/modules/hall-ui/public/work.js +3 -47
  36. package/modules/lifecycle/kickoff-seed.js +9 -5
  37. package/modules/onboarding/genesis-home.js +1 -1
  38. package/modules/provisioning/module.json +2 -1
  39. package/modules/provisioning/seams.js +10 -0
  40. package/package-lock.json +306 -3
  41. package/package.json +4 -2
  42. package/release-notes.json +24 -0
  43. package/scripts/bongos/package-core.js +4 -2
  44. package/scripts/bongos/run-unit-tests.js +4 -0
  45. package/src/bongos/module-scope-map.js +2 -0
  46. package/src/module-api.js +1 -1
  47. package/tests/cutover_codemod.mjs +1 -1
  48. package/tests/front_door_guide_db.mjs +115 -0
  49. package/tests/front_door_guide_existing.mjs +238 -0
  50. package/tests/front_door_guide_plan.mjs +344 -0
  51. package/tests/genesis_home.mjs +80 -2
  52. package/tests/package_core.mjs +11 -7
  53. package/tests/pruned_lockfile_integrity.mjs +4 -2
  54. package/tests/status_page_no_dead_uptime.mjs +1 -1
  55. package/tests/task_lib.mjs +46 -0
@@ -7,6 +7,7 @@ const api = require('../../src/module-api');
7
7
  const { pool } = api;
8
8
  const provisioning = require('./provisioning');
9
9
  const { selfUpdateChannel } = require('./core-upgrade');
10
+ const { ALWAYS_ON_CORE, optionalModules } = require('./starter-bundles');
10
11
 
11
12
  // The `provisioning.projectPublishIdentity` port (task 1003578, ADR 0247 D4): the name and
12
13
  // description the publish gate judges, for the control-plane project a hub catalog row was
@@ -44,6 +45,11 @@ async function projectPublishIdentity(db, { slug, host } = {}) {
44
45
  // question names both halves of the ADR 0246 projection.
45
46
  // • PROVIDES port `provisioning.projectPublishIdentity` ({ slug, host }) → { name,
46
47
  // description } | null — see projectPublishIdentity above.
48
+ // • PROVIDES port `provisioning.moduleCatalog` () → { core: [key], optional: [{ key,
49
+ // label, summary }] } — the modules a NEW project gets and may opt into, with the
50
+ // owner-facing words the creation picker shows (task 1005273). The start-a-project
51
+ // guide recommends only from this list, so its plan can never name a module the
52
+ // picker does not offer. Read-only; no database.
47
53
  function registerProvisioningSeams() {
48
54
  if (api.hasProvider('provisioning.instanceState')) return;
49
55
  api.registerProvider('provisioning.instanceState', (slug) => provisioning.instanceStateForSlug(pool, slug));
@@ -51,6 +57,10 @@ function registerProvisioningSeams() {
51
57
  api.registerProvider('provisioning.projectOwnedBy', (target) => provisioning.projectOwnedBy(pool, target));
52
58
  api.registerProvider('provisioning.projectPublishIdentity', (target) => projectPublishIdentity(pool, target));
53
59
  api.registerProvider('provisioning.selfUpdateChannel', () => selfUpdateChannel(pool));
60
+ api.registerProvider('provisioning.moduleCatalog', () => ({
61
+ core: [...ALWAYS_ON_CORE],
62
+ optional: optionalModules().map(({ key, label, summary }) => ({ key, label, summary })),
63
+ }));
54
64
  }
55
65
 
56
66
  module.exports = { registerProvisioningSeams, projectPublishIdentity };
package/package-lock.json CHANGED
@@ -1,16 +1,232 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.25.12",
3
+ "version": "1.25.14",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.25.12",
9
+ "version": "1.25.14",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
13
- "pg": "^8.20.0"
13
+ "pg": "^8.20.0",
14
+ "pino": "^9.14.0",
15
+ "@simplewebauthn/browser": "^13.3.0",
16
+ "@simplewebauthn/server": "^13.3.3"
17
+ }
18
+ },
19
+ "node_modules/@hexagon/base64": {
20
+ "version": "1.1.28",
21
+ "resolved": "https://registry.npmjs.org/@hexagon/base64/-/base64-1.1.28.tgz",
22
+ "integrity": "sha512-lhqDEAvWixy3bZ+UOYbPwUbBkwBq5C1LAJ/xPC8Oi+lL54oyakv/npbA0aU2hgCsx/1NUd4IBvV03+aUBWxerw==",
23
+ "license": "MIT"
24
+ },
25
+ "node_modules/@levischuck/tiny-cbor": {
26
+ "version": "0.2.11",
27
+ "resolved": "https://registry.npmjs.org/@levischuck/tiny-cbor/-/tiny-cbor-0.2.11.tgz",
28
+ "integrity": "sha512-llBRm4dT4Z89aRsm6u2oEZ8tfwL/2l6BwpZ7JcyieouniDECM5AqNgr/y08zalEIvW3RSK4upYyybDcmjXqAow==",
29
+ "license": "MIT"
30
+ },
31
+ "node_modules/@peculiar/asn1-android": {
32
+ "version": "2.11.0",
33
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-android/-/asn1-android-2.11.0.tgz",
34
+ "integrity": "sha512-llW/qjavL+tOxt5i9whUv4wsbsLpUwI6k/DrvKsdA/H7A/TB/6CosMFgvei28fcJ8ncD0c5lig1oBBlo4KGMCw==",
35
+ "license": "MIT",
36
+ "dependencies": {
37
+ "@peculiar/asn1-schema": "^2.11.0",
38
+ "asn1js": "^3.0.10",
39
+ "tslib": "^2.8.1"
40
+ },
41
+ "engines": {
42
+ "node": ">=14"
43
+ }
44
+ },
45
+ "node_modules/@peculiar/asn1-cms": {
46
+ "version": "2.11.0",
47
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-cms/-/asn1-cms-2.11.0.tgz",
48
+ "integrity": "sha512-SlAiDoT/Cd8qaNmbTt78gqyaEvu2fQd6ML6KWJkdjXGrgDKnHHrusVkfQUelkfinL2p665IIADb0JBixtT8W1g==",
49
+ "license": "MIT",
50
+ "dependencies": {
51
+ "@peculiar/asn1-schema": "^2.11.0",
52
+ "@peculiar/asn1-x509": "^2.11.0",
53
+ "@peculiar/asn1-x509-attr": "^2.11.0",
54
+ "asn1js": "^3.0.10",
55
+ "tslib": "^2.8.1"
56
+ },
57
+ "engines": {
58
+ "node": ">=14"
59
+ }
60
+ },
61
+ "node_modules/@peculiar/asn1-csr": {
62
+ "version": "2.11.0",
63
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-csr/-/asn1-csr-2.11.0.tgz",
64
+ "integrity": "sha512-M/ED0yJ05qMK+UADPKnIa8vhAeewOJALSxTAZB7RQ/batRHhIJZkwznCcWAbFO5saHJ1yEQ+m4lncEcG9RnQSg==",
65
+ "license": "MIT",
66
+ "dependencies": {
67
+ "@peculiar/asn1-schema": "^2.11.0",
68
+ "@peculiar/asn1-x509": "^2.11.0",
69
+ "asn1js": "^3.0.10",
70
+ "tslib": "^2.8.1"
71
+ },
72
+ "engines": {
73
+ "node": ">=14"
74
+ }
75
+ },
76
+ "node_modules/@peculiar/asn1-ecc": {
77
+ "version": "2.11.0",
78
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-ecc/-/asn1-ecc-2.11.0.tgz",
79
+ "integrity": "sha512-jj1alGEKev7/un+cI+exyVK9m31lmP7cCBMCZuCb0wkFQH2zmKmJzNiG4wqXFNzlcP8timHLnzf3lV3OxBpb/Q==",
80
+ "license": "MIT",
81
+ "dependencies": {
82
+ "@peculiar/asn1-schema": "^2.11.0",
83
+ "@peculiar/asn1-x509": "^2.11.0",
84
+ "asn1js": "^3.0.10",
85
+ "tslib": "^2.8.1"
86
+ },
87
+ "engines": {
88
+ "node": ">=14"
89
+ }
90
+ },
91
+ "node_modules/@peculiar/asn1-pfx": {
92
+ "version": "2.11.0",
93
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-pfx/-/asn1-pfx-2.11.0.tgz",
94
+ "integrity": "sha512-ykSAWRu8KkmzU8LRpk9ZQC3zuLmBEtoSMjIv9XHVamD5W7amqreV5wttKqnvtjWOzzSJQxA/HVT8/tHwpEEGSQ==",
95
+ "license": "MIT",
96
+ "dependencies": {
97
+ "@peculiar/asn1-cms": "^2.11.0",
98
+ "@peculiar/asn1-pkcs8": "^2.11.0",
99
+ "@peculiar/asn1-rsa": "^2.11.0",
100
+ "@peculiar/asn1-schema": "^2.11.0",
101
+ "asn1js": "^3.0.10",
102
+ "tslib": "^2.8.1"
103
+ },
104
+ "engines": {
105
+ "node": ">=14"
106
+ }
107
+ },
108
+ "node_modules/@peculiar/asn1-pkcs8": {
109
+ "version": "2.11.0",
110
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs8/-/asn1-pkcs8-2.11.0.tgz",
111
+ "integrity": "sha512-lragjkjQGnQ5luxC+sxoAfAO/jBiQ7hOEGlDKJUk7MC5zY3AzjB2DU0GyPUH1Sswdv10t7DurY0zylOYMLb88w==",
112
+ "license": "MIT",
113
+ "dependencies": {
114
+ "@peculiar/asn1-schema": "^2.11.0",
115
+ "@peculiar/asn1-x509": "^2.11.0",
116
+ "asn1js": "^3.0.10",
117
+ "tslib": "^2.8.1"
118
+ },
119
+ "engines": {
120
+ "node": ">=14"
121
+ }
122
+ },
123
+ "node_modules/@peculiar/asn1-pkcs9": {
124
+ "version": "2.11.0",
125
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-pkcs9/-/asn1-pkcs9-2.11.0.tgz",
126
+ "integrity": "sha512-gDdFjpqV0weJjgNUvueUVf4D8uVbpq+VbG0TsxLAY2QGljAkJyL9qwQ7avol9j0jaYSJ7Ey7v7RZp0M3GTcQSA==",
127
+ "license": "MIT",
128
+ "dependencies": {
129
+ "@peculiar/asn1-cms": "^2.11.0",
130
+ "@peculiar/asn1-pfx": "^2.11.0",
131
+ "@peculiar/asn1-pkcs8": "^2.11.0",
132
+ "@peculiar/asn1-schema": "^2.11.0",
133
+ "@peculiar/asn1-x509": "^2.11.0",
134
+ "@peculiar/asn1-x509-attr": "^2.11.0",
135
+ "asn1js": "^3.0.10",
136
+ "tslib": "^2.8.1"
137
+ },
138
+ "engines": {
139
+ "node": ">=14"
140
+ }
141
+ },
142
+ "node_modules/@peculiar/asn1-rsa": {
143
+ "version": "2.11.0",
144
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-rsa/-/asn1-rsa-2.11.0.tgz",
145
+ "integrity": "sha512-S2sBJmbfI09Kzdt9cEhE6pDNjHpVTkURs+811+PxS8AvsTLxC4woMNRhxHYaIbClkkNfAVt0tZxJdINVfUmzuA==",
146
+ "license": "MIT",
147
+ "dependencies": {
148
+ "@peculiar/asn1-schema": "^2.11.0",
149
+ "@peculiar/asn1-x509": "^2.11.0",
150
+ "asn1js": "^3.0.10",
151
+ "tslib": "^2.8.1"
152
+ },
153
+ "engines": {
154
+ "node": ">=14"
155
+ }
156
+ },
157
+ "node_modules/@peculiar/asn1-schema": {
158
+ "version": "2.11.0",
159
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-schema/-/asn1-schema-2.11.0.tgz",
160
+ "integrity": "sha512-8xh4avo53/vXO6UEv9yaoJ83hY581geaLTygf61NPIXP5AeIZCPjJhpTaYU23IZkG+NpLN/C9FYzWp7hphIT9A==",
161
+ "license": "MIT",
162
+ "dependencies": {
163
+ "@peculiar/utils": "^2.0.2",
164
+ "asn1js": "^3.0.10",
165
+ "tslib": "^2.8.1"
166
+ },
167
+ "engines": {
168
+ "node": ">=14"
169
+ }
170
+ },
171
+ "node_modules/@peculiar/asn1-x509": {
172
+ "version": "2.11.0",
173
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509/-/asn1-x509-2.11.0.tgz",
174
+ "integrity": "sha512-J1sHAwGNlk+8J+FeR1eLVc6Gq0T9f9ITc3HWyPYgJraoW6U8AJuQiWVJ3SCEpltfTdpOY7fHdHT5oKAsbK/jww==",
175
+ "license": "MIT",
176
+ "dependencies": {
177
+ "@peculiar/asn1-schema": "^2.11.0",
178
+ "@peculiar/utils": "^2.0.2",
179
+ "asn1js": "^3.0.10",
180
+ "tslib": "^2.8.1"
181
+ },
182
+ "engines": {
183
+ "node": ">=14"
184
+ }
185
+ },
186
+ "node_modules/@peculiar/asn1-x509-attr": {
187
+ "version": "2.11.0",
188
+ "resolved": "https://registry.npmjs.org/@peculiar/asn1-x509-attr/-/asn1-x509-attr-2.11.0.tgz",
189
+ "integrity": "sha512-Fgvnd9REmLxEj/4cbDP54dNUNUXkzUksXLqEHqs1mHBuSRjSTCUSPM/WQIZYSvrdG7ND9CX1AQtPoIBekhgQSA==",
190
+ "license": "MIT",
191
+ "dependencies": {
192
+ "@peculiar/asn1-schema": "^2.11.0",
193
+ "@peculiar/asn1-x509": "^2.11.0",
194
+ "asn1js": "^3.0.10",
195
+ "tslib": "^2.8.1"
196
+ },
197
+ "engines": {
198
+ "node": ">=14"
199
+ }
200
+ },
201
+ "node_modules/@peculiar/utils": {
202
+ "version": "2.0.3",
203
+ "resolved": "https://registry.npmjs.org/@peculiar/utils/-/utils-2.0.3.tgz",
204
+ "integrity": "sha512-+oL3HPFRIZ1St2K50lWCXiioIgSoxzz7R1J3uF6neO2yl1sgmpgY6XXJH4BdpoDkMWznQTeYF6oWNDZLCdQ4eQ==",
205
+ "license": "MIT",
206
+ "dependencies": {
207
+ "tslib": "^2.8.1"
208
+ }
209
+ },
210
+ "node_modules/@peculiar/x509": {
211
+ "version": "1.14.3",
212
+ "resolved": "https://registry.npmjs.org/@peculiar/x509/-/x509-1.14.3.tgz",
213
+ "integrity": "sha512-C2Xj8FZ0uHWeCXXqX5B4/gVFQmtSkiuOolzAgutjTfseNOHT3pUjljDZsTSxXFGgio54bCzVFqmEOUrIVk8RDA==",
214
+ "license": "MIT",
215
+ "dependencies": {
216
+ "@peculiar/asn1-cms": "^2.6.0",
217
+ "@peculiar/asn1-csr": "^2.6.0",
218
+ "@peculiar/asn1-ecc": "^2.6.0",
219
+ "@peculiar/asn1-pkcs9": "^2.6.0",
220
+ "@peculiar/asn1-rsa": "^2.6.0",
221
+ "@peculiar/asn1-schema": "^2.6.0",
222
+ "@peculiar/asn1-x509": "^2.6.0",
223
+ "pvtsutils": "^1.3.6",
224
+ "reflect-metadata": "^0.2.2",
225
+ "tslib": "^2.8.1",
226
+ "tsyringe": "^4.10.0"
227
+ },
228
+ "engines": {
229
+ "node": ">=20.0.0"
14
230
  }
15
231
  },
16
232
  "node_modules/@pinojs/redact": {
@@ -19,6 +235,31 @@
19
235
  "integrity": "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==",
20
236
  "license": "MIT"
21
237
  },
238
+ "node_modules/@simplewebauthn/browser": {
239
+ "version": "13.3.0",
240
+ "resolved": "https://registry.npmjs.org/@simplewebauthn/browser/-/browser-13.3.0.tgz",
241
+ "integrity": "sha512-BE/UWv6FOToAdVk0EokzkqQQDOWtNydYlY6+OrmiZ5SCNmb41VehttboTetUM3T/fr6EAFYVXjz4My2wg230rQ==",
242
+ "license": "MIT"
243
+ },
244
+ "node_modules/@simplewebauthn/server": {
245
+ "version": "13.3.3",
246
+ "resolved": "https://registry.npmjs.org/@simplewebauthn/server/-/server-13.3.3.tgz",
247
+ "integrity": "sha512-LelX/lcy5cjc15A86i/aNxHhB5eU7dd20QsbP0VLAf9e38+SLlsnqCCyecx3xqfGofhmX05h1J9fKRYWxw+luA==",
248
+ "license": "MIT",
249
+ "dependencies": {
250
+ "@hexagon/base64": "^1.1.27",
251
+ "@levischuck/tiny-cbor": "^0.2.2",
252
+ "@peculiar/asn1-android": "^2.6.0",
253
+ "@peculiar/asn1-ecc": "^2.6.1",
254
+ "@peculiar/asn1-rsa": "^2.6.1",
255
+ "@peculiar/asn1-schema": "^2.6.0",
256
+ "@peculiar/asn1-x509": "^2.6.1",
257
+ "@peculiar/x509": "^1.14.3"
258
+ },
259
+ "engines": {
260
+ "node": ">=20.0.0"
261
+ }
262
+ },
22
263
  "node_modules/accepts": {
23
264
  "version": "1.3.8",
24
265
  "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
@@ -38,6 +279,20 @@
38
279
  "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
39
280
  "license": "MIT"
40
281
  },
282
+ "node_modules/asn1js": {
283
+ "version": "3.0.10",
284
+ "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.10.tgz",
285
+ "integrity": "sha512-S2s3aOytiKdFRdulw2qPE51MzjzVOisppcVv7jVFR+Kw0kxwvFrDcYA0h7Ndqbmj0HkMIXYWaoj7fli8kgx1eg==",
286
+ "license": "BSD-3-Clause",
287
+ "dependencies": {
288
+ "pvtsutils": "^1.3.6",
289
+ "pvutils": "^1.1.5",
290
+ "tslib": "^2.8.1"
291
+ },
292
+ "engines": {
293
+ "node": ">=12.0.0"
294
+ }
295
+ },
41
296
  "node_modules/atomic-sleep": {
42
297
  "version": "1.0.0",
43
298
  "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
@@ -804,6 +1059,24 @@
804
1059
  "url": "https://opencollective.com/express"
805
1060
  }
806
1061
  },
1062
+ "node_modules/pvtsutils": {
1063
+ "version": "1.3.6",
1064
+ "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz",
1065
+ "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==",
1066
+ "license": "MIT",
1067
+ "dependencies": {
1068
+ "tslib": "^2.8.1"
1069
+ }
1070
+ },
1071
+ "node_modules/pvutils": {
1072
+ "version": "1.2.0",
1073
+ "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.2.0.tgz",
1074
+ "integrity": "sha512-BbubeCEyTuQjVMakvJQ/Sxbc93F2pwmbsxONT/ZRrwU7Ua38d8unYTwXpTVLAKJ4BDuH9IGztCjQcd/N/39Dvg==",
1075
+ "license": "MIT",
1076
+ "engines": {
1077
+ "node": ">=16.0.0"
1078
+ }
1079
+ },
807
1080
  "node_modules/qs": {
808
1081
  "version": "6.15.2",
809
1082
  "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
@@ -858,6 +1131,12 @@
858
1131
  "node": ">= 12.13.0"
859
1132
  }
860
1133
  },
1134
+ "node_modules/reflect-metadata": {
1135
+ "version": "0.2.2",
1136
+ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.2.tgz",
1137
+ "integrity": "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==",
1138
+ "license": "Apache-2.0"
1139
+ },
861
1140
  "node_modules/safe-buffer": {
862
1141
  "version": "5.2.1",
863
1142
  "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
@@ -1061,6 +1340,30 @@
1061
1340
  "node": ">=0.6"
1062
1341
  }
1063
1342
  },
1343
+ "node_modules/tslib": {
1344
+ "version": "2.8.1",
1345
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
1346
+ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
1347
+ "license": "0BSD"
1348
+ },
1349
+ "node_modules/tsyringe": {
1350
+ "version": "4.10.0",
1351
+ "resolved": "https://registry.npmjs.org/tsyringe/-/tsyringe-4.10.0.tgz",
1352
+ "integrity": "sha512-axr3IdNuVIxnaK5XGEUFTu3YmAQ6lllgrvqfEoR16g/HGnYY/6We4oWENtAnzK6/LpJ2ur9PAb80RBt7/U4ugw==",
1353
+ "license": "MIT",
1354
+ "dependencies": {
1355
+ "tslib": "^1.9.3"
1356
+ },
1357
+ "engines": {
1358
+ "node": ">= 6.0.0"
1359
+ }
1360
+ },
1361
+ "node_modules/tsyringe/node_modules/tslib": {
1362
+ "version": "1.14.1",
1363
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
1364
+ "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==",
1365
+ "license": "0BSD"
1366
+ },
1064
1367
  "node_modules/type-is": {
1065
1368
  "version": "1.6.18",
1066
1369
  "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.25.12",
3
+ "version": "1.25.14",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -25,7 +25,9 @@
25
25
  "dependencies": {
26
26
  "express": "^4.21.2",
27
27
  "pg": "^8.20.0",
28
- "pino": "^9.14.0"
28
+ "pino": "^9.14.0",
29
+ "@simplewebauthn/browser": "^13.3.0",
30
+ "@simplewebauthn/server": "^13.3.3"
29
31
  },
30
32
  "overrides": {
31
33
  "undici": "^6.29.1"
@@ -11782,5 +11782,29 @@
11782
11782
  "id": "1005288",
11783
11783
  "text": "Decided how every project gets a sandbox: a free copy of the app that always shows the newest finished work, while the real site only changes when a person presses promote. Fake data and test keys by default. Costs the owner n"
11784
11784
  }
11785
+ ],
11786
+ "1.25.13": [
11787
+ {
11788
+ "id": "1005273",
11789
+ "text": "The project guide now ends with a written plan (with recommended features drawn only from what Bongos really offers), saves the chat so visitors can come back to it, moves it onto their account when they sign up, and deletes i"
11790
+ }
11791
+ ],
11792
+ "1.25.14": [
11793
+ {
11794
+ "id": "1004753",
11795
+ "text": "Designed how a project owner can give a teammate access to help run their hosted project, without letting anyone who merely signs in act on it."
11796
+ },
11797
+ {
11798
+ "id": "1005109",
11799
+ "text": "Founders setting up a new project can now copy each setup task's prompt straight from the Genesis page, without opening the task."
11800
+ },
11801
+ {
11802
+ "id": "1005269",
11803
+ "text": "Adding a security card works again on sites that install Bongos as a package: the card libraries are now included in the released core."
11804
+ },
11805
+ {
11806
+ "id": "1005279",
11807
+ "text": "The project guide now asks whether you are starting fresh or already have something, and for an existing project plans from your own description, without ever reading your files or code."
11808
+ }
11785
11809
  ]
11786
11810
  }
@@ -288,7 +288,9 @@ function isNpmStripped(pathRel) {
288
288
  // published core without it crashes MODULE_NOT_FOUND at startup (task 1003160).
289
289
  // discord.js (+ its undici requirement) is an OPTIONAL MODULE dependency, not
290
290
  // core; a consumer that enables the discord module installs it itself.
291
- const CORE_DEP_NAMES = ['express', 'pg', 'pino'];
291
+ // The security-card libraries joined in task 1005269: routes/my-passkeys.js serves the browser bundle
292
+ // and requires the server lib, and a package without them answers bundle_missing on every instance.
293
+ const CORE_DEP_NAMES = ['express', 'pg', 'pino', '@simplewebauthn/browser', '@simplewebauthn/server'];
292
294
 
293
295
  // Pure — takes the source package.json's `dependencies`/`overrides` as plain
294
296
  // objects so this is unit-testable with no disk I/O. Throws if a required core
@@ -928,7 +930,7 @@ function main() {
928
930
  const sourcePkgLock = JSON.parse(pkgLockRaw.toString('utf8'));
929
931
  const corePkgJson = buildPackageJson({ version, sourceDeps: sourcePkgJson.dependencies, sourceOverrides: sourcePkgJson.overrides });
930
932
  const corePkgLock = prunePackageLock(sourcePkgLock, {
931
- name: corePkgJson.name, version, rootRanges: { express: corePkgJson.dependencies.express, pg: corePkgJson.dependencies.pg },
933
+ name: corePkgJson.name, version, rootRanges: { ...corePkgJson.dependencies },
932
934
  });
933
935
  console.error(`[package-core] synthesized package.json (${Object.keys(corePkgJson.dependencies).join(', ')}) + pruned package-lock.json (${Object.keys(corePkgLock.packages).length - 1} of ${Object.keys(sourcePkgLock.packages).length - 1} locked packages kept).`);
934
936
 
@@ -100,6 +100,10 @@ const INTEGRATION = new Set([
100
100
  // task 1004941: a rules proposal round-trips to a new version the weekly run's loader
101
101
  // reads, on real SQL (the one-active index, the CHECKs). DB-free sibling: market_watch_rules.
102
102
  'market_watch_rules_db',
103
+ // tasks 1005272/1005273: the start-a-project guide's SQL on a real engine: the migrations,
104
+ // the one-account attach rule, and the retention sweep keeping spend on the books.
105
+ // DB-free siblings: front_door_guide, front_door_guide_plan.
106
+ 'front_door_guide_db',
103
107
  // task 1004940: the weekly ask's SQL store — once per week by constraint, one pooled
104
108
  // proposal per similar answer, the project guard on an answer. DB-free sibling:
105
109
  // market_watch_ask.
@@ -190,6 +190,8 @@ const MODULE_GLOBS = {
190
190
  // signed-out visitor. Its test sits at the repo root, listed by exact path.
191
191
  'front-door-guide': [
192
192
  'modules/front-door-guide/', 'tests/front_door_guide.mjs',
193
+ 'tests/front_door_guide_plan.mjs', 'tests/front_door_guide_db.mjs',
194
+ 'tests/front_door_guide_existing.mjs',
193
195
  ],
194
196
  // The /raise investor page (task 1004847, ADR 0384): hub-only.
195
197
  raise: [
package/src/module-api.js CHANGED
@@ -81,7 +81,7 @@ const { sleep } = require('./sleep');
81
81
  // MAJOR (see allowBoxScope below): passes the request through untouched.
82
82
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
83
83
 
84
- const CORE_VERSION = '1.25.12'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
84
+ const CORE_VERSION = '1.25.14'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
85
85
 
86
86
  // A namespaced logger so a module's log lines are attributable + consistent.
87
87
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -183,7 +183,7 @@ t('planCodemod rewrites host files, skips core files, reports unmapped', () => {
183
183
 
184
184
  t('every CORE_INTERNAL_MAP target is exported by the core package (a rewrite never outruns an export)', () => {
185
185
  const { buildPackageJson } = require('../scripts/bongos/package-core.js');
186
- const pkg = buildPackageJson({ version: '0.0.0-test', sourceDeps: { express: '^4.0.0', pg: '^8.0.0', pino: '^9.0.0' } });
186
+ const pkg = buildPackageJson({ version: '0.0.0-test', sourceDeps: { express: '^4.0.0', pg: '^8.0.0', pino: '^9.0.0', '@simplewebauthn/browser': '^13.0.0', '@simplewebauthn/server': '^13.0.0' } });
187
187
  for (const mapped of Object.values(CORE_INTERNAL_MAP)) {
188
188
  assert.ok(pkg.exports[`./${mapped}`], `@bongos/core must export ./${mapped} (targeted by the codemod)`);
189
189
  }
@@ -0,0 +1,115 @@
1
+ // tests/front_door_guide_db.mjs — the start-a-project guide's SQL against a REAL Postgres
2
+ // (tasks 1005272, 1005273).
3
+ //
4
+ // What only a real engine can say: both migrations apply, and apply again as no-ops; a
5
+ // turn and a plan land in one statement each; only replies count as a visitor's messages;
6
+ // a chat attaches to one account and is never moved to another; and the retention sweep
7
+ // deletes an abandoned chat after the set number of days while its spend stays in the
8
+ // daily and monthly sums.
9
+ //
10
+ // The module is default:false, so CI's migrate.sh does not apply its migrations; this
11
+ // file applies them itself. Rows use a visitor hash and builder ids no real instance has,
12
+ // and are deleted before and after. Self-skips without a reachable Postgres; in the
13
+ // INTEGRATION set (scripts/bongos/run-unit-tests.js) so the DB-free lane never runs it.
14
+ //
15
+ // Run: DATABASE_URL=... node tests/front_door_guide_db.mjs
16
+
17
+ import { createRequire } from 'node:module';
18
+ import { readFileSync } from 'node:fs';
19
+ import { strict as assert } from 'node:assert';
20
+ import { insertTestBuilders } from './helpers.mjs';
21
+
22
+ const require = createRequire(import.meta.url);
23
+ const { Pool } = require('pg');
24
+ const db = require('../modules/front-door-guide/db.js');
25
+ const sql = (n) => readFileSync(new URL(`../modules/front-door-guide/migrations/${n}`, import.meta.url), 'utf8');
26
+ const M1 = sql('front_door_guide_001_conversations.sql');
27
+ const M2 = sql('front_door_guide_002_plan_and_account.sql');
28
+ const M3 = sql('front_door_guide_003_starting_point.sql');
29
+
30
+ const pool = new Pool({ connectionString: process.env.DATABASE_URL || undefined });
31
+ try {
32
+ await pool.query('SELECT 1');
33
+ } catch (e) {
34
+ console.log(`front_door_guide_db.mjs SKIPPED — no reachable Postgres (${e.code || e.message}).`);
35
+ await pool.end().catch(() => {});
36
+ process.exit(0);
37
+ }
38
+
39
+ const x = (text, params) => pool.query(text, params);
40
+ const V = 't1005273-visitor';
41
+ const ALICE = 91005273, BOB = 91005274;
42
+
43
+ async function cleanup() {
44
+ await x(`DELETE FROM front_door_guide_calls WHERE visitor_hash LIKE $1`, [`${V}%`]).catch(() => {});
45
+ await x(`DELETE FROM front_door_guide_conversations WHERE visitor_hash LIKE $1`, [`${V}%`]).catch(() => {});
46
+ await x('DELETE FROM builders WHERE id = ANY($1)', [[ALICE, BOB]]).catch(() => {});
47
+ }
48
+
49
+ const call = (over = {}) => ({ visitorHash: V, model: 'claude-opus-5-5', inputTokens: 800, outputTokens: 200, cacheReadTokens: 0, cacheWriteTokens: 0, costMicro: 9000, stopReason: 'end_turn', ...over });
50
+
51
+ try {
52
+ for (const m of [M1, M2, M3, M1, M2, M3]) await x(m); // applies, then re-applies as a no-op
53
+ await cleanup();
54
+ await insertTestBuilders(pool, [{ id: ALICE, login: 't1005273-alice' }, { id: BOB, login: 't1005273-bob' }]);
55
+
56
+ const dayBefore = await db.siteSpendMicro('day', x);
57
+
58
+ // A turn and a plan.
59
+ const conv = await db.createConversation('hash-a-1005273', V, x);
60
+ const turned = await db.recordTurn(conv.id, { messages: [{ role: 'user', content: 'hi' }, { role: 'assistant', content: 'hello' }], status: 'open', endReason: null }, call(), x);
61
+ assert.equal(turned.visitor_messages, 1);
62
+ assert.equal(Number(turned.spend_micro), 9000);
63
+ const planned = await db.savePlan(conv.id, { summary: 'A plan' }, call({ costMicro: 20000 }), x);
64
+ assert.equal(planned.plan.summary, 'A plan');
65
+ assert.equal(planned.status, 'ended');
66
+ assert.equal(planned.end_reason, 'planned');
67
+ const again = await db.savePlan(conv.id, { summary: 'Overwrite?' }, call({ costMicro: 1 }), x);
68
+ assert.equal(again.plan.summary, 'A plan', 'a stored plan is never overwritten');
69
+ await db.recordPlanSpend(conv.id, call({ costMicro: 5 }), x);
70
+
71
+ const usage = await db.visitorUsage(V, x);
72
+ assert.equal(usage.messages, 1, 'only replies are messages');
73
+ assert.equal(usage.spendMicro, 9000 + 20000 + 1 + 5);
74
+
75
+ // Attach: the token holder's account, once; never moved to another.
76
+ assert.equal(await db.attachToBuilder(conv.id, 'wrong-hash', ALICE, x), null);
77
+ const mine = await db.attachToBuilder(conv.id, 'hash-a-1005273', ALICE, x);
78
+ assert.equal(Number(mine.builder_id), ALICE);
79
+ assert.ok(mine.attached_at);
80
+ assert.equal(await db.attachToBuilder(conv.id, 'hash-a-1005273', BOB, x), null);
81
+ assert.equal((await db.latestForBuilder(ALICE, x)).plan.summary, 'A plan');
82
+ assert.equal(await db.latestForBuilder(BOB, x), null);
83
+
84
+ // The sweep: an abandoned chat older than the setting goes; a recent one and an
85
+ // attached one stay; the abandoned chat's spend stays on the books.
86
+ const abandoned = await db.createConversation('hash-b-1005273', V, x);
87
+ await db.recordTurn(abandoned.id, { messages: [], status: 'open', endReason: null }, call({ costMicro: 7000 }), x);
88
+ const recent = await db.createConversation('hash-c-1005273', V, x);
89
+ await x(`UPDATE front_door_guide_conversations SET updated_at = now() - interval '15 days' WHERE id = ANY($1)`, [[abandoned.id, conv.id]]);
90
+ await x(`UPDATE front_door_guide_conversations SET updated_at = now() - interval '13 days' WHERE id = $1`, [recent.id]);
91
+ const before = await db.siteSpendMicro('day', x);
92
+
93
+ const deleted = await db.deleteAbandoned(14, x);
94
+ assert.ok(deleted >= 1);
95
+ const left = (await x(`SELECT id FROM front_door_guide_conversations WHERE visitor_hash = $1 ORDER BY id`, [V])).rows.map((r) => String(r.id));
96
+ assert.deepEqual(left, [String(conv.id), String(recent.id)], 'the abandoned chat is gone; the attached and the recent stay');
97
+ const orphan = await x(`SELECT conversation_id, cost_micro FROM front_door_guide_calls WHERE visitor_hash = $1 AND cost_micro = 7000`, [V]);
98
+ assert.equal(orphan.rows.length, 1);
99
+ assert.equal(orphan.rows[0].conversation_id, null);
100
+ assert.equal(await db.siteSpendMicro('day', x), before, 'the budgets still count the deleted chat\'s money');
101
+ assert.ok(before >= dayBefore + 9000 + 20000 + 1 + 5 + 7000);
102
+
103
+ // The starting point (task 1005279): set, read back, and nothing else accepted.
104
+ assert.equal((await db.setStartingPoint(conv.id, 'existing', x)).starting_point, 'existing');
105
+ await assert.rejects(x(`UPDATE front_door_guide_conversations SET starting_point = 'repo' WHERE id = $1`, [conv.id]));
106
+
107
+ // Refusals the schema owns.
108
+ await assert.rejects(x(`INSERT INTO front_door_guide_calls (visitor_hash, model, cost_micro, kind) VALUES ($1, 'm', 1, 'other')`, [V]));
109
+ await assert.rejects(x(`INSERT INTO front_door_guide_calls (visitor_hash, model, cost_micro) VALUES ($1, 'm', -1)`, [V]));
110
+
111
+ console.log('front_door_guide_db.mjs: all checks passed');
112
+ } finally {
113
+ await cleanup();
114
+ await pool.end();
115
+ }