@ai-ecoverse/slicc-agent 3.52.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/README.md +17 -13
  2. package/dist/client.js +1 -1
  3. package/dist/client.js.map +1 -1
  4. package/dist/host.js.map +1 -1
  5. package/dist/index.js +0 -3
  6. package/dist/index.js.map +2 -2
  7. package/dist/main.js +95 -22
  8. package/dist/main.js.map +2 -2
  9. package/dist/mcp/accounts.js +18 -14
  10. package/dist/mcp/accounts.js.map +2 -2
  11. package/dist/mcp/connection.js +0 -2
  12. package/dist/mcp/connection.js.map +2 -2
  13. package/dist/mcp/credentials.js +6 -15
  14. package/dist/mcp/credentials.js.map +2 -2
  15. package/dist/mcp/index.js +0 -1
  16. package/dist/mcp/index.js.map +2 -2
  17. package/dist/mcp/oauth.js +15 -20
  18. package/dist/mcp/oauth.js.map +2 -2
  19. package/dist/mcp/runtime.js +36 -14
  20. package/dist/mcp/runtime.js.map +2 -2
  21. package/dist/mcp/tools.js +4 -6
  22. package/dist/mcp/tools.js.map +2 -2
  23. package/dist/models/index.js +7 -4
  24. package/dist/models/index.js.map +2 -2
  25. package/dist/monitor/index.js +5 -10
  26. package/dist/monitor/index.js.map +2 -2
  27. package/dist/monitor/redact.js +4 -5
  28. package/dist/monitor/redact.js.map +2 -2
  29. package/dist/secrets/credentials.js +32 -0
  30. package/dist/secrets/credentials.js.map +7 -0
  31. package/dist/secrets/endpoints.js +111 -0
  32. package/dist/secrets/endpoints.js.map +7 -0
  33. package/dist/secrets/fetch.js +160 -0
  34. package/dist/secrets/fetch.js.map +7 -0
  35. package/dist/secrets/records.js +35 -0
  36. package/dist/secrets/records.js.map +7 -0
  37. package/dist/secrets/store.js +50 -0
  38. package/dist/secrets/store.js.map +7 -0
  39. package/dist/secrets/vault.js +58 -13
  40. package/dist/secrets/vault.js.map +2 -2
  41. package/dist/services.js.map +2 -2
  42. package/dist/settings.js +85 -23
  43. package/dist/settings.js.map +2 -2
  44. package/dist/skills/index.js +26 -3
  45. package/dist/skills/index.js.map +2 -2
  46. package/dist/spectrum/settings-port.js +24 -6
  47. package/dist/spectrum/settings-port.js.map +2 -2
  48. package/dist/types/host.d.ts +1 -1
  49. package/dist/types/index.d.ts +0 -1
  50. package/dist/types/main.d.ts +7 -2
  51. package/dist/types/mcp/accounts.d.ts +10 -4
  52. package/dist/types/mcp/connection.d.ts +0 -2
  53. package/dist/types/mcp/credentials.d.ts +6 -4
  54. package/dist/types/mcp/oauth.d.ts +3 -2
  55. package/dist/types/mcp/runtime.d.ts +18 -4
  56. package/dist/types/models/index.d.ts +2 -0
  57. package/dist/types/monitor/index.d.ts +0 -1
  58. package/dist/types/monitor/redact.d.ts +2 -2
  59. package/dist/types/secrets/credentials.d.ts +5 -0
  60. package/dist/types/secrets/endpoints.d.ts +27 -0
  61. package/dist/types/secrets/fetch.d.ts +13 -0
  62. package/dist/types/secrets/records.d.ts +13 -0
  63. package/dist/types/secrets/store.d.ts +7 -0
  64. package/dist/types/secrets/vault.d.ts +31 -1
  65. package/dist/types/services.d.ts +8 -1
  66. package/dist/types/settings.d.ts +17 -2
  67. package/dist/types/spectrum/settings-port.d.ts +6 -4
  68. package/package.json +5 -3
  69. package/dist/credentials.js +0 -100
  70. package/dist/credentials.js.map +0 -7
  71. package/dist/types/credentials.d.ts +0 -12
@@ -1,15 +1,17 @@
1
- import type { CredentialStore } from '@earendil-works/pi-ai';
2
1
  import { type McpServerConfig } from './config.ts';
