Skip to content

Commit 7a5f73e

Browse files
refactor(ui)!: fold the providers upload context into fields and data-objectstack, retire @object-ui/providers (#30550)
<!-- claude-projects-attribution: {"github_login":"os-sales"} --> _Requested by **Sales** · [project thread](https://claude.ai/code/project/chan_01D5bWFY3rFzgJcytD5gD4Uu?thread=cmsg_01D5bWFY3rFzgJcytD5gD4UuXx8nkFj47cDx3oQ4JtqdJS)_ Part of #25921 (the providers/upload fold only; the card's barrel batches and `clearSharedDiscoveryCache` stay on it). Clause-②: yes (narrowing) Metadata-protocol: none Skills-docs: follow-up #30559 ## 维护者速读 - 改了什么:文件、图片、头像字段的上传上下文 `UploadProvider` / `useUpload` 搬进 `@object-ui/fields`,连 ObjectStack 存储服务的上传适配器搬进 `@object-ui/data-objectstack`,两边共用的上传契约类型放进 `@object-ui/types`,`@object-ui/providers` 整包退役。 - 为什么改:这个包只剩上传一件事,少一个要单独发布和维护的包;访问服务器的取数逻辑回到 data 包里,字段包不再依赖一个只为它存在的包。 - 风险与回滚:上传行为不变,预签名请求逐字节相同,控制台和附件面板照常上传;外部宿主若仍从 `@object-ui/providers` 导入,升级时编译报错,changeset 写了改从哪里导入。回滚就是 revert 本 PR。 - 先看:`ui/packages/fields/src/widgets/UploadProvider.tsx`(上下文与无 provider 时的本地回退),`ui/packages/data-objectstack/src/upload-adapter.ts`(三步上传,与原包代码相同),`.changeset/25921-providers-upload-fold.md`(BREAKING 说明与迁移行)。 - 两分钟验证:`pnpm --dir ui exec vitest run packages/data-objectstack/src/objectstack-upload-scope-12055.test.ts apps/console/src/__tests__/App.uploadAltitude-10131.test.tsx`,预期两个文件全部通过。 - 需要你做的:无,席位落地。PR 自身的改动行数(additions+deletions,GitHub 把两处搬移认作改名)是 2482 行,不到 3000 行。 ## What changes `@object-ui/providers` had one job left: the upload context the file, image and avatar widgets of `@object-ui/fields` upload through, plus the adapters that fill it. This PR moves each piece to the package that owns it and retires the package. - **`@object-ui/types`** gains `ui/packages/types/src/upload.ts`: the `UploadAdapter`, `UploadOptions` and `UploadResult` interfaces, unchanged in shape. They live here, as `DataSource` does, because `@object-ui/fields` and `@object-ui/data-objectstack` do not depend on each other and both need them. - **`@object-ui/fields`** gains `src/widgets/UploadProvider.tsx` (`UploadProvider`, `useUpload`, `UploadProviderProps`) and re-exports the three contract types from its entry. `AvatarField`, `FileField` and `ImageField` read it relatively. `createObjectUrlAdapter` moves in as a module-private function: it is still the `blob:` fallback `useUpload` answers with when no provider is mounted, and it is no longer exported. - **`@object-ui/data-objectstack`** gains `src/upload-adapter.ts` (`createObjectStackUploadAdapter`, `ObjectStackUploadAdapterOptions`): fetch logic against an ObjectStack server, so it sits beside the other fetch logic (ui/AGENTS.md section 3). The three-step presign, PUT and complete flow is the original code. Its `scope` option stays typed as `API.UploadScope`, and the objectui#12055 test moved with it. - **Retired with no replacement:** `createS3Adapter`, `createAzureBlobAdapter`, `S3AdapterOptions`, `AzureBlobAdapterOptions`. They had zero consumers in the workspace and zero in `objectstack-ai/hotcrm` (shallow clone at `6961ab1`; every upload name 0 hits, while a control name hits). A host that uploads to its own bucket writes an `UploadAdapter` against `@object-ui/types`. - **Importers re-pointed:** the console `App.tsx` (import only; the `UploadProvider` wrap is unchanged), `ProfilePage.tsx`, app-shell's `RecordAttachmentsPanel.tsx`, `SettingsPage.tsx` and one renderer comment, and every test that imported or mocked the package. The `@object-ui/providers` dependency leaves the console, app-shell and fields manifests, its alias lines leave `ui/vitest.config.mts` and four vite configs, and it leaves the `.changeset/config.json` fixed group, the root `CONTRIBUTING.md` package table, two gate fixture lists and the lockfile (regenerated with `pnpm install --lockfile-only`, deletions only). - **One gate floor moves:** `ui/scripts/__tests__/check-doc-links.test.ts` counts the decidable links in every package README, and the retired README carried 2 of them (127 on the merge base, 125 here), so its floor moves from 126 to 125 with the measurement in its comment, as the `@object-ui/plugin-ai` retirement did. The site-absolute floor is unchanged (48 measured, floor 39). - **One PR, no re-export shim**, as the seat ruled. Two changesets: `25921-providers-upload-fold.md` (fields and data-objectstack, patch, `!`, BREAKING paragraph, one FROM line naming the package, ADR-0087 marker `runtime-export-retired @object-ui/providers#*`) and `25921-upload-adapter-contract.md` (types, patch, widening). **Changed lines: 2482 on the PR (+350 / −2132, 63 files; GitHub reads the two moved files as renames), under the 3000-line threshold** (seat correction; AGENTS.md reads the PR's `additions + deletions`). `dispatch-gates` counts with `--no-renames`, so it counts the moved code once as deleted and once as added and arrives at about 3,200 lines. 2386 of the deletions are the retired package's own nine files (its `CHANGELOG.md` alone is 1524). ## Why The package existed so the widgets and the console could share one upload context. With the theme, data-source and metadata providers retired earlier (objectui#13453), every remaining export belonged to either the widgets or the ObjectStack data adapter. ## Tests Behaviour is not changed, so the existing tests are the proof; they were re-pointed, not rewritten. All runs on `4e1e0e0e` (the scripts/ run first on `15c54522`, see Verification), under the shared verify lock: - `pnpm --dir ui exec vitest run packages/fields/ packages/data-objectstack/ packages/types/ packages/cli/src/__tests__/workspace-vite.test.ts`: 801 files passed, 1 skipped; 16261 tests passed, 7 skipped. This includes the moved objectui#12055 presign-body test and its compile-time pins. - `pnpm --filter @object-ui/console test` (the whole console project, since `App.tsx` changed): 298 files, 2939 tests passed, including `App.uploadAltitude-10131`, the three `FormPage` upload tests and the five `ProfilePage` tests. - app-shell and plugin-form upload sites (every `views/__tests__/` file, the `ActionParamDialog`, `RecordDetailView`, settings and chatbot files that render an upload site, plus `WizardForm.nextMidUpload`, `affordanceGrantMap-12082`, `uploadInFlightSave`): 104 files, 937 tests passed. - `pnpm --dir ui exec vitest run scripts/`: on `15c54522` 169 files passed and 1 failed, the doc-links floor above (expected 125 to be at least 126). With the floor moved, `check-doc-links.test.ts` alone passes 123/123; the full rerun on the final head is in the report. No ablation: nothing tested changed behaviour. ## Acceptance notes - Behaviour is unchanged: `UploadProvider`, `useUpload` and `createObjectStackUploadAdapter` keep their signatures and bodies, and the presign request body is pinned by the moved objectui#12055 test. - The plugin-form `WizardForm.nextMidUpload` test used to mock the `@object-ui/providers` module. A mock of the `@object-ui/fields` barrel would not reach the widgets, which import `./UploadProvider.js` relatively, so the test now mounts the real `UploadProvider` with a deferred adapter. It drives the same pending upload. - Mentions of `@object-ui/providers` this PR leaves alone, because they are outside its file surface or are historical text that stays true: - `skills/objectui/guides/project-setup.md:249` and `:307` (governed; they still tell a reader to install `@object-ui/providers` for uploads, a follow-up). - `ui/.claude/skills/objectui-contributor/guides/console-development.md:409` (governed). - `content/docs/releases/v18/18-2.mdx:374` (release text). - The retired package's README held the `UploadProvider` usage guide. It now lives in `ui/packages/fields/README.md` (an `UploadProvider` section) and `ui/packages/data-objectstack/README.md` (a File Uploads section), added in the patch round (seat correction). - Historical comments that stay accurate: `ui/packages/types/src/theme.ts:68,77`, `ui/packages/types/src/__tests__/p2-spec-exports.test.ts:256`, `ui/scripts/__tests__/one-authority-per-exported-name-6273.test.ts:616`, the objectui#4194 error text quoted in `ui/packages/plugin-editor/vite.config.ts:64` and `ui/packages/plugin-markdown/vite.config.ts:64`, and `ui/.changeset/13453-*`, `13464-*`, `13465-*`, `25685-*` (not read by the root changeset config). ## Verification - Build: `turbo run build --filter=@object-ui/console... --filter='./packages/**' --filter='@objectstack/dogfood^...'`, 113/113 tasks, exit 0 (console `tsc` and `vite build` included). - Type-check, each exit 0: `@object-ui/types`, `fields`, `data-objectstack`, `app-shell`, `plugin-form`, `console`, `cli`, `plugin-editor`, `plugin-markdown`, `runner` (`pnpm --filter PKG run type-check`, which compiles each package's tests where it has a test tsconfig). - `dispatch-gates --commands`: 60 commands, all run. 59 exit 0; `pnpm --dir ui exec vitest run scripts/` exited 1 on `15c54522` for the doc-links floor above, and its rerun on the final head is in the report. `check-adr-0087-registration --base origin/main` verifies `@object-ui/providers#*` (package deleted, absent from the workspace and the fixed group). `check:type-check-debt` exit 0 on the final head. - Outside the derived list: `pnpm --dir ui run check:spec-symbols` exit 0; `check-platform-checklist --changed-from origin/main` exit 0 (0 anchored files); eslint on the 45 changed ui source files, 0 errors (the one react-compiler ref warning in `UploadProvider.tsx` is the same warning the original file carried). - hotcrm census: shallow clone of `objectstack-ai/hotcrm` at `6961ab1`, 0 hits for `@object-ui/providers`, `UploadProvider`, `useUpload`, `createObjectStackUploadAdapter`, `createS3Adapter`, `createAzureBlobAdapter`, `createObjectUrlAdapter`, with a control name hitting. - The full dogfood battery (the title carries `!`) runs on the final head under the lock; its count goes in the dev report on #25921. - `origin/main` has moved 5 commits since the base; `git merge-tree --write-tree HEAD origin/main` exits 0, and the one shared file (`ui/packages/fields/src/index.tsx`) is changed in a different region. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (`packages/spec` untouched.) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. (eslint on every changed ui source file: 0 errors.) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset. - [x] 6. `packages/spec` touched: not touched, nothing to regenerate. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. (The retired package's `CHANGELOG.md` is deleted with it, not edited.) - [ ] 8. Title, body and comments are in English. (The body carries the Chinese maintainer summary the dispatch rules require; everything else is English.) - [x] The *Before Submitting* list in CONTRIBUTING.md is done. --- _Generated by [Claude Code](https://claude.ai/code/session_01L6bhgWy2L8Kga6GXBtvjpK)_ <!-- signed: domain:ui#1 · os-sales · session_01L6bhgWn6zhNa4LL7VB1rtL --> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent a0c68ae commit 7a5f73e

63 files changed

Lines changed: 350 additions & 2132 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@object-ui/fields': patch
3+
'@object-ui/data-objectstack': patch
4+
---
5+
6+
refactor(fields, data-objectstack)!: `UploadProvider` moves into `@object-ui/fields`, the ObjectStack upload adapter into `@object-ui/data-objectstack`, and `@object-ui/providers` is retired
7+
8+
Clause-②: yes (narrowing) — `@object-ui/fields` gains `UploadProvider`, `useUpload`, `UploadProviderProps` and the three upload contract types, and `@object-ui/data-objectstack` gains `createObjectStackUploadAdapter` and `ObjectStackUploadAdapterOptions`; the whole `@object-ui/providers` package is retired, which takes `createS3Adapter`, `createAzureBlobAdapter`, their option types and the exported `createObjectUrlAdapter` with it.
9+
Metadata-protocol: none
10+
11+
<!-- adr-0087: not-required (runtime-export-retired @object-ui/providers#*) the retired operand is a published ui package whose entry held a React upload context, its hook, four upload adapter factories and their TypeScript option and result types; no packages/spec schema, registered node type, ADR-0087 conversion surface or stored shape names any of them, so there is nothing for `objectstack migrate meta` to rewrite, and a consumer meets the move at its own import, where the compiler names the missing module -->
12+
13+
**BREAKING.** `@object-ui/providers` is retired: `18.3.0` is its last published version, and it gets no further release. Its one remaining job was the upload context the file, image and avatar widgets of `@object-ui/fields` upload through, so that context now lives in `@object-ui/fields` itself, and the adapter that talks to an ObjectStack server's storage service lives in `@object-ui/data-objectstack`, beside the other fetch logic against that server. The upload contract the two share is `@object-ui/types`'.
14+
15+
What leaves, and what to do:
16+
17+
- FROM `@object-ui/providers` TO `@object-ui/fields` and `@object-ui/data-objectstack`: import `UploadProvider`, `useUpload` and the `UploadProviderProps`, `UploadAdapter`, `UploadOptions` and `UploadResult` types from `@object-ui/fields` (the three contract types also from `@object-ui/types`), and `createObjectStackUploadAdapter` with `ObjectStackUploadAdapterOptions` from `@object-ui/data-objectstack`, then drop the `@object-ui/providers` dependency. `createS3Adapter`, `createAzureBlobAdapter`, `S3AdapterOptions` and `AzureBlobAdapterOptions` had no consumer and leave with no replacement: a host that uploads to its own bucket writes an object with a `name` and an `upload(file, options)` method against the `UploadAdapter` type of `@object-ui/types` and hands it to `UploadProvider`. `createObjectUrlAdapter` is no longer exported: it stays the local `blob:` adapter `useUpload` falls back to when no `UploadProvider` is mounted.
18+
19+
What does not change: `UploadProvider`, `useUpload` and `createObjectStackUploadAdapter` keep their signatures and behaviour, the presigned upload request is the same, and the widgets read the same context.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/types': patch
3+
---
4+
5+
feat(types): `@object-ui/types` publishes the upload adapter contract, `UploadAdapter`, `UploadOptions` and `UploadResult`
6+
7+
Clause-②: yes (widening)
8+
Metadata-protocol: none
9+
10+
The three interfaces the file, image and avatar widgets upload through, unchanged in shape from the `@object-ui/providers` package they leave. They live here, as `DataSource` does, because `@object-ui/fields` (whose `UploadProvider` reads an adapter) and `@object-ui/data-objectstack` (whose `createObjectStackUploadAdapter` builds one) do not depend on each other. A host that writes its own adapter types it from here. Nothing existing changes.

‎.changeset/config.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@
114114
"@object-ui/plugin-timeline",
115115
"@object-ui/plugin-tree",
116116
"@object-ui/plugin-view",
117-
"@object-ui/providers",
118117
"@object-ui/react",
119118
"@object-ui/react-runtime",
120119
"@object-ui/types"

‎CONTRIBUTING.md‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,6 @@ Atoms and fields stay light; heavy widgets live in lazy-loaded plugins.
467467
| Package | Description |
468468
| :--- | :--- |
469469
| [`@object-ui/app-shell`](ui/packages/app-shell) | The Console's shell, views and Studio; a private workspace package, last published to npm as 18.2.0 |
470-
| [`@object-ui/providers`](ui/packages/providers) | The upload adapter context the file and image fields upload through |
471470
| [`@object-ui/auth`](ui/packages/auth) | `AuthProvider`, `useAuth`, `AuthGuard`, sign-in forms |
472471
| [`@object-ui/permissions`](ui/packages/permissions) | Object / field / row-level permission guards and hooks |
473472
| [`@object-ui/i18n`](ui/packages/i18n) | Language packs, RTL layout, date and currency formatting |

‎pnpm-lock.yaml‎

Lines changed: 0 additions & 34 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎ui/apps/console/package.json‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,6 @@
8484
"@object-ui/plugin-timeline": "workspace:*",
8585
"@object-ui/plugin-tree": "workspace:*",
8686
"@object-ui/plugin-view": "workspace:*",
87-
"@object-ui/providers": "workspace:*",
8887
"@object-ui/react": "workspace:*",
8988
"@object-ui/test-support": "workspace:*",
9089
"@object-ui/types": "workspace:*",

‎ui/apps/console/src/App.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ import { lazy, Suspense, useCallback, useEffect, useMemo } from 'react';
1616
import { BrowserRouter, Routes, Route, Navigate, Outlet, matchPath, useLocation, useNavigate } from 'react-router-dom';
1717
import { useNativeHostRouting } from '@object-ui/mobile';
1818
import { AuthProvider, useAuth, createAuthenticatedFetch } from '@object-ui/auth';
19-
import { UploadProvider, createObjectStackUploadAdapter } from '@object-ui/providers';
19+
import { UploadProvider } from '@object-ui/fields';
20+
import { createObjectStackUploadAdapter } from '@object-ui/data-objectstack';
2021
import { DevMasterDetail } from './dev/DevMasterDetail';
2122
import { DevLists } from './dev/DevLists';
2223
import { DevModal } from './dev/DevModal';

‎ui/apps/console/src/__tests__/App.uploadAltitude-10131.test.tsx‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,10 +81,10 @@ const { adapterOptions, uploadSpy, passthrough, stub, MINTED_FILE_ID } = vi.hois
8181
return { adapterOptions, uploadSpy, passthrough, stub, MINTED_FILE_ID };
8282
});
8383

84-
// The console's OWN adapter factory, replaced by a spy that mints a `sys_file`
85-
// id. `UploadProvider` / `useUpload` stay real — the context lookup is the
86-
// thing under test.
87-
vi.mock('@object-ui/providers', async (importOriginal) => ({
84+
// The console's OWN adapter factory (`@object-ui/data-objectstack`), replaced by
85+
// a spy that mints a `sys_file` id. `UploadProvider` / `useUpload`
86+
// (`@object-ui/fields`) stay real — the context lookup is the thing under test.
87+
vi.mock('@object-ui/data-objectstack', async (importOriginal) => ({
8888
...(await importOriginal<Record<string, unknown>>()),
8989
createObjectStackUploadAdapter: (opts: Record<string, unknown>) => {
9090
adapterOptions.push(opts);

‎ui/apps/console/src/components/FormPage.avatarUpload-10785.test.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
3030
import { render, screen, waitFor, cleanup } from '@testing-library/react';
3131
import userEvent from '@testing-library/user-event';
3232
import { MemoryRouter, Route, Routes } from 'react-router-dom';
33-
import { UploadProvider } from '@object-ui/providers';
33+
import { UploadProvider } from '@object-ui/fields';
3434
import { createI18n } from '@object-ui/i18n';
3535
import { FormPage } from './FormPage';
3636

‎ui/apps/console/src/components/FormPage.chromeI18n-11071.test.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ import { render, screen, waitFor, cleanup } from '@testing-library/react';
3131
import userEvent from '@testing-library/user-event';
3232
import { MemoryRouter, Route, Routes } from 'react-router-dom';
3333
import { createI18n } from '@object-ui/i18n';
34-
import { UploadProvider } from '@object-ui/providers';
34+
import { UploadProvider } from '@object-ui/fields';
3535
import { FormPage } from './FormPage';
3636

3737
const { toastError } = vi.hoisted(() => ({ toastError: vi.fn() }));

0 commit comments

Comments
 (0)