import {z} from 'zod' export type GetApiExperimentalFlowDraftsDraftIdArgs = {draft_id: string}; export type GetApiExperimentalFlowDraftsDraftIdOptions = {baseUrl?: string | undefined, OAuth10?: string | undefined, fetch?: typeof fetch | undefined}; export const userName = z.string(); export const messageName = z.string(); export const notifyMethods = z.object({email: messageName.optional(), sms: messageName.optional(), "email-link-only": z.boolean().optional()}); export const notifyKind = z.enum(["standard", "confirmation"]); export const notifyDetails = z.object({users: z.array(userName), methods: notifyMethods, kind: notifyKind.optional()}); export const notifyAction = z.object({notify: notifyDetails}); export const documentName = z.string(); export const allowViewingDetails = z.object({users: z.array(userName), documents: z.array(documentName)}); export const allowViewingAction = z.object({"allow-viewing": allowViewingDetails}); export const denyViewingDetails = z.object({users: z.array(userName), documents: z.array(documentName)}); export const denyViewingAction = z.object({"deny-viewing": denyViewingDetails}); export const callbackName = z.string().max(128); export const callbackDetails = z.object({"callback-name": callbackName}); export const callbackAction = z.object({callback: callbackDetails}); export const systemAction = z.union([notifyAction, allowViewingAction, denyViewingAction, callbackAction]); export const approvedBy = z.object({documents: z.array(documentName), users: z.array(userName)}); export const approvedByGroupOf = z.object({"required-approvals": z.number().int().gte(0).lte(18446744073709552000), documents: z.array(documentName), users: z.array(userName)}); export const signedBy = z.object({documents: z.array(documentName), users: z.array(userName)}); export const signedByGroupOf = z.object({"required-signatures": z.number().int().gte(0).lte(18446744073709552000), documents: z.array(documentName), users: z.array(userName)}); export const viewedBy = z.object({documents: z.array(documentName), users: z.array(userName)}); export const url = z.string(); export const redirectTo = z.object({users: z.array(userName), url: url}); export const expect = z.object({"approved-by": approvedBy.optional(), "approved-by-group-of": approvedByGroupOf.optional(), "signed-by": signedBy.optional(), "signed-by-group-of": signedByGroupOf.optional(), "viewed-by": viewedBy.optional(), "redirect-to": redirectTo.optional()}); export const flowDSLStageRegular = z.record(z.string(), z.object({actions: z.array(systemAction), expect: expect})); export const confirmationAction = z.object({notify: z.object({users: z.array(userName), methods: notifyMethods, kind: z.literal("confirmation")})}); export const flowDSLStageConfirmation = z.record(z.string(), z.object({actions: z.array(confirmationAction), expect: z.object({})})); export const flowDSLStage = z.union([flowDSLStageRegular, flowDSLStageConfirmation]); export const dslVersion = z.string(); export const allowRejections = z.boolean(); export const timeOfDay = z.string(); export const reminderRelativeTime = z.object({time_of_day: timeOfDay, time_zone: z.string()}); export const reminderRepeat = z.enum(["never", "periodically"]); export const reminderDate = z.union([z.object({type: z.literal("absolute"), date_time: z.string()}), z.object({type: z.literal("relative"), days_delay: z.number().int().gte(1).lte(365), time: reminderRelativeTime.optional(), repeat: reminderRepeat.optional()})]); export const automaticReminderMethod = z.enum(["email", "sms", "email-and-sms"]); export const automaticReminder = z.object({"user-name": userName, date: reminderDate, method: automaticReminderMethod}); export const flowDSL = z.object({stages: z.array(flowDSLStage), "dsl-version": dslVersion, "allow-rejections": allowRejections.optional(), "automatic-reminders": z.array(automaticReminder).optional()}); export const documentID = z.string(); export const userIdType = z.enum(["email", "phone_number", "user_id", "full_name"]); export const onfidoMethod = z.enum(["document", "document_and_photo", "document_and_video", "document_and_motion"]); export const onfidoCountry = z.string(); export const onfidoDocumentType = z.enum(["national_identity_card", "driving_licence", "passport", "residence_permit"]); export const onfidoDocumentCapture = z.enum(["mobile_only", "mobile_or_desktop"]); export const onfidoAdditionalReportInfo = z.enum(["driving_licence_info", "address_info"]); export const nOUiLocale = z.enum(["nb", "en"]); export const uiLocale = z.enum(["nb-NO", "en-GB", "da-DK", "sv-SE", "fi-FI", "sv-FI"]); export const tupasBank = z.enum(["nordea", "opbank", "danske", "handelsbanken", "aland", "sbank", "aktia", "popbank", "savingsbank", "omasp", "mobileid"]); export const authenticationConfiguration = z.union([z.object({provider: z.literal("sms_otp"), max_failures: z.number().int().gte(0).lte(255), attempts_per_sms: z.number().int().gte(1).lte(5).optional()}), z.object({provider: z.literal("onfido"), max_failures: z.number().int().gte(0).lte(255), method: onfidoMethod.optional(), allowed_document_countries: z.array(onfidoCountry).optional(), allowed_document_types: z.array(onfidoDocumentType).optional(), document_capture: onfidoDocumentCapture.optional(), additional_report_info: onfidoAdditionalReportInfo.optional(), email: z.string().optional()}), z.object({provider: z.literal("se_bankid"), max_failures: z.number().int().gte(0).lte(255)}), z.object({provider: z.literal("dk_mitid"), max_failures: z.number().int().gte(0).lte(255)}), z.object({provider: z.literal("no_bankid"), max_failures: z.number().int().gte(0).lte(255), ui_locale: nOUiLocale.optional()}), z.object({provider: z.literal("ftn"), max_failures: z.number().int().gte(0).lte(255), ui_locale: uiLocale.optional(), force_bank: tupasBank.optional()})]); export const userConfiguration = z.object({id: z.string(), id_type: userIdType, auth_to_view: authenticationConfiguration.optional(), auth_to_view_archived: authenticationConfiguration.optional()}); export const message = z.string(); export const processParameters = z.object({documents: z.record(z.string(), documentID), users: z.record(z.string(), userConfiguration), messages: z.record(z.string(), message)}); export const callbackUrl = z.string(); export const flowCallbackAuthType = z.enum(["none", "basic"]); export const callbackVersion = z.literal("v1"); export const getCallback = z.object({url: callbackUrl, auth_type: flowCallbackAuthType, version: callbackVersion}); export const uTCTime = z.string(); export const userID = z.string(); export const folderID = z.string(); export const getDraft = z.object({id: z.string(), title: z.string().optional(), process: flowDSL.optional(), process_parameters: processParameters.optional(), callback: getCallback.optional(), created: uTCTime, author_id: userID, folder_id: folderID, duration: z.object({days: z.number().int().gte(0).lte(365).optional(), hours: z.number().int().gte(0).lte(8760).optional(), minutes: z.number().int().gte(0).lte(525600).optional()}).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 }; /** * Get a Flow draft * * GET /experimental/flow/drafts/{draft_id} * * Also accepts auth: OAuth2.0, SessionCookie + XToken */ export const getApiExperimentalFlowDraftsDraftId = async (args: GetApiExperimentalFlowDraftsDraftIdArgs, options?: GetApiExperimentalFlowDraftsDraftIdOptions) => { const {baseUrl = "https://scrive.com", fetch: fetchFn = fetch, OAuth10} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('accept', "application/json;charset=utf-8") if (OAuth10 !== undefined) headers.set('authorization', `oauth1 ${OAuth10}`) const url = `${baseUrl.replace(/\/+$/, '')}/experimental/flow/drafts/${encodeURIComponent(String(args.draft_id))}${query.size > 0 ? `?${query}` : ''}` const res = await fetchFn(url, {method: "GET", headers}) if (!res.ok) throw new Error(`Request failed with status ${res.status}`, {cause: {status: res.status, body: await res.text()}}) return validateResponse(getDraft, await res.json()) };