@opengeni/vaults-keeper 0.0.0-stage → 3.2.2
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.
- package/LICENSE +190 -0
- package/README.md +147 -2
- package/dist/bootstrap.d.ts +40 -0
- package/dist/config.d.ts +41 -0
- package/dist/connection.d.ts +37 -0
- package/dist/contract.d.ts +6 -0
- package/dist/errors.d.ts +36 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +1450 -0
- package/dist/index.js.map +1 -0
- package/dist/mapping.d.ts +59 -0
- package/dist/naming.d.ts +8 -0
- package/dist/operations.d.ts +7 -0
- package/dist/provider.d.ts +81 -0
- package/dist/sdk.d.ts +81 -0
- package/package.json +42 -4
- package/src/bootstrap.ts +182 -0
- package/src/config.ts +161 -0
- package/src/connection.ts +75 -0
- package/src/contract.ts +29 -0
- package/src/errors.ts +196 -0
- package/src/index.ts +45 -0
- package/src/mapping.ts +373 -0
- package/src/naming.ts +44 -0
- package/src/operations.ts +65 -0
- package/src/provider.ts +681 -0
- package/src/sdk.ts +282 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/contract.ts","../src/config.ts","../src/errors.ts","../src/naming.ts","../src/mapping.ts","../src/operations.ts","../src/sdk.ts","../src/provider.ts","../src/bootstrap.ts","../src/connection.ts"],"sourcesContent":["/**\n * The shared vault contracts this adapter implements, re-exported for the\n * package's modules so every file names one source.\n */\nexport {\n VaultProviderError,\n type ProviderCallBudget,\n type ProviderCallOperation,\n type ProviderFieldMeta,\n type ProviderFieldValue,\n type ProviderItemMeta,\n type ProviderVault,\n type ProviderWriteField,\n type ProviderWriteItem,\n type VaultProvider,\n type VaultProviderAuthority,\n type VaultProviderCapabilities,\n type VaultProviderContext,\n type VaultProviderErrorCode,\n} from \"@opengeni/vaults\";\nexport {\n VAULT_LIMITS,\n parseTotpInput,\n type SecretMaterial,\n type TotpParams,\n type VaultFieldKind,\n type VaultItemType,\n type VaultProviderOperations,\n} from \"@opengeni/contracts\";\n","import { VaultProviderError } from \"./contract\";\nimport type { KeyValueStorage } from \"./sdk\";\n\n/** Region prefixes of a one-time token (`US:…`), as mapped by SDK 17.6.0 `initializeStorage`. */\nexport const KEEPER_REGION_HOSTS = {\n US: \"keepersecurity.com\",\n EU: \"keepersecurity.eu\",\n AU: \"keepersecurity.com.au\",\n GOV: \"govcloud.keepersecurity.us\",\n JP: \"keepersecurity.jp\",\n CA: \"keepersecurity.ca\",\n IL5: \"il5.keepersecurity.us\",\n} as const;\n\n/**\n * Hosts a configuration may talk to. The SDK treats an unknown token prefix\n * as a host name, so without this list a crafted token or configuration could\n * point Opengeni's server at an arbitrary host.\n */\nexport const KEEPER_DEFAULT_ALLOWED_HOSTS: readonly string[] = Object.values(KEEPER_REGION_HOSTS);\n\n/** Keys of the standard KSM JSON configuration. Bytes are standard base64. */\nexport const KEEPER_CONFIG_KEYS = [\n \"hostname\",\n \"clientId\",\n \"clientKey\",\n \"privateKey\",\n \"appKey\",\n \"appOwnerPublicKey\",\n \"serverPublicKeyId\",\n \"serverPublicKey\",\n] as const;\nexport type KeeperConfigKey = (typeof KEEPER_CONFIG_KEYS)[number];\nconst KNOWN = new Set<string>(KEEPER_CONFIG_KEYS);\n\nexport type KeeperConfigValues = Map<KeeperConfigKey, string>;\n\nfunction invalid(message: string): never {\n throw new VaultProviderError(\"provider_auth_invalid\", message);\n}\n\n/**\n * Parses a bound KSM configuration (JSON, or base64 of JSON as Keeper tools\n * export it, or the already parsed string record). Unknown keys are dropped;\n * the client must already be bound (appKey present).\n */\nexport function parseKeeperConfiguration(\n input: string | Readonly<Record<string, string>>,\n): KeeperConfigValues {\n if (typeof input !== \"string\") {\n if (!input || typeof input !== \"object\" || Array.isArray(input)) {\n return invalid(\"The Keeper configuration is not KSM JSON\");\n }\n return valuesOf(input);\n }\n let text = input.trim();\n if (!text.startsWith(\"{\")) {\n try {\n text = Buffer.from(text, \"base64\").toString(\"utf8\").trim();\n } catch {\n invalid(\"The Keeper configuration is not KSM JSON\");\n }\n }\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n return invalid(\"The Keeper configuration is not KSM JSON\");\n }\n if (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n return invalid(\"The Keeper configuration is not KSM JSON\");\n }\n return valuesOf(parsed as Record<string, unknown>);\n}\n\nfunction valuesOf(parsed: Readonly<Record<string, unknown>>): KeeperConfigValues {\n const values: KeeperConfigValues = new Map();\n for (const [key, value] of Object.entries(parsed)) {\n if (!KNOWN.has(key)) continue;\n if (typeof value !== \"string\" || value.length === 0 || value.length > 4096) {\n invalid(`The Keeper configuration has an invalid ${key}`);\n }\n values.set(key as KeeperConfigKey, value);\n }\n for (const key of [\"hostname\", \"clientId\", \"privateKey\", \"appKey\"] as const) {\n if (!values.get(key)) {\n invalid(\n key === \"appKey\"\n ? \"The Keeper configuration is not bound yet; connect with a one-time token\"\n : `The Keeper configuration has no ${key}`,\n );\n }\n }\n return values;\n}\n\n/** The canonical JSON form (sorted known keys) handed to the persistence callback. */\nexport function serializeKeeperConfiguration(values: KeeperConfigValues): string {\n const out: Record<string, string> = {};\n for (const key of KEEPER_CONFIG_KEYS) {\n const value = values.get(key);\n if (value !== undefined) out[key] = value;\n }\n return JSON.stringify(out);\n}\n\n/** The canonical string record of a bound configuration, for structured storage. */\nexport function keeperConfigurationRecord(\n configuration: string | Readonly<Record<string, string>>,\n): Record<string, string> {\n return JSON.parse(\n serializeKeeperConfiguration(parseKeeperConfiguration(configuration)),\n ) as Record<string, string>;\n}\n\nexport function assertAllowedHost(\n hostname: string | undefined,\n allowed: readonly string[],\n): string {\n const host = (hostname ?? \"\").trim().toLowerCase();\n if (!host || !allowed.includes(host)) {\n throw new VaultProviderError(\n \"provider_auth_invalid\",\n \"The Keeper region host is not one Opengeni connects to\",\n );\n }\n return host;\n}\n\n/**\n * In-memory KSM storage over a copy of the configuration. Nothing reaches\n * disk; `changed` reports whether the SDK rewrote any persisted key (binding,\n * server key rotation) so the caller can persist the new configuration.\n */\nexport function memoryKeeperStorage(initial: KeeperConfigValues = new Map()): KeyValueStorage & {\n readonly values: KeeperConfigValues;\n changed(): boolean;\n} {\n const values: KeeperConfigValues = new Map(initial);\n const before = serializeKeeperConfiguration(initial);\n const set = (key: string, value: string) => {\n // Session keys (folder, record and file keys) are never persisted by the\n // SDK; only configuration keys arrive here.\n if (!KNOWN.has(key)) throw new Error(`unexpected Keeper storage key ${key}`);\n values.set(key as KeeperConfigKey, value);\n };\n return {\n values,\n changed: () => serializeKeeperConfiguration(values) !== before,\n getString: async (key) => values.get(key as KeeperConfigKey),\n saveString: async (key, value) => set(key, value),\n getBytes: async (key) => {\n const value = values.get(key as KeeperConfigKey);\n return value === undefined ? undefined : new Uint8Array(Buffer.from(value, \"base64\"));\n },\n saveBytes: async (key, value) => set(key, Buffer.from(value).toString(\"base64\")),\n delete: async (key) => {\n values.delete(key as KeeperConfigKey);\n },\n };\n}\n","import { VaultProviderError } from \"./contract\";\n\n/**\n * Keeper Secrets Manager errors as SDK 17.6.0 raises them: a non-200 response\n * becomes `new Error(<first 1000 bytes of the body>)`, where the body is JSON\n * such as `{\"path\":\"…\",\"result_code\":\"access_denied\",\"message\":\"…\"}` (older\n * servers use `error` for the code); an empty error body becomes\n * `unknown ksm error, code <status>`; exhausted throttle retries raise\n * `KeeperThrottleError`; request deadlines raise `KeeperError(\"Request to …\n * timed out after …ms\")`. These shapes come from the SDK source and Keeper's\n * documentation; Keeper does not publish a complete result-code table, so the\n * message patterns below are deliberately conservative.\n */\nconst AUTH_HINT =\n /signature|client ?id|clientid|one[- ]?time|token|expired|ip address|ip lock|locked out|not bound|unbound|device|revoked/i;\nconst NOT_FOUND_HINT = /not found|does not exist|no such|unknown (?:record|folder)/i;\nconst CONFLICT_HINT = /revision|out of (?:date|sync)|conflict|modified/i;\n\nexport interface KeeperErrorBody {\n code: string | null;\n message: string;\n retryAfterSeconds: number | null;\n}\n\n/** Parses the JSON error body the SDK embeds in its Error message. */\nexport function keeperErrorBody(error: unknown): KeeperErrorBody | null {\n if (!(error instanceof Error)) return null;\n const text = error.message.trim();\n if (!text.startsWith(\"{\")) return null;\n try {\n const body = JSON.parse(text) as Record<string, unknown>;\n const code = body.result_code ?? body.error;\n const retry = body.retry_after;\n return {\n code: typeof code === \"string\" ? code.slice(0, 64) : null,\n message: typeof body.message === \"string\" ? body.message : \"\",\n retryAfterSeconds: typeof retry === \"number\" && retry >= 0 ? retry : null,\n };\n } catch {\n // A body cut at 1000 bytes may not parse; fall back to the code alone.\n const code = /\"(?:result_code|error)\"\\s*:\\s*\"([a-z_]{1,64})\"/.exec(text)?.[1] ?? null;\n return { code, message: \"\", retryAfterSeconds: null };\n }\n}\n\nfunction safeCode(code: string | null): string {\n return code && /^[a-z0-9_]{1,64}$/i.test(code) ? code : \"error\";\n}\n\nexport function isAbortLike(error: unknown): boolean {\n if (!(error instanceof Error)) return false;\n return (\n error.name === \"AbortError\" ||\n error.name === \"TimeoutError\" ||\n /timed out after \\d+ms/.test(error.message)\n );\n}\n\n/**\n * Maps any failure of a read-side operation. stderr-like SDK text never\n * leaves this function; only a closed result code may appear in messages.\n */\nexport function mapKeeperError(error: unknown, subject: string): VaultProviderError {\n if (error instanceof VaultProviderError) return error;\n if (error instanceof Error && error.name === \"KeeperThrottleError\") {\n return new VaultProviderError(\n \"provider_rate_limited\",\n \"Keeper is rate limiting this application\",\n 60_000,\n );\n }\n if (isAbortLike(error)) {\n return new VaultProviderError(\n \"provider_unavailable\",\n `Keeper did not answer in time (${subject})`,\n );\n }\n const body = keeperErrorBody(error);\n if (body) {\n const { code, message } = body;\n if (code === \"throttled\") {\n return new VaultProviderError(\n \"provider_rate_limited\",\n \"Keeper is rate limiting this application\",\n (body.retryAfterSeconds ?? 60) * 1000,\n );\n }\n if (\n code === \"access_denied\" ||\n code === \"invalid_client\" ||\n code === \"invalid_client_version\"\n ) {\n if (code !== \"access_denied\" || AUTH_HINT.test(message)) {\n return new VaultProviderError(\n \"provider_auth_invalid\",\n \"Keeper rejected this application's credentials; reconnect with a new one-time token\",\n );\n }\n if (NOT_FOUND_HINT.test(message)) {\n return new VaultProviderError(\n \"provider_not_found\",\n \"No such Keeper shared folder or record\",\n );\n }\n return new VaultProviderError(\n \"provider_permission_denied\",\n `The Keeper application may not ${subject}`,\n );\n }\n if (\n NOT_FOUND_HINT.test(message) ||\n (code && /not_found|invalid_record|record_uid/.test(code))\n ) {\n return new VaultProviderError(\"provider_not_found\", \"No such Keeper shared folder or record\");\n }\n if (CONFLICT_HINT.test(message) || (code && /revision|conflict/.test(code))) {\n return new VaultProviderError(\n \"provider_conflict\",\n \"The Keeper record changed since it was read; read it again before writing\",\n );\n }\n return new VaultProviderError(\n \"provider_unavailable\",\n `Keeper rejected the request (${safeCode(code)})`,\n );\n }\n const status =\n error instanceof Error ? /unknown ksm error, code (\\d{3})/.exec(error.message)?.[1] : undefined;\n if (status) {\n const code = Number(status);\n if (code === 401) {\n return new VaultProviderError(\n \"provider_auth_invalid\",\n \"Keeper rejected this application's credentials\",\n );\n }\n if (code === 403) {\n return new VaultProviderError(\n \"provider_permission_denied\",\n `The Keeper application may not ${subject}`,\n );\n }\n if (code === 404)\n return new VaultProviderError(\"provider_not_found\", \"No such Keeper shared folder or record\");\n if (code === 429)\n return new VaultProviderError(\n \"provider_rate_limited\",\n \"Keeper is rate limiting this application\",\n 60_000,\n );\n return new VaultProviderError(\"provider_unavailable\", `Keeper returned HTTP ${code}`);\n }\n return new VaultProviderError(\"provider_unavailable\", `Keeper could not ${subject}`);\n}\n\n/** Tracks one mutation's requests so a failure can be classified as definite or unknown. */\nexport interface MutationTracker {\n /** Requests started for the mutation itself. */\n sent: number;\n /** Status of the last mutation response, if one arrived. */\n lastStatus: number | null;\n}\n\n/**\n * Statuses with which Keeper refuses a request before applying it: a bad or\n * unauthorised request (400, 401, 403), a missing target (404), a revision\n * conflict (409) or throttling (429). Any other status after the request was\n * sent (5xx from Keeper or a proxy, an unexpected 2xx or 3xx) may follow an\n * applied change.\n */\nexport const KEEPER_DEFINITE_REJECTION_STATUSES: ReadonlySet<number> = new Set([\n 400, 401, 403, 404, 409, 429,\n]);\n\n/**\n * A mutation failure is definite only when nothing was sent, or Keeper\n * answered the last request with a known rejection status. A transport\n * failure, deadline or abort after sending, any other status (502 included),\n * or any failure after a 200, leaves the outcome unknown.\n */\nexport function mapKeeperMutationError(\n error: unknown,\n subject: string,\n tracker: MutationTracker,\n): VaultProviderError {\n const definite =\n tracker.sent === 0 ||\n (tracker.lastStatus !== null && KEEPER_DEFINITE_REJECTION_STATUSES.has(tracker.lastStatus));\n if (!definite) {\n return new VaultProviderError(\n \"provider_outcome_unknown\",\n `Keeper may or may not have completed \"${subject}\"; check the record before retrying`,\n );\n }\n return mapKeeperError(error, subject);\n}\n","import { type TotpParams, VAULT_LIMITS } from \"./contract\";\n\n// Mirrors contracts isValidSecretName (Q-10): no / { } # \\ or control chars,\n// trimmed, 1..120 chars, not \"id:…\"; field names additionally may not be \"otp\".\nconst FORBIDDEN_NAME_CHARS = /[/{}#\\\\\\u0000-\\u001f\\u007f-\\u009f]/g;\n\nexport function nameKey(name: string): string {\n return name.normalize(\"NFC\").trim().toLowerCase();\n}\n\nexport function safeSecretName(raw: string, fallback: string): string {\n const max = VAULT_LIMITS.nameMaxChars;\n let name = raw.replace(FORBIDDEN_NAME_CHARS, \"-\").trim().slice(0, max).trim();\n if (!name) name = fallback.replace(FORBIDDEN_NAME_CHARS, \"-\").trim().slice(0, max) || \"item\";\n if (/^id:/i.test(name)) name = `id-${name.slice(3)}`;\n return name;\n}\n\nexport function safeFieldName(raw: string, fallback: string): string {\n const name = safeSecretName(raw, fallback);\n return nameKey(name) === \"otp\" ? \"otp-code\" : name;\n}\n\n/** Appends \" (2)\", \" (3)\" … so names are unique case-insensitively. */\nexport function uniqueName(name: string, taken: Set<string>): string {\n let candidate = name;\n for (let n = 2; taken.has(nameKey(candidate)); n += 1) {\n const suffix = ` (${n})`;\n candidate = `${name.slice(0, VAULT_LIMITS.nameMaxChars - suffix.length)}${suffix}`;\n }\n taken.add(nameKey(candidate));\n return candidate;\n}\n\n/** A canonical otpauth URI for a parsed seed, for stores that require URIs. */\nexport function totpUri(params: TotpParams, label: string): string {\n const query = new URLSearchParams({\n secret: params.secretBase32,\n algorithm: params.algorithm,\n digits: String(params.digits),\n period: String(params.periodSeconds),\n });\n return `otpauth://totp/${encodeURIComponent(label || \"Opengeni\")}?${query.toString()}`;\n}\n","import {\n type ProviderItemMeta,\n type ProviderWriteField,\n type ProviderWriteItem,\n type TotpParams,\n VAULT_LIMITS,\n type VaultFieldKind,\n type VaultItemType,\n VaultProviderError,\n parseTotpInput,\n} from \"./contract\";\nimport { nameKey, safeFieldName, safeSecretName, totpUri, uniqueName } from \"./naming\";\nimport type { KeeperFile, KeeperRecord } from \"./sdk\";\n\n/**\n * External field ids are positional, because Keeper record fields have no\n * ids of their own: `f:<type>` for standard fields, `c:<label or type>` for\n * custom fields, `#n` for repeats, `@notes` for the record notes and\n * `@file:<fileUid>` for attachments.\n */\nexport const NOTES_FIELD_ID = \"@notes\";\nexport const FILE_FIELD_PREFIX = \"@file:\";\n\nexport interface KeeperFieldEntry {\n type: string;\n label?: string;\n value?: unknown[];\n [key: string]: unknown;\n}\nexport interface KeeperRecordData {\n title?: string;\n type?: string;\n fields?: KeeperFieldEntry[];\n custom?: KeeperFieldEntry[];\n notes?: string;\n [key: string]: unknown;\n}\n\nexport type MappedSource =\n | { kind: \"field\"; list: \"fields\" | \"custom\"; index: number }\n | { kind: \"notes\" }\n | { kind: \"file\"; file: KeeperFile };\n\nexport interface MappedKeeperField {\n externalFieldId: string;\n name: string;\n kind: VaultFieldKind;\n source: MappedSource;\n /** Plain value for text/concealed/totp fields; files are read separately. */\n value: string;\n}\n\nconst CONCEALED_TYPES = new Set([\"password\", \"secret\", \"pinCode\", \"note\"]);\nconst TOTP_TYPES = new Set([\"oneTimeCode\", \"otp\"]);\nconst CONCEALED_COMPLEX = new Set([\"paymentCard\", \"bankAccount\", \"keyPair\", \"securityQuestion\"]);\nconst SKIPPED_TYPES = new Set([\"fileRef\", \"passkey\", \"recordRef\", \"cardRef\", \"addressRef\"]);\nconst DATE_TYPES = new Set([\"date\", \"birthDate\", \"expirationDate\"]);\nconst STANDARD_NAMES: Record<string, string> = {\n login: \"username\",\n password: \"password\",\n oneTimeCode: \"one-time password\",\n otp: \"one-time password\",\n url: \"website\",\n email: \"email\",\n note: \"note\",\n pinCode: \"PIN\",\n};\nconst API_KEY_TYPES = new Set([\n \"serverCredentials\",\n \"databaseCredentials\",\n \"sshKeys\",\n \"softwareLicense\",\n \"pamDatabase\",\n \"pamMachine\",\n]);\n\nexport function itemTypeForRecordType(type: string | undefined): VaultItemType {\n if (type === \"login\") return \"login\";\n if (type === \"encryptedNotes\") return \"note\";\n if (type === \"file\") return \"file\";\n if (type && API_KEY_TYPES.has(type)) return \"api_key\";\n return \"note\";\n}\n\nfunction kindFor(entry: KeeperFieldEntry): VaultFieldKind | null {\n if (SKIPPED_TYPES.has(entry.type)) return null;\n if (TOTP_TYPES.has(entry.type)) return \"totp\";\n if (CONCEALED_TYPES.has(entry.type) || CONCEALED_COMPLEX.has(entry.type)) return \"concealed\";\n return \"text\";\n}\n\nfunction valueText(entry: KeeperFieldEntry): string {\n const values = Array.isArray(entry.value) ? entry.value : [];\n if (values.length === 0) return \"\";\n if (DATE_TYPES.has(entry.type) && typeof values[0] === \"number\") {\n const date = new Date(values[0]);\n return Number.isNaN(date.getTime()) ? String(values[0]) : date.toISOString();\n }\n if (\n values.length === 1 &&\n (typeof values[0] === \"string\" ||\n typeof values[0] === \"number\" ||\n typeof values[0] === \"boolean\")\n ) {\n return String(values[0]);\n }\n return JSON.stringify(values.length === 1 ? values[0] : values);\n}\n\nclass Collector {\n readonly fields: MappedKeeperField[] = [];\n private readonly names = new Set<string>();\n private readonly ids = new Map<string, number>();\n add(baseId: string, rawName: string, kind: VaultFieldKind, source: MappedSource, value: string) {\n const seen = (this.ids.get(baseId) ?? 0) + 1;\n this.ids.set(baseId, seen);\n this.fields.push({\n externalFieldId: seen === 1 ? baseId : `${baseId}#${seen}`,\n name: uniqueName(safeFieldName(rawName, \"field\"), this.names),\n kind,\n source,\n value,\n });\n }\n}\n\nexport interface MappedKeeperRecord {\n meta: ProviderItemMeta;\n fields: MappedKeeperField[];\n}\n\nexport function recordData(record: KeeperRecord): KeeperRecordData {\n const data = record.data as unknown;\n return data && typeof data === \"object\" ? (data as KeeperRecordData) : {};\n}\n\nexport function mapRecord(record: KeeperRecord): MappedKeeperRecord {\n const data = recordData(record);\n const collector = new Collector();\n const websites: string[] = [];\n const lists: Array<[\"fields\" | \"custom\", KeeperFieldEntry[]]> = [\n [\"fields\", Array.isArray(data.fields) ? data.fields : []],\n [\"custom\", Array.isArray(data.custom) ? data.custom : []],\n ];\n for (const [list, entries] of lists) {\n entries.forEach((entry, index) => {\n if (!entry || typeof entry !== \"object\" || typeof entry.type !== \"string\") return;\n const kind = kindFor(entry);\n if (!kind) return;\n const value = valueText(entry);\n if (entry.type === \"url\") {\n for (const url of Array.isArray(entry.value) ? entry.value : []) {\n if (typeof url === \"string\" && url.trim()) websites.push(url);\n }\n }\n // A one-time code field without a seed has nothing to compute.\n if (kind === \"totp\" && !value) return;\n const label = typeof entry.label === \"string\" && entry.label.trim() ? entry.label : \"\";\n const name =\n list === \"fields\" ? label || STANDARD_NAMES[entry.type] || entry.type : label || entry.type;\n const baseId = list === \"fields\" ? `f:${entry.type}` : `c:${label || entry.type}`;\n collector.add(baseId, name, kind, { kind: \"field\", list, index }, value);\n });\n }\n if (typeof data.notes === \"string\" && data.notes) {\n collector.add(NOTES_FIELD_ID, \"notes\", \"concealed\", { kind: \"notes\" }, data.notes);\n }\n for (const file of record.files ?? []) {\n const fileData = (file.data ?? {}) as { title?: unknown; name?: unknown };\n const name =\n (typeof fileData.title === \"string\" && fileData.title) ||\n (typeof fileData.name === \"string\" && fileData.name) ||\n \"file\";\n collector.add(`${FILE_FIELD_PREFIX}${file.fileUid}`, name, \"file\", { kind: \"file\", file }, \"\");\n }\n return {\n meta: {\n externalItemId: record.recordUid,\n name: safeSecretName(typeof data.title === \"string\" ? data.title : \"\", record.recordUid),\n type: itemTypeForRecordType(typeof data.type === \"string\" ? data.type : undefined),\n websites,\n fields: collector.fields.map(({ externalFieldId, name, kind }) => ({\n externalFieldId,\n name,\n kind,\n })),\n version: Number.isFinite(record.revision) ? String(record.revision) : null,\n updatedAt: null,\n },\n fields: collector.fields,\n };\n}\n\n/** The record's file size as Keeper reports it, if any. */\nexport function fileSize(file: KeeperFile): number | null {\n const size = (file.data as { size?: unknown } | undefined)?.size;\n return typeof size === \"number\" && size >= 0 ? size : null;\n}\n\nexport function totpParamsFor(value: string): TotpParams | null {\n try {\n return parseTotpInput(value);\n } catch {\n return null;\n }\n}\n\nfunction unavailable(message: string): never {\n throw new VaultProviderError(\"provider_unavailable\", message);\n}\n\nfunction textValue(field: ProviderWriteField): string {\n const value = field.value ?? \"\";\n if (Buffer.byteLength(value, \"utf8\") > VAULT_LIMITS.textValueMaxBytes) {\n unavailable(`The value of \"${field.name}\" is larger than Opengeni stores`);\n }\n return value;\n}\n\nfunction totpValue(field: ProviderWriteField, label: string): string {\n const params = totpParamsFor(textValue(field));\n if (!params) unavailable(`\"${field.name}\" is not a TOTP seed or otpauth:// URI`);\n return totpUri(params, label);\n}\n\nfunction customEntry(field: ProviderWriteField, title: string): KeeperFieldEntry {\n if (field.kind === \"file\") unavailable(\"Keeper files cannot be written from Opengeni\");\n if (field.kind === \"totp\")\n return { type: \"oneTimeCode\", label: field.name, value: [totpValue(field, title)] };\n return {\n type: field.kind === \"concealed\" ? \"secret\" : \"text\",\n label: field.name,\n value: [textValue(field)],\n };\n}\n\n/** Record data for a create; Keeper `login` and `encryptedNotes` record types only. */\nexport function buildCreateData(item: ProviderWriteItem): KeeperRecordData {\n const title = item.name;\n for (const field of item.fields) {\n if (field.remove) unavailable(\"A new Keeper record has no fields to remove\");\n }\n if (item.type === \"login\") {\n let login: string | null = null;\n let password: string | null = null;\n let otp: string | null = null;\n const custom: KeeperFieldEntry[] = [];\n const concealed = item.fields.filter((field) => field.kind === \"concealed\");\n for (const field of item.fields) {\n const key = nameKey(field.name);\n if (field.kind === \"text\" && key === \"username\" && login === null) login = textValue(field);\n else if (\n field.kind === \"concealed\" &&\n password === null &&\n (key === \"password\" || concealed.length === 1)\n ) {\n password = textValue(field);\n } else if (field.kind === \"totp\" && otp === null) otp = totpValue(field, title);\n else custom.push(customEntry(field, title));\n }\n const [first, ...rest] = item.websites.filter((url) => url.trim().length > 0);\n for (const url of rest) custom.push({ type: \"url\", label: \"website\", value: [url] });\n return {\n type: \"login\",\n title,\n notes: \"\",\n fields: [\n { type: \"login\", value: login === null ? [] : [login] },\n { type: \"password\", value: password === null ? [] : [password] },\n { type: \"url\", value: first ? [first] : [] },\n { type: \"fileRef\", value: [] },\n { type: \"oneTimeCode\", value: otp === null ? [] : [otp] },\n ],\n custom,\n };\n }\n if (item.type === \"note\") {\n let note: string | null = null;\n const custom: KeeperFieldEntry[] = [];\n for (const field of item.fields) {\n if (note === null && (field.kind === \"text\" || field.kind === \"concealed\"))\n note = textValue(field);\n else custom.push(customEntry(field, title));\n }\n return {\n type: \"encryptedNotes\",\n title,\n notes: \"\",\n fields: [\n { type: \"note\", value: note === null ? [] : [note] },\n { type: \"date\", value: [] },\n ],\n custom,\n };\n }\n return unavailable(\n item.type === \"passkey\"\n ? \"Passkeys live only in Opengeni vaults\"\n : item.type === \"api_key\"\n ? \"Keeper has no API key record type; create a login or a secure note\"\n : \"Keeper file records cannot be created from Opengeni\",\n );\n}\n\nfunction setEntryValue(entry: KeeperFieldEntry, field: ProviderWriteField, title: string) {\n if (field.kind === \"file\") unavailable(\"Keeper files cannot be written from Opengeni\");\n if (TOTP_TYPES.has(entry.type)) {\n entry.value = [totpValue(field, title)];\n return;\n }\n const current = Array.isArray(entry.value) ? entry.value : [];\n const scalar = current.length <= 1 && (current.length === 0 || typeof current[0] === \"string\");\n if (!scalar || CONCEALED_COMPLEX.has(entry.type) || DATE_TYPES.has(entry.type)) {\n unavailable(`\"${field.name}\" is a structured Keeper field; edit it in Keeper`);\n }\n entry.value = [field.kind === \"totp\" ? totpValue(field, title) : textValue(field)];\n}\n\n/**\n * Applies a field patch to a fetched record in place. Untouched fields are\n * preserved; custom fields can be removed, standard fields are emptied.\n */\nexport function applyPatch(record: KeeperRecord, item: ProviderWriteItem): void {\n const data = recordData(record);\n data.fields = Array.isArray(data.fields) ? data.fields : [];\n data.custom = Array.isArray(data.custom) ? data.custom : [];\n const title = item.name;\n const mapped = mapRecord(record).fields;\n const removals: number[] = [];\n for (const field of item.fields) {\n const target = field.externalFieldId\n ? mapped.find((candidate) => candidate.externalFieldId === field.externalFieldId)\n : mapped.find((candidate) => nameKey(candidate.name) === nameKey(field.name));\n if (field.externalFieldId && !target) {\n throw new VaultProviderError(\n \"provider_not_found\",\n `The Keeper record has no field ${field.externalFieldId}`,\n );\n }\n if (!target) {\n if (field.remove) continue;\n data.custom.push(customEntry(field, title));\n continue;\n }\n const source = target.source;\n if (source.kind === \"file\") unavailable(\"Keeper files cannot be changed from Opengeni\");\n if (source.kind === \"notes\") {\n data.notes = field.remove ? \"\" : textValue(field);\n continue;\n }\n const entry = data[source.list]![source.index]!;\n if (field.remove) {\n if (source.list === \"custom\") removals.push(source.index);\n else entry.value = [];\n continue;\n }\n setEntryValue(entry, field, title);\n }\n for (const index of removals.sort((a, b) => b - a)) data.custom.splice(index, 1);\n data.title = title;\n const websites = item.websites.filter((url) => url.trim().length > 0);\n const current = mapRecord(record).meta.websites;\n if (JSON.stringify(websites) !== JSON.stringify(current)) {\n const standard = data.fields.find((entry) => entry.type === \"url\");\n data.custom = data.custom.filter(\n (entry) => !(entry.type === \"url\" && entry.label === \"website\"),\n );\n const [first, ...rest] = websites;\n if (standard) standard.value = first ? [first] : [];\n else if (first) rest.unshift(first);\n for (const url of rest) data.custom.push({ type: \"url\", label: \"website\", value: [url] });\n }\n}\n","import { providerOperations } from \"@opengeni/vaults\";\nimport {\n VaultProviderError,\n type ProviderWriteItem,\n type VaultProvider,\n type VaultProviderOperations,\n} from \"./contract\";\n\nfunction refused(what: string): never {\n throw new VaultProviderError(\n \"provider_permission_denied\",\n `${what} is not enabled for this vault connection`,\n );\n}\n\nfunction checkWrite(operations: VaultProviderOperations, item: ProviderWriteItem) {\n const totp = item.fields.some((field) => field.kind === \"totp\" && !field.remove);\n if (item.externalItemId !== undefined) {\n if (!operations.updateItem) refused(\"Updating items\");\n if (totp && !operations.updateTotp) refused(\"Changing one-time password seeds\");\n if (item.fields.some((field) => field.remove) && !operations.removeField)\n refused(\"Removing fields\");\n return;\n }\n if (!operations.createItemTypes.includes(item.type)) refused(`Creating ${item.type} items`);\n if (totp && !operations.createTotp) refused(\"Adding one-time password seeds\");\n}\n\n/**\n * Narrows an adapter to the operations verified when its connection was set\n * up: what it reports and what it will do. It never widens the adapter's own\n * operations, and refused calls make no provider request.\n */\nexport function restrictToOperations<P extends VaultProvider>(\n provider: P,\n verified: VaultProviderOperations | undefined,\n fileFieldPrefix: string,\n): P {\n if (!verified) return provider;\n const effective = () =>\n providerOperations(provider.capabilities(), { operations: verified, writeAccess: \"unknown\" });\n return {\n ...provider,\n capabilities() {\n const base = provider.capabilities();\n const operations = effective();\n const writes =\n operations.createItemTypes.length > 0 || operations.updateItem || operations.archiveItem;\n return { ...base, write: base.write && writes, operations };\n },\n async readFields(ctx, vaultId, itemId, fieldIds) {\n if (!effective().readFiles && fieldIds.some((id) => id.startsWith(fileFieldPrefix)))\n refused(\"Reading files\");\n return provider.readFields(ctx, vaultId, itemId, fieldIds);\n },\n async writeItem(ctx, vaultId, item) {\n checkWrite(effective(), item);\n return provider.writeItem(ctx, vaultId, item);\n },\n async archiveItem(ctx, vaultId, itemId) {\n if (!effective().archiveItem) refused(\"Archiving items\");\n return provider.archiveItem(ctx, vaultId, itemId);\n },\n };\n}\n","import * as nodeCrypto from \"node:crypto\";\nimport { constants as fsConstants, readFileSync } from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as nodePath from \"node:path\";\nimport type * as KeeperSdkModule from \"@keeper-security/secrets-manager-core\";\nimport { VaultProviderError } from \"./contract\";\n\n/** The official SDK release this adapter is written and tested against. */\nexport const KEEPER_SDK_VERSION = \"17.6.0\";\nexport const KEEPER_SDK_PACKAGE = \"@keeper-security/secrets-manager-core\";\n/** SHA-256 of `dist/index.cjs.js` in @keeper-security/secrets-manager-core 17.6.0. */\nexport const KEEPER_SDK_SHA256 = \"94787ce51324f36c1b62d19ac29fbe3b9b206305695e508b76585a4d6e39635c\";\n\nexport type KeeperSdk = typeof KeeperSdkModule;\nexport type KeeperRecord = KeeperSdkModule.KeeperRecord;\nexport type KeeperFolder = KeeperSdkModule.KeeperFolder;\nexport type KeeperFile = KeeperSdkModule.KeeperFile;\nexport type KeeperSecrets = KeeperSdkModule.KeeperSecrets;\nexport type KeyValueStorage = KeeperSdkModule.KeyValueStorage;\nexport type SecretManagerOptions = KeeperSdkModule.SecretManagerOptions;\nexport type KeeperQueryFunction = NonNullable<SecretManagerOptions[\"queryFunction\"]>;\nexport type KeeperHttpResponse = Awaited<ReturnType<KeeperQueryFunction>>;\n\n/**\n * Bounded log capture for one SDK instance. The SDK reports skipped records,\n * folders and files only through `console.error`; those lines carry record\n * UIDs and error text, so they are inspected here and never forwarded.\n */\nexport class CapturedConsole {\n readonly lines: string[] = [];\n private static readonly MAX_LINES = 200;\n private static readonly MAX_CHARS = 500;\n private push(args: unknown[]) {\n if (this.lines.length >= CapturedConsole.MAX_LINES) return;\n const text = args\n .map((arg) => (arg instanceof Error ? `${arg.name}: ${arg.message}` : String(arg)))\n .join(\" \");\n this.lines.push(text.slice(0, CapturedConsole.MAX_CHARS));\n }\n readonly error = (...args: unknown[]) => this.push(args);\n readonly warn = (...args: unknown[]) => this.push(args);\n readonly log = (...args: unknown[]) => this.push(args);\n readonly info = (...args: unknown[]) => this.push(args);\n readonly debug = (...args: unknown[]) => this.push(args);\n\n /** True when the SDK dropped a record, folder or file it could not decrypt. */\n get skippedSomething(): boolean {\n return this.lines.some((line) => /skipped due to error|could not be decrypted/.test(line));\n }\n}\n\nfunction denied(module: string): never {\n throw new Error(`The Keeper SDK may not use ${module} inside Opengeni`);\n}\n\n/**\n * Modules handed to each SDK instance. `fs` exposes only its constants (read\n * at load for symlink-safe flags); every function is absent, so the SDK's\n * on-disk config and response cache cannot write anything. `https` and `os`\n * are empty: all network goes through the adapter's own transport.\n */\nconst FS_STUB = Object.freeze({ constants: fsConstants });\nconst HTTPS_STUB = Object.freeze({});\nconst OS_STUB = Object.freeze({});\n\nfunction sdkRequire(name: string): unknown {\n switch (name) {\n case \"crypto\":\n return nodeCrypto;\n case \"path\":\n return nodePath;\n case \"fs\":\n return FS_STUB;\n case \"https\":\n return HTTPS_STUB;\n case \"os\":\n return OS_STUB;\n default:\n return denied(name);\n }\n}\n\ntype SdkFactory = (\n module: { exports: Record<string, unknown> },\n exports: Record<string, unknown>,\n require: (name: string) => unknown,\n console: CapturedConsole,\n) => void;\n\nlet compiled: { sha256: string; factory: SdkFactory } | null = null;\n\n/** Reads the installed SDK's CommonJS build (a read only; nothing is executed here). */\nexport function readInstalledKeeperSdkSource(): string {\n const require = createRequire(import.meta.url);\n let path: string;\n try {\n path = require.resolve(KEEPER_SDK_PACKAGE);\n } catch {\n throw new VaultProviderError(\n \"provider_unavailable\",\n `${KEEPER_SDK_PACKAGE} ${KEEPER_SDK_VERSION} is not installed on this Opengeni server`,\n );\n }\n return readFileSync(path, \"utf8\");\n}\n\n/**\n * Compiles the pinned SDK once. The source must match the 17.6.0 build byte\n * for byte; any other version is refused rather than run with unknown\n * semantics.\n */\nfunction factoryFor(source: string, expectedSha256: string): SdkFactory {\n const sha256 = nodeCrypto.createHash(\"sha256\").update(source).digest(\"hex\");\n if (compiled && compiled.sha256 === sha256) return compiled.factory;\n if (sha256 !== expectedSha256) {\n throw new VaultProviderError(\n \"provider_unavailable\",\n `The installed Keeper SDK is not ${KEEPER_SDK_PACKAGE} ${KEEPER_SDK_VERSION}`,\n );\n }\n // eslint-disable-next-line no-new-func -- a fresh module scope per instance is the isolation boundary.\n const factory = new Function(\"module\", \"exports\", \"require\", \"console\", source) as SdkFactory;\n compiled = { sha256, factory };\n return factory;\n}\n\nexport interface KeeperSdkInstance {\n sdk: KeeperSdk;\n console: CapturedConsole;\n}\n\nexport interface KeeperSdkLoader {\n /** A new, private SDK module instance (its own key cache and platform). */\n instance(): KeeperSdkInstance;\n}\n\n/**\n * The SDK keeps decrypted application, folder and record keys in a\n * module-global cache and reads keys from that cache before storage, so one\n * module instance must never serve two connections. Each operation evaluates\n * the pinned CommonJS build in a fresh scope, which gives it its own cache,\n * platform and storage serialization, and is discarded afterwards.\n */\nexport function createKeeperSdkLoader(\n options: { source?: string | (() => string); expectedSha256?: string } = {},\n): KeeperSdkLoader {\n let factory: SdkFactory | null = null;\n return {\n instance() {\n if (!factory) {\n const source =\n typeof options.source === \"function\"\n ? options.source()\n : (options.source ?? readInstalledKeeperSdkSource());\n factory = factoryFor(source, options.expectedSha256 ?? KEEPER_SDK_SHA256);\n }\n const captured = new CapturedConsole();\n const module = { exports: {} as Record<string, unknown> };\n factory(module, module.exports, sdkRequire, captured);\n return { sdk: module.exports as unknown as KeeperSdk, console: captured };\n },\n };\n}\n\n/** Default transport limits. */\nexport const KEEPER_REQUEST_TIMEOUT_MS = 15_000;\nexport const KEEPER_MAX_RESPONSE_BYTES = 32 * 1024 * 1024;\n\nasync function readBounded(response: Response, maxBytes: number): Promise<Uint8Array> {\n const declared = Number(response.headers.get(\"content-length\") ?? \"NaN\");\n if (Number.isFinite(declared) && declared > maxBytes) {\n await response.body?.cancel().catch(() => {});\n throw new VaultProviderError(\n \"provider_unavailable\",\n \"Keeper returned more data than Opengeni reads\",\n );\n }\n if (!response.body) return new Uint8Array();\n const reader = response.body.getReader();\n const chunks: Uint8Array[] = [];\n let total = 0;\n for (;;) {\n const { done, value } = await reader.read();\n if (done) break;\n total += value.byteLength;\n if (total > maxBytes) {\n await reader.cancel().catch(() => {});\n throw new VaultProviderError(\n \"provider_unavailable\",\n \"Keeper returned more data than Opengeni reads\",\n );\n }\n chunks.push(value);\n }\n const out = new Uint8Array(total);\n let offset = 0;\n for (const chunk of chunks) {\n out.set(chunk, offset);\n offset += chunk.byteLength;\n }\n return out;\n}\n\nfunction withDeadline(signal: AbortSignal | undefined, timeoutMs: number): AbortSignal {\n const timeout = AbortSignal.timeout(timeoutMs);\n return signal ? AbortSignal.any([signal, timeout]) : timeout;\n}\n\n/**\n * The `fetch` the adapter's transports call. Servers pass a DNS-pinned fetch\n * (for example `pinnedFetch` from `@opengeni/network`); the adapter still sets\n * the method, headers, body, abort signal and `redirect: \"error\"`, and refuses\n * any redirect status a manual-redirect fetch returns.\n */\nexport type KeeperFetch = (input: string | URL, init: RequestInit) => Promise<Response>;\n\nasync function refuseRedirect(response: Response): Promise<void> {\n if (response.status >= 300 && response.status < 400) {\n await response.body?.cancel().catch(() => {});\n throw new VaultProviderError(\"provider_unavailable\", \"Keeper answered with a redirect\");\n }\n}\n\n/**\n * The SDK's request function, reimplemented over `fetch` so requests follow no\n * redirects, honour the caller's abort signal, and read bounded bodies. Headers\n * match the SDK's `postFunction` (PublicKeyId, TransmissionKey, Authorization).\n */\nexport function createKeeperFetchTransport(\n options: { fetch?: KeeperFetch; maxResponseBytes?: number; signal?: AbortSignal } = {},\n): KeeperQueryFunction {\n const fetchImpl: KeeperFetch = options.fetch ?? ((input, init) => globalThis.fetch(input, init));\n const maxBytes = options.maxResponseBytes ?? KEEPER_MAX_RESPONSE_BYTES;\n return async (url, transmissionKey, payload, _allowUnverifiedCertificate, timeoutMs) => {\n const response = await fetchImpl(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/octet-stream\",\n PublicKeyId: String(transmissionKey.publicKeyId),\n TransmissionKey: Buffer.from(transmissionKey.encryptedKey).toString(\"base64\"),\n Authorization: `Signature ${Buffer.from(payload.signature).toString(\"base64\")}`,\n \"User-Agent\": `Opengeni (KSM JS ${KEEPER_SDK_VERSION})`,\n },\n body: payload.payload as Uint8Array<ArrayBuffer>,\n redirect: \"error\",\n signal: withDeadline(options.signal, timeoutMs ?? KEEPER_REQUEST_TIMEOUT_MS),\n });\n await refuseRedirect(response);\n const data = await readBounded(response, maxBytes);\n return { statusCode: response.status, headers: Object.fromEntries(response.headers), data };\n };\n}\n\n/** Downloads an encrypted file body from a Keeper-issued URL, bounded in size and time. */\nexport type KeeperFileFetcher = (\n url: string,\n options: { signal?: AbortSignal; maxBytes: number; timeoutMs: number },\n) => Promise<Uint8Array>;\n\nexport function createKeeperFileFetcher(\n fetchImpl: KeeperFetch = (input, init) => globalThis.fetch(input, init),\n): KeeperFileFetcher {\n return async (url, options) => {\n const parsed = new URL(url);\n if (parsed.protocol !== \"https:\") {\n throw new VaultProviderError(\"provider_unavailable\", \"Keeper returned a non-HTTPS file URL\");\n }\n const response = await fetchImpl(parsed, {\n redirect: \"error\",\n signal: withDeadline(options.signal, options.timeoutMs),\n });\n await refuseRedirect(response);\n if (!response.ok) {\n await response.body?.cancel().catch(() => {});\n throw new VaultProviderError(\n \"provider_unavailable\",\n `Keeper file storage returned HTTP ${response.status}`,\n );\n }\n return readBounded(response, options.maxBytes);\n };\n}\n","import {\n type ProviderCallBudget,\n type ProviderFieldValue,\n type ProviderItemMeta,\n type ProviderVault,\n type SecretMaterial,\n VAULT_LIMITS,\n type VaultProvider,\n type VaultProviderCapabilities,\n type VaultProviderContext,\n VaultProviderError,\n type VaultProviderOperations,\n} from \"./contract\";\nimport {\n KEEPER_DEFAULT_ALLOWED_HOSTS,\n type KeeperConfigValues,\n assertAllowedHost,\n memoryKeeperStorage,\n parseKeeperConfiguration,\n serializeKeeperConfiguration,\n} from \"./config\";\nimport { type MutationTracker, mapKeeperError, mapKeeperMutationError } from \"./errors\";\nimport {\n FILE_FIELD_PREFIX,\n type MappedKeeperField,\n type MappedKeeperRecord,\n applyPatch,\n buildCreateData,\n fileSize,\n mapRecord,\n totpParamsFor,\n} from \"./mapping\";\nimport { safeSecretName } from \"./naming\";\nimport { restrictToOperations } from \"./operations\";\nimport {\n type CapturedConsole,\n KEEPER_REQUEST_TIMEOUT_MS,\n type KeeperFetch,\n type KeeperFileFetcher,\n type KeeperQueryFunction,\n type KeeperRecord,\n type KeeperSdk,\n type KeeperSdkLoader,\n type SecretManagerOptions,\n createKeeperFetchTransport,\n createKeeperFileFetcher,\n createKeeperSdkLoader,\n} from \"./sdk\";\n\nexport const KEEPER_VALUE_CACHE_MS = VAULT_LIMITS.providerValueCacheMs;\n\n/** What KSM 17.6.0 can do for an application (see README for the evidence). */\nexport const KEEPER_OPERATIONS: VaultProviderOperations = {\n createItemTypes: [\"login\", \"note\"],\n updateItem: true,\n removeField: true,\n archiveItem: false,\n archiveKind: \"none\",\n deleteItem: false,\n restoreItem: false,\n readFiles: true,\n writeFiles: false,\n createTotp: true,\n updateTotp: true,\n createVault: false,\n restoreFieldHistory: false,\n};\n\n/**\n * Persists a changed configuration; the parent stores it encrypted with\n * compare-and-swap. `configuration` is canonical JSON of a string record\n * (binary entries are base64). `previous` is null for the first save after\n * binding a one-time token.\n */\nexport type PersistKeeperConfiguration = (\n configuration: string,\n context: { previous: string | null; reason: \"bind\" | \"rotation\" },\n) => Promise<void>;\n\nexport interface KeeperRuntimeOptions {\n /** Hosts the configuration may name (default: Keeper's seven region hosts). */\n allowedHosts?: readonly string[];\n /** Per-request deadline handed to the SDK (default 15 s). */\n requestTimeoutMs?: number;\n /**\n * The fetch both default transports use (KSM API and file downloads).\n * Servers pass a DNS-pinned fetch; the per-call abort signal and deadline\n * are still applied. Ignored where `queryFunction` or `fetchFile` is given.\n */\n fetch?: KeeperFetch;\n /** SDK request function (tests); defaults to a bounded, no-redirect fetch transport. */\n queryFunction?: KeeperQueryFunction;\n /** Encrypted file download (tests); defaults to a bounded HTTPS fetch. */\n fetchFile?: KeeperFileFetcher;\n /** SDK loader (tests or bundlers that ship the SDK source themselves). */\n sdk?: KeeperSdkLoader;\n now?: () => number;\n}\n\nexport interface KeeperVaultProviderOptions extends KeeperRuntimeOptions {\n /** Operations verified at setup; the adapter narrows to them and never widens. */\n operations?: VaultProviderOperations;\n /**\n * The bound KSM configuration from bootstrap or Keeper tooling: JSON, base64\n * JSON, or the parsed string record.\n */\n configuration: string | Readonly<Record<string, string>>;\n /** Awaited whenever the SDK changes the configuration (server key rotation). */\n persistConfiguration: PersistKeeperConfiguration;\n valueCacheMs?: number;\n}\n\nexport type KeeperVaultProvider = VaultProvider & {\n readonly id: \"keeper\";\n /** The configuration as last persisted or pending persistence. */\n currentConfiguration(): string;\n close(): Promise<void>;\n};\n\n/** Keeper record and folder UIDs are 16-byte web-safe base64 (22 chars). */\nconst KEEPER_UID = /^[A-Za-z0-9_-]{16,64}$/;\nfunction assertUids(...uids: string[]) {\n for (const uid of uids) {\n if (!KEEPER_UID.test(uid)) {\n throw new VaultProviderError(\"provider_not_found\", \"No such Keeper shared folder or record\");\n }\n }\n}\n\nexport interface KeeperOperation {\n sdk: KeeperSdk;\n options: SecretManagerOptions;\n console: CapturedConsole;\n tracker: MutationTracker & { mutating: boolean };\n}\n\n/**\n * Runs one operation in a fresh SDK instance over an in-memory copy of the\n * configuration, with the adapter's host allowlist, deadline and throttle\n * policy. Shared by the provider and bootstrap.\n */\nexport async function runKeeperOperation<T>(input: {\n runtime: KeeperRuntimeOptions;\n loader: KeeperSdkLoader;\n config: KeeperConfigValues;\n signal?: AbortSignal;\n work: (op: KeeperOperation, storage: ReturnType<typeof memoryKeeperStorage>) => Promise<T>;\n beforeNetwork?: (storage: ReturnType<typeof memoryKeeperStorage>) => void;\n /** Bootstrap sets the host inside `work`; every request is still checked. */\n hostInConfig?: boolean;\n}): Promise<{ result: T; storage: ReturnType<typeof memoryKeeperStorage> }> {\n const allowed = (input.runtime.allowedHosts ?? KEEPER_DEFAULT_ALLOWED_HOSTS).map((host) =>\n host.toLowerCase(),\n );\n const { sdk, console } = input.loader.instance();\n const storage = memoryKeeperStorage(input.config);\n const transport =\n input.runtime.queryFunction ??\n createKeeperFetchTransport({\n ...(input.signal ? { signal: input.signal } : {}),\n ...(input.runtime.fetch ? { fetch: input.runtime.fetch } : {}),\n });\n const tracker = { sent: 0, lastStatus: null as number | null, mutating: false };\n const queryFunction: KeeperQueryFunction = async (\n url,\n transmissionKey,\n payload,\n allow,\n timeoutMs,\n ) => {\n input.signal?.throwIfAborted();\n const parsed = new URL(url);\n if (parsed.protocol !== \"https:\" || !parsed.pathname.startsWith(\"/api/rest/sm/v1/\")) {\n throw new VaultProviderError(\"provider_unavailable\", \"Refused an unexpected Keeper request\");\n }\n assertAllowedHost(parsed.hostname, allowed);\n if (tracker.mutating) {\n tracker.sent += 1;\n tracker.lastStatus = null;\n }\n const response = await transport(url, transmissionKey, payload, false, timeoutMs);\n if (tracker.mutating) tracker.lastStatus = response.statusCode;\n return response;\n };\n const options: SecretManagerOptions = {\n storage,\n queryFunction,\n requestTimeoutMs: input.runtime.requestTimeoutMs ?? KEEPER_REQUEST_TIMEOUT_MS,\n // Never sleep inside a request: surface the server's back-off to the caller.\n throttleSleep: (ms) =>\n Promise.reject(\n new VaultProviderError(\n \"provider_rate_limited\",\n \"Keeper is rate limiting this application\",\n ms,\n ),\n ),\n onDecryptionError: () => {\n throw new VaultProviderError(\n \"provider_inventory_incomplete\",\n \"Keeper returned a folder Opengeni could not decrypt\",\n );\n },\n };\n input.beforeNetwork?.(storage);\n if (input.hostInConfig !== false) assertAllowedHost(storage.values.get(\"hostname\"), allowed);\n const result = await input.work({ sdk, options, console, tracker }, storage);\n return { result, storage };\n}\n\ntype CachedRecords = { at: number; records: Promise<KeeperRecord[]> };\ntype CachedRecord = { at: number; record: Promise<MappedKeeperRecord> };\n\nfunction cacheFor<V>(map: WeakMap<ProviderCallBudget, Map<string, V>>, budget: ProviderCallBudget) {\n let cache = map.get(budget);\n if (!cache) {\n cache = new Map();\n map.set(budget, cache);\n }\n return cache;\n}\n\nexport function createKeeperVaultProvider(\n options: KeeperVaultProviderOptions,\n): KeeperVaultProvider {\n let config = parseKeeperConfiguration(options.configuration);\n let persisted = serializeKeeperConfiguration(config);\n let pending: string | null = null;\n const loader = options.sdk ?? createKeeperSdkLoader();\n const now = options.now ?? Date.now;\n const valueCacheMs = options.valueCacheMs ?? KEEPER_VALUE_CACHE_MS;\n const fetchFile = options.fetchFile ?? createKeeperFileFetcher(options.fetch);\n let queue: Promise<unknown> = Promise.resolve();\n // Per provider instance (one bound application) and per attempt budget.\n // Core shares one budget across every provider in an attempt, so a\n // module-level cache keyed only by budget would let one connection reuse\n // another's records for the same folder and record uids.\n const attemptListCaches = new WeakMap<ProviderCallBudget, Map<string, CachedRecords>>();\n const attemptRecordCaches = new WeakMap<ProviderCallBudget, Map<string, CachedRecord>>();\n\n async function flushPending() {\n if (pending === null) return;\n const next = pending;\n try {\n await options.persistConfiguration(next, { previous: persisted, reason: \"rotation\" });\n } catch {\n throw new VaultProviderError(\n \"provider_unavailable\",\n \"Opengeni could not save the updated Keeper configuration\",\n );\n }\n persisted = next;\n if (pending === next) pending = null;\n }\n\n function serialized<T>(work: () => Promise<T>): Promise<T> {\n const run = queue.then(work, work);\n queue = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n\n /** One budgeted, serialized operation in its own SDK instance. */\n function operation<T>(\n ctx: VaultProviderContext,\n op: \"list\" | \"read\" | \"write\",\n subject: string,\n work: (keeper: KeeperOperation) => Promise<T>,\n ): Promise<T> {\n ctx.signal?.throwIfAborted();\n ctx.budget.take(op);\n return serialized(async () => {\n ctx.signal?.throwIfAborted();\n await flushPending();\n let outcome: { result: T; storage: ReturnType<typeof memoryKeeperStorage> } | null = null;\n let failure: unknown = null;\n let storageRef: ReturnType<typeof memoryKeeperStorage> | null = null;\n let tracker: KeeperOperation[\"tracker\"] | null = null;\n try {\n outcome = await runKeeperOperation({\n runtime: options,\n loader,\n config,\n ...(ctx.signal ? { signal: ctx.signal } : {}),\n beforeNetwork: (storage) => {\n storageRef = storage;\n },\n work: (keeper) => {\n tracker = keeper.tracker;\n return work(keeper);\n },\n });\n } catch (error) {\n failure = error;\n }\n // Keep any configuration the SDK changed (for example a rotated server key id), even on failure.\n const storage = outcome?.storage ?? storageRef;\n let persistError: VaultProviderError | null = null;\n if (storage?.changed()) {\n config = new Map(storage.values);\n pending = serializeKeeperConfiguration(config);\n try {\n await flushPending();\n } catch (error) {\n persistError = error as VaultProviderError;\n }\n }\n if (failure !== null) {\n const usedTracker = tracker as KeeperOperation[\"tracker\"] | null;\n if (op === \"write\" && usedTracker && (usedTracker.sent > 0 || usedTracker.mutating)) {\n throw mapKeeperMutationError(failure, subject, usedTracker);\n }\n if (op !== \"write\" && failure instanceof Error && failure.name === \"AbortError\") {\n ctx.signal?.throwIfAborted();\n }\n throw mapKeeperError(failure, subject);\n }\n // A completed write stays successful; its configuration is retried on the next call.\n if (persistError && op !== \"write\") throw persistError;\n return outcome!.result;\n });\n }\n\n function reportFresh(ctx: VaultProviderContext) {\n const at = new Date(now()).toISOString();\n ctx.onFreshness?.({\n state: \"current\",\n lastCheckedAt: at,\n sourceSyncedAt: at,\n source: \"live\",\n errorCode: null,\n retryAt: null,\n });\n }\n\n function incomplete(): never {\n throw new VaultProviderError(\n \"provider_inventory_incomplete\",\n \"Keeper returned records Opengeni could not decrypt; the listing is incomplete\",\n );\n }\n\n /** All records visible to the application, cached per attempt. */\n function allRecords(ctx: VaultProviderContext): Promise<KeeperRecord[]> {\n const cache = cacheFor(attemptListCaches, ctx.budget);\n const key = ctx.cacheEpoch ?? \"\";\n const cached = cache.get(key);\n if (cached && !ctx.forceRefresh && now() - cached.at < valueCacheMs) return cached.records;\n const records = operation(\n ctx,\n \"list\",\n \"list records\",\n async ({ sdk, options: sdkOptions, console }) => {\n const secrets = await sdk.getSecrets2(sdkOptions);\n if (console.skippedSomething) incomplete();\n return secrets.records;\n },\n );\n const entry = { at: now(), records };\n cache.set(key, entry);\n records.catch(() => {\n if (cache.get(key) === entry) cache.delete(key);\n });\n return records;\n }\n\n async function fetchRecord(\n keeper: KeeperOperation,\n externalVaultId: string,\n externalItemId: string,\n ): Promise<KeeperRecord> {\n const secrets = await keeper.sdk.getSecrets2(keeper.options, {\n recordsFilter: [externalItemId],\n });\n const record = secrets.records.find((candidate) => candidate.recordUid === externalItemId);\n if (!record) {\n if (keeper.console.skippedSomething) {\n throw new VaultProviderError(\n \"provider_unavailable\",\n \"Opengeni could not decrypt this Keeper record\",\n );\n }\n throw new VaultProviderError(\"provider_not_found\", \"No such Keeper record\");\n }\n // A record is addressed through its shared folder; never read across folders.\n if (record.folderUid !== externalVaultId) {\n throw new VaultProviderError(\n \"provider_not_found\",\n \"No such Keeper record in this shared folder\",\n );\n }\n return record;\n }\n\n function materialFor(mapped: MappedKeeperRecord, field: MappedKeeperField): SecretMaterial {\n if (field.kind === \"totp\") {\n const params = totpParamsFor(field.value);\n if (!params) {\n throw new VaultProviderError(\n \"provider_unavailable\",\n `The one-time code in Keeper record \"${mapped.meta.name}\" is not a valid TOTP seed`,\n );\n }\n return { type: \"totp\", params };\n }\n return { type: \"text\", value: field.value };\n }\n\n async function readFile(keeper: KeeperOperation, field: MappedKeeperField, signal?: AbortSignal) {\n if (field.source.kind !== \"file\") throw new Error(\"not a file field\");\n const file = field.source.file;\n const limit = VAULT_LIMITS.fileValueMaxBytes;\n const size = fileSize(file);\n if (size === null || size > limit) {\n throw new VaultProviderError(\n \"provider_unavailable\",\n `\"${field.name}\" is larger than Opengeni reads from Keeper`,\n );\n }\n if (!file.url)\n throw new VaultProviderError(\"provider_unavailable\", \"Keeper returned no download URL\");\n const encrypted = await fetchFile(file.url, {\n ...(signal ? { signal } : {}),\n // AES-GCM adds a 12-byte nonce and a 16-byte tag.\n maxBytes: limit + 28,\n timeoutMs: options.requestTimeoutMs ?? KEEPER_REQUEST_TIMEOUT_MS,\n });\n // The file key was unwrapped into this instance's cache when the record was fetched.\n const plain = await keeper.sdk.platform.decrypt(encrypted, file.fileUid);\n if (plain.byteLength > limit) {\n throw new VaultProviderError(\n \"provider_unavailable\",\n `\"${field.name}\" is larger than Opengeni reads from Keeper`,\n );\n }\n return new Uint8Array(plain);\n }\n\n const provider: KeeperVaultProvider = {\n id: \"keeper\",\n\n capabilities(): VaultProviderCapabilities {\n return {\n write: true,\n createVault: false,\n totp: true,\n // Legacy flag means file writes; reads are declared in operations.readFiles.\n files: false,\n groupGrants: false,\n passkeys: false,\n operations: {\n ...KEEPER_OPERATIONS,\n createItemTypes: [...KEEPER_OPERATIONS.createItemTypes],\n },\n };\n },\n\n async validate(ctx) {\n const name = await operation(\n ctx,\n \"list\",\n \"validate\",\n async ({ sdk, options: sdkOptions }) => {\n const secrets = await sdk.getSecrets2(sdkOptions);\n const title = secrets.appData?.title;\n return typeof title === \"string\" && title.trim() ? title.trim().slice(0, 200) : null;\n },\n );\n return { accountName: name };\n },\n\n async listVaults(ctx): Promise<ProviderVault[]> {\n const folders = await operation(\n ctx,\n \"list\",\n \"list shared folders\",\n async ({ sdk, options: sdkOptions, console }) => {\n const result = await sdk.getFolders(sdkOptions);\n if (console.skippedSomething) incomplete();\n return result;\n },\n );\n reportFresh(ctx);\n return folders\n .filter((folder) => !folder.parentUid)\n .map((folder) => ({\n externalVaultId: folder.folderUid,\n name: safeSecretName(folder.name ?? \"\", folder.folderUid),\n contentVersion: null,\n itemCount: null,\n // KSM does not tell an application whether a shared folder is editable.\n writeAccess: \"unknown\" as const,\n }));\n },\n\n async listItems(ctx, externalVaultId): Promise<ProviderItemMeta[]> {\n assertUids(externalVaultId);\n const records = await allRecords(ctx);\n const metas = records\n .filter((record) => record.folderUid === externalVaultId)\n .map((record) => mapRecord(record).meta);\n if (metas.length > VAULT_LIMITS.itemsPerVault) {\n throw new VaultProviderError(\n \"provider_inventory_incomplete\",\n \"The Keeper shared folder has more records than Opengeni mirrors at once\",\n );\n }\n for (const meta of metas) assertMirrorable(meta);\n reportFresh(ctx);\n return metas;\n },\n\n async readFields(ctx, externalVaultId, externalItemId, externalFieldIds) {\n assertUids(externalVaultId, externalItemId);\n const wantsFile = externalFieldIds.some((id) => id.startsWith(\"@file:\"));\n const cache = cacheFor(attemptRecordCaches, ctx.budget);\n const key = `${ctx.cacheEpoch ?? \"\"}|${externalVaultId}/${externalItemId}`;\n const cached = cache.get(key);\n if (!wantsFile && cached && !ctx.forceRefresh && now() - cached.at < valueCacheMs) {\n const mapped = await cached.record;\n return externalFieldIds.map((externalFieldId) => {\n const field = mapped.fields.find(\n (candidate) => candidate.externalFieldId === externalFieldId,\n );\n if (!field)\n throw new VaultProviderError(\n \"provider_not_found\",\n `Keeper record has no field ${externalFieldId}`,\n );\n return { externalFieldId, material: materialFor(mapped, field) };\n });\n }\n let resolveMapped!: (value: MappedKeeperRecord) => void;\n let rejectMapped!: (error: unknown) => void;\n const mappedPromise = new Promise<MappedKeeperRecord>((resolve, reject) => {\n resolveMapped = resolve;\n rejectMapped = reject;\n });\n mappedPromise.catch(() => {});\n const entry = { at: now(), record: mappedPromise };\n cache.set(key, entry);\n try {\n return await operation(ctx, \"read\", \"read record\", async (keeper) => {\n const record = await fetchRecord(keeper, externalVaultId, externalItemId);\n const mapped = mapRecord(record);\n // Files are read on demand and never cached.\n resolveMapped({\n ...mapped,\n fields: mapped.fields.filter((field) => field.kind !== \"file\"),\n });\n const values: ProviderFieldValue[] = [];\n for (const externalFieldId of externalFieldIds) {\n const field = mapped.fields.find(\n (candidate) => candidate.externalFieldId === externalFieldId,\n );\n if (!field) {\n throw new VaultProviderError(\n \"provider_not_found\",\n `Keeper record \"${mapped.meta.name}\" has no field ${externalFieldId}`,\n );\n }\n values.push({\n externalFieldId,\n material:\n field.kind === \"file\"\n ? { type: \"bytes\", value: await readFile(keeper, field, ctx.signal) }\n : materialFor(mapped, field),\n });\n }\n return values;\n });\n } catch (error) {\n rejectMapped(error);\n if (cache.get(key) === entry) cache.delete(key);\n throw error;\n }\n },\n\n async writeItem(ctx, externalVaultId, item): Promise<ProviderItemMeta> {\n assertUids(externalVaultId);\n const meta = await writeRecord(ctx, externalVaultId, item);\n // Drop this attempt's cached listings and values; the record changed.\n attemptRecordCaches.get(ctx.budget)?.clear();\n attemptListCaches.get(ctx.budget)?.clear();\n return meta;\n },\n\n async archiveItem() {\n throw new VaultProviderError(\n \"provider_unavailable\",\n \"Keeper Secrets Manager applications cannot archive or trash records; remove it in Keeper\",\n );\n },\n\n currentConfiguration: () => serializeKeeperConfiguration(config),\n close: async () => {\n await queue.catch(() => {});\n },\n };\n\n function writeRecord(\n ctx: VaultProviderContext,\n externalVaultId: string,\n item: Parameters<VaultProvider[\"writeItem\"]>[2],\n ): Promise<ProviderItemMeta> {\n if (item.externalItemId === undefined) {\n const data = buildCreateData(item);\n return operation(ctx, \"write\", \"create record\", async (keeper) => {\n const folders = await keeper.sdk.getFolders(keeper.options);\n const folder = folders.find((candidate) => candidate.folderUid === externalVaultId);\n if (!folder || folder.parentUid) {\n throw new VaultProviderError(\"provider_not_found\", \"No such Keeper shared folder\");\n }\n keeper.tracker.mutating = true;\n const recordUid = await keeper.sdk.createSecret2(\n keeper.options,\n { folderUid: externalVaultId },\n data,\n );\n keeper.tracker.mutating = false;\n try {\n return mapRecord(await fetchRecord(keeper, externalVaultId, recordUid)).meta;\n } catch {\n const meta = mapRecord({\n recordUid,\n folderUid: externalVaultId,\n data,\n revision: Number.NaN,\n }).meta;\n return { ...meta, version: null };\n }\n });\n }\n const recordUid = item.externalItemId;\n assertUids(recordUid);\n return operation(ctx, \"write\", \"update record\", async (keeper) => {\n const record = await fetchRecord(keeper, externalVaultId, recordUid);\n if (\n item.expectedVersion !== undefined &&\n item.expectedVersion !== null &&\n String(record.revision) !== item.expectedVersion\n ) {\n throw new VaultProviderError(\n \"provider_conflict\",\n \"The Keeper record changed since it was read; read it again before writing\",\n );\n }\n applyPatch(record, item);\n keeper.tracker.mutating = true;\n await keeper.sdk.updateSecret2(keeper.options, record);\n keeper.tracker.mutating = false;\n try {\n return mapRecord(await fetchRecord(keeper, externalVaultId, recordUid)).meta;\n } catch {\n return { ...mapRecord(record).meta, version: null };\n }\n });\n }\n\n return restrictToOperations(provider, options.operations, FILE_FIELD_PREFIX);\n}\n\n/**\n * Opengeni mirrors at most `fieldsPerItem` fields and `websitesPerItem`\n * websites of up to `websiteMaxChars` each. A larger record would be cut down\n * and then look complete, so the listing is reported incomplete instead.\n */\nfunction assertMirrorable(meta: ProviderItemMeta): void {\n if (\n meta.fields.length > VAULT_LIMITS.fieldsPerItem ||\n meta.websites.length > VAULT_LIMITS.websitesPerItem ||\n meta.websites.some((website) => website.length > VAULT_LIMITS.websiteMaxChars)\n ) {\n throw new VaultProviderError(\n \"provider_inventory_incomplete\",\n `A Keeper record has more than ${VAULT_LIMITS.fieldsPerItem} fields or ${VAULT_LIMITS.websitesPerItem} websites (or a website over ${VAULT_LIMITS.websiteMaxChars} characters), more than Opengeni mirrors`,\n );\n }\n}\n","import { VaultProviderError } from \"./contract\";\nimport {\n KEEPER_DEFAULT_ALLOWED_HOSTS,\n KEEPER_REGION_HOSTS,\n assertAllowedHost,\n memoryKeeperStorage,\n parseKeeperConfiguration,\n serializeKeeperConfiguration,\n} from \"./config\";\nimport { mapKeeperMutationError } from \"./errors\";\nimport {\n type KeeperRuntimeOptions,\n type KeeperVaultProvider,\n type PersistKeeperConfiguration,\n createKeeperVaultProvider,\n runKeeperOperation,\n} from \"./provider\";\nimport { createKeeperSdkLoader } from \"./sdk\";\n\nexport interface KeeperBootstrapOptions extends KeeperRuntimeOptions {\n /** One-time access token, `REGION:key` (for example `US:…`), or a bare key with `hostname`. */\n oneTimeToken: string;\n /** Region host for a token without a region prefix. */\n hostname?: string;\n signal?: AbortSignal;\n /**\n * Awaited with the bound configuration (`previous: null`, `reason: \"bind\"`)\n * as soon as Keeper has accepted the token, before bootstrap returns or\n * reports a later failure. The token is spent at that point, so this is the\n * only copy of the credential.\n */\n persistConfiguration?: PersistKeeperConfiguration;\n}\n\nexport interface KeeperBootstrapResult {\n /** Bound KSM configuration (JSON). Store it encrypted; it is the connection's credential. */\n configuration: string;\n /** The Secrets Manager application's title. */\n accountName: string | null;\n}\n\nconst TOKEN_PART = /^[A-Za-z0-9_-]{16,128}$/;\n\nfunction invalidToken(): never {\n throw new VaultProviderError(\n \"provider_auth_invalid\",\n \"That is not a Keeper Secrets Manager one-time access token\",\n );\n}\n\n/** The region host a token names, checked against the allowlist before any network call. */\nexport function keeperTokenHost(oneTimeToken: string, hostname?: string): string {\n const parts = oneTimeToken.trim().split(\":\");\n if (parts.length === 1) {\n if (!TOKEN_PART.test(parts[0]!)) invalidToken();\n if (!hostname) {\n throw new VaultProviderError(\n \"provider_auth_invalid\",\n \"This one-time token has no region prefix; choose the Keeper region\",\n );\n }\n return hostname;\n }\n if (parts.length !== 2 && !(parts.length === 4 && parts[0]!.toUpperCase() === \"IL5\"))\n invalidToken();\n if (!TOKEN_PART.test(parts[1]!)) invalidToken();\n const region = parts[0]!.toUpperCase() as keyof typeof KEEPER_REGION_HOSTS;\n return KEEPER_REGION_HOSTS[region] ?? parts[0]!;\n}\n\n/**\n * Redeems a one-time access token once: generates the client key pair in\n * memory, binds it with the first `get_secret` call, and returns the bound\n * configuration. The token is never retried; an ambiguous failure means the\n * customer must generate a new token.\n */\nexport async function bootstrapKeeperConfiguration(\n options: KeeperBootstrapOptions,\n): Promise<KeeperBootstrapResult> {\n const token = options.oneTimeToken.trim();\n const allowed = (options.allowedHosts ?? KEEPER_DEFAULT_ALLOWED_HOSTS).map((host) =>\n host.toLowerCase(),\n );\n assertAllowedHost(keeperTokenHost(token, options.hostname), allowed);\n const loader = options.sdk ?? createKeeperSdkLoader();\n let tracker: { sent: number; lastStatus: number | null; mutating: boolean } | null = null;\n let bindStorage: ReturnType<typeof memoryKeeperStorage> | null = null;\n let accountName: string | null = null;\n let failure: unknown = null;\n try {\n await runKeeperOperation({\n runtime: options,\n loader,\n config: new Map(),\n hostInConfig: false,\n ...(options.signal ? { signal: options.signal } : {}),\n work: async (keeper, storage) => {\n tracker = keeper.tracker;\n bindStorage = storage;\n await keeper.sdk.initializeStorage(storage, token, options.hostname);\n assertAllowedHost(storage.values.get(\"hostname\"), allowed);\n keeper.tracker.mutating = true;\n const secrets = await keeper.sdk.getSecrets2(keeper.options);\n keeper.tracker.mutating = false;\n const title = secrets.appData?.title;\n accountName = typeof title === \"string\" && title.trim() ? title.trim().slice(0, 200) : null;\n },\n });\n } catch (error) {\n failure = error;\n }\n\n // Keeper binds the key pair when it answers the first request. Once the\n // SDK has unwrapped the app key the token is spent, so the configuration is\n // kept (and persisted) even if something after the bind failed.\n const bound = bindStorage as ReturnType<typeof memoryKeeperStorage> | null;\n if (bound?.values.get(\"appKey\")) {\n bound.values.delete(\"clientKey\");\n const configuration = serializeKeeperConfiguration(bound.values);\n parseKeeperConfiguration(configuration);\n if (options.persistConfiguration) {\n try {\n await options.persistConfiguration(configuration, { previous: null, reason: \"bind\" });\n } catch {\n throw new VaultProviderError(\n \"provider_unavailable\",\n \"Keeper accepted the one-time token but Opengeni could not save the connection; generate a new token and connect again\",\n );\n }\n }\n return { configuration, accountName };\n }\n\n try {\n if (failure === null) {\n throw new VaultProviderError(\n \"provider_outcome_unknown\",\n \"Keeper did not complete binding; generate a new one-time token\",\n );\n }\n throw failure;\n } catch (error) {\n if (error instanceof VaultProviderError && error.code === \"provider_outcome_unknown\")\n throw error;\n const used = tracker as { sent: number; lastStatus: number | null; mutating: boolean } | null;\n const mapped = used\n ? mapKeeperMutationError(error, \"redeem the one-time token\", used)\n : error instanceof VaultProviderError\n ? error\n : new VaultProviderError(\n \"provider_auth_invalid\",\n \"Keeper could not use that one-time token\",\n );\n if (mapped.code === \"provider_outcome_unknown\") {\n throw new VaultProviderError(\n \"provider_outcome_unknown\",\n \"Keeper may have redeemed the one-time token; generate a new one and connect again\",\n );\n }\n if (mapped.code === \"provider_auth_invalid\" || mapped.code === \"provider_permission_denied\") {\n throw new VaultProviderError(\n \"provider_auth_invalid\",\n \"Keeper rejected the one-time token (expired, already used, or IP-locked); generate a new one\",\n );\n }\n throw mapped;\n }\n}\n\n/**\n * Bootstrap, then a provider over the bound configuration. The configuration\n * is persisted through `persistConfiguration` (reason `\"bind\"`) before this\n * returns and before the provider makes any request.\n */\nexport async function bootstrapKeeperVaultProvider(\n options: KeeperBootstrapOptions & { persistConfiguration: PersistKeeperConfiguration },\n): Promise<KeeperBootstrapResult & { provider: KeeperVaultProvider }> {\n const { oneTimeToken: _token, hostname: _hostname, signal: _signal, ...runtime } = options;\n const result = await bootstrapKeeperConfiguration(options);\n const provider = createKeeperVaultProvider({ ...runtime, configuration: result.configuration });\n return { ...result, provider };\n}\n","import { VaultProviderError, type VaultProviderOperations } from \"./contract\";\nimport { bootstrapKeeperConfiguration } from \"./bootstrap\";\nimport { keeperConfigurationRecord } from \"./config\";\nimport {\n type KeeperRuntimeOptions,\n type KeeperVaultProvider,\n createKeeperVaultProvider,\n} from \"./provider\";\n\n/** What a server stores for a Keeper connection: setup input, or the bound configuration. */\nexport type KeeperConnectionCredentials =\n | { oneTimeToken: string; hostname?: string }\n | { configuration: string | Readonly<Record<string, string>> };\n\n/**\n * Durable, encrypted storage for the bound configuration. Called with\n * `reason: \"bind\"` when a one-time token is redeemed (before anything else\n * runs) and `reason: \"rotation\"` when Keeper rotates its key.\n */\nexport type PersistKeeperConfigurationRecord = (\n configuration: Record<string, string>,\n context: { reason: \"bind\" | \"rotation\" },\n) => Promise<void>;\n\nexport interface OpenKeeperConnectionOptions extends KeeperRuntimeOptions {\n credentials: KeeperConnectionCredentials;\n /** Required: without durable storage a redeemed token or a rotated key would be lost. */\n persistConfiguration?: PersistKeeperConfigurationRecord;\n /** Operations verified at setup; the provider narrows to them. */\n operations?: VaultProviderOperations;\n valueCacheMs?: number;\n signal?: AbortSignal;\n}\n\n/**\n * One Keeper connection for a server: redeems a one-time token or opens a\n * stored configuration, and returns the provider with the bound configuration\n * as a string record. The one-time token is never part of the result. Each\n * call has its own provider; SDK state is per operation, so connections never\n * share keys.\n */\nexport async function openKeeperConnection(\n options: OpenKeeperConnectionOptions,\n): Promise<{ provider: KeeperVaultProvider; configuration: Record<string, string> }> {\n const persist = options.persistConfiguration;\n if (!persist) {\n throw new VaultProviderError(\n \"provider_unavailable\",\n \"Keeper connections need durable configuration storage on this server\",\n );\n }\n const { credentials, persistConfiguration: _persist, operations, signal, ...runtime } = options;\n let configuration: Record<string, string>;\n if (\"oneTimeToken\" in credentials) {\n const bound = await bootstrapKeeperConfiguration({\n ...runtime,\n oneTimeToken: credentials.oneTimeToken,\n ...(credentials.hostname ? { hostname: credentials.hostname } : {}),\n ...(signal ? { signal } : {}),\n persistConfiguration: (next, context) =>\n persist(keeperConfigurationRecord(next), { reason: context.reason }),\n });\n configuration = keeperConfigurationRecord(bound.configuration);\n } else {\n configuration = keeperConfigurationRecord(credentials.configuration);\n }\n const provider = createKeeperVaultProvider({\n ...runtime,\n configuration,\n ...(operations ? { operations } : {}),\n persistConfiguration: (next, context) =>\n persist(keeperConfigurationRecord(next), { reason: context.reason }),\n });\n return { provider, configuration };\n}\n"],"mappings":"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","names":["require","storage","recordUid"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type ProviderItemMeta, type ProviderWriteItem, type TotpParams, type VaultFieldKind, type VaultItemType } from "./contract.js";
|
|
2
|
+
import type { KeeperFile, KeeperRecord } from "./sdk.js";
|
|
3
|
+
/**
|
|
4
|
+
* External field ids are positional, because Keeper record fields have no
|
|
5
|
+
* ids of their own: `f:<type>` for standard fields, `c:<label or type>` for
|
|
6
|
+
* custom fields, `#n` for repeats, `@notes` for the record notes and
|
|
7
|
+
* `@file:<fileUid>` for attachments.
|
|
8
|
+
*/
|
|
9
|
+
export declare const NOTES_FIELD_ID = "@notes";
|
|
10
|
+
export declare const FILE_FIELD_PREFIX = "@file:";
|
|
11
|
+
export interface KeeperFieldEntry {
|
|
12
|
+
type: string;
|
|
13
|
+
label?: string;
|
|
14
|
+
value?: unknown[];
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
export interface KeeperRecordData {
|
|
18
|
+
title?: string;
|
|
19
|
+
type?: string;
|
|
20
|
+
fields?: KeeperFieldEntry[];
|
|
21
|
+
custom?: KeeperFieldEntry[];
|
|
22
|
+
notes?: string;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
export type MappedSource = {
|
|
26
|
+
kind: "field";
|
|
27
|
+
list: "fields" | "custom";
|
|
28
|
+
index: number;
|
|
29
|
+
} | {
|
|
30
|
+
kind: "notes";
|
|
31
|
+
} | {
|
|
32
|
+
kind: "file";
|
|
33
|
+
file: KeeperFile;
|
|
34
|
+
};
|
|
35
|
+
export interface MappedKeeperField {
|
|
36
|
+
externalFieldId: string;
|
|
37
|
+
name: string;
|
|
38
|
+
kind: VaultFieldKind;
|
|
39
|
+
source: MappedSource;
|
|
40
|
+
/** Plain value for text/concealed/totp fields; files are read separately. */
|
|
41
|
+
value: string;
|
|
42
|
+
}
|
|
43
|
+
export declare function itemTypeForRecordType(type: string | undefined): VaultItemType;
|
|
44
|
+
export interface MappedKeeperRecord {
|
|
45
|
+
meta: ProviderItemMeta;
|
|
46
|
+
fields: MappedKeeperField[];
|
|
47
|
+
}
|
|
48
|
+
export declare function recordData(record: KeeperRecord): KeeperRecordData;
|
|
49
|
+
export declare function mapRecord(record: KeeperRecord): MappedKeeperRecord;
|
|
50
|
+
/** The record's file size as Keeper reports it, if any. */
|
|
51
|
+
export declare function fileSize(file: KeeperFile): number | null;
|
|
52
|
+
export declare function totpParamsFor(value: string): TotpParams | null;
|
|
53
|
+
/** Record data for a create; Keeper `login` and `encryptedNotes` record types only. */
|
|
54
|
+
export declare function buildCreateData(item: ProviderWriteItem): KeeperRecordData;
|
|
55
|
+
/**
|
|
56
|
+
* Applies a field patch to a fetched record in place. Untouched fields are
|
|
57
|
+
* preserved; custom fields can be removed, standard fields are emptied.
|
|
58
|
+
*/
|
|
59
|
+
export declare function applyPatch(record: KeeperRecord, item: ProviderWriteItem): void;
|
package/dist/naming.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type TotpParams } from "./contract.js";
|
|
2
|
+
export declare function nameKey(name: string): string;
|
|
3
|
+
export declare function safeSecretName(raw: string, fallback: string): string;
|
|
4
|
+
export declare function safeFieldName(raw: string, fallback: string): string;
|
|
5
|
+
/** Appends " (2)", " (3)" … so names are unique case-insensitively. */
|
|
6
|
+
export declare function uniqueName(name: string, taken: Set<string>): string;
|
|
7
|
+
/** A canonical otpauth URI for a parsed seed, for stores that require URIs. */
|
|
8
|
+
export declare function totpUri(params: TotpParams, label: string): string;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type VaultProvider, type VaultProviderOperations } from "./contract.js";
|
|
2
|
+
/**
|
|
3
|
+
* Narrows an adapter to the operations verified when its connection was set
|
|
4
|
+
* up: what it reports and what it will do. It never widens the adapter's own
|
|
5
|
+
* operations, and refused calls make no provider request.
|
|
6
|
+
*/
|
|
7
|
+
export declare function restrictToOperations<P extends VaultProvider>(provider: P, verified: VaultProviderOperations | undefined, fileFieldPrefix: string): P;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { type VaultProvider, type VaultProviderOperations } from "./contract.js";
|
|
2
|
+
import { type KeeperConfigValues, memoryKeeperStorage } from "./config.js";
|
|
3
|
+
import { type MutationTracker } from "./errors.js";
|
|
4
|
+
import { type CapturedConsole, type KeeperFetch, type KeeperFileFetcher, type KeeperQueryFunction, type KeeperSdk, type KeeperSdkLoader, type SecretManagerOptions } from "./sdk.js";
|
|
5
|
+
export declare const KEEPER_VALUE_CACHE_MS: 60000;
|
|
6
|
+
/** What KSM 17.6.0 can do for an application (see README for the evidence). */
|
|
7
|
+
export declare const KEEPER_OPERATIONS: VaultProviderOperations;
|
|
8
|
+
/**
|
|
9
|
+
* Persists a changed configuration; the parent stores it encrypted with
|
|
10
|
+
* compare-and-swap. `configuration` is canonical JSON of a string record
|
|
11
|
+
* (binary entries are base64). `previous` is null for the first save after
|
|
12
|
+
* binding a one-time token.
|
|
13
|
+
*/
|
|
14
|
+
export type PersistKeeperConfiguration = (configuration: string, context: {
|
|
15
|
+
previous: string | null;
|
|
16
|
+
reason: "bind" | "rotation";
|
|
17
|
+
}) => Promise<void>;
|
|
18
|
+
export interface KeeperRuntimeOptions {
|
|
19
|
+
/** Hosts the configuration may name (default: Keeper's seven region hosts). */
|
|
20
|
+
allowedHosts?: readonly string[];
|
|
21
|
+
/** Per-request deadline handed to the SDK (default 15 s). */
|
|
22
|
+
requestTimeoutMs?: number;
|
|
23
|
+
/**
|
|
24
|
+
* The fetch both default transports use (KSM API and file downloads).
|
|
25
|
+
* Servers pass a DNS-pinned fetch; the per-call abort signal and deadline
|
|
26
|
+
* are still applied. Ignored where `queryFunction` or `fetchFile` is given.
|
|
27
|
+
*/
|
|
28
|
+
fetch?: KeeperFetch;
|
|
29
|
+
/** SDK request function (tests); defaults to a bounded, no-redirect fetch transport. */
|
|
30
|
+
queryFunction?: KeeperQueryFunction;
|
|
31
|
+
/** Encrypted file download (tests); defaults to a bounded HTTPS fetch. */
|
|
32
|
+
fetchFile?: KeeperFileFetcher;
|
|
33
|
+
/** SDK loader (tests or bundlers that ship the SDK source themselves). */
|
|
34
|
+
sdk?: KeeperSdkLoader;
|
|
35
|
+
now?: () => number;
|
|
36
|
+
}
|
|
37
|
+
export interface KeeperVaultProviderOptions extends KeeperRuntimeOptions {
|
|
38
|
+
/** Operations verified at setup; the adapter narrows to them and never widens. */
|
|
39
|
+
operations?: VaultProviderOperations;
|
|
40
|
+
/**
|
|
41
|
+
* The bound KSM configuration from bootstrap or Keeper tooling: JSON, base64
|
|
42
|
+
* JSON, or the parsed string record.
|
|
43
|
+
*/
|
|
44
|
+
configuration: string | Readonly<Record<string, string>>;
|
|
45
|
+
/** Awaited whenever the SDK changes the configuration (server key rotation). */
|
|
46
|
+
persistConfiguration: PersistKeeperConfiguration;
|
|
47
|
+
valueCacheMs?: number;
|
|
48
|
+
}
|
|
49
|
+
export type KeeperVaultProvider = VaultProvider & {
|
|
50
|
+
readonly id: "keeper";
|
|
51
|
+
/** The configuration as last persisted or pending persistence. */
|
|
52
|
+
currentConfiguration(): string;
|
|
53
|
+
close(): Promise<void>;
|
|
54
|
+
};
|
|
55
|
+
export interface KeeperOperation {
|
|
56
|
+
sdk: KeeperSdk;
|
|
57
|
+
options: SecretManagerOptions;
|
|
58
|
+
console: CapturedConsole;
|
|
59
|
+
tracker: MutationTracker & {
|
|
60
|
+
mutating: boolean;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Runs one operation in a fresh SDK instance over an in-memory copy of the
|
|
65
|
+
* configuration, with the adapter's host allowlist, deadline and throttle
|
|
66
|
+
* policy. Shared by the provider and bootstrap.
|
|
67
|
+
*/
|
|
68
|
+
export declare function runKeeperOperation<T>(input: {
|
|
69
|
+
runtime: KeeperRuntimeOptions;
|
|
70
|
+
loader: KeeperSdkLoader;
|
|
71
|
+
config: KeeperConfigValues;
|
|
72
|
+
signal?: AbortSignal;
|
|
73
|
+
work: (op: KeeperOperation, storage: ReturnType<typeof memoryKeeperStorage>) => Promise<T>;
|
|
74
|
+
beforeNetwork?: (storage: ReturnType<typeof memoryKeeperStorage>) => void;
|
|
75
|
+
/** Bootstrap sets the host inside `work`; every request is still checked. */
|
|
76
|
+
hostInConfig?: boolean;
|
|
77
|
+
}): Promise<{
|
|
78
|
+
result: T;
|
|
79
|
+
storage: ReturnType<typeof memoryKeeperStorage>;
|
|
80
|
+
}>;
|
|
81
|
+
export declare function createKeeperVaultProvider(options: KeeperVaultProviderOptions): KeeperVaultProvider;
|
package/dist/sdk.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type * as KeeperSdkModule from "@keeper-security/secrets-manager-core";
|
|
2
|
+
/** The official SDK release this adapter is written and tested against. */
|
|
3
|
+
export declare const KEEPER_SDK_VERSION = "17.6.0";
|
|
4
|
+
export declare const KEEPER_SDK_PACKAGE = "@keeper-security/secrets-manager-core";
|
|
5
|
+
/** SHA-256 of `dist/index.cjs.js` in @keeper-security/secrets-manager-core 17.6.0. */
|
|
6
|
+
export declare const KEEPER_SDK_SHA256 = "94787ce51324f36c1b62d19ac29fbe3b9b206305695e508b76585a4d6e39635c";
|
|
7
|
+
export type KeeperSdk = typeof KeeperSdkModule;
|
|
8
|
+
export type KeeperRecord = KeeperSdkModule.KeeperRecord;
|
|
9
|
+
export type KeeperFolder = KeeperSdkModule.KeeperFolder;
|
|
10
|
+
export type KeeperFile = KeeperSdkModule.KeeperFile;
|
|
11
|
+
export type KeeperSecrets = KeeperSdkModule.KeeperSecrets;
|
|
12
|
+
export type KeyValueStorage = KeeperSdkModule.KeyValueStorage;
|
|
13
|
+
export type SecretManagerOptions = KeeperSdkModule.SecretManagerOptions;
|
|
14
|
+
export type KeeperQueryFunction = NonNullable<SecretManagerOptions["queryFunction"]>;
|
|
15
|
+
export type KeeperHttpResponse = Awaited<ReturnType<KeeperQueryFunction>>;
|
|
16
|
+
/**
|
|
17
|
+
* Bounded log capture for one SDK instance. The SDK reports skipped records,
|
|
18
|
+
* folders and files only through `console.error`; those lines carry record
|
|
19
|
+
* UIDs and error text, so they are inspected here and never forwarded.
|
|
20
|
+
*/
|
|
21
|
+
export declare class CapturedConsole {
|
|
22
|
+
readonly lines: string[];
|
|
23
|
+
private static readonly MAX_LINES;
|
|
24
|
+
private static readonly MAX_CHARS;
|
|
25
|
+
private push;
|
|
26
|
+
readonly error: (...args: unknown[]) => void;
|
|
27
|
+
readonly warn: (...args: unknown[]) => void;
|
|
28
|
+
readonly log: (...args: unknown[]) => void;
|
|
29
|
+
readonly info: (...args: unknown[]) => void;
|
|
30
|
+
readonly debug: (...args: unknown[]) => void;
|
|
31
|
+
/** True when the SDK dropped a record, folder or file it could not decrypt. */
|
|
32
|
+
get skippedSomething(): boolean;
|
|
33
|
+
}
|
|
34
|
+
/** Reads the installed SDK's CommonJS build (a read only; nothing is executed here). */
|
|
35
|
+
export declare function readInstalledKeeperSdkSource(): string;
|
|
36
|
+
export interface KeeperSdkInstance {
|
|
37
|
+
sdk: KeeperSdk;
|
|
38
|
+
console: CapturedConsole;
|
|
39
|
+
}
|
|
40
|
+
export interface KeeperSdkLoader {
|
|
41
|
+
/** A new, private SDK module instance (its own key cache and platform). */
|
|
42
|
+
instance(): KeeperSdkInstance;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The SDK keeps decrypted application, folder and record keys in a
|
|
46
|
+
* module-global cache and reads keys from that cache before storage, so one
|
|
47
|
+
* module instance must never serve two connections. Each operation evaluates
|
|
48
|
+
* the pinned CommonJS build in a fresh scope, which gives it its own cache,
|
|
49
|
+
* platform and storage serialization, and is discarded afterwards.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createKeeperSdkLoader(options?: {
|
|
52
|
+
source?: string | (() => string);
|
|
53
|
+
expectedSha256?: string;
|
|
54
|
+
}): KeeperSdkLoader;
|
|
55
|
+
/** Default transport limits. */
|
|
56
|
+
export declare const KEEPER_REQUEST_TIMEOUT_MS = 15000;
|
|
57
|
+
export declare const KEEPER_MAX_RESPONSE_BYTES: number;
|
|
58
|
+
/**
|
|
59
|
+
* The `fetch` the adapter's transports call. Servers pass a DNS-pinned fetch
|
|
60
|
+
* (for example `pinnedFetch` from `@opengeni/network`); the adapter still sets
|
|
61
|
+
* the method, headers, body, abort signal and `redirect: "error"`, and refuses
|
|
62
|
+
* any redirect status a manual-redirect fetch returns.
|
|
63
|
+
*/
|
|
64
|
+
export type KeeperFetch = (input: string | URL, init: RequestInit) => Promise<Response>;
|
|
65
|
+
/**
|
|
66
|
+
* The SDK's request function, reimplemented over `fetch` so requests follow no
|
|
67
|
+
* redirects, honour the caller's abort signal, and read bounded bodies. Headers
|
|
68
|
+
* match the SDK's `postFunction` (PublicKeyId, TransmissionKey, Authorization).
|
|
69
|
+
*/
|
|
70
|
+
export declare function createKeeperFetchTransport(options?: {
|
|
71
|
+
fetch?: KeeperFetch;
|
|
72
|
+
maxResponseBytes?: number;
|
|
73
|
+
signal?: AbortSignal;
|
|
74
|
+
}): KeeperQueryFunction;
|
|
75
|
+
/** Downloads an encrypted file body from a Keeper-issued URL, bounded in size and time. */
|
|
76
|
+
export type KeeperFileFetcher = (url: string, options: {
|
|
77
|
+
signal?: AbortSignal;
|
|
78
|
+
maxBytes: number;
|
|
79
|
+
timeoutMs: number;
|
|
80
|
+
}) => Promise<Uint8Array>;
|
|
81
|
+
export declare function createKeeperFileFetcher(fetchImpl?: KeeperFetch): KeeperFileFetcher;
|
package/package.json
CHANGED
|
@@ -1,6 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opengeni/vaults-keeper",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "3.2.2",
|
|
4
|
+
"description": "Keeper Secrets Manager provider for Opengeni vaults on the pinned official SDK, with one SDK instance per operation. Load it only through dynamic import() from the API and worker.",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/Cloudgeni-ai/opengeni.git",
|
|
9
|
+
"directory": "packages/vaults-keeper"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"src",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"type": "module",
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"main": "./dist/index.js",
|
|
19
|
+
"module": "./dist/index.js",
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"exports": {
|
|
22
|
+
".": {
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"publishConfig": {
|
|
28
|
+
"access": "public",
|
|
29
|
+
"provenance": true
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "bun ../../scripts/build-typescript-package.ts",
|
|
33
|
+
"typecheck": "tsc --noEmit",
|
|
34
|
+
"prepublishOnly": "bash ../../scripts/prepublish-guard"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@keeper-security/secrets-manager-core": "17.6.0",
|
|
38
|
+
"@opengeni/contracts": "3.2.2",
|
|
39
|
+
"@opengeni/vaults": "3.2.2"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"node": ">=20"
|
|
43
|
+
}
|
|
44
|
+
}
|