import {z} from 'zod' export type AccessPolicy = {accessPattern?: ('NUMBER_LIMITED' | 'READ_CONFIRM' | 'TIME_LIMITED' | 'UNRESTRICTED') | undefined, count?: number | undefined, numberLimit?: number | undefined}; export type TimestampReq = {date?: number | undefined, hours?: number | undefined, minutes?: number | undefined, month?: number | undefined, nanos?: number | undefined, seconds?: number | undefined, time?: number | undefined, year?: number | undefined}; export type CPAssociationRequest = {visibility?: ('PRIVATE' | 'PUBLIC' | 'RESTRICTED') | undefined}; export type AssociationRequest = {aliases?: {[key: string]: string} | undefined, termsAndConditionsUrl?: string | undefined}; export type Invitation = {associationRequest?: AssociationRequest | undefined, serviceUrls?: Array | undefined}; export type PersonCredentialIssuanceNotification = {credentialTypeExtendedName?: string | undefined, credentialTypeHref?: string | undefined, personEmail?: string | undefined, personHref?: string | undefined, result?: ('FAILED_ISSUANCE' | 'SUCCESSFUL_ISSUANCE') | undefined}; export type ChannelSendError = {channel?: ('EMAIL' | 'PUSH_NOTIFICATION' | 'SMS') | undefined, code?: number | undefined}; export type PersonInfoNotification = {params?: {[key: string]: string} | undefined, requestedChannels?: (Array<'EMAIL' | 'PUSH_NOTIFICATION' | 'SMS'>) | undefined, sendErrors?: Array | undefined, type?: string | undefined}; export type MessageInfo = {cpAssociationRequest?: CPAssociationRequest | undefined, credentials?: Array | undefined, invitation?: Invitation | undefined, personCredentialIssuanceNotification?: PersonCredentialIssuanceNotification | undefined, personInfoNotification?: PersonInfoNotification | undefined}; export type SourceInfo = Record; export type MessageReq = {accessPolicy?: AccessPolicy | undefined, availableToDestination?: boolean | undefined, code?: string | undefined, createdDtm?: TimestampReq | undefined, destId?: string | undefined, destName?: string | undefined, destType?: ('CREDENTIAL_PROVIDER' | 'PERSON' | 'SERVICE_PROVIDER' | 'SYSTEM') | undefined, emailDetails?: Record | undefined, emailTo?: string | undefined, expiringDtm?: TimestampReq | undefined, footer?: string | undefined, id?: string | undefined, info?: MessageInfo | undefined, lastUpdatedDtm?: TimestampReq | undefined, notBeforeDtm?: TimestampReq | undefined, note?: string | undefined, permittedOperations?: Array | undefined, previousMessageId?: string | undefined, readCount?: number | undefined, secureContent?: string | undefined, sourceId?: string | undefined, sourceInfo?: SourceInfo | undefined, sourceName?: string | undefined, sourceType?: ('CREDENTIAL_PROVIDER' | 'PERSON' | 'SERVICE_PROVIDER' | 'SYSTEM') | undefined, status?: ('ACTIVE' | 'ASSOC_REQ_ACCEPTED' | 'ASSOC_REQ_DECLINED' | 'DELETED' | 'EXPIRED' | 'INVITE_ACCEPTED' | 'INVITE_DECLINED' | 'NOT_SENT' | 'PENDING') | undefined, subject?: string | undefined, type?: ('ASSOCIATION_REQUEST' | 'CREDENTIAL' | 'INVITATION' | 'NOTICE' | 'PERSON_NOTIFICATION') | undefined}; export type CreateApiApiMessagesArgs = {body: MessageReq}; export type CreateApiApiMessagesOptions = {baseUrl: string, fetch?: typeof fetch | undefined}; export const accessPolicy = z.object({accessPattern: z.enum(["NUMBER_LIMITED", "READ_CONFIRM", "TIME_LIMITED", "UNRESTRICTED"]).optional(), count: z.number().int().optional(), numberLimit: z.number().int().optional()}); export const timestampRes = z.object({date: z.number().int().optional(), day: z.number().int().optional(), hours: z.number().int().optional(), minutes: z.number().int().optional(), month: z.number().int().optional(), nanos: z.number().int().optional(), seconds: z.number().int().optional(), time: z.number().int().optional(), timezoneOffset: z.number().int().optional(), year: z.number().int().optional()}); export const cPAssociationRequest = z.object({visibility: z.enum(["PRIVATE", "PUBLIC", "RESTRICTED"]).optional()}); export const associationRequest = z.object({aliases: z.record(z.string(), z.string()).optional(), termsAndConditionsUrl: z.string().optional()}); export const invitation = z.object({associationRequest: associationRequest.optional(), serviceUrls: z.array(z.string()).optional()}); export const personCredentialIssuanceNotification = z.object({credentialTypeExtendedName: z.string().optional(), credentialTypeHref: z.string().optional(), personEmail: z.string().optional(), personHref: z.string().optional(), result: z.enum(["FAILED_ISSUANCE", "SUCCESSFUL_ISSUANCE"]).optional()}); export const channelSendError = z.object({channel: z.enum(["EMAIL", "PUSH_NOTIFICATION", "SMS"]).optional(), code: z.number().int().optional()}); export const personInfoNotification = z.object({params: z.record(z.string(), z.string()).optional(), requestedChannels: z.array(z.enum(["EMAIL", "PUSH_NOTIFICATION", "SMS"])).optional(), sendErrors: z.array(channelSendError).optional(), type: z.string().optional()}); export const messageInfo = z.object({cpAssociationRequest: cPAssociationRequest.optional(), credentials: z.array(z.string()).optional(), invitation: invitation.optional(), personCredentialIssuanceNotification: personCredentialIssuanceNotification.optional(), personInfoNotification: personInfoNotification.optional()}); export const sourceInfo = z.object({}); export const messageRes = z.object({accessPolicy: accessPolicy.optional(), availableToDestination: z.boolean().optional(), code: z.string().optional(), createdDtm: timestampRes.optional(), destId: z.string().optional(), destName: z.string().optional(), destType: z.enum(["CREDENTIAL_PROVIDER", "PERSON", "SERVICE_PROVIDER", "SYSTEM"]).optional(), emailDetails: z.object({}).optional(), emailTo: z.string().optional(), expiringDtm: timestampRes.optional(), footer: z.string().optional(), href: z.string().optional(), id: z.string().optional(), info: messageInfo.optional(), lastUpdatedDtm: timestampRes.optional(), notBeforeDtm: timestampRes.optional(), note: z.string().optional(), permittedOperations: z.array(z.string()).optional(), previousMessageId: z.string().optional(), readCount: z.number().int().optional(), secureContent: z.string().optional(), sourceId: z.string().optional(), sourceInfo: sourceInfo.optional(), sourceName: z.string().optional(), sourceType: z.enum(["CREDENTIAL_PROVIDER", "PERSON", "SERVICE_PROVIDER", "SYSTEM"]).optional(), status: z.enum(["ACTIVE", "ASSOC_REQ_ACCEPTED", "ASSOC_REQ_DECLINED", "DELETED", "EXPIRED", "INVITE_ACCEPTED", "INVITE_DECLINED", "NOT_SENT", "PENDING"]).optional(), subject: z.string().optional(), type: z.enum(["ASSOCIATION_REQUEST", "CREDENTIAL", "INVITATION", "NOTICE", "PERSON_NOTIFICATION"]).optional()}); export const validateResponse = async ( schema: { readonly '~standard': { readonly validate: (value: unknown) => ({ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }) | Promise<{ readonly value: Output; readonly issues?: undefined } | { readonly issues: ReadonlyArray<{ readonly message: string; readonly path?: ReadonlyArray | undefined }> }> } }, value: unknown ): Promise => { const result = await schema['~standard'].validate(value) if (result.issues !== undefined) { const detail = result.issues .map(({ message, path }) => path?.length ? `${path.map((segment) => String(typeof segment === 'object' ? segment.key : segment)).join('.')}: ${message}` : message ) .join('; ') throw new Error(`Response does not match the schema: ${detail}`, { cause: { issues: result.issues } }) } return result.value }; /** * Create a message * * POST /api/messages */ export const createApiApiMessages = async (args: CreateApiApiMessagesArgs, options: CreateApiApiMessagesOptions) => { const {baseUrl, fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") const url = `${baseUrl.replace(/\/+$/, '')}/api/messages${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "POST", headers, body: JSON.stringify(args.body)}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(messageRes, await res.json()) };