refactor: apply repository naming contract
Apply the accepted pre-release package, service, type, directory, and role renames as one repository-wide change.
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/credentials/credentials-local/README.md
|
||||
README.md: 462618b990f8d07e9b855248db1e149b3c673964
|
||||
README.zh.md: c3aa2fc942a2e6b73ef9e51a6d3079f11abc1dde
|
||||
README.md: 63895d34fe8396d55c1d6ef29b3e3d9a9dc17264
|
||||
README.zh.md: 3c60fb7bbf06a0ae9ec905f36a5c543c2fb6af1b
|
||||
@@ -15,7 +15,7 @@ The launching environment wins because a per-run override (`DEEPSEEK_API_KEY=…
|
||||
|
||||
Everything below it loses to the managed store, so a key written by the Models page takes effect immediately even when an older key sits in a `.env`. Those two layers still resolve when nothing is stored, and `describe()` names them `project-env` or `user-env` with `writable: true` — storing a key replaces them as the effective source.
|
||||
|
||||
Under the product CLI, resolution reads the launcher's frozen [environment snapshot](../../util/environment/README.md) rather than `process.env`: only the snapshot can say whether a value came from the launching shell or from a file. A composition the product CLI did not boot has the inherited environment as its only layer, which keeps embedders on the semantics they already had.
|
||||
Under the product CLI, resolution reads the launcher's frozen [environment snapshot](../../util/launch-environment/README.md) rather than `process.env`: only the snapshot can say whether a value came from the launching shell or from a file. A composition the product CLI did not boot has the inherited environment as its only layer, which keeps embedders on the semantics they already had.
|
||||
|
||||
## Config
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
它之下的所有来源优先级都低于受管存储,因此 Models 页写入的密钥会立即生效,即使某个 `.env` 里还留着更旧的密钥。没有存储任何东西时这两层仍会参与解析,`describe()` 会把来源报告为 `project-env` 或 `user-env` 且 `writable: true`——存入一个密钥就会取代它们成为生效来源。
|
||||
|
||||
在产品 CLI(命令行界面)下,解析读取的是启动器冻结的[环境快照](../../util/environment/README.md)而不是 `process.env`:只有快照才说得清某个值来自启动 shell 还是来自某个文件。并非由产品 CLI 启动的组合只有继承环境这一层,这让嵌入方保持它们原有的语义。
|
||||
在产品 CLI(命令行界面)下,解析读取的是启动器冻结的[环境快照](../../util/launch-environment/README.md)而不是 `process.env`:只有快照才说得清某个值来自启动 shell 还是来自某个文件。并非由产品 CLI 启动的组合只有继承环境这一层,这让嵌入方保持它们原有的语义。
|
||||
|
||||
## 配置
|
||||
|
||||
|
||||
@@ -34,9 +34,9 @@
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-atomic-write": "workspace:^",
|
||||
"@deepseek-ai/dsh-credentials": "workspace:^",
|
||||
"@deepseek-ai/dsh-environment": "workspace:^",
|
||||
"@deepseek-ai/dsh-launch-environment": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-paths": "workspace:^",
|
||||
"@deepseek-ai/dsh-home-paths": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -47,9 +47,9 @@
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-atomic-write": "workspace:^",
|
||||
"@deepseek-ai/dsh-credentials": "workspace:^",
|
||||
"@deepseek-ai/dsh-environment": "workspace:^",
|
||||
"@deepseek-ai/dsh-launch-environment": "workspace:^",
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/dsh-paths": "workspace:^",
|
||||
"@deepseek-ai/dsh-home-paths": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
}
|
||||
}
|
||||
@@ -42,11 +42,11 @@ import { mkdir, readFile, stat } from 'node:fs/promises'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
import { Document, parseDocument, type YAMLError } from 'yaml'
|
||||
import { withFileLock, writeFileAtomic } from '@deepseek-ai/dsh-atomic-write'
|
||||
import { canonicalizeWatchPath, resolveDshHome } from '@deepseek-ai/dsh-paths'
|
||||
import { environmentOf } from '@deepseek-ai/dsh-environment'
|
||||
import { Credentials, credentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { canonicalizeWatchPath, resolveDshHome } from '@deepseek-ai/dsh-home-paths'
|
||||
import { launchEnvironmentOf } from '@deepseek-ai/dsh-launch-environment'
|
||||
import { CredentialProvider, credentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import type { CredentialInfo, CredentialRef, ResolvedCredential } from '@deepseek-ai/dsh-credentials'
|
||||
import type { EnvironmentEntry } from '@deepseek-ai/dsh-environment'
|
||||
import type { LaunchEnvironmentEntry } from '@deepseek-ai/dsh-launch-environment'
|
||||
|
||||
/** Basename of the credentials document inside the harness home. */
|
||||
export const CREDENTIALS_FILENAME = '.credentials.yaml'
|
||||
@@ -204,9 +204,9 @@ function renderDocument(text: string | undefined, ref: CredentialRef, value: str
|
||||
}
|
||||
|
||||
/** File-backed credentials provider (`$DSH_HOME/.credentials.yaml`). */
|
||||
export class CredentialsLocal extends Credentials {
|
||||
export class LocalCredentialProvider extends CredentialProvider {
|
||||
/* jscpd:ignore-start -- deliberate config-surface and lifecycle symmetry with
|
||||
settings-local (prefer symmetry for parallel values); extracting the shared
|
||||
settings-file (prefer symmetry for parallel values); extracting the shared
|
||||
shape would couple the two providers' teardown semantics across packages. */
|
||||
static Config: z<Config> = z.object({
|
||||
path: z.string(),
|
||||
@@ -248,7 +248,7 @@ export class CredentialsLocal extends Credentials {
|
||||
|
||||
/** The inherited-environment value for a reference, or `undefined` when empty or unset. */
|
||||
private inherited(ref: CredentialRef): string | undefined {
|
||||
const entry = environmentOf(this.ctx).getFrom(ref, ['process'])
|
||||
const entry = launchEnvironmentOf(this.ctx).getFrom(ref, ['process'])
|
||||
return entry !== undefined && entry.value.length > 0 ? entry.value : undefined
|
||||
}
|
||||
|
||||
@@ -257,8 +257,8 @@ export class CredentialsLocal extends Credentials {
|
||||
* it. The invoking project ranks over the user's home file, matching the
|
||||
* environment layering: the more specific location wins.
|
||||
*/
|
||||
private dotenvFallback(ref: CredentialRef): EnvironmentEntry | undefined {
|
||||
const entry = environmentOf(this.ctx).getFrom(ref, ['project-env', 'user-env'])
|
||||
private dotenvFallback(ref: CredentialRef): LaunchEnvironmentEntry | undefined {
|
||||
const entry = launchEnvironmentOf(this.ctx).getFrom(ref, ['project-env', 'user-env'])
|
||||
return entry !== undefined && entry.value.length > 0 ? entry : undefined
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ export class CredentialsLocal extends Credentials {
|
||||
}
|
||||
await this.loadInitial()
|
||||
if (!this.spec.watch) return
|
||||
/* jscpd:ignore-start -- same watcher discipline as settings-local by design:
|
||||
/* jscpd:ignore-start -- same watcher discipline as settings-file by design:
|
||||
the serialized-refresh and quiesce-on-dispose shape is the reviewed
|
||||
lifecycle contract, not accidental repetition. */
|
||||
const watcher = chokidarWatch(await canonicalizeWatchPath(this.spec.filename), {
|
||||
@@ -342,7 +342,7 @@ export class CredentialsLocal extends Credentials {
|
||||
}
|
||||
|
||||
/* jscpd:ignore-start -- the operation-chain and reload lifecycle is the same
|
||||
reviewed contract as settings-local, deliberately mirrored (prefer symmetry
|
||||
reviewed contract as settings-file, deliberately mirrored (prefer symmetry
|
||||
for parallel values); the two providers own different documents and
|
||||
failure policies, so extracting a shared helper would couple their teardown
|
||||
semantics across packages for a handful of lines. */
|
||||
@@ -434,7 +434,7 @@ export class CredentialsLocal extends Credentials {
|
||||
this.text = text
|
||||
}
|
||||
|
||||
/* jscpd:ignore-start -- same deliberate mirror of settings-local's reload and
|
||||
/* jscpd:ignore-start -- same deliberate mirror of settings-file's reload and
|
||||
reconcile policy: warn-and-keep on a reload, throw on a write, invariant
|
||||
failures propagate. */
|
||||
/**
|
||||
@@ -493,4 +493,4 @@ export class CredentialsLocal extends Credentials {
|
||||
}
|
||||
}
|
||||
|
||||
export default CredentialsLocal
|
||||
export default LocalCredentialProvider
|
||||
@@ -4,7 +4,7 @@ import { mkdtemp, rm } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { credentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { CredentialsLocal } from '../src/index.ts'
|
||||
import { LocalCredentialProvider } from '../src/index.ts'
|
||||
|
||||
// The atomic write is the gated asynchronous hold point inside a queued
|
||||
// write; gating it makes the dispose-versus-queued-write race fully
|
||||
@@ -42,7 +42,7 @@ describe('write-drain teardown', () => {
|
||||
const dir = await mkdtemp(join(tmpdir(), 'dsh-credentials-drain-'))
|
||||
cleanups.push(() => rm(dir, { recursive: true, force: true }))
|
||||
const ctx = new Context()
|
||||
const fiber = ctx.plugin(CredentialsLocal, { path: join(dir, '.credentials.yaml'), watch: false })
|
||||
const fiber = ctx.plugin(LocalCredentialProvider, { path: join(dir, '.credentials.yaml'), watch: false })
|
||||
await fiber
|
||||
const service = ctx.credentials
|
||||
|
||||
|
||||
@@ -4,9 +4,9 @@ import { mkdir, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { credentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { createEnvironmentSnapshot, DSH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-environment'
|
||||
import { createLaunchEnvironmentSnapshot, DSH_LAUNCH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-launch-environment'
|
||||
import type { CredentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { CredentialsLocal, resolveSpec } from '../src/index.ts'
|
||||
import { LocalCredentialProvider, resolveSpec } from '../src/index.ts'
|
||||
|
||||
/** Credential documents are seeded owner-only, exactly as the provider creates them. */
|
||||
function writeCredentials(file: string, text: string): Promise<void> {
|
||||
@@ -29,9 +29,9 @@ async function tempDir(): Promise<string> {
|
||||
return dir
|
||||
}
|
||||
|
||||
async function boot(config: ConstructorParameters<typeof CredentialsLocal>[1]): Promise<Context> {
|
||||
async function boot(config: ConstructorParameters<typeof LocalCredentialProvider>[1]): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
const fiber = ctx.plugin(CredentialsLocal, config)
|
||||
const fiber = ctx.plugin(LocalCredentialProvider, config)
|
||||
cleanups.push(async () => {
|
||||
await fiber.dispose()
|
||||
})
|
||||
@@ -102,7 +102,7 @@ describe('layering and reads', () => {
|
||||
const path = join(dir, 'occupied')
|
||||
await mkdir(path)
|
||||
const ctx = new Context()
|
||||
await expect(ctx.plugin(CredentialsLocal, { path, watch: false })).rejects.toThrow()
|
||||
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false })).rejects.toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -111,11 +111,11 @@ describe('layer ladder', () => {
|
||||
// invoking directory's .env supplies no credential at all.
|
||||
async function bootLayered(
|
||||
path: string,
|
||||
layers: Parameters<typeof createEnvironmentSnapshot>[0],
|
||||
layers: Parameters<typeof createLaunchEnvironmentSnapshot>[0],
|
||||
): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
ctx.provide(DSH_ENVIRONMENT_KEY, createEnvironmentSnapshot(layers))
|
||||
const fiber = ctx.plugin(CredentialsLocal, { path, watch: false })
|
||||
ctx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, createLaunchEnvironmentSnapshot(layers))
|
||||
const fiber = ctx.plugin(LocalCredentialProvider, { path, watch: false })
|
||||
cleanups.push(async () => { await fiber.dispose() })
|
||||
await fiber
|
||||
return ctx
|
||||
@@ -175,7 +175,7 @@ describe('layer ladder', () => {
|
||||
const ctx = new Context()
|
||||
// Before the contents are read at all: serving secrets out of a
|
||||
// world-readable file would make the 0600 the provider writes meaningless.
|
||||
await expect(ctx.plugin(CredentialsLocal, { path, watch: false }))
|
||||
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false }))
|
||||
.rejects.toThrow(/readable beyond its owner \(mode 644\)/)
|
||||
})
|
||||
|
||||
@@ -187,14 +187,14 @@ describe('layer ladder', () => {
|
||||
// reached at all is a misconfiguration: the parent is a file, so the
|
||||
// check fails with ENOTDIR rather than concluding "no credentials yet".
|
||||
const ctx = new Context()
|
||||
await expect(ctx.plugin(CredentialsLocal, { path: join(notADirectory, '.credentials.yaml'), watch: false }))
|
||||
await expect(ctx.plugin(LocalCredentialProvider, { path: join(notADirectory, '.credentials.yaml'), watch: false }))
|
||||
.rejects.toThrow(/ENOTDIR/)
|
||||
})
|
||||
|
||||
it('propagates a permission check rejected before the OS lookup', async () => {
|
||||
const dir = await tempDir()
|
||||
const ctx = new Context()
|
||||
await expect(ctx.plugin(CredentialsLocal, { path: join(dir, '.credentials\0.yaml'), watch: false }))
|
||||
await expect(ctx.plugin(LocalCredentialProvider, { path: join(dir, '.credentials\0.yaml'), watch: false }))
|
||||
.rejects.toMatchObject({ code: 'ERR_INVALID_ARG_VALUE' })
|
||||
})
|
||||
|
||||
@@ -206,7 +206,7 @@ describe('layer ladder', () => {
|
||||
// rather than silently serve nothing.
|
||||
await mkdir(path, { mode: 0o700 })
|
||||
const ctx = new Context()
|
||||
await expect(ctx.plugin(CredentialsLocal, { path, watch: false })).rejects.toThrow(/EISDIR/)
|
||||
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false })).rejects.toThrow(/EISDIR/)
|
||||
})
|
||||
|
||||
it('lets only the inherited environment shadow the store, read-only', async () => {
|
||||
@@ -240,7 +240,7 @@ describe('document validation', () => {
|
||||
const path = join(dir, '.credentials.yaml')
|
||||
await writeCredentials(path, text)
|
||||
const ctx = new Context()
|
||||
await expect(ctx.plugin(CredentialsLocal, { path, watch: false })).rejects.toThrow(message)
|
||||
await expect(ctx.plugin(LocalCredentialProvider, { path, watch: false })).rejects.toThrow(message)
|
||||
})
|
||||
|
||||
it('never puts a credential value in a diagnostic', async () => {
|
||||
@@ -253,7 +253,7 @@ describe('document validation', () => {
|
||||
await writeCredentials(path, `DSH_CRED_TEST: "${secret}\n`)
|
||||
let failure: unknown
|
||||
try {
|
||||
await new Context().plugin(CredentialsLocal, { path, watch: false })
|
||||
await new Context().plugin(LocalCredentialProvider, { path, watch: false })
|
||||
} catch (error) {
|
||||
failure = error
|
||||
}
|
||||
@@ -386,7 +386,7 @@ describe('document writes', () => {
|
||||
it('refuses writes after disposal', async () => {
|
||||
const dir = await tempDir()
|
||||
const ctx = new Context()
|
||||
const fiber = ctx.plugin(CredentialsLocal, { path: join(dir, '.credentials.yaml'), watch: false })
|
||||
const fiber = ctx.plugin(LocalCredentialProvider, { path: join(dir, '.credentials.yaml'), watch: false })
|
||||
await fiber
|
||||
// Capture the handle first: disposal also removes the ctx.credentials service.
|
||||
const service = ctx.credentials
|
||||
|
||||
@@ -8,7 +8,7 @@ import { mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { credentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { CredentialsLocal } from '../src/index.ts'
|
||||
import { LocalCredentialProvider } from '../src/index.ts'
|
||||
|
||||
/** Credential documents are seeded owner-only, exactly as the provider creates them. */
|
||||
function writeCredentials(file: string, text: string): Promise<void> {
|
||||
@@ -31,9 +31,9 @@ async function tempDir(): Promise<string> {
|
||||
return dir
|
||||
}
|
||||
|
||||
async function boot(config: ConstructorParameters<typeof CredentialsLocal>[1]): Promise<Context> {
|
||||
async function boot(config: ConstructorParameters<typeof LocalCredentialProvider>[1]): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
const fiber = ctx.plugin(CredentialsLocal, config)
|
||||
const fiber = ctx.plugin(LocalCredentialProvider, config)
|
||||
cleanups.push(async () => { await fiber.dispose() })
|
||||
await fiber
|
||||
return ctx
|
||||
|
||||
@@ -4,7 +4,7 @@ import { chmod, mkdtemp, rm, writeFile } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { credentialRef } from '@deepseek-ai/dsh-credentials'
|
||||
import { CredentialsLocal } from '../src/index.ts'
|
||||
import { LocalCredentialProvider } from '../src/index.ts'
|
||||
|
||||
const fsHarness = vi.hoisted(() => ({
|
||||
nextReadError: undefined as NodeJS.ErrnoException | undefined,
|
||||
@@ -78,9 +78,9 @@ async function tempDir(): Promise<string> {
|
||||
return dir
|
||||
}
|
||||
|
||||
async function boot(config: ConstructorParameters<typeof CredentialsLocal>[1]): Promise<Context> {
|
||||
async function boot(config: ConstructorParameters<typeof LocalCredentialProvider>[1]): Promise<Context> {
|
||||
const ctx = new Context()
|
||||
const fiber = ctx.plugin(CredentialsLocal, config)
|
||||
const fiber = ctx.plugin(LocalCredentialProvider, config)
|
||||
cleanups.push(async () => {
|
||||
await fiber.dispose()
|
||||
})
|
||||
@@ -174,7 +174,7 @@ describe('watcher pipeline', () => {
|
||||
const path = join(dir, '.credentials.yaml')
|
||||
await writeCredentials(path, 'DSH_CRED_PIPE: initial\n')
|
||||
const ctx = new Context()
|
||||
const fiber = ctx.plugin(CredentialsLocal, { path, debounceMs: 5 })
|
||||
const fiber = ctx.plugin(LocalCredentialProvider, { path, debounceMs: 5 })
|
||||
await fiber
|
||||
let disposed = false
|
||||
let postDisposeCommits = 0
|
||||
|
||||
@@ -21,16 +21,16 @@
|
||||
"path": "../../util/atomic-write"
|
||||
},
|
||||
{
|
||||
"path": "../../util/environment"
|
||||
"path": "../../util/launch-environment"
|
||||
},
|
||||
{
|
||||
"path": "../../util/paths"
|
||||
"path": "../../util/home-paths"
|
||||
},
|
||||
{
|
||||
"path": "../credentials"
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
"path": "../../runtime-diagnostics/invariants"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -37,17 +37,17 @@ export interface ResolvedCredential {
|
||||
|
||||
/** Source and writability facts for one reference, safe for configuration UIs — never the value. */
|
||||
export interface CredentialInfo {
|
||||
/** Whether {@link Credentials.resolve} would currently return a value. */
|
||||
/** Whether {@link CredentialProvider.resolve} would currently return a value. */
|
||||
configured: boolean
|
||||
/** Source layer currently supplying the value; absent while unconfigured. */
|
||||
source?: string
|
||||
/** Whether {@link Credentials.set} would currently succeed for this reference. */
|
||||
/** Whether {@link CredentialProvider.set} would currently succeed for this reference. */
|
||||
writable: boolean
|
||||
}
|
||||
|
||||
declare module '@deepseek-ai/cordis' {
|
||||
interface Context {
|
||||
credentials: Credentials
|
||||
credentials: CredentialProvider
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ declare module '@deepseek-ai/cordis' {
|
||||
* value is absent everywhere — `resolve` skips it, `describe` reports it
|
||||
* unconfigured — so a blank never masquerades as a configured secret.
|
||||
*/
|
||||
export abstract class Credentials extends Service {
|
||||
export abstract class CredentialProvider extends Service {
|
||||
constructor(ctx: Context) {
|
||||
super(ctx, 'credentials')
|
||||
}
|
||||
@@ -142,4 +142,4 @@ export abstract class Credentials extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
export default Credentials
|
||||
export default CredentialProvider
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { Context } from '@deepseek-ai/cordis'
|
||||
import InvariantService from '@deepseek-ai/dsh-invariants'
|
||||
import InvariantRegistry from '@deepseek-ai/dsh-invariants'
|
||||
import { credentialRef } from '../src/index.ts'
|
||||
import * as CredentialsInvariant from '../src/invariant.ts'
|
||||
import { MemoryCredentials } from './memory.ts'
|
||||
@@ -10,7 +10,7 @@ const REF = credentialRef('DEEPSEEK_API_KEY')
|
||||
describe('credentials invariant companion', () => {
|
||||
it('accepts a committed change emitted by a live service', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(InvariantService)
|
||||
await ctx.plugin(InvariantRegistry)
|
||||
await ctx.plugin(CredentialsInvariant)
|
||||
await ctx.plugin(MemoryCredentials)
|
||||
|
||||
@@ -19,7 +19,7 @@ describe('credentials invariant companion', () => {
|
||||
|
||||
it('fails an update event emitted without a live service', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(InvariantService)
|
||||
await ctx.plugin(InvariantRegistry)
|
||||
await ctx.plugin(CredentialsInvariant)
|
||||
|
||||
expect(() => { ctx.emit('credentials/updated', REF) }).toThrow(/invariant violated by "@deepseek-ai\/dsh-credentials"/)
|
||||
@@ -27,7 +27,7 @@ describe('credentials invariant companion', () => {
|
||||
|
||||
it('reserves the package name against duplicate registration', async () => {
|
||||
const ctx = new Context()
|
||||
await ctx.plugin(InvariantService)
|
||||
await ctx.plugin(InvariantRegistry)
|
||||
await ctx.plugin(CredentialsInvariant)
|
||||
|
||||
expect(() => {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import { Credentials } from '../src/index.ts'
|
||||
import { CredentialProvider } from '../src/index.ts'
|
||||
import type { CredentialInfo, CredentialRef, ResolvedCredential } from '../src/index.ts'
|
||||
|
||||
/**
|
||||
* In-memory credentials provider for interface and consumer tests: one
|
||||
* always-writable `memory` source seeded from plugin config.
|
||||
*/
|
||||
export class MemoryCredentials extends Credentials {
|
||||
export class MemoryCredentials extends CredentialProvider {
|
||||
private readonly store = new Map<string, string>()
|
||||
|
||||
constructor(ctx: Context, seed: Record<string, string> = {}) {
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"path": "../../util/brand"
|
||||
},
|
||||
{
|
||||
"path": "../../support/invariants"
|
||||
"path": "../../runtime-diagnostics/invariants"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user