import { isEncodable, type Encodable } from "@automate.ax/codec" import { integrationScope } from "@automate.ax/catalog" import { isPlainObject } from "@zachsents/zippy" import { SquareClient } from "square" import * as z from "zod" import { defineAction, type DefinedAction } from "../../automation/actions" import type { ResolvedIntegrationAccount } from "../../automation/integrations" import type { Readable } from "node:stream" const SQUARE_SECRET_SCHEMA = z.object({ accessToken: z.string().min(1) }) type InputObject = Record /** Codec-safe form of an official Square SDK type. */ export type SquareValue = unknown extends T ? Encodable : T extends readonly (infer TItem)[] ? SquareValue[] : T extends object ? { [TKey in keyof T]: SquareValue } & { readonly [key: string]: Encodable } : T extends Encodable ? T : never /** Official Square request type accepted by an action. */ export type SquareInputValue = T extends unknown ? T extends Readable ? never : T extends Blob | File ? T : T extends readonly (infer TItem)[] ? SquareInputValue[] : T extends object ? { [TKey in keyof T]: SquareInputValue } : T : never /** Durable top-level request object for an official Square SDK input. */ export type SquareInputObject = { [TKey in keyof T]: SquareInputValue } & InputObject /** Portable public type for one Square-backed action definition. */ export type SquareDefinedAction< TInput extends InputObject, TOutput, > = DefinedAction, z.ZodType>, "square"> /** * Preserves declaration emit on public Square SDK names. * * @param action - Fully built action with matching runtime schemas. */ export function squareAction( action: SquareDefinedAction, ): SquareDefinedAction { return action } /** Normal or paginated result shape returned by official Square SDK methods. */ type SquareOperationResult = T | { hasNextPage(): boolean; response: T } /** * Defines one generated Square operation without repeating builder types. * * @param options - Validated operation metadata and SDK invocation. * @param options.allowedKeys - Accepted top-level request fields. * @param options.description - Public action description. * @param options.execute - Official SDK method binding. * @param options.name - Public action name. * @param options.replaySafety - Retry classification for ambiguous failures. * @param options.requiredKeys - Required top-level request fields. * @param options.scopes - Seller OAuth permissions required by the operation. */ export function defineSquareOperation(options: { allowedKeys: readonly string[] description: string execute: ( api: SquareClient, input: SquareInputObject, ) => PromiseLike> name: string replaySafety: "safe" | "unsafe" requiredKeys: readonly string[] scopes: readonly string[] }): SquareDefinedAction, TOutput> { return squareAction, TOutput>( defineAction(options.name) .describe(options.description) .account( "square", options.scopes.length > 1 ? integrationScope.and(...options.scopes) : options.scopes[0], ) .input( squareInputSchema({ allowedKeys: options.allowedKeys, requiredKeys: options.requiredKeys, }), ) .output(squareObjectSchema()) .retry({ replaySafety: options.replaySafety }) .handler(async ({ account, input }) => fromSquare( await options.execute(getSquareApi(account), input), ), ), ) } /** * Creates an official Square client for one resolved seller account. * * @param account - Resolved account carrying an encrypted-at-rest access token. */ export function getSquareApi(account: ResolvedIntegrationAccount<"square">) { return new SquareClient({ maxRetries: 0, token: SQUARE_SECRET_SCHEMA.parse(account.secret).accessToken, }) } /** * Runtime schema for one official Square SDK request object. * * @param options - Generated top-level request contract. * @param options.allowedKeys - Accepted request field names. * @param options.requiredKeys - Required request field names. */ export function squareInputSchema(options: { allowedKeys: readonly string[] requiredKeys: readonly string[] }): z.ZodType> { const allowedKeys = new Set(options.allowedKeys) return z.custom>( (value) => isPlainObject(value) && isEncodable(value) && Object.keys(value).every((key) => allowedKeys.has(key)) && options.requiredKeys.every((key) => value[key] !== undefined), { message: "Expected a valid Square request object." }, ) } /** Runtime schema for an official Square response object. */ export function squareObjectSchema(): z.ZodType> { return z.custom>( (value) => isPlainObject(value) && isEncodable(value), { message: "Expected an encodable Square response object." }, ) } /** * Returns the provider response from a normal or paginated SDK result. * * @param value - Official SDK response or paginated response wrapper. */ export function fromSquare( value: T | { hasNextPage(): boolean; response: T }, ): SquareValue { return squareObjectSchema().parse( typeof value === "object" && value !== null && "hasNextPage" in value && typeof value.hasNextPage === "function" && "response" in value ? value.response : value, ) }