import {z} from 'zod' export type ProductTags = {applications?: (Array<'LO Connect' | 'Encompass Smart Client' | 'urn:elli:application:consumerconnect' | 'urn:elli:application:tpoconnect' | 'urn:elli:application:developerconnect'>) | undefined, categories?: (Array<'APPRAISAL' | 'FLOOD' | 'VERIF' | 'ClosingFees' | 'PRODUCTPRICING'>) | undefined, workflows?: (Array<'interactive' | 'automated'>) | undefined}; export type ProductCredentialPropertySchema = {id: string, type: 'string' | 'number' | 'boolean', title: string, required?: boolean | undefined, pattern?: string | undefined, minimum?: number | undefined, maximum?: number | undefined, secret?: boolean | undefined, scope?: ('user' | 'company') | undefined}; export type ProductCredentialSchema = Array; export type ProductWebhook = {resource: 'urn:elli:epc:transaction' | 'urn:elli:epc:transaction:event', url: string, signingkey: string, events: Array<'created' | 'updated'>}; export type ProductWebhooks = Array; export type ProductAccessEntitlements = {allow: Array, deny: Array}; export type ProductDataEntitlementsField = {fieldId?: string | undefined, jsonPath: string, description?: string | undefined}; export type ProductDataEntitlementsFields = Array; export type ProductRequestDataEntitlementsSchema = {fields: ProductDataEntitlementsFields}; export type ProductRequestType = string; export type ProductResourceType = string; export type ProductDataEntitlementsResources = Array; export type ProductDataEntitlementsResultFormat = 'application/vnd.productpricing-lock-1.0.0.json' | 'application/vnd.productpricing-extendlock-1.0.0.json' | 'application/vnd.productpricing-relock-1.0.0.json' | 'application/vnd.productpricing-cancellock-1.0.0.json' | 'application/vnd.productpricing-lock-and-confirm-1.0.0.json'; export type ProductDataEntitlementsResult = {action?: ('LOCK' | 'RELOCK' | 'EXTEND' | 'CANCEL' | 'LOCK_CONFIRM') | undefined, formats?: Array | undefined}; export type ProductDataEntitlementsResults = Array; export type ProductResponseDataEntitlementsSchema = {fields: ProductDataEntitlementsFields, resources?: ProductDataEntitlementsResources | undefined, results?: ProductDataEntitlementsResults | undefined}; export type ProductTransactionDataEntitlements = Array<{requestTypes: Array, request: ProductRequestDataEntitlementsSchema, response: ProductResponseDataEntitlementsSchema}>; export type ResourceCreatedUpdated = string; export type ProductDataEntitlements = {origin: ProductRequestDataEntitlementsSchema, transactions: ProductTransactionDataEntitlements, created?: ResourceCreatedUpdated | undefined, createdBy?: ResourceCreatedUpdated | undefined, updated?: ResourceCreatedUpdated | undefined, updatedBy?: ResourceCreatedUpdated | undefined}; export type ProductEntitlements = {access: ProductAccessEntitlements, data: ProductDataEntitlements}; export type ProductRequest = {name: unknown, listingName: unknown, requestTypes: unknown, interfaceUrl: unknown, adminInterfaceUrl?: unknown, tags?: ProductTags | undefined, credentials?: ProductCredentialSchema | undefined, webhooks: ProductWebhooks, extensionLimit?: number | undefined, entitlements: ProductEntitlements}; export type CreateApiProductsArgs = {Authorization: string, view?: ('id' | 'credential' | 'integrationType' | 'entitlement' | 'webhook' | 'complete') | undefined, body: ProductRequest}; export type CreateApiProductsOptions = {baseUrl?: string | undefined, fetch?: typeof fetch | undefined}; export const resourceId = z.string(); export const productRequestType = z.string(); export const productTags = z.object({applications: z.array(z.enum(["LO Connect", "Encompass Smart Client", "urn:elli:application:consumerconnect", "urn:elli:application:tpoconnect", "urn:elli:application:developerconnect"])).optional(), categories: z.array(z.enum(["APPRAISAL", "FLOOD", "VERIF", "ClosingFees", "PRODUCTPRICING"])).optional(), workflows: z.array(z.enum(["interactive", "automated"])).optional()}); export const productCredentialPropertySchema = z.object({id: z.string(), type: z.enum(["string", "number", "boolean"]), title: z.string(), required: z.boolean().optional(), pattern: z.string().optional(), minimum: z.number().int().optional(), maximum: z.number().int().optional(), secret: z.boolean().optional(), scope: z.enum(["user", "company"]).optional()}); export const productCredentialSchema = z.array(productCredentialPropertySchema); export const productWebhook = z.object({resource: z.enum(["urn:elli:epc:transaction", "urn:elli:epc:transaction:event"]), url: z.string(), signingkey: z.string(), events: z.array(z.enum(["created", "updated"]))}); export const productWebhooks = z.array(productWebhook); export const productAccessEntitlements = z.object({allow: z.array(z.string()), deny: z.array(z.string())}); export const productDataEntitlementsField = z.object({fieldId: z.string().optional(), jsonPath: z.string(), description: z.string().optional()}); export const productDataEntitlementsFields = z.array(productDataEntitlementsField); export const productRequestDataEntitlementsSchema = z.object({fields: productDataEntitlementsFields}); export const productResourceType = z.string(); export const productDataEntitlementsResources = z.array(productResourceType); export const productDataEntitlementsResultFormat = z.enum(["application/vnd.productpricing-lock-1.0.0.json", "application/vnd.productpricing-extendlock-1.0.0.json", "application/vnd.productpricing-relock-1.0.0.json", "application/vnd.productpricing-cancellock-1.0.0.json", "application/vnd.productpricing-lock-and-confirm-1.0.0.json"]); export const productDataEntitlementsResult = z.object({action: z.enum(["LOCK", "RELOCK", "EXTEND", "CANCEL", "LOCK_CONFIRM"]).optional(), formats: z.array(productDataEntitlementsResultFormat).optional()}); export const productDataEntitlementsResults = z.array(productDataEntitlementsResult); export const productResponseDataEntitlementsSchema = z.object({fields: productDataEntitlementsFields, resources: productDataEntitlementsResources.optional(), results: productDataEntitlementsResults.optional()}); export const productTransactionDataEntitlements = z.array(z.object({requestTypes: z.array(productRequestType), request: productRequestDataEntitlementsSchema, response: productResponseDataEntitlementsSchema})); export const resourceCreatedUpdated = z.string(); export const productDataEntitlements = z.object({origin: productRequestDataEntitlementsSchema, transactions: productTransactionDataEntitlements, created: resourceCreatedUpdated.optional(), createdBy: resourceCreatedUpdated.optional(), updated: resourceCreatedUpdated.optional(), updatedBy: resourceCreatedUpdated.optional()}); export const productEntitlements = z.object({access: productAccessEntitlements, data: productDataEntitlements}); export const resourceCreatedUpdatedBy = z.string(); export const product = z.object({id: resourceId.optional(), partnerId: z.number().int(), name: z.string(), listingName: z.string(), requestTypes: z.array(productRequestType), environment: z.enum(["sandbox", "production"]).optional(), status: z.enum(["development", "inReview", "approved", "deprecated"]).optional(), integrationType: z.enum(["ASYNC", "P2P"]), interfaceUrl: z.string().optional(), adminInterfaceUrl: z.string().optional(), tags: productTags.optional(), credentials: productCredentialSchema.optional(), webhooks: productWebhooks, extensionLimit: z.number().int().optional(), entitlements: productEntitlements, created: resourceCreatedUpdated.optional(), createdBy: resourceCreatedUpdatedBy.optional(), updated: resourceCreatedUpdated.optional(), updatedBy: resourceCreatedUpdatedBy.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 }; /** * Register a new product * * POST /products */ export const createApiProducts = async (args: CreateApiProductsArgs, options?: CreateApiProductsOptions) => { const {baseUrl = "https://api.elliemae.com/oauth2/v1", fetch: fetchFn = fetch} = options ?? {} const query = new URLSearchParams() const headers = new Headers() headers.set('content-type', "application/json") headers.set('accept', "application/json") if (args.Authorization != null) headers.set("Authorization", String(args.Authorization)) if (args.view != null) query.append("view", String(args.view)) const url = `${baseUrl.replace(/\/+$/, '')}/products${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(product, await res.json()) };