Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions .changeset/package-dependency-dual-source-c7.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
"@objectstack/spec": major
---

BREAKING(spec): `@objectstack/spec/kernel` 改名 `PackageDependencySchema` → `ResolvedPackageDependencySchema`;裸名 `PackageDependency(Schema)` 现在全包唯一地指 `@objectstack/spec/cloud` 的清单声明形 (#4741, #4535 C7)

`PackageDependency` / `PackageDependencySchema` 曾由 `./cloud` 与 `./kernel` 各自导出一个声明 —— 同名、键集**完全不相交(0 个共享属性)**的**两个概念**(#4411 陷阱):

| 入口 | 键集 | 语义 | 处置 |
|:--|:--|:--|:--|
| `./cloud`(**保名**) | `packageId` / `versionRange` / `optional` | **声明形**:作者写进包清单的依赖行,嵌在 `PackageManifestSchema.dependencies[]` → `sys_package_version.manifest_json` | 裸名唯一归属 |
| `./kernel`(**改名**) | `name` / `versionConstraint` / `type` / `resolvedVersion` | **解析形**:依赖解析器在图上走的边,嵌在 `DependencyGraphNodeSchema.dependencies[]`,并经 `PluginSecurityProtocol` 发布给 SBOM / 冲突报告 | → `ResolvedPackageDependencySchema`,字段与校验逐字不变 |

两边都不是 `.strict()`,所以把一侧的文档粘到另一侧时**不会响亮报错,只会静默剥掉全部外来键**(ADR-0104 silent-strip 类)—— 这正是共用一个名字所掩盖的失败模式,也是本次不留任何别名的原因。

## FROM → TO

```ts
// FROM —— 编译期起以 TS2305 失败
import { PackageDependencySchema, type PackageDependency } from '@objectstack/spec/kernel';

// TO —— 同一声明、同一形状,名字点明它是「解析结果」而非「清单声明」
import {
ResolvedPackageDependencySchema,
type ResolvedPackageDependency,
} from '@objectstack/spec/kernel';
```

运行时命名空间对象同步改键:`PluginSecurityProtocol.PackageDependency` → `PluginSecurityProtocol.ResolvedPackageDependency`(指向同一 schema)。

**要的是清单里写的依赖声明?** `import { PackageDependencySchema, type PackageDependency } from '@objectstack/spec/cloud'` —— 本次未动其形状,仅补了一段互指 docblock。

**受影响面实测**:`objectstack` / `cloud` / `objectui` 三仓 import 级扫描,`./kernel` 侧零外部 importer(唯一读者是同文件的 `DependencyGraphNodeSchema` 与 `PluginSecurityProtocol`),预期无人受影响。零 importer 不等于有死侧可删(#4653 判则),故走改名而非删除。

不保留旧名别名:在 `./kernel` 上 re-export 任何一侧的 `PackageDependencySchema` 都会重开本次关闭的陷阱 —— 要么复活双源,要么把清单声明形谎报成解析器合法输入(承接表不变式 3 会在 build 阶段直接拒绝这条路线)。

## 零元数据迁移、零形状变更

本次只动 TS 导出名与内部 JSON Schema def 名(`kernel/PackageDependency` → `kernel/ResolvedPackageDependency`,走 `RENAMED_DEFS` 承接表,**4 keys carry**:`name` / `versionConstraint` / `type` / `resolvedVersion` 在新 def 名下逐个健在)。

- **无字段增删、无类型变更、无词表变化** —— 两个 schema 的 body 一字未改(对照 C10 的 checksum 对象→字符串、C16 的 3→5 词表拓宽:本簇均不适用)。`type` 的 `.default('required')`、cloud 侧 `optional` 的 `.default(false)` 都原样保留,并由新增的 pin 用 `parse` 实测钉住(#4666 默认值盲区的自卫)。
- **无 tombstone**:tombstone 的前提是有 key 退役;本次 4 个 key 全数承接,一个都没离开契约,伪造 tombstone 会污染 ADR-0087 登记(`renamed-defs.ts` 头注明列的第 2 种错误处置)。已按 #4767 的 `retiredKey()` 先例逐条评估后排除,非沉默跳过。
- **无 ADR-0087 conversion**:没有作者路径发生位移,注册迁移等于让消费者跑一次不该跑的转换。
- 发布的 JSON Schema `$id` 随之移动:`…/kernel/PackageDependency.json` → `…/kernel/ResolvedPackageDependency.json`。

⚠️ 同前缀近邻 `PackageDependencyConflict(Schema)` 与 `PackageDependencyResolutionResult(Schema)` 是**不同概念**,一字未动,并由 pin 显式断言健在。
1 change: 0 additions & 1 deletion content/docs/references/cloud/meta.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
"marketplace",
"marketplace-admin",
"---Tenancy & Security---",
"plugin-security",
"tenant"
]
}
19 changes: 17 additions & 2 deletions content/docs/references/cloud/package-version.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ See `docs/adr/0003-package-as-first-class-citizen.md` for the full rationale.
## TypeScript Usage

```typescript
import { CreatePackageVersionRequestSchema, PackageManifestSchema, PackageVersionSchema, PackageVersionStatusSchema, PublishPackageVersionRequestSchema, UpdatePackageVersionRequestSchema } from '@objectstack/spec/cloud';
import type { CreatePackageVersionRequest, PackageManifest, PackageVersion, PackageVersionStatus, PublishPackageVersionRequest, UpdatePackageVersionRequest } from '@objectstack/spec/cloud';
import { CreatePackageVersionRequestSchema, PackageDependencySchema, PackageManifestSchema, PackageVersionSchema, PackageVersionStatusSchema, PublishPackageVersionRequestSchema, UpdatePackageVersionRequestSchema } from '@objectstack/spec/cloud';
import type { CreatePackageVersionRequest, PackageDependency, PackageManifest, PackageVersion, PackageVersionStatus, PublishPackageVersionRequest, UpdatePackageVersionRequest } from '@objectstack/spec/cloud';

// Validate data
const result = CreatePackageVersionRequestSchema.parse(data);
Expand All @@ -55,6 +55,21 @@ Create a new draft package version
| **createdBy** | `string` | ✅ | User ID creating this version |


---

## PackageDependency

Package dependency declaration

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **packageId** | `string` | ✅ | Manifest ID of the dependency |
| **versionRange** | `string` | ✅ | Semver version range (e.g. ^1.0.0) |
| **optional** | `boolean` | ✅ | Whether this dependency is optional |


---

## PackageManifest
Expand Down
34 changes: 0 additions & 34 deletions content/docs/references/cloud/plugin-security.mdx

This file was deleted.

36 changes: 18 additions & 18 deletions content/docs/references/kernel/plugin-security.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ Features:
## TypeScript Usage

```typescript
import { DependencyGraphSchema, DependencyGraphNodeSchema, PackageDependencySchema, PackageDependencyConflictSchema, PackageDependencyResolutionResultSchema, PluginProvenanceSchema, PluginTrustScoreSchema, SBOMSchema, SBOMEntrySchema, SecurityPolicySchema, SecurityScanResultSchema, SecurityVulnerabilitySchema, VulnerabilitySeverity } from '@objectstack/spec/kernel';
import type { DependencyGraph, DependencyGraphNode, PackageDependency, PackageDependencyConflict, PackageDependencyResolutionResult, PluginProvenance, PluginTrustScore, SBOM, SBOMEntry, SecurityPolicy, SecurityScanResult, SecurityVulnerability, VulnerabilitySeverity } from '@objectstack/spec/kernel';
import { DependencyGraphSchema, DependencyGraphNodeSchema, PackageDependencyConflictSchema, PackageDependencyResolutionResultSchema, PluginProvenanceSchema, PluginTrustScoreSchema, ResolvedPackageDependencySchema, SBOMSchema, SBOMEntrySchema, SecurityPolicySchema, SecurityScanResultSchema, SecurityVulnerabilitySchema, VulnerabilitySeverity } from '@objectstack/spec/kernel';
import type { DependencyGraph, DependencyGraphNode, PackageDependencyConflict, PackageDependencyResolutionResult, PluginProvenance, PluginTrustScore, ResolvedPackageDependency, SBOM, SBOMEntry, SecurityPolicy, SecurityScanResult, SecurityVulnerability, VulnerabilitySeverity } from '@objectstack/spec/kernel';

// Validate data
const result = DependencyGraphSchema.parse(data);
Expand Down Expand Up @@ -73,22 +73,6 @@ A node in the dependency graph representing a resolved package
| **metadata** | `{ name: string; description?: string; license?: string; homepage?: string }` | optional | Additional metadata about the package |


---

## PackageDependency

A package dependency with its version constraint

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **name** | `string` | ✅ | Package name or identifier |
| **versionConstraint** | `string` | ✅ | Semver range (e.g., `^1.0.0`, `>=2.0.0 <3.0.0`) |
| **type** | `Enum<'required' \| 'optional' \| 'peer' \| 'dev'>` | ✅ | Category of the dependency relationship |
| **resolvedVersion** | `string` | optional | Concrete version resolved during dependency resolution |


---

## PackageDependencyConflict
Expand Down Expand Up @@ -159,6 +143,22 @@ Trust score and verification status for a plugin
| **updatedAt** | `string` | ✅ | ISO 8601 timestamp when the trust score was last updated |


---

## ResolvedPackageDependency

A resolver-side package dependency: version constraint plus its resolution outcome

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **name** | `string` | ✅ | Package name or identifier |
| **versionConstraint** | `string` | ✅ | Semver range (e.g., `^1.0.0`, `>=2.0.0 <3.0.0`) |
| **type** | `Enum<'required' \| 'optional' \| 'peer' \| 'dev'>` | ✅ | Category of the dependency relationship |
| **resolvedVersion** | `string` | optional | Concrete version resolved during dependency resolution |


---

## SBOM
Expand Down
4 changes: 2 additions & 2 deletions packages/spec/api-surface.json
Original file line number Diff line number Diff line change
Expand Up @@ -1665,12 +1665,10 @@
"PackageArtifact (type)",
"PackageArtifactInput (type)",
"PackageArtifactSchema (const)",
"PackageDependency (type)",
"PackageDependencyConflict (type)",
"PackageDependencyConflictSchema (const)",
"PackageDependencyResolutionResult (type)",
"PackageDependencyResolutionResultSchema (const)",
"PackageDependencySchema (const)",
"PackageStatus (type)",
"PackageStatusEnum (const)",
"PermissionAction (type)",
Expand Down Expand Up @@ -1798,6 +1796,8 @@
"RequiredActionSchema (const)",
"ResolvedDependency (type)",
"ResolvedDependencySchema (const)",
"ResolvedPackageDependency (type)",
"ResolvedPackageDependencySchema (const)",
"ResourceType (type)",
"ResourceTypeSchema (const)",
"RollbackPackageRequest (type)",
Expand Down
8 changes: 4 additions & 4 deletions packages/spec/authorable-surface.json
Original file line number Diff line number Diff line change
Expand Up @@ -4679,10 +4679,6 @@
"kernel/PackageArtifact:signature",
"kernel/PackageArtifact:size",
"kernel/PackageArtifact:version",
"kernel/PackageDependency:name",
"kernel/PackageDependency:resolvedVersion",
"kernel/PackageDependency:type",
"kernel/PackageDependency:versionConstraint",
"kernel/PackageDependencyConflict:conflicts",
"kernel/PackageDependencyConflict:package",
"kernel/PackageDependencyConflict:resolution",
Expand Down Expand Up @@ -4998,6 +4994,10 @@
"kernel/ResolvedDependency:requiredRange",
"kernel/ResolvedDependency:resolvedVersion",
"kernel/ResolvedDependency:status",
"kernel/ResolvedPackageDependency:name",
"kernel/ResolvedPackageDependency:resolvedVersion",
"kernel/ResolvedPackageDependency:type",
"kernel/ResolvedPackageDependency:versionConstraint",
"kernel/RollbackPackageRequest:packageId",
"kernel/RollbackPackageRequest:rollbackCustomizations",
"kernel/RollbackPackageRequest:snapshotId",
Expand Down
7 changes: 2 additions & 5 deletions packages/spec/dual-source-exports.baseline.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
{
"_comment": "Accepted cross-entry DUAL-SOURCE exports of @objectstack/spec (#4446): names that two or more public entry points export for DIFFERENT declarations, so which type a consumer gets depends on the import path \u2014 the #4411 trap. Shrink-only ratchet, judged by symbol identity (a re-export of one declaration from many entries is fine and not listed). A NEW name here fails check:dual-source-exports: converge on one declaration and re-export it, or rename one side \u2014 growing this list needs maintainer sign-off and shows up as this file in the diff. An entry that stops being dual-source fails until its line is deleted. Regenerate with: tsx scripts/check-dual-source-exports.ts --update (after pnpm build).",
"entries": [
"PackageDependency \u2014 [./cloud (type)] \u2260 [./kernel (type)]",
"PackageDependencySchema \u2014 [./cloud (const)] \u2260 [./kernel (const)]"
]
"_comment": "Accepted cross-entry DUAL-SOURCE exports of @objectstack/spec (#4446): names that two or more public entry points export for DIFFERENT declarations, so which type a consumer gets depends on the import path — the #4411 trap. Shrink-only ratchet, judged by symbol identity (a re-export of one declaration from many entries is fine and not listed). A NEW name here fails check:dual-source-exports: converge on one declaration and re-export it, or rename one side — growing this list needs maintainer sign-off and shows up as this file in the diff. An entry that stops being dual-source fails until its line is deleted. Regenerate with: tsx scripts/check-dual-source-exports.ts --update (after pnpm build).",
"entries": []
}
2 changes: 1 addition & 1 deletion packages/spec/json-schema.manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -980,7 +980,6 @@
"kernel/OpsFilePath",
"kernel/OpsPluginStructure",
"kernel/PackageArtifact",
"kernel/PackageDependency",
"kernel/PackageDependencyConflict",
"kernel/PackageDependencyResolutionResult",
"kernel/PackageStatusEnum",
Expand Down Expand Up @@ -1039,6 +1038,7 @@
"kernel/RealTimeNotificationConfig",
"kernel/RequiredAction",
"kernel/ResolvedDependency",
"kernel/ResolvedPackageDependency",
"kernel/ResourceType",
"kernel/RollbackPackageRequest",
"kernel/RollbackPackageResponse",
Expand Down
11 changes: 11 additions & 0 deletions packages/spec/scripts/lib/renamed-defs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ export const RENAMED_DEFS: Readonly<Record<string, string>> = {
// platform-wide canonical vocabulary and objectui pins it by reference
// (spec-derived-unions.test.ts).
'studio/ActionLocation': 'studio/ActionContributionLocation',

// #4741 / ADR-0112 D9a — `PackageDependency` was published by TWO defs whose
// key sets are ENTIRELY disjoint (zero shared properties): `cloud` is the
// DECLARATION form an author writes into a package manifest
// (`packageId` / `versionRange` / `optional`), `kernel` is the RESOLVER form
// the dependency graph walks (`name` / `versionConstraint` / `type` /
// `resolvedVersion`). Two concepts, not two spellings. The resolver side
// takes the descriptive name; `cloud/PackageDependency` keeps the bare one
// and is deliberately absent from this table — it is neither source nor
// target, and it is emitted byte-for-byte unchanged by this build.
'kernel/PackageDependency': 'kernel/ResolvedPackageDependency', // 4 keys carried
};

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/spec/src/cloud/package-version.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ export type PackageVersionStatus = z.infer<typeof PackageVersionStatusSchema>;
/**
* A single dependency declared in a package manifest.
* Follows npm-style `"package_id": "version_range"` semantics.
*
* This is the DECLARATION-side shape — what an author writes into
* `manifestJson.dependencies[]`. The resolver-side shape (a constraint plus
* the `resolvedVersion` it resolved to) is a different concept and lives in
* `@objectstack/spec/kernel` as `ResolvedPackageDependency`; before #4741 it
* also went by `PackageDependency`, so which type a consumer got depended on
* nothing but the import path (#4411). The bare name is now this one alone.
*/
export const PackageDependencySchema = lazySchema(() => z.object({
/** Manifest ID of the required package (e.g. `com.objectstack.core`). */
Expand Down
Loading
Loading