PageSourceSearch

https://bambuser.com/docs/assets/js/d1f7bbcc.83dfc38a.js

js bambuser.com collected 2026-09-24 08:29:06 UTC 11,013 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkbambuser_docs||=[]).push([[2969],{44967(e,t,a){a.r(t),a.d(t,{assets:()=>c,contentTitle:()=>o,default:()=>h,frontMatter:()=>i,metadata:()=>r,toc:()=>d});const r=JSON.parse('{"id":"mobileSDK/ios/vc-ios-provide-search-data","title":"iOS SDK \u2014 Provide Search Data","description":"Return search results when the agent searches the catalogue. Implement provideSearchData, page the results, and reply with a BambuserFactorySpec.","source":"@site/video-consultation/mobileSDK/ios/provide-search-data.mdx","sourceDirName":"mobileSDK/ios","slug":"/mobileSDK/ios/mobile-sdk/ios/provide-search-data","permalink":"/docs/video-consultation/mobileSDK/ios/mobile-sdk/ios/provide-search-data","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"id":"vc-ios-provide-search-data","title":"iOS SDK \u2014 Provide Search Data","description":"Return search results when the agent searches the catalogue. Implement provideSearchData, page the results, and reply with a BambuserFactorySpec.","sidebar_label":"Provide Search Data","slug":"mobile-sdk/ios/provide-search-data"},"sidebar":"someSidebars","previous":{"title":"Provide Product Data","permalink":"/docs/video-consultation/mobileSDK/ios/mobile-sdk/ios/provide-product-data"},"next":{"title":"Cart Integration","permalink":"/docs/video-consultation/mobileSDK/ios/mobile-sdk/ios/cart-integration"}}');var n=a(74848),s=a(28453);const i={id:"vc-ios-provide-search-data",title:"iOS SDK \u2014 Provide Search Data",description:"Return search results when the agent searches the catalogue. Implement provideSearchData, page the results, and reply with a BambuserFactorySpec.",sidebar_label:"Provide Search Data",slug:"mobile-sdk/ios/provide-search-data"},o="Provide Search Data",c={},d=[{value:"When to implement",id:"when-to-implement",level:2},{value:"Handler signature",id:"handler-signature",level:2},{value:"Wire the handler",id:"wire-the-handler",level:2},{value:"Build the factory spec",id:"build-the-factory-spec",level:2},{value:"Empty query",id:"empty-query",level:2},{value:"Pagination behaviour",id:"pagination-behaviour",level:2},{value:"See also",id:"see-also",level:2}];function l(e){const t={a:"a",code:"code",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.header,{children:(0,n.jsx)(t.h1,{id:"provide-search-data",children:"Provide Search Data"})}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.code,{children:"provideSearchData"})," fires when the agent types into the widget's search field. The SDK hands you the query and a page number, you look up your catalogue, and return a paginated ",(0,n.jsx)(t.code,{children:"BambuserFactorySpec"})," that renders as a searchable product list in the agent's tool."]}),"\n",(0,n.jsx)(t.h2,{id:"when-to-implement",children:"When to implement"}),"\n",(0,n.jsxs)(t.p,{children:["Same rule as ",(0,n.jsx)(t.code,{children:"provideProductData"})," \u2014 only when the catalogue can't be exposed to BamHub. If BamHub has your catalogue, search inside the call is automatic and this handler is optional."]}),"\n",(0,n.jsx)(t.h2,{id:"handler-signature",children:"Handler signature"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-swift",children:"public struct BambuserCallHandlers {\n    public var provideSearchData: (\n        (BambuserSearchRequest) async -> BambuserReply<BambuserFactorySpec>\n    )?\n}\n"})}),"\n",(0,n.jsxs)(t.p,{children:[(0,n.jsx)(t.code,{children:"BambuserSearchRequest"})," fields:"]}),"\n",(0,n.jsxs)(t.table,{children:[(0,n.jsx)(t.thead,{children:(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.th,{children:"Field"}),(0,n.jsx)(t.th,{children:"Type"}),(0,n.jsx)(t.th,{children:"Notes"})]})}),(0,n.jsxs)(t.tbody,{children:[(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"term"})}),(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"String"})}),(0,n.jsx)(t.td,{children:"The query the agent typed. May be empty."})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"page"})}),(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"Int"})}),(0,n.jsx)(t.td,{children:"1-based page index requested."})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"callbackKey"})}),(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"String"})}),(0,n.jsx)(t.td,{children:"Internal \u2014 the SDK echoes it back automatically."})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"raw"})}),(0,n.jsx)(t.td,{children:(0,n.jsx)(t.code,{children:"BambuserJSONValue"})}),(0,n.jsx)(t.td,{children:"Full JSON entry, in case you need a field the SDK hasn't modelled."})]})]})]}),"\n",(0,n.jsxs)(t.p,{children:["Return values: ",(0,n.jsx)(t.code,{children:".reply(spec)"})," / ",(0,n.jsx)(t.code,{children:".error(message:)"})," / ",(0,n.jsx)(t.code,{children:".skip"}),", same as ",(0,n.jsx)(t.code,{children:"provideProductData"}),"."]}),"\n",(0,n.jsx)(t.h2,{id:"wire-the-handler",children:"Wire the handler"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-swift",children:'handlers.provideSearchData = { request in\n    let query = request.term\n        .trimmingCharacters(in: .whitespace
1sAndNewlines)\n        .lowercased()\n\n    // "Verify function" \u2014 surface a searchable error to the agent\n    // when the query is unusable.\n    guard query.count <= 100 else {\n        return .error(message: "Search term too long")\n    }\n\n    let matches = query.isEmpty\n        ? ProductCatalog.all\n        : ProductCatalog.all.filter { product in\n            product.name.lowercased().contains(query)\n                || product.brand.lowercased().contains(query)\n                || product.category.lowercased().contains(query)\n                || product.id.lowercased().contains(query)\n        }\n\n    let pageSize = 10\n    let totalMatches = matches.count\n    let totalPages = max(1, Int(ceil(Double(totalMatches) / Double(pageSize))))\n    let pageIndex = max(1, min(request.page, totalPages))\n    let start = (pageIndex - 1) * pageSize\n    let end = min(start + pageSize, totalMatches)\n    let pageItems = totalMatches == 0 ? [] : Array(matches[start..<end])\n\n    let response = BambuserSearchResponse(\n        products: pageItems.map { p in\n            BambuserSearchProduct(\n                name: p.name,\n                imageUrl: p.imageURL.absoluteString,\n                sku: p.id,\n                price: BambuserPrice(current: p.price)\n            )\n        },\n        currency: pageItems.first?.currency ?? "USD",\n        locale: "en-US",\n        pagination: BambuserSearchPagination(\n            totalPages: totalPages,\n            totalMatches: totalMatches,\n            currentPageIndex: pageIndex\n        )\n    )\n    return .reply(response.factorySpec)\n}\n'})}),"\n",(0,n.jsx)(t.h2,{id:"build-the-factory-spec",children:"Build the factory spec"}),"\n",(0,n.jsx)(t.p,{children:"The search response chain the widget expects:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{children:'factory\n  .currency("USD")\n  .locale("en-US")\n  .pagination(p => p.totalPages(N).totalMatches(N).currentPageIndex(N))\n  .products(f => matches.map(item => f().name(...).sku(...).price(...)))\n'})}),"\n",(0,n.jsx)(t.p,{children:"Which in Swift is:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-swift",children:'BambuserFactorySpec([\n    .method("currency",   args: [.string(currency)]),\n    .method("locale",     args: [.string(locale)]),\n    .method("pagination", factory: BambuserFactorySpec([\n        .method("totalPages",       args: [.int(totalPages)]),\n        .method("totalMatches",     args: [.int(totalMatches)]),\n        .method("currentPageIndex", args: [.int(currentPageIndex)]),\n    ])),\n    .method("products", items: products.map { p in\n        BambuserFactoryItem(\n            factoryArgs: [],\n            spec: BambuserFactorySpec([\n                .method("name",     args: [.string(p.name)]),\n                .method("sku",      args: [.string(p.sku)]),\n                .method("imageUrl", args: [.string(p.imageUrl)]),\n                .method("price", factory: BambuserFactorySpec([\n                    .method("current", args: [.double(p.price.current)]),\n                ])),\n            ])\n        )\n    }),\n])\n'})}),"\n",(0,n.jsxs)(t.p,{children:["The reference ",(0,n.jsx)(t.a,{href:"https://github.com/bambuser/BambuserCallsShopperSDK/tree/main/BambuserCallsShopperDemo/BambuserCallsShopperDemo/Bambuser/BambuserSearchResponse.swift",children:(0,n.jsx)(t.code,{children:"BambuserSearchResponse"})})," model in the demo has a ",(0,n.jsx)(t.code,{children:".factorySpec"})," computed property that generates this \u2014 copy it into your app and adapt."]}),"\n",(0,n.jsx)(t.h2,{id:"empty-query",children:"Empty query"}),"\n",(0,n.jsx)(t.p,{children:"The agent typically opens the search tool without typing anything. Return the first page of your full catalogue in that case (per the example above). If your catalogue is too large to page freely, return a curated set (best-sellers, featured items) instead."}),"\n",(0,n.jsx)(t.h2,{id:"pagination-behaviour",children:"Pagination behaviour"}),"\n",(0,n.jsxs)(t.p,{children:["The agent-side widget paginates by re-firing ",(0,n.jsx)(t.code,{children:"provideSearchData"})," with the same ",(0,n.jsx)(t.code,{children:"term"})," and an incremented ",(0,n.jsx)(t.code,{children:"page"}),". Compute ",(0,n.jsx)(t.code,{children:"totalPages"})," and ",(0,n.jsx)(t.code,{children:"totalMatches"}),' from your backend response, not from the local page slice \u2014 the widget\'s UI uses those to render "showing X of Y" and page controls.']}),"\n",(0,n.jsx)(t.h2,{id:"see-also",children:"See also"}),"\n",(0,n.jsxs)(t.ul,{children:["\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.a,{href:"/docs/video-consultation/mobileSDK/ios/mobile-sdk/ios/provide-product-data",children:"Provide Product Data"})," \u2014 single-product lookups."]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.a,{href:"/docs/video-consultation/mobileSDK/ios/mobile-sdk/ios/cart-integration",children:"Cart Integration"}),"."]}),"\n",(0,n.jsxs)(t.li,{children:[(0,n.jsx)(t.a,{href:"/docs/video-consultation/mobileSDK/ios/mobile-sdk/ios/architecture",children:"Architecture"}),"."]}),"\n"]})]})}function h(e={}){const{wrapper:t}={...(0,s.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(l,{...e})}):l(e)}},28453(e,t,a){a.d(t,{R:()=>i,x:()=>o});var r=a(96540);const n={},s=r.createContext(n);function i(e){const t=r.useContext(s);return r.useMemo(function(){return"function"==typeof e?e(t):{...t,...e}},[t,e])}function o(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:i(e.components),r.createElement(s.Provider,{value:t},e.children)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.