flowmarkup:
  title: Paginated API Fetcher
  version: 1
  documentation: >
    Demonstrates yield for lazy iteration over paginated API results.
    Yields items one-by-one; consumer controls consumption mode:
    - onYield: streaming (constant memory)
    - $yields in output: materialized list
    - output: var (string form): materialized list (yields-only flow)
  requires:
    REQUEST: ["api.example.com"]
  input:
    api_url: URL
  yields:
    $kind: MAP
    $type: application/json
    _notes_: Individual items from paginated API responses.
  do:
  - set: {cursor: null, has_more: true, page_count: 0}
    # Security: Always bound pagination loops to prevent infinite iteration
    # on malicious or malformed API responses.
    # Defense-in-depth: maxIterations is enforced by the engine independently
    # of the while condition, so even a CEL evaluation bug cannot cause an
    # infinite loop.
  - while:
      condition: =has_more && page_count < 1000
      maxIterations: 1000
      do:
      - set: {page_count: =page_count + 1}
      - request:
          method: GET
          url: "=api_url + '?cursor=' + (cursor ?? '')"
          timeout: 30s
          parseAs: JSON
          result: {response: =RESULT.body}
      - forEach:
          items: =response.data
          maxItems: 10000
          do:
          - yield: =item
      - if:
          condition: =response.next_cursor == null
          then:
          - set: {has_more: false}
          else:
          - set: {cursor: =response.next_cursor}
