// FIXME: Update this file to be type safe and remove this and next line // @ts-strict-ignore import { UserKeyDefinitionOptions, UserKeyDefinition } from "../../platform/state"; // eslint-disable-next-line -- `StateDefinition` used as an argument import { StateDefinition } from "../../platform/state/state-definition"; import { ClassifiedFormat } from "./classified-format"; import { Classifier } from "./classifier"; /** Encryption and storage settings for data stored by a `SecretState`. */ export class SecretKeyDefinition { private constructor( readonly stateDefinition: StateDefinition, readonly key: string, readonly classifier: Classifier, readonly options: UserKeyDefinitionOptions, // type erasure is necessary here because typescript doesn't support // higher kinded types that generalize over collections. The invariants // needed to make this typesafe are maintained by the static factories. readonly deconstruct: (value: any) => [Id, any][], readonly reconstruct: ([inners, ids]: (readonly [Id, any])[]) => Outer, ) {} /** Converts the secret key to the `KeyDefinition` used for secret storage. */ toEncryptedStateKey() { const secretKey = new UserKeyDefinition[]>( this.stateDefinition, this.key, { cleanupDelayMs: this.options.cleanupDelayMs, deserializer: (jsonValue) => jsonValue as ClassifiedFormat[], // Clear encrypted state on logout clearOn: this.options.clearOn, }, ); return secretKey; } /** * Define a secret state for a single value * @param stateDefinition The domain of the secret's durable state. * @param key Domain key that identifies the stored value. This key must not be reused * in any capacity. * @param classifier Partitions the value into encrypted, discarded, and public data. * @param options Configures the operation of the secret state. */ static value( stateDefinition: StateDefinition, key: string, classifier: Classifier, options: UserKeyDefinitionOptions, ) { return new SecretKeyDefinition( stateDefinition, key, classifier, options, (value) => [[null, value]], ([[, inner]]) => inner, ); } /** * Define a secret state for an array of values. Each item is encrypted separately. * @param stateDefinition The domain of the secret's durable state. * @param key Domain key that identifies the stored items. This key must not be reused * in any capacity. * @param classifier Partitions each item into encrypted, discarded, and public data. * @param options Configures the operation of the secret state. */ static array( stateDefinition: StateDefinition, key: string, classifier: Classifier, options: UserKeyDefinitionOptions, ) { return new SecretKeyDefinition( stateDefinition, key, classifier, options, (value) => value.map((v: any, id: number) => [id, v]), (values) => values.map(([, v]) => v), ); } /** * Define a secret state for a record. Each property is encrypted separately. * @param stateDefinition The domain of the secret's durable state. * @param key Domain key that identifies the stored properties. This key must not be reused * in any capacity. * @param classifier Partitions each property into encrypted, discarded, and public data. * @param options Configures the operation of the secret state. */ static record( stateDefinition: StateDefinition, key: string, classifier: Classifier, options: UserKeyDefinitionOptions, ) { return new SecretKeyDefinition, Id, Item, Disclosed, Secret>( stateDefinition, key, classifier, options, (value) => Object.entries(value) as [Id, Item][], (values) => Object.fromEntries(values) as Record, ); } }