import {z} from 'zod' export type GetApiExperimentalFlowDraftsOptions = {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 callbackUrl = z.string(); export const authMethod = z.union([z.object({type: z.literal("basic"), user: z.string(), password: z.string()}), z.object({type: z.literal("none")})]); export const callbackVersion = z.literal("v1"); export const callback = z.object({url: callbackUrl, auth: authMethod.optional(), version: callbackVersion}); export const uTCTime = z.string(); export const userID = z.string(); export const folderID = z.string(); export const draftsListItem = z.object({id: z.string(), title: z.string().optional(), process: flowDSL.optional(), callback: callback.optional(), created: uTCTime, author_id: userID, folder_id: folderID}); export const getApiExperimentalFlowDraftsResponse = z.array(draftsListItem); 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 }; /** * List Flow drafts * * GET /experimental/flow/drafts * * Also accepts auth: OAuth2.0, SessionCookie + XToken */ export const getApiExperimentalFlowDrafts = async (options?: GetApiExperimentalFlowDraftsOptions) => { 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${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(getApiExperimentalFlowDraftsResponse, await res.json()) };