Files
deepseek-harness/packages/storage/storage/src/index.ts
T
imccyu ec601ca13d build(vendor): rescope the vendored Cordis packages into @deepseek-ai
Machine-produced by `pnpm run rescope-vendor --apply` plus the regeneration it
prints: `pnpm install` for the lockfile, `pnpm run gen-third-party-notices`,
`verify-translation-pairing --write` for the touched bilingual pairs,
`gen-doc-graphs`, and one typert snapshot whose ids embed character offsets.
`pnpm run rescope-vendor --check` verifies the result.

Renames nine vendored packages (cordis, cosmokit, schemastery and the six
@cordisjs plugins) and every reference that resolves them: manifest names and
dependency keys, module specifiers including declare-module merges, cordis.yml
plugin names, tsconfig paths, every Markdown fence, and `docs/` prose.
Directory names, upstream versions, and dependency ranges are unchanged, so
vendor/README.md still reads as an upstream snapshot; its manifest table gains
an upstream-name column so THIRD_PARTY_NOTICES keeps MIT attribution pointed
at each fork's origin.

The tutorial tier follows the rename end to end: its yaml fences named plugins
the Loader can no longer resolve, its `ts ignore-check` fences disagreed with
the compiled fences beside them, and its prose quoted both. The contracts that
told readers to keep upstream names — the root convention and the vendoring
cookbook's tree comment and manifest invariant — now say to rescope instead.

Two rules read `@deepseek-ai/` as "another workspace plugin": the client bundle
purity gate now names the vendored libraries a browser bundle inlines, and the
files where a bare `cordis` is an agent-preset id keep that product data.
2026-08-10 22:04:13 +08:00

99 lines
3.4 KiB
TypeScript

/**
* Storage hub (`ctx.storage`): a named backend registry plus mounted
* data-form facilities. The hub itself performs no IO — backends own media,
* data forms (the domain layer first) own semantics.
* @module @deepseek-ai/dsh-storage
*/
import { Context, Service } from '@deepseek-ai/cordis'
import { StorageError } from './error.ts'
import { BackendRegistry } from './registry.ts'
export { BackendRegistry } from './registry.ts'
export { StorageError } from './error.ts'
export type { StorageErrorCode } from './error.ts'
export { UNIT_NAME_RE } from './backend.ts'
export type { StorageBackend, KvFacet, KvUnit, KvUnitDescriptor } from './backend.ts'
/**
* Derive the Cordis lifecycle service that one named backend plugin provides.
* Domain-form providers inject these keys so activation cannot race backend
* registration even though callers continue resolving backends through the
* storage registry.
* @param name - Backend registry name.
* @returns the corresponding lifecycle-only service key.
*/
export function storageBackendServiceKey(name: string): string {
return `storage.backend.${name}`
}
declare module '@deepseek-ai/cordis' {
interface Context {
storage: Storage
}
}
/**
* Data forms mountable on the hub, keyed by form name. Form owners extend
* this map via declaration merging (the domain layer merges
* `domain: DomainFacility`) and mount the facility in their `apply`.
*/
export interface StorageForms {}
/**
* The storage hub service. Backends register under `backend`; data forms
* mount under their `StorageForms` key and are reached as `ctx.storage.<form>`.
*/
export class Storage extends Service {
/** Named backend table; multiple backends stay mounted side by side. */
readonly backend: BackendRegistry = new BackendRegistry()
private readonly forms = new Map<keyof StorageForms, unknown>()
constructor(ctx: Context) {
super(ctx, 'storage')
}
/**
* Mount a data-form facility on the hub. Mounting is an effect: the
* returned disposer unmounts the form.
* @param form - Form key declared in {@link StorageForms}.
* @param facility - The facility instance to expose.
* @returns the disposer that unmounts the form.
*/
mount<K extends keyof StorageForms>(form: K, facility: StorageForms[K]): () => void {
if (this.forms.has(form)) {
throw new StorageError('duplicate-mount', `storage form '${String(form)}' is already mounted`)
}
this.forms.set(form, facility)
return () => {
// Same stale-disposer guard as BackendRegistry.register.
if (this.forms.get(form) === facility) {
this.forms.delete(form)
}
}
}
/**
* Resolve a mounted data form.
* @param form - Form key declared in {@link StorageForms}.
* @returns the mounted facility.
*/
form<K extends keyof StorageForms>(form: K): StorageForms[K] {
if (!this.forms.has(form)) {
throw new StorageError('form-not-mounted', `storage form '${String(form)}' is not mounted`)
}
return this.forms.get(form) as StorageForms[K]
}
/** Domain data form; present once the domain layer plugin is loaded. */
get domain(): StorageForms extends { domain: infer D } ? D : never {
return this.form('domain' as keyof StorageForms)
}
}
// Service packages default-export their service class and nothing else
// plugin-shaped (packages/AGENTS.md): mixing a default export with a
// function-plugin `apply` makes the Loader drop the plugin namespace.
export default Storage