Skip to content

feat(connector-openapi): resolve providerConfig.spec from a package-relative file path (#3016)#3024

Merged
os-zhuang merged 2 commits into
mainfrom
claude/loving-sagan-wxr59d
Jul 16, 2026
Merged

feat(connector-openapi): resolve providerConfig.spec from a package-relative file path (#3016)#3024
os-zhuang merged 2 commits into
mainfrom
claude/loving-sagan-wxr59d

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Closes #3016(ADR-0096 后续项,承接 #2977 / #2994 / #3001)

背景

ADR-0096 的典型示例把 OpenAPI 实例写成 providerConfig: { spec: './billing-openapi.json' },但已落地的 openapi provider 工厂只接受内联文档对象或 http(s) URL,文件路径会被直接拒绝。本 PR 补全 spec 联合形态:内联对象 | 文件路径 | 远程 URL

设计

文件系统访问不放进 connector 包,而是由宿主注入能力(与 ADR-0096「provider 工厂只依赖 @objectstack/spec 纯类型」的结构保持一致):

  • @objectstack/specConnectorProviderContext 新增可选的 loadPackageFile(relativePath) 能力(纯类型,Prime Directive ✨ Set up Copilot instructions #2):按声明该 connector 的 stack/package 根目录解析相对路径并读取 UTF-8 文本;无文件系统的宿主(edge/browser)为 undefined。另更新 providerConfig 的 describe/TSDoc,自动生成的 references 文档会带上 spec 三种形态。
  • @objectstack/service-automation — 新增 packageRoot 插件选项(相对文件引用的解析基准,默认 process.cwd())与导出的 createPackageFileLoader(packageRoot):实现根目录约束(拒绝绝对路径与 .. 逃逸路径,含 Windows 盘符形式);node:fs/node:path 在闭包内懒加载,非 Node 宿主只有真正解引用文件时才会失败。materializeDeclaredConnectors 将该能力注入每个 provider 工厂的 ctx。读取/解析失败沿用既有 reconcile 策略:启动时 fatal,reload 时跳过该条目(旧连接器继续服务)。
  • @objectstack/connector-openapi — 非 URL 的字符串 spec 现在经 ctx.loadPackageFile 读取并按 OpenAPI JSON 解析;文件缺失/不可读、JSON 不可解析、宿主无文件访问能力各有清晰报错。
  • @objectstack/cliserve/dev 把项目目录(objectstack.config.ts 所在目录)作为 automation 服务的 packageRoot 传入,与 standalone sqlite 默认库的锚定方式一致。

Showcase 示例(第二个提交)

新增 StatusOpenApiConnector:provider: 'openapi' 声明式实例,OpenAPI 文档以包相对路径引用(src/system/connectors/status-openapi.json),由无参 ConnectorOpenApiPlugin(只贡献 provider 工厂)在启动时物化;getHealth 指向运行中的服务器自身 GET /api/v1/health,零外部依赖。与既有 rest 内联实例(StatusApiConnector)互补,并同步修正了 connectors: 集合还是「纯 descriptor」时代的过期注释与 coverage 说明。

实机验证:--fresh 随机端口启动 showcase,GET /api/v1/automation/connectors 列出 showcase_status_openapi(origin: declarative,action getHealth)。

测试

  • connector-openapi/openapi-provider.test.ts:文件路径 happy path(经注入的 loader)、loader 失败透传、JSON 不可解析、宿主无文件访问;既有内联/URL 用例不变。
  • service-automation/connector-materialization.test.ts:createPackageFileLoader 单测(happy path、绝对路径拒绝、.. 逃逸拒绝、缺失文件报错含解析后路径);物化策略集成测试(工厂收到可用的 loadPackageFile、缺失文件启动 fatal、逃逸路径启动 fatal、reload 软失败且旧连接器继续服务)。
  • pnpm turbo test(spec / service-automation / connector-openapi / example-showcase)全绿;@objectstack/cli build 通过。

其他

  • 更新 ADR-0096「Deliberate scope boundaries」中原先声明的 non-goal,记录本次交付方式。
  • 已按要求添加 changeset(4 个包 minor)。
  • 已知边界:file-path spec 的文件内容变化不会触发 reload 重物化(签名只覆盖条目本身,与 URL spec 行为一致)。

🤖 Generated with Claude Code

https://claude.ai/code/session_016eY7byWABTUPtJG7R2AEFU

…elative file path (#3016)

ADR-0096 follow-up: complete the spec union (inline object | file path |
remote URL) for the declarative openapi provider.

- spec: ConnectorProviderContext gains an optional host-injected
  loadPackageFile capability (pure type)
- service-automation: packageRoot option + createPackageFileLoader with a
  root-confinement guard (rejects absolute and ..-escaping paths; lazy
  node:fs/node:path imports); capability injected into every provider ctx;
  failures follow the reconcile policy (fatal at boot, soft on reload)
- connector-openapi: non-URL string specs are read via ctx.loadPackageFile
  and parsed as OpenAPI JSON with clear errors
- cli: serve/dev anchor packageRoot to the objectstack.config.ts directory
- tests: file-path happy path, missing file (fatal at boot / skipped on
  reload), traversal rejection; ADR-0096 scope-boundary note updated

Closes #3016

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016eY7byWABTUPtJG7R2AEFU
@vercel

vercel Bot commented Jul 16, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
spec Canceled Canceled Jul 16, 2026 6:13am

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Jul 16, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 4 package(s): @objectstack/cli, packages/connectors, packages/services, @objectstack/spec.

105 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/agents.mdx (via @objectstack/spec)
  • content/docs/ai/skills-reference.mdx (via packages/cli, @objectstack/spec)
  • content/docs/ai/skills.mdx (via @objectstack/spec)
  • content/docs/api/client-sdk.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/data-flow.mdx (via @objectstack/cli)
  • content/docs/api/environment-routing.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-catalog.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/api/error-handling-client.mdx (via @objectstack/spec)
  • content/docs/api/error-handling-server.mdx (via @objectstack/spec)
  • content/docs/api/index.mdx (via @objectstack/spec)
  • content/docs/automation/approvals.mdx (via packages/spec)
  • content/docs/automation/flows.mdx (via @objectstack/spec)
  • content/docs/automation/hook-bodies.mdx (via packages/cli, packages/spec)
  • content/docs/automation/hooks.mdx (via @objectstack/spec)
  • content/docs/automation/index.mdx (via @objectstack/spec)
  • content/docs/automation/webhooks.mdx (via packages/services, @objectstack/spec)
  • content/docs/automation/workflows.mdx (via @objectstack/spec)
  • content/docs/concepts/architecture.mdx (via @objectstack/spec)
  • content/docs/concepts/design-principles.mdx (via packages/spec)
  • content/docs/concepts/index.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-driven.mdx (via @objectstack/spec)
  • content/docs/concepts/metadata-lifecycle.mdx (via packages/spec)
  • content/docs/concepts/north-star.mdx (via packages/spec)
  • content/docs/data-modeling/analytics.mdx (via @objectstack/spec)
  • content/docs/data-modeling/drivers.mdx (via @objectstack/spec)
  • content/docs/data-modeling/external-datasources.mdx (via @objectstack/spec)
  • content/docs/data-modeling/field-types.mdx (via @objectstack/spec)
  • content/docs/data-modeling/fields.mdx (via @objectstack/spec)
  • content/docs/data-modeling/formulas.mdx (via @objectstack/spec)
  • content/docs/data-modeling/index.mdx (via @objectstack/spec)
  • content/docs/data-modeling/objects.mdx (via @objectstack/spec)
  • content/docs/data-modeling/queries.mdx (via @objectstack/spec)
  • content/docs/data-modeling/schema-design.mdx (via @objectstack/spec)
  • content/docs/data-modeling/seed-data.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation-rules.mdx (via @objectstack/spec)
  • content/docs/data-modeling/validation.mdx (via @objectstack/spec)
  • content/docs/deployment/backup-restore.mdx (via @objectstack/cli)
  • content/docs/deployment/self-hosting.mdx (via @objectstack/cli)
  • content/docs/deployment/troubleshooting.mdx (via @objectstack/spec)
  • content/docs/getting-started/build-with-claude-code.mdx (via @objectstack/spec)
  • content/docs/getting-started/cli.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/getting-started/common-patterns.mdx (via @objectstack/spec)
  • content/docs/getting-started/examples.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-reference.mdx (via @objectstack/spec)
  • content/docs/getting-started/quick-start.mdx (via @objectstack/spec)
  • content/docs/getting-started/validating-metadata.mdx (via @objectstack/spec)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/kernel/cluster.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/auth-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/cache-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/data-engine.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/index.mdx (via @objectstack/spec)
  • content/docs/kernel/contracts/metadata-service.mdx (via packages/spec)
  • content/docs/kernel/contracts/storage-service.mdx (via packages/spec)
  • content/docs/kernel/index.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/audit-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/cli)
  • content/docs/kernel/runtime-services/email-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/index.mdx (via packages/cli, packages/services, packages/spec)
  • content/docs/kernel/runtime-services/queue-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/settings-service.mdx (via packages/services)
  • content/docs/kernel/runtime-services/sharing-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/sms-service.mdx (via packages/spec)
  • content/docs/kernel/runtime-services/storage-service.mdx (via packages/spec)
  • content/docs/kernel/services-checklist.mdx (via @objectstack/spec)
  • content/docs/permissions/authentication.mdx (via @objectstack/cli)
  • content/docs/permissions/authorization.mdx (via @objectstack/spec)
  • content/docs/permissions/permission-sets.mdx (via @objectstack/spec)
  • content/docs/permissions/permissions-matrix.mdx (via @objectstack/spec)
  • content/docs/permissions/positions.mdx (via @objectstack/spec)
  • content/docs/permissions/sharing-rules.mdx (via @objectstack/spec)
  • content/docs/plugins/adding-a-metadata-type.mdx (via @objectstack/spec)
  • content/docs/plugins/development.mdx (via @objectstack/spec)
  • content/docs/plugins/index.mdx (via @objectstack/spec)
  • content/docs/plugins/packages.mdx (via @objectstack/cli, packages/services, @objectstack/spec)
  • content/docs/protocol/backward-compatibility.mdx (via @objectstack/spec)
  • content/docs/protocol/diagram.mdx (via packages/spec)
  • content/docs/protocol/kernel/config-resolution.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/services, @objectstack/spec)
  • content/docs/protocol/kernel/lifecycle.mdx (via @objectstack/spec)
  • content/docs/protocol/kernel/plugin-spec.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/cli)
  • content/docs/protocol/kernel/runtime-capabilities.mdx (via @objectstack/spec)
  • content/docs/protocol/knowledge.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/index.mdx (via packages/spec)
  • content/docs/protocol/objectql/query-syntax.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/schema.mdx (via @objectstack/spec)
  • content/docs/protocol/objectql/security.mdx (via packages/spec)
  • content/docs/protocol/objectql/state-machine.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/actions.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/concept.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/index.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/layout-dsl.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/record-alert.mdx (via @objectstack/spec)
  • content/docs/protocol/objectui/widget-contract.mdx (via @objectstack/spec)
  • content/docs/releases/implementation-status.mdx (via @objectstack/cli, @objectstack/spec)
  • content/docs/releases/index.mdx (via @objectstack/spec)
  • content/docs/releases/v12.mdx (via @objectstack/spec)
  • content/docs/releases/v13.mdx (via @objectstack/spec)
  • content/docs/releases/v9.mdx (via @objectstack/spec)
  • content/docs/ui/create-vs-edit-form.mdx (via @objectstack/spec)
  • content/docs/ui/dashboards.mdx (via @objectstack/spec)
  • content/docs/ui/forms.mdx (via @objectstack/spec)
  • content/docs/ui/index.mdx (via @objectstack/spec)
  • content/docs/ui/setup-app.mdx (via @objectstack/spec)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

- spec: providerConfig describe/TSDoc now documents the spec union
  (inline object | package-relative file path | http(s) URL) so the
  auto-generated references pick it up
- showcase: StatusOpenApiConnector — a provider: 'openapi' declarative
  instance whose OpenAPI document is referenced as a package-relative
  file path (src/system/connectors/status-openapi.json), materialized at
  boot by an option-less ConnectorOpenApiPlugin; getHealth dispatches
  GET /api/v1/health against the running server itself
- coverage notes + stale connectors: comment updated (the collection has
  held provider-bound instances since ADR-0096, not only descriptors)

Verified: booted the showcase (--fresh, random port); GET
/api/v1/automation/connectors lists showcase_status_openapi
(origin: declarative) with the getHealth action.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016eY7byWABTUPtJG7R2AEFU
@github-actions github-actions Bot added the dependencies Pull requests that update a dependency file label Jul 16, 2026
@os-zhuang os-zhuang marked this pull request as ready for review July 16, 2026 07:48
@os-zhuang os-zhuang merged commit 10a570a into main Jul 16, 2026
18 checks passed
@os-zhuang os-zhuang deleted the claude/loving-sagan-wxr59d branch July 16, 2026 07:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(connector-openapi): declarative provider — resolve providerConfig.spec from a file path (ADR-0096 follow-up)

2 participants