/** * Stamps `x-speakeasy-pagination` on operations whose request body has * a `cursor` string field plus a `limit` integer field. Detection is * shape-based so new paginated routes get SDK pagination automatically. * * Locked field names: `cursor` in, `next_cursor` out. */ export function applyPaginationExtensions({ openApiDocument, }: { openApiDocument: Record; }): void { const paths = openApiDocument.paths as Record | undefined; if (!paths || typeof paths !== "object") return; for (const pathItem of Object.values(paths)) { if (!pathItem || typeof pathItem !== "object") continue; for (const op of Object.values(pathItem as Record)) { if (!op || typeof op !== "object") continue; if (!hasCursorPaginationShape(op as Record)) continue; (op as Record)["x-speakeasy-pagination"] = { type: "cursor", inputs: [ { name: "cursor", in: "requestBody", type: "cursor" }, { name: "limit", in: "requestBody", type: "limit" }, ], outputs: { nextCursor: "$.next_cursor" }, }; } } } const hasCursorPaginationShape = (op: Record): boolean => { const requestBody = op.requestBody as Record | undefined; const content = requestBody?.content as Record | undefined; const json = content?.["application/json"] as | Record | undefined; const schema = json?.schema as Record | undefined; const props = schema?.properties as Record | undefined; if (!props) return false; const cursorProp = props.cursor as Record | undefined; const limitProp = props.limit as Record | undefined; if (!cursorProp || !limitProp) return false; if (cursorProp.type !== "string") return false; if (limitProp.type !== "integer" && limitProp.type !== "number") return false; return true; };