Add provider-instance identity and auth.json storage for multiple credentials per provider. - Export provider-instance key parsing, validation, and reserved metadata helpers. - Resolve, list, mutate, and select named credential instances atomically in auth storage. - Preserve legacy bare-key hydration and document the auth.json instance contract. - Cover provider instance parsing, storage behavior, and concurrent writes. Files changed: .changeset/fn-8651-provider-instances.md | 7 + docs/secrets.md | 8 + .../src/__tests__/oauth-credential-interop.test.ts | 16 ++ packages/core/src/index.ts | 16 ++ packages/core/src/oauth-credential-interop.ts | 15 +- packages/core/src/provider-instance.test.ts | 24 +++ packages/core/src/provider-instance.ts | 65 +++++++ .../src/__tests__/auth-storage-concurrency.test.ts | 13 ++ .../src/__tests__/auth-storage-instances.test.ts | 75 ++++++++ packages/engine/src/auth-storage.ts | 214 +++++++++++++-------- 10 files changed, 367 insertions(+), 86 deletions(-) Fusion-Task-Id: FN-8651 Fusion-Task-Lineage: cfabe496-60f9-4166-a09f-87ea2028cfd9 Co-authored-by: Fusion (runfusion.ai) <noreply@runfusion.ai>
25 lines
1.3 KiB
TypeScript
25 lines
1.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
DEFAULT_PROVIDER_INSTANCE_ID,
|
|
PROVIDER_INSTANCE_ID_MAX_LENGTH,
|
|
formatProviderInstanceKey,
|
|
isReservedAuthStorageKey,
|
|
parseProviderInstanceKey,
|
|
} from "./provider-instance.js";
|
|
|
|
describe("provider instance keys", () => {
|
|
it("round trips bare defaults and named instances", () => {
|
|
expect(parseProviderInstanceKey(formatProviderInstanceKey({ providerId: "anthropic", instanceId: DEFAULT_PROVIDER_INSTANCE_ID }))).toEqual({ providerId: "anthropic", instanceId: DEFAULT_PROVIDER_INSTANCE_ID });
|
|
expect(parseProviderInstanceKey(formatProviderInstanceKey({ providerId: "anthropic", instanceId: "work" }))).toEqual({ providerId: "anthropic", instanceId: "work" });
|
|
});
|
|
|
|
it("rejects non-invertible provider and instance names", () => {
|
|
for (const value of ["", " ", "a b", "a[b", "a]b", "a".repeat(PROVIDER_INSTANCE_ID_MAX_LENGTH + 1)]) {
|
|
expect(() => formatProviderInstanceKey({ providerId: value, instanceId: "work" })).toThrow();
|
|
expect(() => formatProviderInstanceKey({ providerId: "provider", instanceId: value })).toThrow();
|
|
}
|
|
for (const key of ["p[", "p]", "p[]", "p[a[b]", "p[default]", ""]) expect(parseProviderInstanceKey(key)).toBeUndefined();
|
|
expect(isReservedAuthStorageKey("__fusionDefaultInstances")).toBe(true);
|
|
});
|
|
});
|