Repository navigation
Commit d70e94a
fix(cloud-connection): an install-local install connects and records the package's declared datasources (#28132)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} -->
_Requested by **Elon** · [project
thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9DNZYoA6dDo1ZK7uh4DbA5hi)_
Fixes #28039
Clause-②: yes (widening)
Metadata-protocol: none
Skills-docs: `content/docs/data-modeling/external-datasources.mdx` gains
one callout under "When auto-connect fails" (an installed package's
datasources are registered as code and connected at install and every
restart; a failed one is installed with its failed `status`; the install
answer's `datasources`; `409` on a held name). `skills/**`: none — `git
grep -n -i "datasource"
skills/objectstack-platform/references/operations.md` has no line on
install-local and datasources; the install-local rows there (`:107`,
`:344`) describe the CLI and the credential facts, which this change
does not touch.
## 维护者速读
- **改了什么**:通过 marketplace 本地安装(`os package
install`)装进运行中环境的包,现在会像启动其产物时一样,把它声明的数据源注册为代码数据源、记入代码数据源名单并自动连接;卸载时一并撤回。启动路径与安装路径共用一个
runtime 助手 `connectPackageDatasources`。
- **为什么改**:此前安装只注册对象、不管数据源,绑定到包自带数据源的对象读写一律 404
`OBJECT_NOT_FOUND`,后台也不把它当代码数据源。
- **风险与回滚**:启动路径行为不变(既有 53 个数据源启动测试 + runtime 全套 7883
通过);新增两处对外行为:安装答复多一个 `datasources`
字段,包声明的数据源名若已被占用(`default`、后台建的、别的包的)则安装 409 拒绝。回滚即还原本 PR。
- **先看**:`packages/runtime/src/declared-datasources.ts`(助手本体,重点看
`installed` 分支吞掉 fail-fast
改为回报状态)、`packages/cloud-connection/src/marketplace-install-local-plugin.ts`(安装
4b′、重新加载、2a 冲突拒绝)、`packages/runtime/src/app-plugin.ts`(启动路径改为调用助手)。
- **两分钟验证**:`pnpm --filter @objectstack/dogfood exec vitest run
test/install-local-declared-datasources.dogfood.test.ts`,预期 8
个用例全绿:安装后绑定对象可写可读,凭据无法解析的数据源读到 503 `ERR_DATASOURCE_UNAVAILABLE`,卸载后全部撤回。
- **需要你做的**:无,席位落地。凭据从哪来仍由 #27687 裁决,本 PR 不涉及。
## What changes
- **One path.** `AppPlugin.start`'s three datasource steps — the
in-memory metadata registration as `origin: 'code'` stamped with the
declaring package, the `connectDeclared` call through the
`datasource-connection` service, and its fail-fast verdict — move into
`connectPackageDatasources`
(`packages/runtime/src/declared-datasources.ts`, exported from
`@objectstack/runtime`). The boot calls it with the same lists by
reference (#23029's identity pins hold), the same log lines and the same
throw; its names still join the code-datasource set in `init()`.
- **install-local calls it** on install (step 4b′, after the schema
sync, only when the package hot-loaded) and on every `kernel:ready`
rehydrate, with `installed: true`, which differs from the boot in three
ways: the names are contributed to the code-datasource set now; a
fail-fast verdict is logged and reported instead of thrown (the
datasource keeps its retained verdict and the engine's unavailable mark,
so a bound read answers `503 ERR_DATASOURCE_UNAVAILABLE` naming it); and
a reinstall first withdraws what the previous version registered.
- **Uninstall.** The helper registers, once per kernel, the
`runtime.package-datasources` uninstall cleanup on the protocol's
registry (the shape `runtime.package-jobs` uses), so install-local's
`DELETE` and the protocol's `deletePackage` both close the pools, remove
the metadata registrations still stamped with the package and take the
names out of the set. It acts only on what an installed package's call
recorded; a boot artifact records nothing.
- **The install answer** carries `datasources: [{ name, status }]` — the
connection service's own `ConnectStatus` names, nothing new — omitted
for a package that declares none.
- **Step 2a refusal.** A package declaring a datasource name another
holder owns (the host's `default`, a datasource in the metadata service
not stamped with this package) is refused `409 RESOURCE_CONFLICT` with
`details.datasource`, before any write: the connect is idempotent on the
name, so it would have served the package's objects from the holder's
pool, and recording the name as code would have made the holder's own
datasource read-only.
- `CodeDatasourceNames` gains `delete`, and `code-datasource-names.ts` a
`withdrawCodeDatasourceNames` (module-internal, not exported from the
package); the module header now names the post-boot producer.
## Tests
-
`packages/qa/dogfood/test/install-local-declared-datasources.dogfood.test.ts`
(new, real showcase composition, real sqlite driver): install answers
both verdicts; registrations are `origin: 'code'` with
`_packageId`/`_packageVersion`; the code-datasource set holds both
names; the admin list serves `qads_store` `ok` and `qads_vault` `error`
with a `statusReason` naming the credential; write `201` + read `200` of
the bound object; the vault-bound read `503 ERR_DATASOURCE_UNAVAILABLE`;
uninstall `cleanups` carries `runtime.package-datasources` `{ success:
true, removed: 2 }` and leaves no verdict, registration or name
(control: `showcase_external` stays); `showcase_external` and `default`
collisions `409`; a restart's rehydrate reconnects and the object reads.
- `packages/runtime/src/declared-datasources.test.ts` (new): the
installed/boot split — names recorded or not, fail-fast reported or
thrown, reinstall withdrawal, cleanup scoped to its package and to
registrations still stamped with it, no connection service.
## Acceptance notes
- **Measured on `main` `549203d0` first** (same dogfood fixture, source
reverted): install `200` with `hotLoaded: true`, then `POST`/`GET
/data/qads_note` and `GET /data/qads_secret_row` all `404
OBJECT_NOT_FOUND` ("Object 'qads_note' is not registered"); no
connection verdict for either datasource; the code-datasource set held
only `default` and `showcase_external`.
- **The unresolved-credential status.** With an object bound explicitly
the connection service's fail-fast path throws, and `connect()` retains
that verdict as `failed-degraded` (reason naming the credential);
without a bound object it is `failed-credentials`. Both are the
service's existing names, and the admin list maps both to `error`.
Recording `failed-credentials` on the fail-fast path too would be a
change to `service-datasource`'s retained verdict on a refused boot; not
made here.
- **#27687 is not ruled.** The credential resolves the one way the
connection service resolves every `credentialsRef`. The installed
datasources now pass the round-3 gate #27687 measured (`trigger:
'declared-auto'` and `CODE_DATASOURCE_NAMES_SERVICE.has(name)`), so
whatever it rules for code datasources reaches them.
- **`datasourceMapping`** rules in an installed package are not
installed by this door (before or after); the helper is called with no
mapped objects, so D2 (d) never fires for an installed package.
- **objectos `artifact-kernel-factory`** (outside this repo) composes
its own kernels; whether it connects package datasources itself is not
measured here.
- **Out of scope, reported to the seat:** the `503` text for a `failed`
datasource (`DatasourceUnavailableError`,
`packages/objectql/src/driver-connect-errors.ts`) says it "failed to
connect at startup and the server was started with
OS_ALLOW_DRIVER_CONNECT_FAILURE", which is false for an install-time
failure (measured on this PR's dogfood read of `qads_secret_row`) and,
by the same branch, for a Setup-created datasource that failed.
## Verification
<details><summary>Ablations — each leg red, then restored (<code>git
diff HEAD</code> empty)</summary>
All through `scripts/ablation-replace.mjs` (anchor 1 → 0, blob moved)
under the verify lock. The dogfood file resolves
`@objectstack/cloud-connection` and `@objectstack/runtime` to source
(the main-side measurement above ran on reverted source with no
rebuild), so no dist preflight applies.
| Leg | Mutation | Result |
|---|---|---|
| A1 | install step 4b′ connect → `undefined` | dogfood 6 failed / 2
passed |
| A2 | rehydrate connect removed | dogfood 1 failed (rehydrate) |
| A3 | 2a refusal disabled | dogfood 1 failed (409 collisions) |
| A4 | uninstall cleanup registration removed | dogfood 1 failed
(uninstall withdrawal) |
| A5 | `if (!installed) throw err` → `throw err` | unit 1 failed
(fail-fast reported) |
</details>
<details><summary>Local runs at head <code>475a5292</code></summary>
- Measurement on `main` `549203d0` (dogfood fixture, source reverted,
then restored): `Tests 1 passed`, readings in Acceptance notes.
- `pnpm --filter @objectstack/dogfood exec vitest run
test/install-local-declared-datasources.dogfood.test.ts` — `Tests 8
passed (8)`.
- `pnpm --filter @objectstack/runtime test` — `Test Files 484 passed
(484)`, `Tests 7883 passed | 19 skipped (7902)`.
- `pnpm --filter @objectstack/cloud-connection test` — `Test Files 61
passed (61)`, `Tests 758 passed (758)`.
- `pnpm --filter @objectstack/runtime typecheck`, `pnpm --filter
@objectstack/cloud-connection typecheck` — exit 0 (after `pnpm --filter
@objectstack/runtime build`).
- `node scripts/pm/dispatch-gates.mjs --commands`: 92 families, each run
with its exit captured before any pipe; three exited 3 (prerequisite) on
the first pass — `check-plugin-teardown-shape --self-test` (cleared by
fetching the pinned commit), `spec check:skill-examples` and
`check:dual-build-cjs-loads` (cleared by building `client-react`,
`studio` and five plugin/service packages) — and exited 0 on re-run.
`--ran`: `92 derived famil(ies) accounted for — 92 run, 0 NOT-MEASURED`.
- `pnpm lint` — exit 0.
- Dogfood battery: n/a (no `!` in the title, no `(narrowing)` arm).
`test:repo` is CI's.
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_016WV4cx4xgJksGo7iVA8c9A)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 6ab6b72 commit d70e94a
9 files changed
Lines changed: 1094 additions & 100 deletions
File tree
- .changeset
- content/docs/data-modeling
- packages
- cloud-connection/src
- qa/dogfood/test
- runtime/src
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
186 | 186 | | |
187 | 187 | | |
188 | 188 | | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
189 | 200 | | |
190 | 201 | | |
191 | 202 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
632 | 632 | | |
633 | 633 | | |
634 | 634 | | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
635 | 648 | | |
636 | 649 | | |
637 | 650 | | |
| |||
1009 | 1022 | | |
1010 | 1023 | | |
1011 | 1024 | | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
1012 | 1029 | | |
1013 | 1030 | | |
1014 | 1031 | | |
| |||
1788 | 1805 | | |
1789 | 1806 | | |
1790 | 1807 | | |
| 1808 | + | |
| 1809 | + | |
| 1810 | + | |
| 1811 | + | |
| 1812 | + | |
| 1813 | + | |
| 1814 | + | |
| 1815 | + | |
| 1816 | + | |
| 1817 | + | |
| 1818 | + | |
| 1819 | + | |
| 1820 | + | |
| 1821 | + | |
| 1822 | + | |
| 1823 | + | |
| 1824 | + | |
| 1825 | + | |
| 1826 | + | |
| 1827 | + | |
| 1828 | + | |
1791 | 1829 | | |
1792 | 1830 | | |
1793 | 1831 | | |
| |||
1967 | 2005 | | |
1968 | 2006 | | |
1969 | 2007 | | |
| 2008 | + | |
| 2009 | + | |
| 2010 | + | |
| 2011 | + | |
| 2012 | + | |
| 2013 | + | |
| 2014 | + | |
| 2015 | + | |
| 2016 | + | |
| 2017 | + | |
1970 | 2018 | | |
1971 | 2019 | | |
1972 | 2020 | | |
| |||
2026 | 2074 | | |
2027 | 2075 | | |
2028 | 2076 | | |
| 2077 | + | |
| 2078 | + | |
| 2079 | + | |
| 2080 | + | |
| 2081 | + | |
2029 | 2082 | | |
2030 | 2083 | | |
2031 | 2084 | | |
| |||
3477 | 3530 | | |
3478 | 3531 | | |
3479 | 3532 | | |
| 3533 | + | |
| 3534 | + | |
| 3535 | + | |
| 3536 | + | |
| 3537 | + | |
| 3538 | + | |
| 3539 | + | |
| 3540 | + | |
| 3541 | + | |
| 3542 | + | |
| 3543 | + | |
| 3544 | + | |
| 3545 | + | |
| 3546 | + | |
| 3547 | + | |
| 3548 | + | |
| 3549 | + | |
| 3550 | + | |
| 3551 | + | |
| 3552 | + | |
| 3553 | + | |
| 3554 | + | |
| 3555 | + | |
| 3556 | + | |
| 3557 | + | |
| 3558 | + | |
| 3559 | + | |
| 3560 | + | |
| 3561 | + | |
| 3562 | + | |
| 3563 | + | |
| 3564 | + | |
| 3565 | + | |
| 3566 | + | |
| 3567 | + | |
| 3568 | + | |
| 3569 | + | |
| 3570 | + | |
| 3571 | + | |
| 3572 | + | |
| 3573 | + | |
| 3574 | + | |
| 3575 | + | |
| 3576 | + | |
| 3577 | + | |
| 3578 | + | |
| 3579 | + | |
| 3580 | + | |
| 3581 | + | |
| 3582 | + | |
| 3583 | + | |
| 3584 | + | |
| 3585 | + | |
| 3586 | + | |
| 3587 | + | |
| 3588 | + | |
| 3589 | + | |
| 3590 | + | |
| 3591 | + | |
| 3592 | + | |
| 3593 | + | |
| 3594 | + | |
| 3595 | + | |
| 3596 | + | |
| 3597 | + | |
| 3598 | + | |
| 3599 | + | |
| 3600 | + | |
| 3601 | + | |
| 3602 | + | |
| 3603 | + | |
| 3604 | + | |
| 3605 | + | |
| 3606 | + | |
| 3607 | + | |
| 3608 | + | |
| 3609 | + | |
| 3610 | + | |
| 3611 | + | |
| 3612 | + | |
| 3613 | + | |
| 3614 | + | |
| 3615 | + | |
| 3616 | + | |
| 3617 | + | |
| 3618 | + | |
| 3619 | + | |
| 3620 | + | |
| 3621 | + | |
| 3622 | + | |
| 3623 | + | |
| 3624 | + | |
| 3625 | + | |
| 3626 | + | |
| 3627 | + | |
| 3628 | + | |
| 3629 | + | |
| 3630 | + | |
| 3631 | + | |
| 3632 | + | |
| 3633 | + | |
| 3634 | + | |
| 3635 | + | |
| 3636 | + | |
| 3637 | + | |
3480 | 3638 | | |
3481 | 3639 | | |
3482 | 3640 | | |
| |||
0 commit comments