3
2
  export declare const MCP_CREDENTIAL_PREFIX = "mcp:";
3
+ export interface McpRecords {
4
+ mcp(server: string, name?: string): {
5
+ placeholder: string;
6
+ } | undefined;
7
+ }
4
8
  export declare function credentialKey(server: string, url: string): Promise<string>;
5
9
  export declare function secretNames(config: McpServerConfig): string[];
6
10
  export type Resolved = {
7
11
  ok: true;
8
12
  headers: Record<string, string>;
9
- secrets: string[];
10
13
  } | {
11
14
  ok: false;
12
15
  missing: string[];
13
16
  };
14
- export declare function resolveHeaders(server: string, config: McpServerConfig, credentials: CredentialStore): Promise<Resolved>;
15
- export declare function scrub(text: string, secrets: readonly string[]): string;
17
+ export declare function resolveHeaders(server: string, config: McpServerConfig, records: McpRecords): Resolved;
@@ -1,6 +1,6 @@
1
- import type { CredentialStore } from '@earendil-works/pi-ai';
2
1
  import type { AuthProvider, McpFetch } from '@earendil-works/pi-mcp';
3
2
  import { authorizeMcp, McpOAuthAuthorizationRequiredError, type McpOAuthState } from '@earendil-works/pi-mcp/oauth';
3
+ import type { PlainStore } from '../secrets/store.ts';
4
4
  import type { McpSignIn } from '../services.ts';
5
5
  import type { McpServerConfig } from './config.ts';
6
6
  type Provider = Parameters<typeof authorizeMcp>[0];
@@ -25,7 +25,7 @@ export declare class StoredOAuth implements Provider {
25
25
  #private;
26
26
  readonly redirectUrl: string;
27
27
  readonly clientMetadata: Provider['clientMetadata'];
28
- constructor(server: OAuthServer, credentials: CredentialStore, redirectUrl: string);
28
+ constructor(server: OAuthServer, store: PlainStore, redirectUrl: string);
29
29
  get serverUrl(): string;
30
30
  load(): Promise<McpOAuthState>;
31
31
  update(change: (state: McpOAuthState) => McpOAuthState): Promise<void>;
@@ -47,6 +47,7 @@ export type { McpSignIn } from '../services.ts';
47
47
  export declare function beginSignIn(provider: StoredOAuth, server: OAuthServer, options: {
48
48
  fetch: McpFetch;
49
49
  resourceMetadataUrl?: URL;
50
+ register(tokenUrl: string): Promise<void>;
50
51
  }): Promise<McpSignIn>;
51
52
  export interface Callback {
52
53
  code?: string;
@@ -1,20 +1,35 @@
1
1
  import type { Context } from '@earendil-works/chord';
2
- import type { CredentialStore } from '@earendil-works/pi-ai';
3
2
  import type { Registry } from '@earendil-works/pi-durable';
4
3
  import type { ExecutionEnv } from '@earendil-works/pi-durable/env';
5
4
  import type { LickEvent, Licks } from '../licks/licks.ts';
5
+ import type { McpServerSource } from '../secrets/endpoints.ts';
6
+ import type { PlainStore } from '../secrets/store.ts';
6
7
  import { type McpAccounts } from './accounts.ts';
7
8
  import { McpCatalog } from './catalog.ts';
8
9
  import { type McpConfigProblem } from './config.ts';
9
10
  import { McpServerConnection } from './connection.ts';
11
+ import { type McpRecords } from './credentials.ts';
10
12
  export declare const MCP_LOG_MAX_BYTES: number;
11
13
  export { configPath, logPath, shown } from './paths.ts';
14
+ export interface McpVault {
15
+ records: McpRecords & {
16
+ refresh(context: Context): Promise<void>;
17
+ state: {
18
+ subscribe(listener: () => void): () => void;
19
+ };
20
+ };
21
+ fetch(server: string, base: typeof fetch): typeof fetch;
22
+ grant(server: string, base: typeof fetch): typeof fetch;
23
+ servers(list: readonly McpServerSource[]): Promise<void>;
24
+ token(server: string, url: string): Promise<void>;
25
+ }
12
26
  export interface McpAttach {
13
27
  licks: Licks;
14
28
  env: ExecutionEnv;
15
29
  home: string;
16
30
  agentDir?: string;
17
- credentials: CredentialStore;
31
+ store: PlainStore;
32
+ vault: McpVault;
18
33
  fetch: typeof fetch;
19
34
  version: string;
20
35
  reloadMs: number;
@@ -31,14 +46,13 @@ export interface ServerStatus {
31
46
  export type { McpAccounts } from './accounts.ts';
32
47
  export interface McpRuntime extends McpAccounts {
33
48
  status(): ServerStatus[];
34
- secrets(): string[];
35
49
  reload(context: Context): Promise<void>;
36
50
  close(context: Context): Promise<void>;
37
51
  }
38
52
  export declare function problemLick(problem: McpConfigProblem, home: string, dir?: string): LickEvent;
39
53
  export declare function stateLick(connection: McpServerConnection, cors: boolean): LickEvent | undefined;
40
54
  export declare function connectedLick(connection: McpServerConnection): LickEvent;
41
- export declare function logLine(server: string, params: unknown, secrets: readonly string[], at: Date): string;
55
+ export declare function logLine(server: string, params: unknown, at: Date): string;
42
56
  export declare function attachMcp(catalog: McpCatalog, options: McpAttach, context: Context): Promise<McpRuntime>;
43
57
  export declare function startMcp(registry: Registry, options: McpAttach, context: Context): Promise<{
44
58
  catalog: McpCatalog;
@@ -11,6 +11,8 @@ export interface ModelsOptions {
11
11
  agents: Agents;
12
12
  settings: Pick<AgentSettings, 'state'>;
13
13
  catalog: Pick<Models, 'getProviders' | 'getModels'>;
14
+ locked?: () => boolean;
14
15
  }
16
+ export declare const LOCKED_NOTE = "the vault is locked: unlock it to use these accounts";
15
17
  export declare function closest(wanted: string, ids: readonly string[], count?: number): string[];
16
18
  export declare function modelsCommand(options: ModelsOptions): (argv: readonly string[], caller: string | null, context: Context) => Promise<Answer>;
@@ -47,7 +47,6 @@ export interface MonitorOptions {
47
47
  name: string;
48
48
  uid: number;
49
49
  }[]>;
50
- secrets?: () => readonly string[];
51
50
  now?: () => number;
52
51
  timers?: Timers;
53
52
  ttlMs?: number;
@@ -1,5 +1,5 @@
1
1
  export declare const TEXT_MAX = 160;
2
2
  export declare function cut(text: string, max?: number): string;
3
- export declare function redacted(text: string, secrets: readonly string[]): string;
4
- export declare function commandLine(argv: readonly string[], secrets: readonly string[]): string;
3
+ export declare function redacted(text: string): string;
4
+ export declare function commandLine(argv: readonly string[]): string;
5
5
  export declare function program(argv: readonly string[]): string;
@@ -0,0 +1,5 @@
1
+ import type { CredentialStore } from '@earendil-works/pi-ai';
2
+ import type { VaultRecords } from './records.ts';
3
+ export declare const KEYS_IN_VAULT = "model keys are kept in seven's vault: enter them in Settings \u203A Accounts";
4
+ export type FieldsOf = (providerId: string) => Readonly<Record<string, string>> | undefined;
5
+ export declare function vaultCredentials(records: Pick<VaultRecords, 'model' | 'state'>, env?: FieldsOf): CredentialStore;
@@ -0,0 +1,27 @@
1
+ import type { McpServerEntry, ModelEndpoint } from '@ai-ecoverse/slicc-vault';
2
+ import type { ModelRoute } from './fetch.ts';
3
+ import type { AgentRecord } from './records.ts';
4
+ import type { Vault } from './vault.ts';
5
+ export declare const BEDROCK_ENDPOINTS: string[];
6
+ export declare function modelUrl(raw: string): boolean;
7
+ export declare function mcpUrl(raw: string): boolean;
8
+ export declare function pattern(base: string): RegExp;
9
+ export interface ModelBases {
10
+ provider: string;
11
+ urls: readonly string[];
12
+ }
13
+ export declare function modelRoute(bases: () => readonly ModelBases[], records: () => readonly AgentRecord[]): ModelRoute;
14
+ export declare function modelEndpoints(bases: readonly ModelBases[]): ModelEndpoint[];
15
+ export interface McpServerSource {
16
+ server: string;
17
+ url: string;
18
+ names: readonly string[];
19
+ }
20
+ export declare function mcpEndpoints(servers: readonly McpServerSource[], tokens: ReadonlyMap<string, string>): McpServerEntry[];
21
+ export interface Endpoints {
22
+ models(bases: readonly ModelBases[]): Promise<void>;
23
+ servers(servers: readonly McpServerSource[]): Promise<void>;
24
+ token(server: string, url: string): Promise<void>;
25
+ close(): void;
26
+ }
27
+ export declare function vaultEndpoints(vault: Pick<Vault, 'state' | 'connected' | 'endpoints'>): Endpoints;
@@ -0,0 +1,13 @@
1
+ import type { OutgoingRequest } from '@ai-ecoverse/slicc-vault';
2
+ import { type Vault } from './vault.ts';
3
+ type Fetch = typeof fetch;
4
+ type Port = Pick<Vault, 'connected' | 'needed' | 'model' | 'mcp' | 'refresh' | 'grant'>;
5
+ export type ModelRoute = (request: Request) => string | null | undefined;
6
+ export declare function absent(vault: Pick<Vault, 'connected' | 'needed'>): boolean;
7
+ export declare function refusal(error: unknown): Response;
8
+ export declare function safeError(error: unknown, original: OutgoingRequest, ready: OutgoingRequest): DOMException | TypeError;
9
+ export declare function vaultFetch(vault: Port, inner: Fetch, route: ModelRoute): Fetch;
10
+ export declare function mcpFetch(vault: Port, inner: Fetch, server: string): Fetch;
11
+ export declare const NO_VAULT_SIGN_IN = "MCP sign-in needs seven's vault: update seven";
12
+ export declare function grantFetch(vault: Port, server: string, base: Fetch): Fetch;
13
+ export {};
@@ -0,0 +1,13 @@
1
+ import type { AgentRecord } from '@ai-ecoverse/slicc-vault';
2
+ import { type Context, type MutableReplicatedState } from '@earendil-works/chord';
3
+ import type { Vault } from './vault.ts';
4
+ export type { AgentRecord } from '@ai-ecoverse/slicc-vault';
5
+ export interface VaultRecords {
6
+ readonly state: MutableReplicatedState<AgentRecord[]>;
7
+ refresh(context: Context): Promise<void>;
8
+ model(provider: string): AgentRecord | undefined;
9
+ mcp(server: string, name?: string): AgentRecord | undefined;
10
+ close(): void;
11
+ }
12
+ type Source = Pick<Vault, 'state' | 'records' | 'connected' | 'needed'>;
13
+ export declare function vaultRecords(vault: Source): VaultRecords;
@@ -0,0 +1,7 @@
1
+ import type { ExecutionEnv } from '@earendil-works/pi-durable/env';
2
+ export interface PlainStore {
3
+ get(key: string): Promise<unknown>;
4
+ set(key: string, value: unknown): Promise<void>;
5
+ }
6
+ export declare function memoryStore(): PlainStore;
7
+ export declare function fileStore(env: ExecutionEnv, path: string): PlainStore;
@@ -1,3 +1,4 @@
1
+ import type { AgentRecord, ErrorCode, McpServerEntry, ModelEndpoint, OAuthConfig, OutgoingRequest } from '@ai-ecoverse/slicc-vault';
1
2
  import { type MutableReplicatedState } from '@earendil-works/chord';
2
3
  import type { Scrub, Scrubbable, ScrubStream } from './scrub.ts';
3
4
  export type ScrubPair = {
@@ -14,14 +15,43 @@ export interface VaultState {
14
15
  }
15
16
  export declare const WAITING_MS = 2000;
16
17
  export declare const WAITING = "waiting for the vault";
18
+ export declare class VaultRefusal extends Error {
19
+ readonly code: ErrorCode | undefined;
20
+ constructor(code: ErrorCode | undefined, message: string);
21
+ }
22
+ export type RefreshTarget = {
23
+ server: string;
24
+ } | {
25
+ provider: string;
26
+ };
27
+ export interface Granted {
28
+ response: string | Uint8Array;
29
+ records: {
30
+ kind: string;
31
+ name: string;
32
+ placeholder: string;
33
+ }[];
34
+ expiresAt?: number;
35
+ }
36
+ export interface EndpointSet {
37
+ model: ModelEndpoint[];
38
+ mcp: McpServerEntry[];
39
+ }
17
40
  export declare class Vault implements Scrub {
18
41
  #private;
19
42
  readonly state: MutableReplicatedState<VaultState>;
20
43
  constructor(now?: () => number);
21
44
  get needed(): boolean;
22
- connect(port: MessagePort | undefined, scrub: unknown): void;
45
+ get connected(): boolean;
46
+ connect(port: MessagePort | undefined, scrub: unknown, locked?: unknown): void;
23
47
  ready(): Promise<void>;
24
48
  texts<T extends Scrubbable>(texts: readonly T[]): Promise<T[]>;
49
+ model(provider: string | undefined, request: OutgoingRequest): Promise<OutgoingRequest>;
50
+ mcp(server: string, request: OutgoingRequest): Promise<OutgoingRequest>;
51
+ records(): Promise<AgentRecord[]>;
52
+ grant(server: string, response: string | Uint8Array, oauth: OAuthConfig, name?: string): Promise<Granted>;
53
+ refresh(target: RefreshTarget, name?: string): Promise<string>;
54
+ endpoints(set: EndpointSet): Promise<void>;
25
55
  stream(): ScrubStream;
26
56
  }
27
57
  export declare function holdText(state: VaultState): string | undefined;
@@ -278,6 +278,13 @@ export interface AccountState {
278
278
  needs: 'cors-free-transport' | null;
279
279
  group?: 'providers' | 'mcp';
280
280
  secret?: 'api-key' | 'token';
281
+ store?: 'vault';
282
+ fields?: AccountField[];
283
+ }
284
+ export interface AccountField {
285
+ name: string;
286
+ label: string;
287
+ required?: boolean;
281
288
  }
282
289
  export interface BudgetState {
283
290
  provider: string;
@@ -301,7 +308,7 @@ export interface SettingsState {
301
308
  }
302
309
  export interface AgentSettings {
303
310
  readonly state: ReplicatedState<SettingsState>;
304
- connect(providerId: string, secret: string, region: string | null, context: Context): Promise<void>;
311
+ connect(providerId: string, secret: string | null, fields: Record<string, string> | null, context: Context): Promise<void>;
305
312
  disconnect(providerId: string, context: Context): Promise<void>;
306
313
  signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;
307
314
  }
@@ -2,19 +2,34 @@ import type { CredentialStore, Provider } from '@earendil-works/pi-ai';
2
2
  import { type MutableModels } from '@earendil-works/pi-ai/models';
3
3
  import { type Budget } from './adobe.ts';
4
4
  import type { McpAccounts } from './mcp/index.ts';
5
- import type { AgentSettings } from './services.ts';
5
+ import type { VaultRecords } from './secrets/records.ts';
6
+ import type { PlainStore } from './secrets/store.ts';
7
+ import type { AccountField, AgentSettings } from './services.ts';
6
8
  export declare const BEDROCK = "amazon-bedrock";
7
9
  export declare const DEFAULT_MODEL: {
8
10
  provider: string;
9
11
  modelId: string;
10
12
  };
11
13
  export declare const DEFAULT_REGIONS: Readonly<Record<string, string>>;
14
+ export declare const ACCOUNT_FIELDS: Readonly<Record<string, readonly AccountField[]>>;
15
+ export declare const SIGN_IN_NEEDS_VAULT = "Adobe sign-in needs seven's vault: update seven";
16
+ export declare const KEY_NEEDS_VAULT = "API keys are kept in seven's vault: update seven";
12
17
  export declare function sliccProviders(version?: string): Provider[];
13
18
  export declare function withDefaultRegions(credentials: CredentialStore): CredentialStore;
14
19
  export declare function createSliccModels(credentials: CredentialStore, providers?: Provider<import("@earendil-works/pi-ai").Api>[]): MutableModels;
20
+ export interface ProviderFields {
21
+ get(providerId: string): Readonly<Record<string, string>> | undefined;
22
+ env(providerId: string): Readonly<Record<string, string>> | undefined;
23
+ set(providerId: string, fields: Record<string, string> | undefined): Promise<void>;
24
+ }
25
+ export declare function providerFields(store: PlainStore, providers: readonly Provider[]): Promise<ProviderFields>;
15
26
  export declare function shown<T>(run: () => Promise<T>): Promise<T>;
16
27
  export type UsageReader = (token: string) => Promise<Budget | null>;
17
- export declare function createAgentSettings(models: MutableModels, credentials: CredentialStore, providers?: Provider<import("@earendil-works/pi-ai").Api>[], options?: {
28
+ export interface SettingsSources {
29
+ records: VaultRecords;
30
+ fields: ProviderFields;
31
+ }
32
+ export declare function createAgentSettings(models: MutableModels, sources: SettingsSources, providers?: Provider<import("@earendil-works/pi-ai").Api>[], options?: {
18
33
  usage?: UsageReader;
19
34
  every?: number;
20
35
  mcp?: McpAccounts;
@@ -3,9 +3,13 @@ import type { AgentSettings, SignIn } from '../services.ts';
3
3
  import type { AgentAdapter } from './agent-port.ts';
4
4
  import { Emitter } from './emitter.ts';
5
5
  export declare const SETTINGS_KEY = "slicc-agent.settings";
6
+ export type Sealed = {
7
+ sealed: true;
8
+ };
6
9
  export type Login = (providerId: string, signIn: () => Promise<SignIn | null>, options: {
7
10
  signal: AbortSignal;
8
- }) => Promise<string>;
11
+ }) => Promise<string | Sealed>;
12
+ export declare const SIGN_IN_NEEDS_VAULT = "Adobe sign-in needs seven's vault: update seven";
9
13
  export declare class SettingsAdapter extends Emitter<SettingsEvents> implements SettingsPort {
10
14
  #private;
11
15
  constructor(settings: AgentSettings, agent: AgentAdapter, storage: Pick<Storage, 'getItem' | 'setItem'> | null, login?: Login | null, mcp?: Login);
@@ -13,9 +17,7 @@ export declare class SettingsAdapter extends Emitter<SettingsEvents> implements
13
17
  update(patch: Partial<Settings>): void;
14
18
  models(): readonly ModelOption[];
15
19
  accounts(): readonly Account[];
16
- connect(id: string, secret?: string, options?: {
17
- region?: string;
18
- }): Promise<void>;
20
+ connect(id: string, secret?: string, fields?: Record<string, string>): Promise<void>;
19
21
  cancel(id: string): void;
20
22
  disconnect(id: string): void;
21
23
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-agent",
3
- "version": "3.52.0",
3
+ "version": "4.0.0",
4
4
  "description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -62,8 +62,9 @@
62
62
  },
63
63
  "devDependencies": {
64
64
  "@ai-ecoverse/slicc-kernel": "1.47.1",
65
+ "@ai-ecoverse/slicc-scrub": "1.0.0",
65
66
  "@ai-ecoverse/slicc-shared-web": "1.13.1",
66
- "@ai-ecoverse/slicc-spectrum": "1.68.3",
67
+ "@ai-ecoverse/slicc-spectrum": "1.69.2",
67
68
  "@ai-ecoverse/wasm-bash": "5.3.0-18",
68
69
  "@ai-ecoverse/wasm-coreutils": "9.12.0-5",
69
70
  "@ai-ecoverse/wasm-git": "2.55.0-15",
@@ -79,6 +80,7 @@
79
80
  },
80
81
  "dependencies": {
81
82
  "@ai-ecoverse/slicc-browsers": "1.5.0",
83
+ "@ai-ecoverse/slicc-vault": "1.9.0",
82
84
  "@earendil-works/chord": "1.0.4",
83
85
  "@earendil-works/pi-ai": "1.0.4",
84
86
  "@earendil-works/pi-client": "1.0.4",
@@ -91,7 +93,7 @@
91
93
  },
92
94
  "peerDependencies": {
93
95
  "@ai-ecoverse/slicc-kernel": ">=1.47.1 <2",
94
- "@ai-ecoverse/slicc-spectrum": "^1.39.0"
96
+ "@ai-ecoverse/slicc-spectrum": "^1.59.0"
95
97
  },
96
98
  "peerDependenciesMeta": {
97
99
  "@ai-ecoverse/slicc-spectrum": {
@@ -1,100 +0,0 @@
1
- const CREDENTIALS_DATABASE = "slicc-agent-credentials";
2
- function request(operation) {
3
- return new Promise((resolve, reject) => {
4
- operation.onsuccess = () => resolve(operation.result);
5
- operation.onerror = () => reject(operation.error);
6
- });
7
- }
8
- function open(name) {
9
- const opening = indexedDB.open(name, 1);
10
- opening.onupgradeneeded = () => {
11
- opening.result.createObjectStore("keys");
12
- opening.result.createObjectStore("credentials");
13
- };
14
- return request(opening);
15
- }
16
- async function sealingKey(db) {
17
- const keys = db.transaction("keys", "readonly").objectStore("keys");
18
- const existing = await request(keys.get("aes"));
19
- if (existing) return existing;
20
- const key = await crypto.subtle.generateKey({ name: "AES-GCM", length: 256 }, false, [
21
- "encrypt",
22
- "decrypt"
23
- ]);
24
- const store = db.transaction("keys", "readwrite").objectStore("keys");
25
- await request(store.add(key, "aes")).catch(() => void 0);
26
- return await request(
27
- db.transaction("keys", "readonly").objectStore("keys").get("aes")
28
- );
29
- }
30
- class EncryptedCredentialStore {
31
- #db;
32
- #key;
33
- #chains = /* @__PURE__ */ new Map();
34
- constructor(db, key) {
35
- this.#db = db;
36
- this.#key = key;
37
- }
38
- static async open(name = CREDENTIALS_DATABASE) {
39
- const db = await open(name);
40
- return new EncryptedCredentialStore(db, await sealingKey(db));
41
- }
42
- #store(mode) {
43
- return this.#db.transaction("credentials", mode).objectStore("credentials");
44
- }
45
- async read(providerId) {
46
- const sealed = await request(this.#store("readonly").get(providerId));
47
- if (!sealed) return void 0;
48
- const plain = await crypto.subtle.decrypt(
49
- { name: "AES-GCM", iv: sealed.iv },
50
- this.#key,
51
- sealed.data
52
- );
53
- return JSON.parse(new TextDecoder().decode(plain));
54
- }
55
- async list() {
56
- const ids = await request(this.#store("readonly").getAllKeys());
57
- const found = [];
58
- for (const providerId of ids) {
59
- const credential = await this.read(providerId);
60
- if (credential) found.push({ providerId, type: credential.type });
61
- }
62
- return found;
63
- }
64
- #serial(providerId, operation) {
65
- const result = (this.#chains.get(providerId) ?? Promise.resolve()).then(operation);
66
- this.#chains.set(
67
- providerId,
68
- result.catch(() => void 0)
69
- );
70
- return result;
71
- }
72
- modify(providerId, fn) {
73
- return this.#serial(providerId, async () => {
74
- const current = await this.read(providerId);
75
- const next = await fn(current);
76
- if (next === void 0) return current;
77
- const iv = crypto.getRandomValues(new Uint8Array(12));
78
- const data = await crypto.subtle.encrypt(
79
- { name: "AES-GCM", iv },
80
- this.#key,
81
- new TextEncoder().encode(JSON.stringify(next))
82
- );
83
- await request(this.#store("readwrite").put({ iv, data }, providerId));
84
- return next;
85
- });
86
- }
87
- delete(providerId) {
88
- return this.#serial(providerId, async () => {
89
- await request(this.#store("readwrite").delete(providerId));
90
- });
91
- }
92
- close() {
93
- this.#db.close();
94
- }
95
- }
96
- export {
97
- CREDENTIALS_DATABASE,
98
- EncryptedCredentialStore
99
- };
100
- //# sourceMappingURL=credentials.js.map
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../src/credentials.ts"],
4
- "sourcesContent": ["import type { Credential, CredentialInfo, CredentialStore } from '@earendil-works/pi-ai';\n\nexport const CREDENTIALS_DATABASE = 'slicc-agent-credentials';\n\ninterface Sealed {\n iv: Uint8Array<ArrayBuffer>;\n data: ArrayBuffer;\n}\n\nfunction request<T>(operation: IDBRequest<T>): Promise<T> {\n return new Promise((resolve, reject) => {\n operation.onsuccess = () => resolve(operation.result);\n operation.onerror = () => reject(operation.error);\n });\n}\n\nfunction open(name: string): Promise<IDBDatabase> {\n const opening = indexedDB.open(name, 1);\n opening.onupgradeneeded = () => {\n opening.result.createObjectStore('keys');\n opening.result.createObjectStore('credentials');\n };\n return request(opening);\n}\n\nasync function sealingKey(db: IDBDatabase): Promise<CryptoKey> {\n const keys = db.transaction('keys', 'readonly').objectStore('keys');\n const existing = (await request(keys.get('aes'))) as CryptoKey | undefined;\n if (existing) return existing;\n const key = await crypto.subtle.generateKey({ name: 'AES-GCM', length: 256 }, false, [\n 'encrypt',\n 'decrypt',\n ]);\n const store = db.transaction('keys', 'readwrite').objectStore('keys');\n await request(store.add(key, 'aes')).catch(() => undefined);\n return (await request(\n db.transaction('keys', 'readonly').objectStore('keys').get('aes')\n )) as CryptoKey;\n}\n\nexport class EncryptedCredentialStore implements CredentialStore {\n readonly #db: IDBDatabase;\n readonly #key: CryptoKey;\n readonly #chains = new Map<string, Promise<unknown>>();\n\n private constructor(db: IDBDatabase, key: CryptoKey) {\n this.#db = db;\n this.#key = key;\n }\n\n static async open(name = CREDENTIALS_DATABASE): Promise<EncryptedCredentialStore> {\n const db = await open(name);\n return new EncryptedCredentialStore(db, await sealingKey(db));\n }\n\n #store(mode: IDBTransactionMode): IDBObjectStore {\n return this.#db.transaction('credentials', mode).objectStore('credentials');\n }\n\n async read(providerId: string): Promise<Credential | undefined> {\n const sealed = (await request(this.#store('readonly').get(providerId))) as Sealed | undefined;\n if (!sealed) return undefined;\n const plain = await crypto.subtle.decrypt(\n { name: 'AES-GCM', iv: sealed.iv },\n this.#key,\n sealed.data\n );\n return JSON.parse(new TextDecoder().decode(plain)) as Credential;\n }\n\n async list(): Promise<readonly CredentialInfo[]> {\n const ids = (await request(this.#store('readonly').getAllKeys())) as string[];\n const found: CredentialInfo[] = [];\n for (const providerId of ids) {\n const credential = await this.read(providerId);\n if (credential) found.push({ providerId, type: credential.type });\n }\n return found;\n }\n\n #serial<T>(providerId: string, operation: () => Promise<T>): Promise<T> {\n const result = (this.#chains.get(providerId) ?? Promise.resolve()).then(operation);\n this.#chains.set(\n providerId,\n result.catch(() => undefined)\n );\n return result;\n }\n\n modify(\n providerId: string,\n fn: (current: Credential | undefined) => Promise<Credential | undefined>\n ): Promise<Credential | undefined> {\n return this.#serial(providerId, async () => {\n const current = await this.read(providerId);\n const next = await fn(current);\n if (next === undefined) return current;\n const iv = crypto.getRandomValues(new Uint8Array(12));\n const data = await crypto.subtle.encrypt(\n { name: 'AES-GCM', iv },\n this.#key,\n new TextEncoder().encode(JSON.stringify(next))\n );\n await request(this.#store('readwrite').put({ iv, data } satisfies Sealed, providerId));\n return next;\n });\n }\n\n delete(providerId: string): Promise<void> {\n return this.#serial(providerId, async () => {\n await request(this.#store('readwrite').delete(providerId));\n });\n }\n\n close(): void {\n this.#db.close();\n }\n}\n"],
5
- "mappings": "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",
6
- "names": []
7
- }
@@ -1,12 +0,0 @@
1
- import type { Credential, CredentialInfo, CredentialStore } from '@earendil-works/pi-ai';
2
- export declare const CREDENTIALS_DATABASE = "slicc-agent-credentials";
3
- export declare class EncryptedCredentialStore implements CredentialStore {
4
- #private;
5
- private constructor();
6
- static open(name?: string): Promise<EncryptedCredentialStore>;
7
- read(providerId: string): Promise<Credential | undefined>;
8
- list(): Promise<readonly CredentialInfo[]>;
9
- modify(providerId: string, fn: (current: Credential | undefined) => Promise<Credential | undefined>): Promise<Credential | undefined>;
10
- delete(providerId: string): Promise<void>;
11
- close(): void;
12
- }