[{"data":1,"prerenderedAt":8405},["ShallowReactive",2],{"navigation_docs_en":3,"-en-guides-data-connectors-quickstart":445,"-en-guides-data-connectors-quickstart-surround":8400},[4,30,72,132,260,436],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":6},"Getting Started",false,"\u002Fen\u002Fgetting-started","en\u002F1.getting-started",[10,15,20,25],{"title":11,"path":12,"stem":13,"icon":14},"Introduction","\u002Fen\u002Fgetting-started\u002Fintroduction","en\u002F1.getting-started\u002F2.introduction","i-lucide-house",{"title":16,"path":17,"stem":18,"icon":19},"Quickstart","\u002Fen\u002Fgetting-started\u002Finstallation","en\u002F1.getting-started\u002F3.installation","i-lucide-download",{"title":21,"path":22,"stem":23,"icon":24},"Use Cases","\u002Fen\u002Fgetting-started\u002Fuse-cases","en\u002F1.getting-started\u002F4.use-cases","i-lucide-layers",{"title":26,"path":27,"stem":28,"icon":29},"Concepts","\u002Fen\u002Fgetting-started\u002Fconcepts","en\u002F1.getting-started\u002F5.concepts","i-lucide-book",{"title":26,"path":31,"stem":32,"children":33,"page":6},"\u002Fen\u002Fconcepts","en\u002F2.concepts",[34,38,43,48,53,58,63,68],{"title":35,"path":36,"stem":37,"icon":14},"Organization","\u002Fen\u002Fconcepts\u002Forganization","en\u002F2.concepts\u002F1.organization",{"title":39,"path":40,"stem":41,"icon":42},"Data Model","\u002Fen\u002Fconcepts\u002Fdata-model","en\u002F2.concepts\u002F2.data-model","i-lucide-database",{"title":44,"path":45,"stem":46,"icon":47},"Access Control","\u002Fen\u002Fconcepts\u002Faccess-permissions","en\u002F2.concepts\u002F3.access-permissions","i-lucide-user-key",{"title":49,"path":50,"stem":51,"icon":52},"Audit Logs","\u002Fen\u002Fconcepts\u002Faudit-logs","en\u002F2.concepts\u002F4.audit-logs","i-lucide-scroll-text",{"title":54,"path":55,"stem":56,"icon":57},"Introspection","\u002Fen\u002Fconcepts\u002Fintrospection","en\u002F2.concepts\u002F6.introspection","i-lucide-database-search",{"title":59,"path":60,"stem":61,"icon":62},"Query Engine","\u002Fen\u002Fconcepts\u002Fquery-engine","en\u002F2.concepts\u002F7.query-engine","i-lucide-workflow",{"title":64,"path":65,"stem":66,"icon":67},"AI","\u002Fen\u002Fconcepts\u002Fai","en\u002F2.concepts\u002F8.ai","i-lucide-sparkles",{"title":69,"path":70,"stem":71,"icon":42},"Caching","\u002Fen\u002Fconcepts\u002Fcaching","en\u002F2.concepts\u002F9.caching",{"title":73,"path":74,"stem":75,"children":76,"page":6},"Guides","\u002Fen\u002Fguides","en\u002F4.guides",[77,82,87,92,97,102,107,112],{"title":78,"path":79,"stem":80,"icon":81},"REST API Quickstart","\u002Fen\u002Fguides\u002Frest-api","en\u002F4.guides\u002F1.rest-api","i-lucide-plug",{"title":83,"path":84,"stem":85,"icon":86},"SDK Quickstart","\u002Fen\u002Fguides\u002Fsdk","en\u002F4.guides\u002F2.sdk","i-lucide-terminal",{"title":88,"path":89,"stem":90,"icon":91},"Configure SSO","\u002Fen\u002Fguides\u002Fconfigure-sso","en\u002F4.guides\u002F3.configure-sso","i-lucide-key-round",{"title":93,"path":94,"stem":95,"icon":96},"Configure MCP","\u002Fen\u002Fguides\u002Fmcp","en\u002F4.guides\u002F4.mcp","i-lucide-brain-cog",{"title":98,"path":99,"stem":100,"icon":101},"Customize Content Space","\u002Fen\u002Fguides\u002Fcustomize-content-space","en\u002F4.guides\u002F5.customize-content-space","i-lucide-columns-3-cog",{"title":103,"path":104,"stem":105,"icon":106},"Build an Application with AI Assistance","\u002Fen\u002Fguides\u002Fbuild-an-application","en\u002F4.guides\u002F6.build-an-application","i-lucide-route",{"title":108,"path":109,"stem":110,"icon":111},"Horizontal Scaling","\u002Fen\u002Fguides\u002Fhorizontal-scaling","en\u002F4.guides\u002F7.horizontal-scaling","i-lucide-network",{"title":113,"icon":114,"path":115,"stem":116,"children":117,"page":6},"Data Connectors","i-lucide-cable","\u002Fen\u002Fguides\u002Fdata-connectors","en\u002F4.guides\u002F8.data-connectors",[118,122,127],{"title":16,"path":119,"stem":120,"icon":121},"\u002Fen\u002Fguides\u002Fdata-connectors\u002Fquickstart","en\u002F4.guides\u002F8.data-connectors\u002F1.quickstart","i-lucide-rocket",{"title":123,"path":124,"stem":125,"icon":126},"Build a Stripe Connector","\u002Fen\u002Fguides\u002Fdata-connectors\u002Fstripe","en\u002F4.guides\u002F8.data-connectors\u002F2.stripe","i-lucide-hammer",{"title":128,"path":129,"stem":130,"icon":131},"Build with AI Agents","\u002Fen\u002Fguides\u002Fdata-connectors\u002Fai-agents","en\u002F4.guides\u002F8.data-connectors\u002F3.ai-agents","i-lucide-bot",{"title":133,"path":134,"stem":135,"children":136,"page":6},"Developer","\u002Fen\u002Fdeveloper","en\u002F5.developer",[137,191,215,220],{"title":138,"path":139,"stem":140,"children":141,"page":6},"Data Access","\u002Fen\u002Fdeveloper\u002Fapi","en\u002F5.developer\u002F1.api",[142,147,152,157,162,167,172,177,182,186],{"title":143,"path":144,"stem":145,"icon":146},"Overview","\u002Fen\u002Fdeveloper\u002Fapi\u002Foverview","en\u002F5.developer\u002F1.api\u002F1.overview","i-lucide-globe",{"title":148,"path":149,"stem":150,"icon":151},"Errors","\u002Fen\u002Fdeveloper\u002Fapi\u002Ferrors","en\u002F5.developer\u002F1.api\u002F10.errors","i-lucide-alert-triangle",{"title":153,"path":154,"stem":155,"icon":156},"Authentication","\u002Fen\u002Fdeveloper\u002Fapi\u002Fauthentication","en\u002F5.developer\u002F1.api\u002F2.authentication","i-lucide-lock",{"title":158,"path":159,"stem":160,"icon":161},"Reading Data","\u002Fen\u002Fdeveloper\u002Fapi\u002Freading-data","en\u002F5.developer\u002F1.api\u002F3.reading-data","i-lucide-book-open",{"title":163,"path":164,"stem":165,"icon":166},"Writing Data","\u002Fen\u002Fdeveloper\u002Fapi\u002Fwriting-data","en\u002F5.developer\u002F1.api\u002F4.writing-data","i-lucide-pencil",{"title":168,"path":169,"stem":170,"icon":171},"Filtering","\u002Fen\u002Fdeveloper\u002Fapi\u002Ffiltering","en\u002F5.developer\u002F1.api\u002F5.filtering","i-lucide-filter",{"title":173,"path":174,"stem":175,"icon":176},"Field Selection","\u002Fen\u002Fdeveloper\u002Fapi\u002Ffield-selection","en\u002F5.developer\u002F1.api\u002F6.field-selection","i-lucide-list-checks",{"title":178,"path":179,"stem":180,"icon":181},"Sorting & Pagination","\u002Fen\u002Fdeveloper\u002Fapi\u002Fsorting-pagination","en\u002F5.developer\u002F1.api\u002F7.sorting-pagination","i-lucide-arrow-up-down",{"title":183,"path":184,"stem":185,"icon":111},"Relational Data","\u002Fen\u002Fdeveloper\u002Fapi\u002Frelational-data","en\u002F5.developer\u002F1.api\u002F8.relational-data",{"title":187,"path":188,"stem":189,"icon":190},"Files & Assets","\u002Fen\u002Fdeveloper\u002Fapi\u002Ffiles","en\u002F5.developer\u002F1.api\u002F9.files","i-lucide-file-up",{"title":192,"path":193,"stem":194,"children":195,"page":6},"Client SDK","\u002Fen\u002Fdeveloper\u002Fsdk","en\u002F5.developer\u002F2.sdk",[196,200,205,210],{"title":197,"path":198,"stem":199,"icon":19},"Installation","\u002Fen\u002Fdeveloper\u002Fsdk\u002Finstallation","en\u002F5.developer\u002F2.sdk\u002F1.installation",{"title":201,"path":202,"stem":203,"icon":204},"Client Setup","\u002Fen\u002Fdeveloper\u002Fsdk\u002Fclient-setup","en\u002F5.developer\u002F2.sdk\u002F2.client-setup","i-lucide-settings",{"title":206,"path":207,"stem":208,"icon":209},"Type System","\u002Fen\u002Fdeveloper\u002Fsdk\u002Ftype-system","en\u002F5.developer\u002F2.sdk\u002F3.type-system","i-lucide-braces",{"title":211,"path":212,"stem":213,"icon":214},"Advanced","\u002Fen\u002Fdeveloper\u002Fsdk\u002Fadvanced","en\u002F5.developer\u002F2.sdk\u002F5.advanced","i-lucide-puzzle",{"title":216,"path":217,"stem":218,"icon":219},"Application Users","\u002Fen\u002Fdeveloper\u002Fapplication-users","en\u002F5.developer\u002F3.application-users","i-lucide-users",{"title":221,"path":222,"stem":223,"children":224,"icon":214},"Extensions","\u002Fen\u002Fdeveloper\u002Fextensions","en\u002F5.developer\u002F3.extensions\u002Findex",[225,226,231],{"title":143,"path":222,"stem":223,"icon":214},{"title":227,"path":228,"stem":229,"icon":230},"Install and Manage Extensions","\u002Fen\u002Fdeveloper\u002Fextensions\u002Finstall","en\u002F5.developer\u002F3.extensions\u002F1.install","i-lucide-package-plus",{"title":113,"path":232,"stem":233,"children":234,"icon":114},"\u002Fen\u002Fdeveloper\u002Fextensions\u002Fdata-connectors","en\u002F5.developer\u002F3.extensions\u002F2.data-connectors\u002Findex",[235,236,241,245,250,255],{"title":143,"path":232,"stem":233,"icon":114},{"title":237,"path":238,"stem":239,"icon":240},"How Data Connectors Run","\u002Fen\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fruntime","en\u002F5.developer\u002F3.extensions\u002F2.data-connectors\u002F2.runtime","i-lucide-cpu",{"title":242,"path":243,"stem":244,"icon":42},"Data Sources","\u002Fen\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-sources","en\u002F5.developer\u002F3.extensions\u002F2.data-connectors\u002F3.data-sources",{"title":246,"path":247,"stem":248,"icon":249},"Map an External Data Source","\u002Fen\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-source-mapping","en\u002F5.developer\u002F3.extensions\u002F2.data-connectors\u002F4.data-source-mapping","i-lucide-map",{"title":251,"path":252,"stem":253,"icon":254},"Handle Errors","\u002Fen\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Ferrors","en\u002F5.developer\u002F3.extensions\u002F2.data-connectors\u002F5.errors","i-lucide-shield-alert",{"title":256,"path":257,"stem":258,"icon":259},"Test a Data Connector","\u002Fen\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Ftesting","en\u002F5.developer\u002F3.extensions\u002F2.data-connectors\u002F6.testing","i-lucide-flask-conical",{"title":261,"path":262,"stem":263,"children":264,"page":6},"Reference","\u002Fen\u002Freference","en\u002F6.reference",[265,269,274,279,295,299,304,340,369,374],{"title":266,"path":267,"stem":268,"icon":204},"Configuration","\u002Fen\u002Freference\u002Fenvironment-variables","en\u002F6.reference\u002F1.environment-variables",{"title":270,"path":271,"stem":272,"icon":273},"System Requirements","\u002Fen\u002Freference\u002Fsystem-requirements","en\u002F6.reference\u002F2.system-requirements","i-lucide-server",{"title":275,"path":276,"stem":277,"icon":278},"Licensing","\u002Fen\u002Freference\u002Flicensing","en\u002F6.reference\u002F3.licensing","i-lucide-gem",{"title":280,"path":281,"stem":282,"children":283,"icon":81},"Connectors","\u002Fen\u002Freference\u002Fconnectors","en\u002F6.reference\u002F4.connectors\u002Findex",[284,285,290],{"title":280,"path":281,"stem":282,"icon":81},{"title":286,"path":287,"stem":288,"icon":289},"PostgreSQL and Supabase","\u002Fen\u002Freference\u002Fconnectors\u002Fpostgresql-supabase","en\u002F6.reference\u002F4.connectors\u002F1.postgresql-supabase","i-simple-icons-postgresql",{"title":291,"path":292,"stem":293,"icon":294},"MySQL and MariaDB","\u002Fen\u002Freference\u002Fconnectors\u002Fmysql-mariadb","en\u002F6.reference\u002F4.connectors\u002F2.mysql-mariadb","i-simple-icons-mysql",{"title":296,"path":297,"stem":298,"icon":209},"Data Types Representation","\u002Fen\u002Freference\u002Fdata-types","en\u002F6.reference\u002F5.data-types",{"title":300,"path":301,"stem":302,"icon":303},"Permissions Reference","\u002Fen\u002Freference\u002Fpermissions","en\u002F6.reference\u002F6.permissions","i-lucide-shield",{"title":305,"path":306,"stem":307,"children":308,"page":6},"API Reference","\u002Fen\u002Freference\u002Fapi-reference","en\u002F6.reference\u002F7.api-reference",[309,313,318],{"title":310,"path":311,"stem":312,"icon":273},"System Endpoints","\u002Fen\u002Freference\u002Fapi-reference\u002Fsystem-endpoints","en\u002F6.reference\u002F7.api-reference\u002F1.system-endpoints",{"title":314,"path":315,"stem":316,"icon":317},"OpenAPI Spec","\u002Fen\u002Freference\u002Fapi-reference\u002Fopenapi-spec","en\u002F6.reference\u002F7.api-reference\u002F2.openapi-spec","i-lucide-file-code",{"title":319,"path":320,"stem":321,"children":322,"icon":324},"Schema Migration","\u002Fen\u002Freference\u002Fapi-reference\u002Fschema-migration","en\u002F6.reference\u002F7.api-reference\u002F3.schema-migration\u002Findex",[323,325,330,335],{"title":319,"path":320,"stem":321,"icon":324},"i-lucide-database-zap",{"title":326,"path":327,"stem":328,"icon":329},"Apply Migrations","\u002Fen\u002Freference\u002Fapi-reference\u002Fschema-migration\u002Fapply-migrations","en\u002F6.reference\u002F7.api-reference\u002F3.schema-migration\u002F1.apply-migrations","i-lucide-upload",{"title":331,"path":332,"stem":333,"icon":334},"Import Changes","\u002Fen\u002Freference\u002Fapi-reference\u002Fschema-migration\u002Fimport-changes","en\u002F6.reference\u002F7.api-reference\u002F3.schema-migration\u002F2.import-changes","i-lucide-refresh-cw",{"title":336,"path":337,"stem":338,"icon":339},"Operation Reference","\u002Fen\u002Freference\u002Fapi-reference\u002Fschema-migration\u002Foperation-reference","en\u002F6.reference\u002F7.api-reference\u002F3.schema-migration\u002F3.operation-reference","i-lucide-list-tree",{"title":341,"path":342,"stem":343,"children":344,"page":6},"Design Considerations","\u002Fen\u002Freference\u002Fdesign-considerations","en\u002F6.reference\u002F8.design-considerations",[345,349,354,359,364],{"title":143,"path":346,"stem":347,"icon":348},"\u002Fen\u002Freference\u002Fdesign-considerations\u002Foverview","en\u002F6.reference\u002F8.design-considerations\u002F1.overview","i-lucide-compass",{"title":350,"path":351,"stem":352,"icon":353},"Instance Configuration","\u002Fen\u002Freference\u002Fdesign-considerations\u002Finstance-configuration-related-problems","en\u002F6.reference\u002F8.design-considerations\u002F3.instance-configuration-related-problems","i-lucide-wrench",{"title":355,"path":356,"stem":357,"icon":358},"Overly Permissive Public Access","\u002Fen\u002Freference\u002Fdesign-considerations\u002Foverly-permissive","en\u002F6.reference\u002F8.design-considerations\u002F4.overly-permissive","i-lucide-shield-off",{"title":360,"path":361,"stem":362,"icon":363},"No Aggregates","\u002Fen\u002Freference\u002Fdesign-considerations\u002Fno-aggregates","en\u002F6.reference\u002F8.design-considerations\u002F5.no-aggregates","i-lucide-sigma",{"title":365,"path":366,"stem":367,"icon":368},"Cross-Data-Source Referential Integrity","\u002Fen\u002Freference\u002Fdesign-considerations\u002Fcross-data-source-referential-integrity","en\u002F6.reference\u002F8.design-considerations\u002F6.cross-data-source-referential-integrity","i-lucide-unlink",{"title":370,"path":371,"stem":372,"icon":373},"CLI","\u002Fen\u002Freference\u002Fcli","en\u002F6.reference\u002F9.cli","i-lucide-square-terminal",{"title":221,"path":375,"stem":376,"children":377,"page":6},"\u002Fen\u002Freference\u002Fextensions","en\u002F6.reference\u002F9.extensions",[378,383,386,405],{"title":379,"path":380,"stem":381,"icon":382},"Extension Config and Manifest","\u002Fen\u002Freference\u002Fextensions\u002Fmanifest","en\u002F6.reference\u002F9.extensions\u002F1.manifest","i-lucide-file-json",{"title":370,"path":384,"stem":385,"icon":86},"\u002Fen\u002Freference\u002Fextensions\u002Fcli","en\u002F6.reference\u002F9.extensions\u002F2.cli",{"title":387,"path":388,"stem":389,"children":390,"page":6},"Extension Kit","\u002Fen\u002Freference\u002Fextensions\u002Fextension-kit","en\u002F6.reference\u002F9.extensions\u002F3.extension-kit",[391,395,400],{"title":392,"path":393,"stem":394,"icon":81},"Data Connector","\u002Fen\u002Freference\u002Fextensions\u002Fextension-kit\u002Fdata-connector","en\u002F6.reference\u002F9.extensions\u002F3.extension-kit\u002F1.data-connector",{"title":396,"path":397,"stem":398,"icon":399},"Protocol","\u002Fen\u002Freference\u002Fextensions\u002Fextension-kit\u002Fprotocol","en\u002F6.reference\u002F9.extensions\u002F3.extension-kit\u002F2.protocol","i-lucide-arrow-left-right",{"title":401,"path":402,"stem":403,"icon":404},"Schema Helpers","\u002Fen\u002Freference\u002Fextensions\u002Fextension-kit\u002Fexperimental","en\u002F6.reference\u002F9.extensions\u002F3.extension-kit\u002F3.experimental","i-lucide-blocks",{"title":113,"path":406,"stem":407,"children":408,"page":6},"\u002Fen\u002Freference\u002Fextensions\u002Fdata-connectors","en\u002F6.reference\u002F9.extensions\u002F4.data-connectors",[409,413,417,421,426,431],{"title":410,"path":411,"stem":412,"icon":81},"Data Connector API","\u002Fen\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fapi","en\u002F6.reference\u002F9.extensions\u002F4.data-connectors\u002F1.api",{"title":414,"path":415,"stem":416,"icon":176},"Operations and Operators","\u002Fen\u002Freference\u002Fextensions\u002Fdata-connectors\u002Foperations","en\u002F6.reference\u002F9.extensions\u002F4.data-connectors\u002F2.operations",{"title":148,"path":418,"stem":419,"icon":420},"\u002Fen\u002Freference\u002Fextensions\u002Fdata-connectors\u002Ferrors","en\u002F6.reference\u002F9.extensions\u002F4.data-connectors\u002F3.errors","i-lucide-triangle-alert",{"title":422,"path":423,"stem":424,"icon":425},"Runtime Limits","\u002Fen\u002Freference\u002Fextensions\u002Fdata-connectors\u002Flimits","en\u002F6.reference\u002F9.extensions\u002F4.data-connectors\u002F4.limits","i-lucide-gauge",{"title":427,"path":428,"stem":429,"icon":430},"Limitations","\u002Fen\u002Freference\u002Fextensions\u002Fdata-connectors\u002Flimitations","en\u002F6.reference\u002F9.extensions\u002F4.data-connectors\u002F5.limitations","i-lucide-ban",{"title":432,"path":433,"stem":434,"icon":435},"Network Permissions","\u002Fen\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fpermissions","en\u002F6.reference\u002F9.extensions\u002F4.data-connectors\u002F6.permissions","i-lucide-shield-check",{"title":437,"icon":121,"path":438,"stem":439,"children":440,"page":6},"Release Notes","\u002Fen\u002Frelease-notes","en\u002F7.release-notes",[441],{"title":442,"path":443,"stem":444,"icon":121},"Changelog","\u002Fen\u002Frelease-notes\u002Fchangelog","en\u002F7.release-notes\u002F1.changelog",{"id":446,"title":447,"body":448,"description":8393,"extension":8394,"links":8395,"meta":8396,"navigation":8397,"path":119,"seo":8398,"stem":120,"__hash__":8399},"docs_en\u002Fen\u002F4.guides\u002F8.data-connectors\u002F1.quickstart.md","Data Connector Quickstart",{"type":449,"value":450,"toc":8388},"minimark",[451,454,8233,8237,8284,8288,8291,8346,8350,8384],[452,453],"preview",{},[455,456,461,512,515,520,542,547,586,592,595,603,788,935,1098,1290,1443,1447,1451,1690,1797,2132,2547,2677,2841,3012,3151,3164,3168,3317,3477,3565,3568,3691],"tutorial",{"download":457,"name":458,"project":459,"title":460},"\u002Ftutorials\u002Fartic-quickstart\u002Fartic-connector-dist.zip","artic-quickstart","\u002Ftutorials\u002Fartic-quickstart\u002Fartic-connector.zip","artic · data connector",[462,463,464,465,472,473,477,478,482,483,487,488,491,492,496,497,499,500,504,505,487,508,511],"p",{},"Build a read-only data connector extension for the ",[466,467,471],"a",{"href":468,"rel":469},"https:\u002F\u002Fapi.artic.edu\u002Fdocs\u002F",[470],"nofollow","Art Institute of Chicago API",", starting from the ",[466,474,476],{"href":475},"\u002Freference\u002Fextensions\u002Fcli#create-an-extension","CLI scaffold",", and browse its collections in Studio. The connector exposes two ",[466,479,481],{"href":480},"\u002Fconcepts\u002Fdata-model#collections","collections",", ",[484,485,486],"code",{},"artworks"," and ",[484,489,490],{},"artists",", linked by a relation. Each ",[493,494,495],"strong",{},"item"," (a single data object) in ",[484,498,486],{}," is one artwork, with ",[466,501,503],{"href":502},"\u002Fconcepts\u002Fdata-model#fields","fields"," such as ",[484,506,507],{},"title",[484,509,510],{},"dateDisplay",".",[462,513,514],{},"The API needs no key and no signup. Monospace queries the API live through the connector and copies nothing.",[462,516,517],{},[493,518,519],{},"What you'll learn:",[521,522,523,530,533,536,539],"ul",{},[524,525,526,527,529],"li",{},"Adapt the ",[466,528,476],{"href":475}," to read from the Art Institute API.",[524,531,532],{},"Install the extension, create a data source in Studio, and browse its collections there.",[524,534,535],{},"Declare collections, their filters, paging, and a relation, then implement every operation you declare.",[524,537,538],{},"Send every request to the external data source through one function, with a time limit.",[524,540,541],{},"Reject requests the external data source can't serve, with an error class the caller understands.",[462,543,544],{},[493,545,546],{},"Before you start:",[521,548,549,563,574],{},[524,550,551,552,555,556,559,560,511],{},"A self-hosted Monospace ",[493,553,554],{},"instance"," (a running deployment) with an install location for extensions and automatic reloading enabled. See ",[466,557,227],{"href":558},"\u002Fdeveloper\u002Fextensions\u002Finstall#run-monospace-in-docker",". At startup, the instance logs ",[484,561,562],{},"watching installed bundles directory for changes",[524,564,565,566,573],{},"Node.js 22.12 or later and a package manager: npm, pnpm, yarn, or bun. Step 1 runs the ",[466,567,569,572],{"href":568},"\u002Freference\u002Fextensions\u002Fcli",[484,570,571],{},"monospace"," CLI"," without installing it, and the project it creates lists the CLI as a dev dependency.",[524,575,576,577,581,582,511],{},"Permission in Studio to create data sources and read the collections they expose, such as the ",[466,578,580],{"href":579},"\u002Freference\u002Fpermissions#administrator-role","Administrator role"," in your ",[466,583,585],{"href":584},"\u002Fconcepts\u002Forganization#glossary","workspace",[462,587,588,589,511],{},"The example requests use the workspace ",[484,590,591],{},"blog",[462,593,594],{},"The code panel shows the project as of each step and highlights what the step changed. Hover a highlighted term, or a table row, to find it in the code.",[596,597,599,600,602],"tutorial-part",{"title":598},"Scaffold and install","Install the project the ",[466,601,370],{"href":475}," writes before you change any code. Then create a data source in Studio and read the connector's two sample items to check the installation.",[604,605,609,620,631,774],"tutorial-step",{"result":606,"summary":607,"title":608},"The CLI lists seven files and its next steps, and installing the dependencies finishes without errors.","Create a connector project with the CLI.","Scaffold the project",[462,610,611,612,615,616,619],{},"The ",[466,613,370],{"href":614},"\u002Freference\u002Fextensions\u002Fcli#scaffolded-files"," writes a small project that already builds. It has one data connector ",[493,617,618],{},"entry"," (a capability the extension contributes), which serves two sample items.",[462,621,622,623,626,627,630],{},"Pass a new directory, ",[484,624,625],{},"--id",", and ",[484,628,629],{},"--name"," to run the CLI without prompts. It lists the files it wrote and the next commands to run:",[632,633,634,765],"tutorial-terminal",{},[635,636,638,682,709,738],"code-group",{"sync":637},"pm",[639,640,646],"pre",{"className":641,"code":642,"filename":643,"language":644,"meta":645,"style":645},"language-bash shiki shiki-themes monospace-light monospace-light monospace-dark","npx @monospace\u002Fcli@0.2 extension create .\u002Fartic --id example\u002Fartic --name \"Art Institute of Chicago\"\n","npm","bash","",[484,647,648],{"__ignoreMap":645},[649,650,653,657,661,664,667,670,673,676,679],"span",{"class":651,"line":652},"line",1,[649,654,656],{"class":655},"ssBNi","npx",[649,658,660],{"class":659},"suKVh"," @monospace\u002Fcli@0.2",[649,662,663],{"class":659}," extension",[649,665,666],{"class":659}," create",[649,668,669],{"class":659}," .\u002Fartic",[649,671,672],{"class":655}," --id",[649,674,675],{"class":659}," example\u002Fartic",[649,677,678],{"class":655}," --name",[649,680,681],{"class":659}," \"Art Institute of Chicago\"\n",[639,683,686],{"className":641,"code":684,"filename":685,"language":644,"meta":645,"style":645},"pnpx @monospace\u002Fcli@0.2 extension create .\u002Fartic --id example\u002Fartic --name \"Art Institute of Chicago\"\n","pnpm",[484,687,688],{"__ignoreMap":645},[649,689,690,693,695,697,699,701,703,705,707],{"class":651,"line":652},[649,691,692],{"class":655},"pnpx",[649,694,660],{"class":659},[649,696,663],{"class":659},[649,698,666],{"class":659},[649,700,669],{"class":659},[649,702,672],{"class":655},[649,704,675],{"class":659},[649,706,678],{"class":655},[649,708,681],{"class":659},[639,710,713],{"className":641,"code":711,"filename":712,"language":644,"meta":645,"style":645},"yarn dlx @monospace\u002Fcli@0.2 extension create .\u002Fartic --id example\u002Fartic --name \"Art Institute of Chicago\"\n","yarn",[484,714,715],{"__ignoreMap":645},[649,716,717,719,722,724,726,728,730,732,734,736],{"class":651,"line":652},[649,718,712],{"class":655},[649,720,721],{"class":659}," dlx",[649,723,660],{"class":659},[649,725,663],{"class":659},[649,727,666],{"class":659},[649,729,669],{"class":659},[649,731,672],{"class":655},[649,733,675],{"class":659},[649,735,678],{"class":655},[649,737,681],{"class":659},[639,739,742],{"className":641,"code":740,"filename":741,"language":644,"meta":645,"style":645},"bunx @monospace\u002Fcli@0.2 extension create .\u002Fartic --id example\u002Fartic --name \"Art Institute of Chicago\"\n","bun",[484,743,744],{"__ignoreMap":645},[649,745,746,749,751,753,755,757,759,761,763],{"class":651,"line":652},[649,747,748],{"class":655},"bunx",[649,750,660],{"class":659},[649,752,663],{"class":659},[649,754,666],{"class":659},[649,756,669],{"class":659},[649,758,672],{"class":655},[649,760,675],{"class":659},[649,762,678],{"class":655},[649,764,681],{"class":659},[639,766,772],{"className":767,"code":769,"filename":770,"language":771,"meta":645},[768],"language-text","Created the Art Institute of Chicago extension\n\nExtension  example\u002Fartic\nEntry      example\u002Fdata-connector\nDirectory  \u002FUsers\u002FShared\u002Fcode\u002Fartic\n  - .gitignore\n  - README.md\n  - extension.config.json\n  - package.json\n  - src\u002Fdata-connectors\u002Fexample\u002Findex.ts\n  - src\u002Fdata-connectors\u002Fexample\u002Fschema.ts\n  - tsconfig.json\n\nNext steps\n  1. cd .\u002Fartic && npm i\n  2. npm run build\n","output","text",[484,773,769],{"__ignoreMap":645},[462,775,776,777,780,781,784,785,787],{},"Run the first command under ",[484,778,779],{},"Next steps"," to enter the ",[484,782,783],{},"artic"," directory and install its dependencies. The ",[466,786,370],{"href":475}," prints these commands for your package manager.",[604,789,794,816,843,876,900,906,916],{"result":790,"summary":791,"title":792,"file":793},"The `query` handler returns the two sample items in `ROWS`.","Locate the configuration, the schema, and the query handler. Nothing changes in this step.","Inspect the scaffold","src\u002Fdata-connectors\u002Fexample\u002Findex.ts",[462,795,796,803,804,807,808,811,812,511],{},[797,798,801],"tutorial-ref",{"match":799,"file":800},"entrypoint","extension.config.json",[484,802,800],{}," names the extension, ",[484,805,806],{},"example\u002Fartic",", and its only entry, ",[484,809,810],{},"example\u002Fdata-connector",". The entrypoint is the file the ",[466,813,815],{"href":814},"\u002Freference\u002Fextensions\u002Fcli#data-connector-bundles","CLI bundles",[462,817,818,823,824,830,831,837,838,842],{},[797,819,820],{"file":793},[484,821,822],{},"index.ts"," defines the connector with ",[466,825,827],{"href":826},"\u002Freference\u002Fextensions\u002Fextension-kit\u002Fdata-connector#definedataconnector",[484,828,829],{},"defineDataConnector",". Its ",[466,832,834],{"href":833},"\u002Freference\u002Fextensions\u002Fextension-kit\u002Fdata-connector#dataconnectorsetupoptions",[484,835,836],{},"setup"," function runs when a data source starts and receives that data source's configuration. It returns the ",[466,839,841],{"href":840},"\u002Freference\u002Fextensions\u002Fextension-kit\u002Fdata-connector#dataconnectorhandlers","handlers"," Monospace calls:",[521,844,845,854,863],{},[524,846,847,853],{},[797,848,850],{"match":849},"introspect()",[484,851,852],{},"introspect"," reports the schema: the collections, fields, and operations callers can use.",[524,855,856,862],{},[797,857,859],{"match":858},"query()",[484,860,861],{},"query"," handles reads. The scaffold ignores the request and returns the same two items.",[524,864,865,871,872,875],{},[797,866,868],{"match":867},"testConnection()",[484,869,870],{},"testConnection"," reports whether the connection works, and Monospace runs it before it creates a data source. The scaffold returns ",[484,873,874],{},"{ ok: true }"," without sending a request. In step 7, you make it send a request to the Art Institute API.",[462,877,878,885,886,889,890,893,894,511],{},[797,879,882],{"match":880,"file":881},"name: 'items'","src\u002Fdata-connectors\u002Fexample\u002Fschema.ts",[484,883,884],{},"schema.ts"," declares one collection, ",[484,887,888],{},"items",", with an unfiltered ",[484,891,892],{},"readMany",". The sample items are in ",[797,895,897],{"match":896,"file":881},"export const ROWS",[484,898,899],{},"ROWS",[462,901,902,903,905],{},"Monospace offers callers only the operations the schema declares, and it doesn't filter the items ",[484,904,861],{}," returns. Implement each filter, sort, or limit when you declare it.",[462,907,908,909,912,913,915],{},"See ",[466,910,410],{"href":911},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fapi"," for ",[484,914,836],{},", the handlers, and the query shapes.",[917,918,920,921,924,925,928,929,934],"tutorial-aside",{"kind":919},"watch","Connectors don't run in Node.js, so use web APIs such as ",[484,922,923],{},"fetch","; ",[484,926,927],{},"node:"," imports are unavailable. ",[466,930,933],{"href":931,"rel":932},"https:\u002F\u002Ffeedback.monospace.io\u002Frequest?request=new",[470],"Request Node.js API compatibility"," if your connector needs it.",[604,936,940,961,970,992,995,1006,1018,1021],{"result":937,"summary":938,"title":939,"file":800},"The build lists the entry as `example\u002Fartic-connector`.","Rename the entry, move its folder, and allow one host.","Rename the entry and allow the API host",[462,941,942,943,945,946,951,952,955,956,511],{},"In ",[484,944,800],{},", rename the entry to ",[797,947,949],{"match":948},"example\u002Fartic-connector",[484,950,948],{},". A data source uses this entry ID as its ",[484,953,954],{},"provider",". Point the entrypoint at a directory named after the connector, ",[797,957,958],{"match":799},[484,959,960],{},"src\u002Fdata-connectors\u002Fartic\u002F",[462,962,963,964,969],{},"Add the permission ",[797,965,967],{"match":966},"net:api.artic.edu",[484,968,966],{}," to the entry. The connector can reach only the hosts its entry declares. When you create a data source, you approve access to those hosts.",[462,971,972,973,976,977,980,981,984,985,988,989,991],{},"Set the extension and entry icons to ",[484,974,975],{},"lucide:landmark",". In ",[484,978,979],{},"package.json",", rename the package from the scaffold's ",[484,982,983],{},"example-artic"," to ",[484,986,987],{},"artic-connector",", and update the paths in the README. Keep the extension ID, ",[484,990,806],{},", as the scaffold wrote it.",[462,993,994],{},"The code only moves, so the connector still serves the two sample items.",[462,996,908,997,1000,1001,1005],{},[466,998,379],{"href":999},"\u002Freference\u002Fextensions\u002Fmanifest"," for the extension's fields, and ",[466,1002,1004],{"href":1003},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fapi#declare-the-entry","Declare the Entry"," for the entry's fields.",[917,1007,1009,1010,1013,1014,1017],{"kind":1008},"why","The scaffold names every entry ",[484,1011,1012],{},"\u003Cnamespace>\u002Fdata-connector",", so a second scaffolded extension under ",[484,1015,1016],{},"example"," gets the same entry ID. Give your entry a distinct ID.",[462,1019,1020],{},"Move the code, then build to check the rename. The build lists the renamed entry and its artifact directory:",[632,1022,1023,1040,1092],{},[639,1024,1027],{"className":641,"code":1025,"filename":1026,"language":644,"meta":645,"style":645},"mv src\u002Fdata-connectors\u002Fexample src\u002Fdata-connectors\u002Fartic\n","terminal",[484,1028,1029],{"__ignoreMap":645},[649,1030,1031,1034,1037],{"class":651,"line":652},[649,1032,1033],{"class":655},"mv",[649,1035,1036],{"class":659}," src\u002Fdata-connectors\u002Fexample",[649,1038,1039],{"class":659}," src\u002Fdata-connectors\u002Fartic\n",[635,1041,1042,1057,1068,1079],{"sync":637},[639,1043,1045],{"className":641,"code":1044,"filename":643,"language":644,"meta":645,"style":645},"npm run build\n",[484,1046,1047],{"__ignoreMap":645},[649,1048,1049,1051,1054],{"class":651,"line":652},[649,1050,643],{"class":655},[649,1052,1053],{"class":659}," run",[649,1055,1056],{"class":659}," build\n",[639,1058,1060],{"className":641,"code":1059,"filename":685,"language":644,"meta":645,"style":645},"pnpm build\n",[484,1061,1062],{"__ignoreMap":645},[649,1063,1064,1066],{"class":651,"line":652},[649,1065,685],{"class":655},[649,1067,1056],{"class":659},[639,1069,1071],{"className":641,"code":1070,"filename":712,"language":644,"meta":645,"style":645},"yarn build\n",[484,1072,1073],{"__ignoreMap":645},[649,1074,1075,1077],{"class":651,"line":652},[649,1076,712],{"class":655},[649,1078,1056],{"class":659},[639,1080,1082],{"className":641,"code":1081,"filename":741,"language":644,"meta":645,"style":645},"bun run build\n",[484,1083,1084],{"__ignoreMap":645},[649,1085,1086,1088,1090],{"class":651,"line":652},[649,1087,741],{"class":655},[649,1089,1053],{"class":659},[649,1091,1056],{"class":659},[639,1093,1096],{"className":1094,"code":1095,"filename":770,"language":771,"meta":645},[768],"> artic-connector@0.1.0 build\n> monospace extension build\n\nexample\u002Fartic-connector  example\u002Fartic-connector.js\nArtifact                 \u002FUsers\u002FShared\u002Fcode\u002Fartic\u002Fdist\nTo load it, build with --install-to pointing at an engine's extensions directory.\n",[484,1097,1095],{"__ignoreMap":645},[604,1099,1103,1106,1131,1139,1219,1229,1256,1262,1272,1284],{"result":1100,"summary":1101,"title":1102},"Studio lists the entry `example\u002Fartic-connector` under Workspace Settings > Extensions.","Build the project into your instance's extensions directory, and find the extension in Studio.","Install the extension",[462,1104,1105],{},"Install the extension before you change its code. The connector still serves the scaffold's two sample items, so this checks your setup end to end.",[462,1107,1108,1109,1111,1112,1114,1115,1118,1119,1122,1123,1126,1127,1130],{},"Create the quick-start in a directory named ",[484,1110,571],{}," next to ",[484,1113,783],{},", or change the ",[484,1116,1117],{},"--install-to"," path. ",[484,1120,1121],{},"..\u002Fmonospace"," holds the quick-start ",[484,1124,1125],{},"docker-compose.yaml"," and its ",[484,1128,1129],{},"extensions"," directory.",[462,1132,1133,1135,1136,1138],{},[484,1134,1117],{}," builds the project and copies the result into that ",[484,1137,1129],{}," directory. The output lists the artifact and the installed extension directory:",[632,1140,1141,1213],{},[635,1142,1143,1166,1181,1196],{"sync":637},[639,1144,1146],{"className":641,"code":1145,"filename":643,"language":644,"meta":645,"style":645},"npm run build -- --install-to ..\u002Fmonospace\u002Fextensions\n",[484,1147,1148],{"__ignoreMap":645},[649,1149,1150,1152,1154,1157,1160,1163],{"class":651,"line":652},[649,1151,643],{"class":655},[649,1153,1053],{"class":659},[649,1155,1156],{"class":659}," build",[649,1158,1159],{"class":655}," --",[649,1161,1162],{"class":655}," --install-to",[649,1164,1165],{"class":659}," ..\u002Fmonospace\u002Fextensions\n",[639,1167,1169],{"className":641,"code":1168,"filename":685,"language":644,"meta":645,"style":645},"pnpm build --install-to ..\u002Fmonospace\u002Fextensions\n",[484,1170,1171],{"__ignoreMap":645},[649,1172,1173,1175,1177,1179],{"class":651,"line":652},[649,1174,685],{"class":655},[649,1176,1156],{"class":659},[649,1178,1162],{"class":655},[649,1180,1165],{"class":659},[639,1182,1184],{"className":641,"code":1183,"filename":712,"language":644,"meta":645,"style":645},"yarn build --install-to ..\u002Fmonospace\u002Fextensions\n",[484,1185,1186],{"__ignoreMap":645},[649,1187,1188,1190,1192,1194],{"class":651,"line":652},[649,1189,712],{"class":655},[649,1191,1156],{"class":659},[649,1193,1162],{"class":655},[649,1195,1165],{"class":659},[639,1197,1199],{"className":641,"code":1198,"filename":741,"language":644,"meta":645,"style":645},"bun run build --install-to ..\u002Fmonospace\u002Fextensions\n",[484,1200,1201],{"__ignoreMap":645},[649,1202,1203,1205,1207,1209,1211],{"class":651,"line":652},[649,1204,741],{"class":655},[649,1206,1053],{"class":659},[649,1208,1156],{"class":659},[649,1210,1162],{"class":655},[649,1212,1165],{"class":659},[639,1214,1217],{"className":1215,"code":1216,"filename":770,"language":771,"meta":645},[768],"> artic-connector@0.1.0 build\n> monospace extension build --install-to ..\u002Fmonospace\u002Fextensions\n\nexample\u002Fartic-connector  example\u002Fartic-connector.js\nArtifact                 \u002FUsers\u002FShared\u002Fcode\u002Fartic\u002Fdist\nInstalled                \u002FUsers\u002FShared\u002Fcode\u002Fmonospace\u002Fextensions\u002Fexample__artic\nRestart the engine to load it, unless it runs with MONOSPACE_EXTENSIONS__AUTO_RELOAD=true.\n",[484,1218,1216],{"__ignoreMap":645},[462,1220,1221,1225,1226,511],{},[466,1222,1224],{"href":1223},"\u002Freference\u002Fextensions\u002Fcli#install-a-build","Restart the instance"," if automatic reloading is disabled. With automatic reloading enabled, Monospace loads the extension once its files stop changing, and the instance logs ",[484,1227,1228],{},"bundle installed",[462,1230,1231,1232,1235,1236,1238,1239,1242,1243,1245,1246,1248,1249,1251,1252,511],{},"In Studio, open ",[493,1233,1234],{},"Workspace Settings"," (the gear icon in the sidebar), then ",[493,1237,221],{},". The page lists the extension, ",[493,1240,1241],{},"Art Institute of Chicago"," (",[484,1244,806],{},"), and its entry, ",[484,1247,948],{},", marked ",[493,1250,392],{},". The names, IDs, and icon come from ",[797,1253,1254],{"file":800},[484,1255,800],{},[917,1257,1258,1259,511],{"kind":919},"Until Monospace loads the build, the page shows ",[493,1260,1261],{},"No Extensions Available",[462,1263,1264,1265,1268,1269,1271],{},"Run ",[484,1266,1267],{},"docker compose restart monospace"," in ",[484,1270,1121],{}," in these cases:",[521,1273,1274,1277],{},[524,1275,1276],{},"On macOS, the extension doesn't appear. The container can miss changes made on the host through a bind mount.",[524,1278,1279,1280,1283],{},"The instance logged ",[484,1281,1282],{},"failed to watch installed bundles directory; bundle hot reloading is inactive",". The install location didn't exist when the instance started.",[462,1285,908,1286,511],{},[466,1287,1289],{"href":1288},"\u002Fdeveloper\u002Fextensions\u002Finstall#reload-extensions-automatically","Reload Extensions Automatically",[604,1291,1296,1303,1373,1380,1413,1435],{"result":1292,"summary":1293,"title":1294,"file":1295},"Studio lists the two sample items, First and Second. Once you remove the data source, Items is gone from Content.","Create a data source in Studio, review the host it may call, and browse the sample items.","Create a data source and read the sample items","src\u002Fdata-connectors\u002Fartic\u002Fschema.ts",[462,1297,1298,1299,1302],{},"A ",[493,1300,1301],{},"data source"," is a connector configured in one workspace. It adds the connector's collections to that workspace. Create a data source in Studio:",[1304,1305,1306,1318,1336,1347,1361],"ol",{},[524,1307,1308,1309,1311,1312,1315,1316,511],{},"Open ",[493,1310,39],{},", then ",[493,1313,1314],{},"Add Source",", and choose ",[493,1317,1241],{},[524,1319,1320,1321,1323,1324,1327,1328,1331,1332,1335],{},"Enter ",[484,1322,783],{}," as the ",[493,1325,1326],{},"Name",". Leave ",[493,1329,1330],{},"Connection Parameters"," at ",[484,1333,1334],{},"{}",", because this connector has no configuration.",[524,1337,1338,1339,1342,1343,1346],{},"Review ",[493,1340,1341],{},"Permissions",": the data source requests access to ",[484,1344,1345],{},"api.artic.edu",", for the reason declared in step 3. Creating the data source grants this permission.",[524,1348,1349,1350,1353,1354,1357,1358,511],{},"Choose ",[493,1351,1352],{},"Test Connection",". Studio reports ",[493,1355,1356],{},"Connection Test Successful",". Then choose ",[493,1359,1360],{},"Continue",[524,1362,1363,1364,1366,1367,1311,1370,511],{},"Keep ",[484,1365,888],{}," selected, choose ",[493,1368,1369],{},"Review",[493,1371,1372],{},"Add 1 Collection",[462,1374,1375],{},[1376,1377],"img",{"alt":1378,"src":1379},"Studio's Connection Details form for the Art Institute of Chicago connector. It shows Name, Connection Parameters containing an empty JSON object, and Permissions for api.artic.edu with the declared reason.","\u002Fimages\u002Fextensions\u002Ftutorial\u002Fconnection-details.png",[462,1381,1308,1382,1311,1385,1388,1389,487,1392,1395,1396,1398,1399,1403,1404,1408,1409,1412],{},[493,1383,1384],{},"Content",[493,1386,1387],{},"Items",", to see the two sample items, ",[493,1390,1391],{},"First",[493,1393,1394],{},"Second",". The collection is ",[484,1397,888],{}," from ",[797,1400,1401],{"match":880},[484,1402,884],{},", and its items come from ",[797,1405,1406],{"match":896},[484,1407,899],{},". ",[493,1410,1411],{},"Add Item"," is disabled because the collection declares no writes.",[462,1414,1415,1416,1418,1419,1421,1422,1425,1426,1429,1430,1432,1433,511],{},"Remove the sample data source before you change the schema. In ",[493,1417,39],{},", open the menu next to ",[493,1420,783],{},", choose ",[493,1423,1424],{},"Remove Data Source",", and confirm with ",[493,1427,1428],{},"Remove",". Removing a data source removes its collections from the workspace, so ",[493,1431,1387],{}," disappears from ",[493,1434,1384],{},[917,1436,1437,1438,1442],{"kind":1008},"A data source keeps the schema it was created with, and a new build ",[466,1439,1441],{"href":1440},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-sources#update-data-sources-after-an-extension-update","changes only its code",". Part 2 changes the schema, so Part 3 creates the data source again.",[1444,1445,1446],"tutorial-recap",{},"The extension builds and installs, and Studio shows the connector's two sample items. Part 2 replaces the sample data with Art Institute data.",[596,1448,1450],{"title":1449},"Build the connector","Replace the sample with the Art Institute connector by defining its schema and API requests. Add paginated reads, filters, reads by ID, the relation, and failure handling. This part changes code only; request examples show the reads affected by each change and correspond to reads Studio sends in Part 3.",[604,1452,1456,1467,1633,1647,1653,1678],{"result":1453,"summary":1454,"title":1455,"file":1295},"The schema declares `artworks`, and `query` rejects every read until step 8 implements reads.","Replace the sample collection with `artworks` and its four fields.","Declare artworks",[462,1457,942,1458,1460,1461,1463,1464,1466],{},[484,1459,884],{},", replace the ",[484,1462,888],{}," collection with ",[484,1465,486],{},", one item per artwork:",[1468,1469,1470,1486],"table",{},[1471,1472,1473],"thead",{},[1474,1475,1476,1480,1483],"tr",{},[1477,1478,1479],"th",{},"Declaration",[1477,1481,1482],{},"What it means",[1477,1484,1485],{},"Why",[1487,1488,1489,1505,1528,1549,1571,1593,1611],"tbody",{},[1474,1490,1491,1499,1502],{},[1492,1493,1494],"td",{},[797,1495,1497],{"match":1496},"id: field.int32()",[484,1498,1496],{},[1492,1500,1501],{},"Each artwork's ID, a whole number",[1492,1503,1504],{},"The API's IDs fit in 32 bits, so they travel as JSON numbers.",[1474,1506,1507,1516,1522],{},[1492,1508,1509],{},[797,1510,1512,482,1514],{"match":1511},"title: field.string",[484,1513,507],{},[484,1515,510],{},[1492,1517,1518,1519],{},"Text, or ",[484,1520,1521],{},"null",[1492,1523,1524,1525,1527],{},"The connector returns ",[484,1526,1521],{}," where the API has no value.",[1474,1529,1530,1538,1543],{},[1492,1531,1532],{},[797,1533,1535],{"match":1534},"artistId: field.int32",[484,1536,1537],{},"artistId",[1492,1539,1540,1541],{},"The ID of the artwork's artist, or ",[484,1542,1521],{},[1492,1544,1545,1546,1548],{},"Step 12 links it to an ",[484,1547,490],{}," collection.",[1474,1550,1551,1559,1565],{},[1492,1552,1553],{},[797,1554,1556],{"match":1555},"index.primary",[484,1557,1558],{},"index.primary(['id'])",[1492,1560,1561,1564],{},[484,1562,1563],{},"id"," is the primary key",[1492,1566,1567,1568,511],{},"A read of one artwork uses this key, such as ",[484,1569,1570],{},"\u002Fitems\u002Fartworks\u002F27992",[1474,1572,1573,1587,1590],{},[1492,1574,1575,1580,1581,487,1584],{},[797,1576,1578],{"match":1577},"readMany:",[484,1579,892],{}," with ",[484,1582,1583],{},"limit",[484,1585,1586],{},"offset",[1492,1588,1589],{},"Callers list artworks, a page at a time",[1492,1591,1592],{},"Callers can use only declared operations. Step 8 implements this paginated read.",[1474,1594,1595,1602,1608],{},[1492,1596,1597],{},[797,1598,1600],{"match":1599},"output: fields.all()",[484,1601,1599],{},[1492,1603,1604,1605,1607],{},"Callers can select any field with the ",[484,1606,503],{}," parameter, which picks the fields a read returns",[1492,1609,1610],{},"Step 8 returns exactly the fields selected.",[1474,1612,1613,1616,1622],{},[1492,1614,1615],{},"No write",[1492,1617,1618,1619,1621],{},"No create, update, or delete: ",[484,1620,486],{}," is read-only",[1492,1623,1624,1625,1627,1628,1632],{},"The Art Institute API is read-only. So ",[484,1626,800],{}," declares no ",[466,1629,1631],{"href":1630},"\u002Freference\u002Fextensions\u002Fmanifest#capabilities","query capabilities",", which only writes use.",[462,1634,1635,1636,1639,1640,1643,1644,511],{},"An ",[484,1637,1638],{},"int64"," or ",[484,1641,1642],{},"uint64"," field reaches the connector as a string, primary keys included. Don't check its values with ",[484,1645,1646],{},"typeof x === 'number'",[462,1648,908,1649,1652],{},[466,1650,414],{"href":1651},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Foperations"," for everything a collection can declare.",[462,1654,942,1655,1657,1658,1661,1662,1668,1669,1671,1672,511],{},[484,1656,822],{},", remove the ",[484,1659,1660],{},"config"," parameter from ",[797,1663,1666],{"match":1664,"file":1665},"setup()","src\u002Fdata-connectors\u002Fartic\u002Findex.ts",[484,1667,836],{},", because the Art Institute API needs no configuration. Until step 8, make ",[484,1670,861],{}," reject every read with ",[797,1673,1675],{"match":1674,"file":1665},"throw new QueryRejected",[484,1676,1677],{},"QueryRejected",[917,1679,1680,1681,1683,1684,511],{"kind":1008},"Monospace sends ",[484,1682,861],{}," only collections the schema declares. For any other name, the connector throws a plain ",[797,1685,1687],{"match":1686,"file":1665},"Unknown collection",[484,1688,1689],{},"Error",[604,1691,1695,1720,1763,1774],{"result":1692,"summary":1693,"title":1694},"Creating a data source sends a real search request, and fails when the search fails.","Send every request through one function.","Call the search API",[462,1696,1697,1698,1700,1701,1704,1705,1708,1709,1715,1716,1719],{},"Every read goes to a search endpoint on ",[484,1699,1345],{},", such as ",[484,1702,1703],{},"POST \u002Fapi\u002Fv1\u002Fartworks\u002Fsearch",", which takes an Elasticsearch query. Create ",[484,1706,1707],{},"api.ts"," with a ",[797,1710,1712],{"match":1711},"export async function search",[484,1713,1714],{},"search"," function that sends one request to the collection's ",[484,1717,1718],{},"\u002Fsearch"," endpoint. Keeping every request in one function lets step 13 add a time limit in one place.",[521,1721,1722,1738,1747],{},[524,1723,1724,1725,1729,1730,1733,1734,1737],{},"The connector reads ",[797,1726,1728],{"match":1727},"interface SearchResponse","two values from the response",": ",[484,1731,1732],{},"data"," contains the items, and ",[484,1735,1736],{},"pagination.total"," gives the number of matching items.",[524,1739,1740,1741,1746],{},"For a failed HTTP status, the connector throws a plain ",[797,1742,1744],{"match":1743},"if (!response.ok)",[484,1745,1689],{},", which Monospace reports as a failed query.",[524,1748,1749,1755,1756,1758,1759,1762],{},[797,1750,1752],{"match":1751},"export function apiFieldName",[484,1753,1754],{},"apiFieldName"," converts a connector field name to the API's field name (e.g., ",[484,1757,1537],{}," becomes ",[484,1760,1761],{},"artist_id",").",[462,1764,942,1765,1767,1768,1773],{},[484,1766,822],{},", change ",[797,1769,1771],{"match":1770,"file":1665},"size: 0",[484,1772,870],{}," to send a search for zero items. It checks that the API responds, without reading any artworks:",[1775,1776,1778],"tutorial-example",{"note":1777},"Monospace runs `testConnection` when you choose Test Connection in Studio, and before it creates a data source. You create one in step 14.",[639,1779,1784],{"className":1780,"code":1781,"filename":1782,"language":1783,"meta":645,"style":645},"language-http shiki shiki-themes monospace-light monospace-light monospace-dark","POST \u002Fapi\u002Fv1\u002Fartworks\u002Fsearch\n{\"size\": 0}\n","Connector sends","http",[484,1785,1786,1791],{"__ignoreMap":645},[649,1787,1788],{"class":651,"line":652},[649,1789,1790],{},"POST \u002Fapi\u002Fv1\u002Fartworks\u002Fsearch\n",[649,1792,1794],{"class":651,"line":1793},2,[649,1795,1796],{},"{\"size\": 0}\n",[604,1798,1802,1832,1945,1959,1971,2124],{"result":1799,"summary":1800,"title":1801},"A read returns artworks in `id` order, a page at a time, with exactly the fields selected.","Implement `readMany` by translating the sort, the selected fields, and paging into search requests.","Read artworks, one page at a time",[462,1803,942,1804,1806,1807,984,1813,1815,1816,1818,1819,1708,1822,1824,1825,1268,1827,1408,1829,1831],{},[484,1805,884],{},", add ",[797,1808,1810],{"match":1809,"file":1295},"const byId",[484,1811,1812],{},"byId",[484,1814,892],{},": a sort on ",[484,1817,1563],{},", ascending or descending. Create ",[484,1820,1821],{},"read.ts",[484,1823,892],{}," function, and call it from ",[484,1826,861],{},[484,1828,822],{},[484,1830,892],{}," translates each part of the caller's request into the search request:",[1468,1833,1834,1847],{},[1471,1835,1836],{},[1474,1837,1838,1841,1844],{},[1477,1839,1840],{},"Part",[1477,1842,1843],{},"Caller's request",[1477,1845,1846],{},"Search request",[1487,1848,1849,1868,1887,1907,1926],{},[1474,1850,1851,1858,1863],{},[1492,1852,1853],{},[797,1854,1856],{"match":1855},"const size = Math.min",[484,1857,1583],{},[1492,1859,1860],{},[484,1861,1862],{},"limit=3",[1492,1864,1865],{},[484,1866,1867],{},"\"from\": 0, \"size\": 3",[1474,1869,1870,1877,1882],{},[1492,1871,1872],{},[797,1873,1875],{"match":1874},"for (let from = offset",[484,1876,1586],{},[1492,1878,1879],{},[484,1880,1881],{},"offset=995&limit=5",[1492,1883,1884],{},[484,1885,1886],{},"\"from\": 995, \"size\": 5",[1474,1888,1889,1897,1902],{},[1492,1890,1891],{},[797,1892,1894],{"match":1893},"direction === 'descending'",[484,1895,1896],{},"sort",[1492,1898,1899],{},[484,1900,1901],{},"sort[0][id][direction]=desc",[1492,1903,1904],{},[484,1905,1906],{},"\"sort\": [{\"id\": {\"order\": \"desc\"}}]",[1474,1908,1909,1915,1920],{},[1492,1910,1911],{},[797,1912,1914],{"match":1913},"if (sort.length === 0)","No sort",[1492,1916,1917,1918],{},"No ",[484,1919,1896],{},[1492,1921,1922,1925],{},[484,1923,1924],{},"\"sort\": [{\"id\": {\"order\": \"asc\"}}]",", so pages don't overlap",[1474,1927,1928,1935,1940],{},[1492,1929,1930],{},[797,1931,1933],{"match":1932},"fields: select.map",[484,1934,503],{},[1492,1936,1937],{},[484,1938,1939],{},"fields=id,title",[1492,1941,1942],{},[484,1943,1944],{},"\"fields\": [\"id\", \"title\"]",[462,1946,1947,1948,1952,1953,1955,1956,1958],{},"The search API returns at most ",[797,1949,1951],{"match":1950},"const PAGE_SIZE","100 items per request",", so a larger ",[484,1954,1583],{}," becomes several requests. ",[484,1957,892],{}," stops when a page holds fewer items than requested, because no more items remain.",[462,1960,1961,1967,1968,1970],{},[797,1962,1964],{"match":1963},"function toItem",[484,1965,1966],{},"toItem"," returns exactly the selected fields, with ",[484,1969,1521],{}," where the API has no value. The read fails if a returned value doesn't match its field's declared type.",[1775,1972,1974,1984,2028],{"note":1973},"In step 15, Studio sends a read like this when you sort by ID descending.",[639,1975,1978],{"className":1780,"code":1976,"filename":1977,"language":1783,"meta":645,"style":645},"GET \u002Fapi\u002Fblog\u002Fitems\u002Fartworks?fields=id,title&sort[0][id][direction]=desc&limit=3\n","Request",[484,1979,1980],{"__ignoreMap":645},[649,1981,1982],{"class":651,"line":652},[649,1983,1976],{},[639,1985,1987],{"className":1780,"code":1986,"filename":1782,"language":1783,"meta":645,"style":645},"POST \u002Fapi\u002Fv1\u002Fartworks\u002Fsearch\n{\n  \"sort\": [{\"id\": {\"order\": \"desc\"}}],\n  \"fields\": [\"id\", \"title\"],\n  \"from\": 0,\n  \"size\": 3\n}\n",[484,1988,1989,1993,1998,2004,2010,2016,2022],{"__ignoreMap":645},[649,1990,1991],{"class":651,"line":652},[649,1992,1790],{},[649,1994,1995],{"class":651,"line":1793},[649,1996,1997],{},"{\n",[649,1999,2001],{"class":651,"line":2000},3,[649,2002,2003],{},"  \"sort\": [{\"id\": {\"order\": \"desc\"}}],\n",[649,2005,2007],{"class":651,"line":2006},4,[649,2008,2009],{},"  \"fields\": [\"id\", \"title\"],\n",[649,2011,2013],{"class":651,"line":2012},5,[649,2014,2015],{},"  \"from\": 0,\n",[649,2017,2019],{"class":651,"line":2018},6,[649,2020,2021],{},"  \"size\": 3\n",[649,2023,2025],{"class":651,"line":2024},7,[649,2026,2027],{},"}\n",[639,2029,2034],{"className":2030,"code":2031,"filename":2032,"language":2033,"meta":645,"style":645},"language-json shiki shiki-themes monospace-light monospace-light monospace-dark","{\"data\": [\n  {\"id\": 287848, \"title\": \"Eat\"},\n  {\"id\": 286661, \"title\": \"Siebrits-Bartz Anti-Apartheid Collection\"},\n  {\"id\": 286660, \"title\": \"Risen Christ\"}\n]}\n","Response","json",[484,2035,2036,2049,2075,2097,2119],{"__ignoreMap":645},[649,2037,2038,2042,2046],{"class":651,"line":652},[649,2039,2041],{"class":2040},"sTMul","{",[649,2043,2045],{"class":2044},"snHjA","\"data\"",[649,2047,2048],{"class":2040},": [\n",[649,2050,2051,2054,2057,2059,2062,2064,2067,2069,2072],{"class":651,"line":1793},[649,2052,2053],{"class":2040},"  {",[649,2055,2056],{"class":2044},"\"id\"",[649,2058,1729],{"class":2040},[649,2060,2061],{"class":655},"287848",[649,2063,482],{"class":2040},[649,2065,2066],{"class":2044},"\"title\"",[649,2068,1729],{"class":2040},[649,2070,2071],{"class":659},"\"Eat\"",[649,2073,2074],{"class":2040},"},\n",[649,2076,2077,2079,2081,2083,2086,2088,2090,2092,2095],{"class":651,"line":2000},[649,2078,2053],{"class":2040},[649,2080,2056],{"class":2044},[649,2082,1729],{"class":2040},[649,2084,2085],{"class":655},"286661",[649,2087,482],{"class":2040},[649,2089,2066],{"class":2044},[649,2091,1729],{"class":2040},[649,2093,2094],{"class":659},"\"Siebrits-Bartz Anti-Apartheid Collection\"",[649,2096,2074],{"class":2040},[649,2098,2099,2101,2103,2105,2108,2110,2112,2114,2117],{"class":651,"line":2006},[649,2100,2053],{"class":2040},[649,2102,2056],{"class":2044},[649,2104,1729],{"class":2040},[649,2106,2107],{"class":655},"286660",[649,2109,482],{"class":2040},[649,2111,2066],{"class":2044},[649,2113,1729],{"class":2040},[649,2115,2116],{"class":659},"\"Risen Christ\"",[649,2118,2027],{"class":2040},[649,2120,2121],{"class":651,"line":2012},[649,2122,2123],{"class":2040},"]}\n",[917,2125,2126,2127,511],{"kind":1008},"The schema declares no count, no sort on other fields, and no writes, so callers can't request them. A request outside the declaration gets a plain ",[797,2128,2130],{"match":2129},"offer a count",[484,2131,1689],{},[604,2133,2137,2168,2188,2309,2344,2347,2531],{"result":2134,"summary":2135,"title":2136},"The connector translates filters on `id` or `artistId` into search queries, and rejects filters it can't translate.","Declare `equals` and `in` on the ID fields, and translate filters into search queries.","Filter by ID and artist",[462,2138,2139,2140,2142,2143,2152,2153,487,2155,2157,2158,2161,2162,2164,2165,2167],{},"The search API matches IDs exactly, so in ",[484,2141,884],{},", declare ",[797,2144,2146,487,2149],{"match":2145,"file":1295},"const exact",[484,2147,2148],{},"equals",[484,2150,2151],{},"in"," on ",[484,2154,1563],{},[484,2156,1537],{},", with ",[484,2159,2160],{},"and"," to join conditions. The API matches titles case-insensitively, so ",[484,2163,507],{}," gets no filter: ",[484,2166,2148],{}," would return extra items.",[462,2169,2170,2171,1580,2174,2180,2181,1268,2183,1408,2185,2187],{},"Create ",[484,2172,2173],{},"filter.ts",[797,2175,2177],{"match":2176},"export function toQuery",[484,2178,2179],{},"toQuery",", and call it from ",[484,2182,892],{},[484,2184,1821],{},[484,2186,2179],{}," translates each part of the filter:",[1468,2189,2190,2202],{},[1471,2191,2192],{},[1474,2193,2194,2197,2199],{},[1477,2195,2196],{},"Filter",[1477,2198,1843],{},[1477,2200,2201],{},"Search query",[1487,2203,2204,2223,2242,2259,2280],{},[1474,2205,2206,2213,2218],{},[1492,2207,2208],{},[797,2209,2211],{"match":2210},"return { term:",[484,2212,2148],{},[1492,2214,2215],{},[484,2216,2217],{},"filter[artistId][_eq]=40810",[1492,2219,2220],{},[484,2221,2222],{},"{\"term\": {\"artist_id\": 40810}}",[1474,2224,2225,2232,2237],{},[1492,2226,2227],{},[797,2228,2230],{"match":2229},"return { terms:",[484,2231,2151],{},[1492,2233,2234],{},[484,2235,2236],{},"filter[id][_in][]=27992&filter[id][_in][]=28560",[1492,2238,2239],{},[484,2240,2241],{},"{\"terms\": {\"id\": [27992, 28560]}}",[1474,2243,2244,2251,2254],{},[1492,2245,2246],{},[797,2247,2249],{"match":2248},"return { bool: { filter:",[484,2250,2160],{},[1492,2252,2253],{},"Both filters at once",[1492,2255,2256],{},[484,2257,2258],{},"{\"bool\": {\"filter\": [{\"term\": {\"artist_id\": 40810}}, {\"terms\": {\"id\": [27992, 28560]}}]}}",[1474,2260,2261,2269,2274],{},[1492,2262,2263],{},[797,2264,2266],{"match":2265},"should:",[484,2267,2268],{},"or",[1492,2270,2271,2272],{},"A role's permission rules, which Monospace joins with ",[484,2273,2268],{},[1492,2275,2276,2279],{},[484,2277,2278],{},"bool.should",", with at least one match",[1474,2281,2282,2287,2293],{},[1492,2283,2284],{},[797,2285,2286],{"match":1674},"Anything else",[1492,2288,2289,2290],{},"Any other filter, such as ",[484,2291,2292],{},"not",[1492,2294,2295,2296,2298,2299,487,2301,2303,2304,1639,2306,2308],{},"Rejected with ",[484,2297,1677],{}," before any request: \"The Art Institute connector answers only ",[484,2300,2148],{},[484,2302,2151],{},", joined with ",[484,2305,2160],{},[484,2307,2268],{},".\"",[462,2310,2311,2312,2319,2320,2323,2324,1268,2326,2329,2330,2332,2333,2340,2341,2343],{},"For ",[797,2313,2315,1580,2317],{"match":2314},"must_not",[484,2316,2148],{},[484,2318,1521],{},", the connector sends ",[484,2321,2322],{},"bool.must_not.exists",", the search API's test for a missing value. The search API rejects ",[484,2325,1521],{},[484,2327,2328],{},"terms",", so ",[484,2331,2151],{}," ",[797,2334,2336,2337,2339],{"match":2335},"value !== null","leaves ",[484,2338,1521],{}," members out",". An ",[484,2342,2151],{}," filter therefore never matches an artwork whose filtered field has no value.",[462,2345,2346],{},"Declare a filter only where the API matches it exactly. Never skip part of a filter, because the read would return items that filter excludes.",[1775,2348,2350,2359,2400],{"note":2349},"In step 15, Studio sends this filter when you filter Artist ID by `40810`.",[639,2351,2353],{"className":1780,"code":2352,"filename":1977,"language":1783,"meta":645,"style":645},"GET \u002Fapi\u002Fblog\u002Fitems\u002Fartworks?fields=id,title,dateDisplay&filter[artistId][_eq]=40810&limit=3\n",[484,2354,2355],{"__ignoreMap":645},[649,2356,2357],{"class":651,"line":652},[649,2358,2352],{},[639,2360,2362],{"className":1780,"code":2361,"filename":1782,"language":1783,"meta":645,"style":645},"POST \u002Fapi\u002Fv1\u002Fartworks\u002Fsearch\n{\n  \"query\": {\"term\": {\"artist_id\": 40810}},\n  \"sort\": [{\"id\": {\"order\": \"asc\"}}],\n  \"fields\": [\"id\", \"title\", \"date_display\"],\n  \"from\": 0,\n  \"size\": 3\n}\n",[484,2363,2364,2368,2372,2377,2382,2387,2391,2395],{"__ignoreMap":645},[649,2365,2366],{"class":651,"line":652},[649,2367,1790],{},[649,2369,2370],{"class":651,"line":1793},[649,2371,1997],{},[649,2373,2374],{"class":651,"line":2000},[649,2375,2376],{},"  \"query\": {\"term\": {\"artist_id\": 40810}},\n",[649,2378,2379],{"class":651,"line":2006},[649,2380,2381],{},"  \"sort\": [{\"id\": {\"order\": \"asc\"}}],\n",[649,2383,2384],{"class":651,"line":2012},[649,2385,2386],{},"  \"fields\": [\"id\", \"title\", \"date_display\"],\n",[649,2388,2389],{"class":651,"line":2018},[649,2390,2015],{},[649,2392,2393],{"class":651,"line":2024},[649,2394,2021],{},[649,2396,2398],{"class":651,"line":2397},8,[649,2399,2027],{},[639,2401,2403],{"className":2030,"code":2402,"filename":2032,"language":2033,"meta":645,"style":645},"{\"data\": [\n  {\"id\": 20199, \"title\": \"Final Study for \\\"Bathers at Asnières\\\"\", \"dateDisplay\": \"1883\"},\n  {\"id\": 27992, \"title\": \"A Sunday on La Grande Jatte — 1884\", \"dateDisplay\": \"1884–86, border added 1888–89\"},\n  {\"id\": 61616, \"title\": \"Oil Sketch for \\\"A Sunday on La Grande Jatte — 1884\\\"\", \"dateDisplay\": \"1884\"}\n]}\n",[484,2404,2405,2413,2456,2487,2527],{"__ignoreMap":645},[649,2406,2407,2409,2411],{"class":651,"line":652},[649,2408,2041],{"class":2040},[649,2410,2045],{"class":2044},[649,2412,2048],{"class":2040},[649,2414,2415,2417,2419,2421,2424,2426,2428,2430,2433,2436,2439,2441,2444,2446,2449,2451,2454],{"class":651,"line":1793},[649,2416,2053],{"class":2040},[649,2418,2056],{"class":2044},[649,2420,1729],{"class":2040},[649,2422,2423],{"class":655},"20199",[649,2425,482],{"class":2040},[649,2427,2066],{"class":2044},[649,2429,1729],{"class":2040},[649,2431,2432],{"class":659},"\"Final Study for ",[649,2434,2435],{"class":655},"\\\"",[649,2437,2438],{"class":659},"Bathers at Asnières",[649,2440,2435],{"class":655},[649,2442,2443],{"class":659},"\"",[649,2445,482],{"class":2040},[649,2447,2448],{"class":2044},"\"dateDisplay\"",[649,2450,1729],{"class":2040},[649,2452,2453],{"class":659},"\"1883\"",[649,2455,2074],{"class":2040},[649,2457,2458,2460,2462,2464,2467,2469,2471,2473,2476,2478,2480,2482,2485],{"class":651,"line":2000},[649,2459,2053],{"class":2040},[649,2461,2056],{"class":2044},[649,2463,1729],{"class":2040},[649,2465,2466],{"class":655},"27992",[649,2468,482],{"class":2040},[649,2470,2066],{"class":2044},[649,2472,1729],{"class":2040},[649,2474,2475],{"class":659},"\"A Sunday on La Grande Jatte — 1884\"",[649,2477,482],{"class":2040},[649,2479,2448],{"class":2044},[649,2481,1729],{"class":2040},[649,2483,2484],{"class":659},"\"1884–86, border added 1888–89\"",[649,2486,2074],{"class":2040},[649,2488,2489,2491,2493,2495,2498,2500,2502,2504,2507,2509,2512,2514,2516,2518,2520,2522,2525],{"class":651,"line":2006},[649,2490,2053],{"class":2040},[649,2492,2056],{"class":2044},[649,2494,1729],{"class":2040},[649,2496,2497],{"class":655},"61616",[649,2499,482],{"class":2040},[649,2501,2066],{"class":2044},[649,2503,1729],{"class":2040},[649,2505,2506],{"class":659},"\"Oil Sketch for ",[649,2508,2435],{"class":655},[649,2510,2511],{"class":659},"A Sunday on La Grande Jatte — 1884",[649,2513,2435],{"class":655},[649,2515,2443],{"class":659},[649,2517,482],{"class":2040},[649,2519,2448],{"class":2044},[649,2521,1729],{"class":2040},[649,2523,2524],{"class":659},"\"1884\"",[649,2526,2027],{"class":2040},[649,2528,2529],{"class":651,"line":2012},[649,2530,2123],{"class":2040},[917,2532,2533,2534,2536,2537,2539,2540,2543,2544,2546],{"kind":919},"A filter on a field the schema doesn't declare, such as ",[484,2535,507],{},", never reaches the connector. Studio offers no filter for ",[484,2538,507],{}," (step 16), and API requests get ",[484,2541,2542],{},"422"," with a message that starts \"Unknown input field ",[484,2545,507],{},"\".",[604,2548,2552,2564,2583,2595,2670],{"result":2549,"summary":2550,"title":2551},"The connector rejects a read past the 1,000th result with its message, before requesting any item data.","Stop at the API's 1,000th result with a message the caller can act on.","Reject reads past the search window",[462,2553,2554,2555,2559,2560,511],{},"The search API rejects any request that reaches past its ",[797,2556,2558],{"match":2557},"const SEARCH_WINDOW","1,000th result",". A schema can't declare a paging ceiling, so the connector checks it in code. See ",[466,2561,2563],{"href":2562},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Flimitations#no-declarable-page-size-or-depth-limit","No Declarable Page Size or Depth Limit",[462,2565,2566,2567,1268,2569,2571,2572,2574,2575,626,2578,2582],{},"Add the search-window check to ",[484,2568,892],{},[484,2570,1821],{},". For a read past result 1,000, ",[484,2573,892],{}," first counts the matches with a ",[797,2576,2577],{"match":1770},"search for zero items",[797,2579,2581],{"match":2580},"Math.min(end","caps the read at the last match",". A filter that matches fewer than 1,000 artworks makes any offset safe.",[462,2584,2585,2586,2588,2589,2594],{},"If the capped read still reaches past result 1,000, ",[484,2587,892],{}," throws ",[797,2590,2592],{"match":2591},"returns only the first",[484,2593,1677],{}," with a message that tells the caller how to narrow the read:",[1775,2596,2598,2607,2619],{"note":2597},"In step 16, Studio sends a read like this when you show 1,000 artworks per page.",[639,2599,2601],{"className":1780,"code":2600,"filename":1977,"language":1783,"meta":645,"style":645},"GET \u002Fapi\u002Fblog\u002Fitems\u002Fartworks?fields=id&limit=1001\n",[484,2602,2603],{"__ignoreMap":645},[649,2604,2605],{"class":651,"line":652},[649,2606,2600],{},[639,2608,2609],{"className":1780,"code":1781,"filename":1782,"language":1783,"meta":645,"style":645},[484,2610,2611,2615],{"__ignoreMap":645},[649,2612,2613],{"class":651,"line":652},[649,2614,1790],{},[649,2616,2617],{"class":651,"line":1793},[649,2618,1796],{},[639,2620,2623],{"className":2030,"code":2621,"filename":2622,"language":2033,"meta":645,"style":645},"{\"message\":\"Query failed\",\"source\":{\"message\":\"The data source rejected the query\",\"source\":{\"message\":\"the extension returned an error: The Art Institute search API returns only the first 1000 results. Narrow the filter or read an earlier page.\"}}}\n","Response · 422",[484,2624,2625],{"__ignoreMap":645},[649,2626,2627,2629,2632,2635,2638,2641,2644,2647,2649,2651,2654,2656,2658,2660,2662,2664,2667],{"class":651,"line":652},[649,2628,2041],{"class":2040},[649,2630,2631],{"class":2044},"\"message\"",[649,2633,2634],{"class":2040},":",[649,2636,2637],{"class":659},"\"Query failed\"",[649,2639,2640],{"class":2040},",",[649,2642,2643],{"class":2044},"\"source\"",[649,2645,2646],{"class":2040},":{",[649,2648,2631],{"class":2044},[649,2650,2634],{"class":2040},[649,2652,2653],{"class":659},"\"The data source rejected the query\"",[649,2655,2640],{"class":2040},[649,2657,2643],{"class":2044},[649,2659,2646],{"class":2040},[649,2661,2631],{"class":2044},[649,2663,2634],{"class":2040},[649,2665,2666],{"class":659},"\"the extension returned an error: The Art Institute search API returns only the first 1000 results. Narrow the filter or read an earlier page.\"",[649,2668,2669],{"class":2040},"}}}\n",[462,2671,2672,2673,2676],{},"With ",[484,2674,2675],{},"limit=1000",", the read ends at result 1,000, and it succeeds.",[604,2678,2682,2695,2715,2805,2825],{"result":2679,"summary":2680,"title":2681},"A read by ID returns the matching artwork, or `404` when no artwork matches.","Implement reads by ID through `readMany`.","Read one artwork",[462,2683,942,2684,2142,2686,2692,2693,511],{},[484,2685,884],{},[797,2687,2689],{"match":2688,"file":1295},"readOne:",[484,2690,2691],{},"readOne",", a read of one artwork by its ID, with the same filter as ",[484,2694,892],{},[462,2696,942,2697,2699,2700,1824,2702,1268,2704,1408,2706,2708,2709,2714],{},[484,2698,1821],{},", add a ",[484,2701,2691],{},[484,2703,861],{},[484,2705,822],{},[484,2707,2691],{}," calls ",[797,2710,2712],{"match":2711},"limit: 1",[484,2713,892],{}," with the artwork ID, any filter the caller adds, and a limit of one item. This reuses the filter translation from step 9.",[1775,2716,2718,2727,2766],{"note":2717},"In step 15, Studio reads one artwork this way when you open it.",[639,2719,2721],{"className":1780,"code":2720,"filename":1977,"language":1783,"meta":645,"style":645},"GET \u002Fapi\u002Fblog\u002Fitems\u002Fartworks\u002F27992?fields=id,title,dateDisplay\n",[484,2722,2723],{"__ignoreMap":645},[649,2724,2725],{"class":651,"line":652},[649,2726,2720],{},[639,2728,2730],{"className":1780,"code":2729,"filename":1782,"language":1783,"meta":645,"style":645},"POST \u002Fapi\u002Fv1\u002Fartworks\u002Fsearch\n{\n  \"query\": {\"term\": {\"id\": 27992}},\n  \"sort\": [{\"id\": {\"order\": \"asc\"}}],\n  \"fields\": [\"id\", \"title\", \"date_display\"],\n  \"from\": 0,\n  \"size\": 1\n}\n",[484,2731,2732,2736,2740,2745,2749,2753,2757,2762],{"__ignoreMap":645},[649,2733,2734],{"class":651,"line":652},[649,2735,1790],{},[649,2737,2738],{"class":651,"line":1793},[649,2739,1997],{},[649,2741,2742],{"class":651,"line":2000},[649,2743,2744],{},"  \"query\": {\"term\": {\"id\": 27992}},\n",[649,2746,2747],{"class":651,"line":2006},[649,2748,2381],{},[649,2750,2751],{"class":651,"line":2012},[649,2752,2386],{},[649,2754,2755],{"class":651,"line":2018},[649,2756,2015],{},[649,2758,2759],{"class":651,"line":2024},[649,2760,2761],{},"  \"size\": 1\n",[649,2763,2764],{"class":651,"line":2397},[649,2765,2027],{},[639,2767,2769],{"className":2030,"code":2768,"filename":2032,"language":2033,"meta":645,"style":645},"{\"data\": {\"id\": 27992, \"title\": \"A Sunday on La Grande Jatte — 1884\", \"dateDisplay\": \"1884–86, border added 1888–89\"}}\n",[484,2770,2771],{"__ignoreMap":645},[649,2772,2773,2775,2777,2780,2782,2784,2786,2788,2790,2792,2794,2796,2798,2800,2802],{"class":651,"line":652},[649,2774,2041],{"class":2040},[649,2776,2045],{"class":2044},[649,2778,2779],{"class":2040},": {",[649,2781,2056],{"class":2044},[649,2783,1729],{"class":2040},[649,2785,2466],{"class":655},[649,2787,482],{"class":2040},[649,2789,2066],{"class":2044},[649,2791,1729],{"class":2040},[649,2793,2475],{"class":659},[649,2795,482],{"class":2040},[649,2797,2448],{"class":2044},[649,2799,1729],{"class":2040},[649,2801,2484],{"class":659},[649,2803,2804],{"class":2040},"}}\n",[462,2806,2807,2809,2810,2816,2817,2820,2821,2824],{},[484,2808,2691],{}," returns the artwork in ",[797,2811,2813],{"match":2812},"records[0] ?? null",[484,2814,2815],{},"record",", or ",[484,2818,2819],{},"record: null"," when no artwork matches. It doesn't throw for a missing artwork; the caller gets ",[484,2822,2823],{},"404"," with the message \"No record found\".",[917,2826,2827,2828,2830,2831,2833,2834,2836,2837,511],{"kind":919},"Monospace rejects a REST ID that isn't an integer with ",[484,2829,2542],{}," before the connector runs. ",[484,2832,2691],{}," still returns ",[484,2835,2819],{}," for a key that isn't a safe ",[797,2838,2840],{"match":2839},"Number.isSafeInteger","integer",[604,2842,2846,2864,2889,2895],{"result":2843,"summary":2844,"title":2845},"Artwork reads can include each artwork's artist, and artist reads can include their artworks.","Declare a second collection, and link each artwork to its artist.","Add artists and the relation",[462,2847,942,2848,2850,2851,1580,2857,482,2859,2861,2862,511],{},[484,2849,884],{},", add the ",[797,2852,2854,2856],{"match":2853},"name: 'artists'",[484,2855,490],{}," collection",[484,2858,1563],{},[484,2860,507],{},", and the same sort on ",[484,2863,1563],{},[462,2865,2866,2867,2871,2872,984,2875,2878,2879,2885,2886,2888],{},"Add a ",[797,2868,2870],{"match":2869},"defineRelation({","relation"," that links ",[484,2873,2874],{},"artworks.artistId",[484,2876,2877],{},"artists.id",". On an artwork, the to-one ",[797,2880,2882],{"match":2881},"forward: 'artist'",[484,2883,2884],{},"artist"," relation returns a single related item. On an artist, the to-many ",[484,2887,486],{}," relation returns a list of related items.",[462,2890,2891,2892,2894],{},"A relation is a declaration, not code. To include the artists, Monospace reads them by ID with ",[484,2893,2151],{},", which step 9 already translates.",[1775,2896,2898,2907],{"note":2897},"In step 15, Studio uses this read to show the Artist field of each artwork.",[639,2899,2901],{"className":1780,"code":2900,"filename":1977,"language":1783,"meta":645,"style":645},"GET \u002Fapi\u002Fblog\u002Fitems\u002Fartworks?fields=id,title&filter[id][_in][]=27992&filter[id][_in][]=28560&include[artist][fields]=id,title\n",[484,2902,2903],{"__ignoreMap":645},[649,2904,2905],{"class":651,"line":652},[649,2906,2900],{},[639,2908,2910],{"className":2030,"code":2909,"filename":2032,"language":2033,"meta":645,"style":645},"{\"data\": [\n  {\"id\": 27992, \"title\": \"A Sunday on La Grande Jatte — 1884\", \"artist\": {\"id\": 40810, \"title\": \"Georges Seurat\"}},\n  {\"id\": 28560, \"title\": \"The Bedroom\", \"artist\": {\"id\": 40610, \"title\": \"Vincent van Gogh\"}}\n]}\n",[484,2911,2912,2920,2964,3008],{"__ignoreMap":645},[649,2913,2914,2916,2918],{"class":651,"line":652},[649,2915,2041],{"class":2040},[649,2917,2045],{"class":2044},[649,2919,2048],{"class":2040},[649,2921,2922,2924,2926,2928,2930,2932,2934,2936,2938,2940,2943,2945,2947,2949,2952,2954,2956,2958,2961],{"class":651,"line":1793},[649,2923,2053],{"class":2040},[649,2925,2056],{"class":2044},[649,2927,1729],{"class":2040},[649,2929,2466],{"class":655},[649,2931,482],{"class":2040},[649,2933,2066],{"class":2044},[649,2935,1729],{"class":2040},[649,2937,2475],{"class":659},[649,2939,482],{"class":2040},[649,2941,2942],{"class":2044},"\"artist\"",[649,2944,2779],{"class":2040},[649,2946,2056],{"class":2044},[649,2948,1729],{"class":2040},[649,2950,2951],{"class":655},"40810",[649,2953,482],{"class":2040},[649,2955,2066],{"class":2044},[649,2957,1729],{"class":2040},[649,2959,2960],{"class":659},"\"Georges Seurat\"",[649,2962,2963],{"class":2040},"}},\n",[649,2965,2966,2968,2970,2972,2975,2977,2979,2981,2984,2986,2988,2990,2992,2994,2997,2999,3001,3003,3006],{"class":651,"line":2000},[649,2967,2053],{"class":2040},[649,2969,2056],{"class":2044},[649,2971,1729],{"class":2040},[649,2973,2974],{"class":655},"28560",[649,2976,482],{"class":2040},[649,2978,2066],{"class":2044},[649,2980,1729],{"class":2040},[649,2982,2983],{"class":659},"\"The Bedroom\"",[649,2985,482],{"class":2040},[649,2987,2942],{"class":2044},[649,2989,2779],{"class":2040},[649,2991,2056],{"class":2044},[649,2993,1729],{"class":2040},[649,2995,2996],{"class":655},"40610",[649,2998,482],{"class":2040},[649,3000,2066],{"class":2044},[649,3002,1729],{"class":2040},[649,3004,3005],{"class":659},"\"Vincent van Gogh\"",[649,3007,2804],{"class":2040},[649,3009,3010],{"class":651,"line":2006},[649,3011,2123],{"class":2040},[604,3013,3017,3040,3144],{"result":3014,"summary":3015,"title":3016},"Every request stops after 10 seconds, and the connector reports failures using the errors in the table.","Give every request a time limit, and report an API that doesn't respond.","Handle failures",[462,3018,3019,3020,1639,3022,976,3024,3026,3027,3032,3033,3036,3037,3039],{},"Monospace sets no time limit on ",[484,3021,861],{},[484,3023,870],{},[484,3025,1707],{},", give each request a 10-second limit with ",[797,3028,3030],{"match":3029},"AbortSignal.timeout",[484,3031,3029],{},", and throw ",[484,3034,3035],{},"ConnectionFailed"," when ",[484,3038,923],{}," fails. The connector then handles these outcomes:",[1468,3041,3042,3052],{},[1471,3043,3044],{},[1474,3045,3046,3049],{},[1477,3047,3048],{},"Situation",[1477,3050,3051],{},"What the connector does",[1487,3053,3054,3068,3089,3102,3115,3128],{},[1474,3055,3056,3062],{},[1492,3057,3058],{},[797,3059,3061],{"match":3060},"new ConnectionFailed","No response in 10 seconds, or no connection",[1492,3063,3064,3065,3067],{},"Throws ",[484,3066,3035],{},": \"The Art Institute API did not answer.\"",[1474,3069,3070,3076],{},[1492,3071,3072],{},[797,3073,3075],{"match":3074},"Keep the original error as the","The data source's permissions block the host",[1492,3077,3064,3078,3080,3081,3084,3085],{},[484,3079,3035],{}," with the blocked request as its ",[484,3082,3083],{},"cause",". Monospace detects that cause and reports a permission error. See ",[466,3086,3088],{"href":3087},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fpermissions#handle-a-denied-request","Handle a Denied Request",[1474,3090,3091,3096],{},[1492,3092,3093],{},[797,3094,3095],{"match":1743},"The API returns a failed status",[1492,3097,3098,3099,3101],{},"Throws a plain ",[484,3100,1689],{}," (e.g., \"The Art Institute API answered HTTP 403.\"). Monospace reports a failed query",[1474,3103,3104,3110],{},[1492,3105,3106],{},[797,3107,3109],{"match":2591,"file":3108},"src\u002Fdata-connectors\u002Fartic\u002Fread.ts","A read past the 1,000th result",[1492,3111,3064,3112,3114],{},[484,3113,1677],{}," with instructions for narrowing the read (step 10)",[1474,3116,3117,3123],{},[1492,3118,3119],{},[797,3120,3122],{"match":1674,"file":3121},"src\u002Fdata-connectors\u002Fartic\u002Ffilter.ts","A filter the connector can't translate",[1492,3124,3064,3125,3127],{},[484,3126,1677],{}," before sending a request (step 9)",[1474,3129,3130,3135],{},[1492,3131,3132],{},[797,3133,3134],{"match":2812,"file":3108},"No artwork with that ID",[1492,3136,3137,3138,3140,3141,3143],{},"Returns ",[484,3139,2819],{}," without throwing; the caller gets ",[484,3142,2823],{}," (step 11)",[462,3145,908,3146,3150],{},[466,3147,3149],{"href":3148},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Ferrors","Data Connector Errors"," for the error classes.",[1444,3152,3153,3155,3156,487,3158,3160,3161,3163],{},[484,3154,884],{}," declares the operations callers can request, ",[484,3157,1821],{},[484,3159,2173],{}," translate each read into search requests, and ",[484,3162,1707],{}," sends them with a time limit. Part 3 installs the finished extension.",[596,3165,3167],{"title":3166},"Run it","Install the finished extension, create its data source, and browse its collections in Studio. You query the Art Institute API live through the connector from your workspace.",[604,3169,3173,3176,3247,3253,3256,3295,3308],{"result":3170,"summary":3171,"title":3172},"Data Model lists the artic data source with two collections.","Install the finished build, and create the data source again in Studio.","Install the finished extension",[462,3174,3175],{},"Install the finished build over the sample build, as in step 4. The output lists the artifact and the installed extension directory:",[632,3177,3178,3242],{},[635,3179,3180,3198,3212,3226],{"sync":637},[639,3181,3182],{"className":641,"code":1145,"filename":643,"language":644,"meta":645,"style":645},[484,3183,3184],{"__ignoreMap":645},[649,3185,3186,3188,3190,3192,3194,3196],{"class":651,"line":652},[649,3187,643],{"class":655},[649,3189,1053],{"class":659},[649,3191,1156],{"class":659},[649,3193,1159],{"class":655},[649,3195,1162],{"class":655},[649,3197,1165],{"class":659},[639,3199,3200],{"className":641,"code":1168,"filename":685,"language":644,"meta":645,"style":645},[484,3201,3202],{"__ignoreMap":645},[649,3203,3204,3206,3208,3210],{"class":651,"line":652},[649,3205,685],{"class":655},[649,3207,1156],{"class":659},[649,3209,1162],{"class":655},[649,3211,1165],{"class":659},[639,3213,3214],{"className":641,"code":1183,"filename":712,"language":644,"meta":645,"style":645},[484,3215,3216],{"__ignoreMap":645},[649,3217,3218,3220,3222,3224],{"class":651,"line":652},[649,3219,712],{"class":655},[649,3221,1156],{"class":659},[649,3223,1162],{"class":655},[649,3225,1165],{"class":659},[639,3227,3228],{"className":641,"code":1198,"filename":741,"language":644,"meta":645,"style":645},[484,3229,3230],{"__ignoreMap":645},[649,3231,3232,3234,3236,3238,3240],{"class":651,"line":652},[649,3233,741],{"class":655},[649,3235,1053],{"class":659},[649,3237,1156],{"class":659},[649,3239,1162],{"class":655},[649,3241,1165],{"class":659},[639,3243,3245],{"className":3244,"code":1216,"filename":770,"language":771,"meta":645},[768],[484,3246,1216],{"__ignoreMap":645},[462,3248,611,3249,3252],{},[466,3250,3251],{"href":1223},"CLI replaces the entire install directory",". With automatic reloading enabled, Monospace loads the new build once its files stop changing. Without it, restart the instance.",[462,3254,3255],{},"Create the data source again, as in step 5:",[1304,3257,3258,3266,3277,3283],{},[524,3259,1308,3260,1311,3262,1315,3264,511],{},[493,3261,39],{},[493,3263,1314],{},[493,3265,1241],{},[524,3267,1320,3268,1323,3270,3272,3273,1331,3275,511],{},[484,3269,783],{},[493,3271,1326],{},", and leave ",[493,3274,1330],{},[484,3276,1334],{},[524,3278,1349,3279,1311,3281,511],{},[493,3280,1352],{},[493,3282,1360],{},[524,3284,3285,3286,487,3288,1421,3290,1311,3292,511],{},"Keep both collections, ",[484,3287,490],{},[484,3289,486],{},[493,3291,1369],{},[493,3293,3294],{},"Add 2 Collections",[462,3296,3297,3298,3300,3301,1408,3305,3307],{},"Choosing ",[493,3299,1352],{}," or creating a data source runs ",[797,3302,3303],{"match":1770,"file":1665},[484,3304,870],{},[484,3306,870],{}," sends a real search request (step 7), so Monospace doesn't create a data source that can't reach the Art Institute API.",[917,3309,3310,3311,3313,3314,3316],{"kind":919},"If Studio offers ",[484,3312,888],{}," instead, restart the instance as in step 4, then start over from ",[493,3315,1314],{},". Monospace is still running the sample build.",[604,3318,3322,3337,3448,3451,3460],{"result":3319,"summary":3320,"title":3321,"file":3108},"Studio shows the highest IDs first, the works of Georges Seurat, one artwork with its artist, and an artist with his artworks.","Sort, filter, open one artwork, and follow the relation in Studio.","Query the collections",[462,3323,1308,3324,1311,3326,3329,3330,3332,3333,3336],{},[493,3325,1384],{},[493,3327,3328],{},"Artworks",". Studio lists 25 artworks per page in ",[484,3331,1563],{}," order, and shows each artwork's ",[493,3334,3335],{},"Artist"," through the relation. Each action below sends a read that runs code from Part 2:",[1304,3338,3339,3364,3397,3419],{},[524,3340,3341,3344,3345,3348,3349,3352,3353,3359,3360,1762],{},[493,3342,3343],{},"Sort."," Open the menu on the ",[493,3346,3347],{},"ID"," header and choose ",[493,3350,3351],{},"Descending",". The list starts at the highest IDs: 287848 \"Eat\", 286661 \"Siebrits-Bartz Anti-Apartheid Collection\", 286660 \"Risen Christ\". ",[797,3354,3356],{"match":3355},"function toSort",[484,3357,3358],{},"toSort"," translates the sort (",[466,3361,3363],{"href":3362},"#step-read-many","step 8",[524,3365,3366,3369,3370,3372,3373,3376,3377,3380,3381,3383,3384,3388,3389,3392,3393,1762],{},[493,3367,3368],{},"Filter."," Choose the ",[493,3371,2196],{}," button in the toolbar, then ",[493,3374,3375],{},"Artist ID",". Keep ",[493,3378,3379],{},"is",", and enter ",[484,3382,2951],{},". Only works by Georges Seurat remain, because ",[797,3385,3386],{"match":2176,"file":3121},[484,3387,2179],{}," translates the filter into a ",[484,3390,3391],{},"term"," query (",[466,3394,3396],{"href":3395},"#step-filters","step 9",[524,3398,3399,3402,3403,3405,3406,1242,3411,3415,3416,3418],{},[493,3400,3401],{},"Open one artwork."," Choose ",[493,3404,2511],{},". Studio reads the artwork by ID through ",[797,3407,3409],{"match":3408},"export async function readOne",[484,3410,2691],{},[466,3412,3414],{"href":3413},"#step-read-one","step 11","), and its ",[493,3417,3335],{}," field shows Georges Seurat.",[524,3420,3421,3424,3425,3428,3429,3431,3432,3434,3435,3438,3439,3441,3442,1242,3444,1762],{},[493,3422,3423],{},"Follow the relation back."," Open ",[493,3426,3427],{},"Artists",", filter ",[493,3430,3347],{}," by ",[484,3433,2951],{},", and open ",[493,3436,3437],{},"Georges Seurat",". The ",[493,3440,3328],{}," field lists his artworks through the to-many side of the ",[797,3443,2870],{"match":2869,"file":1295},[466,3445,3447],{"href":3446},"#step-artists-relation","step 12",[462,3449,3450],{},"Your data connector serves live queries from Monospace!",[462,3452,3453,3454,487,3457,511],{},"Query these collections over the API like any other collection. See ",[466,3455,168],{"href":3456},"\u002Fdeveloper\u002Fapi\u002Ffiltering",[466,3458,183],{"href":3459},"\u002Fdeveloper\u002Fapi\u002Frelational-data",[462,3461,3462,3463,3465,3466,482,3468,3465,3470,626,3472,3465,3474,511],{},"Studio derives display names from the collection and field names the connector declares. It shows ",[484,3464,486],{}," as ",[493,3467,3328],{},[484,3469,1537],{},[493,3471,3375],{},[484,3473,510],{},[493,3475,3476],{},"Date Display",[604,3478,3482,3498,3520,3526,3537,3559],{"result":3479,"summary":3480,"title":3481,"file":3108},"A page of 1,000 artworks fails with the connector's message, and the filter list offers only declared fields.","Exceed the search window, read the connector's error, and check which filters Studio offers.","Check query limits and available filters",[462,3483,3484,3485,1421,3487,3490,3491,3494,3495,511],{},"On ",[493,3486,3328],{},[493,3488,3489],{},"Reset"," in the filter bar to clear the filter from step 15. Then choose ",[493,3492,3493],{},"25 per Page"," at the bottom, and ",[493,3496,3497],{},"1000 per Page",[462,3499,3500,3501,2588,3503,1242,3507,3511,3512,3515,3516,3519],{},"Studio requests one extra artwork to check for a next page, so this read reaches result 1,001. ",[484,3502,892],{},[797,3504,3505],{"match":2591},[484,3506,1677],{},[466,3508,3510],{"href":3509},"#step-search-window","step 10","), and Studio shows ",[493,3513,3514],{},"Couldn't Load Items",". Choose ",[493,3517,3518],{},"View Details"," to read the connector's message:",[462,3521,3522],{},[1376,3523],{"alt":3524,"src":3525},"Studio's Error Details dialog shows \"Query failed\" and \"The data source rejected the query\". The connector's message states that the search API returns only the first 1000 results.","\u002Fimages\u002Fextensions\u002Ftutorial\u002Ferror-details.png",[462,3527,3528,3529,3431,3531,3533,3534,3536],{},"Filter ",[493,3530,3375],{},[484,3532,2951],{}," again to narrow the read, and the page loads the works of Georges Seurat. ",[493,3535,3489],{}," clears the filter and returns to 25 per page.",[462,3538,3539,3540,3542,3543,3545,3546,482,3548,3550,3551,3553,3554,487,3556,3558],{},"Studio offers only the filters and sorts the schema declares, and only the ",[493,3541,3347],{}," header offers sorting. The ",[493,3544,2196],{}," list offers ",[493,3547,3347],{},[493,3549,3375],{},", and the ",[493,3552,3335],{}," relation. It omits ",[484,3555,507],{},[484,3557,510],{}," because neither field declares a filter.",[462,3560,3561],{},[1376,3562],{"alt":3563,"src":3564},"Studio's Filter list for Artworks, offering only ID, Artist ID, and Artist","\u002Fimages\u002Fextensions\u002Ftutorial\u002Ffilter-fields.png",[1444,3566,3567],{},"The finished extension is installed on your instance, and its data source adds the connector's collections to your workspace. The connector serves live queries. When the Art Institute API can't serve a request, the connector rejects it with a message the caller can act on.",[3569,3570,3572,3586],"tutorial-install",{"title":3571},"Install the prebuilt extension",[462,3573,3574,3575,3578,3579,3582,3583,511],{},"Install the prebuilt extension without the source project. The zip holds one directory, ",[484,3576,3577],{},"artic-connector-dist",", with its ",[484,3580,3581],{},"manifest.json"," and the built connector, ",[484,3584,3585],{},"example\u002Fartic-connector.js",[1304,3587,3588,3609,3636,3676],{},[524,3589,3590,3593,3594,3597,3598,3601,3602,3605,3606,511],{},[493,3591,3592],{},"Unzip the extension into your instance's install location."," The default is ",[484,3595,3596],{},".\u002Fextensions",", relative to the instance's working directory.",[3599,3600],"br",{},"In Docker, the install location is ",[484,3603,3604],{},"\u002Fmonospace\u002Fextensions"," inside the container, so unzip into the host directory you mount there. See ",[466,3607,3608],{"href":558},"Run Monospace in Docker",[524,3610,3611,3614,3615,3619,3620,3623,3624,3626,3627,3629,3630,3632,3633,3635],{},[493,3612,3613],{},"Load the extension."," With ",[3616,3617],"env-var",{"name":3618,"section":1129},"extensions__auto_reload"," set to ",[484,3621,3622],{},"true",", Monospace loads the extension once its files stop changing. Otherwise, restart the instance.",[3599,3625],{},"On macOS, run ",[484,3628,1267],{}," if Studio doesn't list the extension under ",[493,3631,1234],{}," > ",[493,3634,221],{},". The container can miss changes made on the host through a bind mount.",[524,3637,3638,3641,3642,1421,3644,1311,3646,3648,3649,1700,3651,3272,3653,1331,3655,3657,3658,3660,3661,3663,3664,3666,3667,3671,3672,511],{},[493,3639,3640],{},"Create a data source."," In Studio, open ",[493,3643,39],{},[493,3645,1314],{},[493,3647,1241],{},". Enter a ",[493,3650,1326],{},[484,3652,783],{},[493,3654,1330],{},[484,3656,1334],{},", because the connector has no configuration.",[3599,3659],{},"Creating the data source grants access to ",[484,3662,1345],{},", the host the connector declares with ",[484,3665,966],{},". See ",[466,3668,3670],{"href":3669},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-sources#add-a-data-source-in-studio","Add a Data Source in Studio",". To create the data source over the API instead, see ",[466,3673,3675],{"href":3674},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fpermissions#approve-permissions","Approve Permissions",[524,3677,3678,3424,3681,1311,3683,3685,3686,3431,3688,3690],{},[493,3679,3680],{},"Query the collections.",[493,3682,1384],{},[493,3684,3328],{},", and filter ",[493,3687,3375],{},[484,3689,2951],{}," to list the works of Georges Seurat.",[3692,3693,3694,3699,3706,3932,4091,4299,4923,5477,5945,7430,8123],"template",{"v-slot:files":645},[3695,3696,3698],"h2",{"id":3697},"final-code","Final code",[639,3700,3704],{"className":3701,"code":3702,"filename":3703,"language":771,"meta":645},[768],"dist\nnode_modules\n",".gitignore",[484,3705,3702],{"__ignoreMap":645},[639,3707,3709],{"className":2030,"code":3708,"filename":800,"language":2033,"meta":645,"style":645},"{\n    \"$schema\": \".\u002Fnode_modules\u002F@monospace\u002Fcli\u002Fschemas\u002Fextension.config.schema.json\",\n    \"entries\": [\n        {\n            \"engine\": {\n                \"entrypoint\": \".\u002Fsrc\u002Fdata-connectors\u002Fartic\u002Findex.ts\",\n                \"permissions\": [\n                    { \"permission\": \"net:api.artic.edu\", \"reason\": \"Read artworks and artists from the Art Institute of Chicago API\" }\n                ]\n            },\n            \"icon\": \"lucide:landmark\",\n            \"id\": \"example\u002Fartic-connector\",\n            \"name\": \"Art Institute of Chicago\",\n            \"type\": \"dataConnector\",\n            \"version\": \"0.1.0\"\n        }\n    ],\n    \"icon\": \"lucide:landmark\",\n    \"id\": \"example\u002Fartic\",\n    \"name\": \"Art Institute of Chicago\",\n    \"version\": \"0.1.0\"\n}\n",[484,3710,3711,3715,3728,3735,3740,3748,3760,3767,3793,3799,3805,3818,3831,3844,3857,3868,3874,3880,3892,3905,3917,3927],{"__ignoreMap":645},[649,3712,3713],{"class":651,"line":652},[649,3714,1997],{"class":2040},[649,3716,3717,3720,3722,3725],{"class":651,"line":1793},[649,3718,3719],{"class":2044},"    \"$schema\"",[649,3721,1729],{"class":2040},[649,3723,3724],{"class":659},"\".\u002Fnode_modules\u002F@monospace\u002Fcli\u002Fschemas\u002Fextension.config.schema.json\"",[649,3726,3727],{"class":2040},",\n",[649,3729,3730,3733],{"class":651,"line":2000},[649,3731,3732],{"class":2044},"    \"entries\"",[649,3734,2048],{"class":2040},[649,3736,3737],{"class":651,"line":2006},[649,3738,3739],{"class":2040},"        {\n",[649,3741,3742,3745],{"class":651,"line":2012},[649,3743,3744],{"class":2044},"            \"engine\"",[649,3746,3747],{"class":2040},": {\n",[649,3749,3750,3753,3755,3758],{"class":651,"line":2018},[649,3751,3752],{"class":2044},"                \"entrypoint\"",[649,3754,1729],{"class":2040},[649,3756,3757],{"class":659},"\".\u002Fsrc\u002Fdata-connectors\u002Fartic\u002Findex.ts\"",[649,3759,3727],{"class":2040},[649,3761,3762,3765],{"class":651,"line":2024},[649,3763,3764],{"class":2044},"                \"permissions\"",[649,3766,2048],{"class":2040},[649,3768,3769,3772,3775,3777,3780,3782,3785,3787,3790],{"class":651,"line":2397},[649,3770,3771],{"class":2040},"                    { ",[649,3773,3774],{"class":2044},"\"permission\"",[649,3776,1729],{"class":2040},[649,3778,3779],{"class":659},"\"net:api.artic.edu\"",[649,3781,482],{"class":2040},[649,3783,3784],{"class":2044},"\"reason\"",[649,3786,1729],{"class":2040},[649,3788,3789],{"class":659},"\"Read artworks and artists from the Art Institute of Chicago API\"",[649,3791,3792],{"class":2040}," }\n",[649,3794,3796],{"class":651,"line":3795},9,[649,3797,3798],{"class":2040},"                ]\n",[649,3800,3802],{"class":651,"line":3801},10,[649,3803,3804],{"class":2040},"            },\n",[649,3806,3808,3811,3813,3816],{"class":651,"line":3807},11,[649,3809,3810],{"class":2044},"            \"icon\"",[649,3812,1729],{"class":2040},[649,3814,3815],{"class":659},"\"lucide:landmark\"",[649,3817,3727],{"class":2040},[649,3819,3821,3824,3826,3829],{"class":651,"line":3820},12,[649,3822,3823],{"class":2044},"            \"id\"",[649,3825,1729],{"class":2040},[649,3827,3828],{"class":659},"\"example\u002Fartic-connector\"",[649,3830,3727],{"class":2040},[649,3832,3834,3837,3839,3842],{"class":651,"line":3833},13,[649,3835,3836],{"class":2044},"            \"name\"",[649,3838,1729],{"class":2040},[649,3840,3841],{"class":659},"\"Art Institute of Chicago\"",[649,3843,3727],{"class":2040},[649,3845,3847,3850,3852,3855],{"class":651,"line":3846},14,[649,3848,3849],{"class":2044},"            \"type\"",[649,3851,1729],{"class":2040},[649,3853,3854],{"class":659},"\"dataConnector\"",[649,3856,3727],{"class":2040},[649,3858,3860,3863,3865],{"class":651,"line":3859},15,[649,3861,3862],{"class":2044},"            \"version\"",[649,3864,1729],{"class":2040},[649,3866,3867],{"class":659},"\"0.1.0\"\n",[649,3869,3871],{"class":651,"line":3870},16,[649,3872,3873],{"class":2040},"        }\n",[649,3875,3877],{"class":651,"line":3876},17,[649,3878,3879],{"class":2040},"    ],\n",[649,3881,3883,3886,3888,3890],{"class":651,"line":3882},18,[649,3884,3885],{"class":2044},"    \"icon\"",[649,3887,1729],{"class":2040},[649,3889,3815],{"class":659},[649,3891,3727],{"class":2040},[649,3893,3895,3898,3900,3903],{"class":651,"line":3894},19,[649,3896,3897],{"class":2044},"    \"id\"",[649,3899,1729],{"class":2040},[649,3901,3902],{"class":659},"\"example\u002Fartic\"",[649,3904,3727],{"class":2040},[649,3906,3908,3911,3913,3915],{"class":651,"line":3907},20,[649,3909,3910],{"class":2044},"    \"name\"",[649,3912,1729],{"class":2040},[649,3914,3841],{"class":659},[649,3916,3727],{"class":2040},[649,3918,3920,3923,3925],{"class":651,"line":3919},21,[649,3921,3922],{"class":2044},"    \"version\"",[649,3924,1729],{"class":2040},[649,3926,3867],{"class":659},[649,3928,3930],{"class":651,"line":3929},22,[649,3931,2027],{"class":2040},[639,3933,3935],{"className":2030,"code":3934,"filename":979,"language":2033,"meta":645,"style":645},"{\n    \"name\": \"artic-connector\",\n    \"type\": \"module\",\n    \"version\": \"0.1.0\",\n    \"private\": true,\n    \"scripts\": {\n        \"build\": \"monospace extension build\",\n        \"typecheck\": \"tsc --noEmit\"\n    },\n    \"dependencies\": {\n        \"@monospace\u002Fextension-kit\": \"^0.3.0\"\n    },\n    \"devDependencies\": {\n        \"@monospace\u002Fcli\": \"^0.2.1\",\n        \"rolldown\": \"^1.2.0\",\n        \"typescript\": \"^6.0.3\"\n    }\n}\n",[484,3936,3937,3941,3952,3964,3975,3986,3993,4005,4015,4020,4027,4037,4041,4048,4060,4072,4082,4087],{"__ignoreMap":645},[649,3938,3939],{"class":651,"line":652},[649,3940,1997],{"class":2040},[649,3942,3943,3945,3947,3950],{"class":651,"line":1793},[649,3944,3910],{"class":2044},[649,3946,1729],{"class":2040},[649,3948,3949],{"class":659},"\"artic-connector\"",[649,3951,3727],{"class":2040},[649,3953,3954,3957,3959,3962],{"class":651,"line":2000},[649,3955,3956],{"class":2044},"    \"type\"",[649,3958,1729],{"class":2040},[649,3960,3961],{"class":659},"\"module\"",[649,3963,3727],{"class":2040},[649,3965,3966,3968,3970,3973],{"class":651,"line":2006},[649,3967,3922],{"class":2044},[649,3969,1729],{"class":2040},[649,3971,3972],{"class":659},"\"0.1.0\"",[649,3974,3727],{"class":2040},[649,3976,3977,3980,3982,3984],{"class":651,"line":2012},[649,3978,3979],{"class":2044},"    \"private\"",[649,3981,1729],{"class":2040},[649,3983,3622],{"class":655},[649,3985,3727],{"class":2040},[649,3987,3988,3991],{"class":651,"line":2018},[649,3989,3990],{"class":2044},"    \"scripts\"",[649,3992,3747],{"class":2040},[649,3994,3995,3998,4000,4003],{"class":651,"line":2024},[649,3996,3997],{"class":2044},"        \"build\"",[649,3999,1729],{"class":2040},[649,4001,4002],{"class":659},"\"monospace extension build\"",[649,4004,3727],{"class":2040},[649,4006,4007,4010,4012],{"class":651,"line":2397},[649,4008,4009],{"class":2044},"        \"typecheck\"",[649,4011,1729],{"class":2040},[649,4013,4014],{"class":659},"\"tsc --noEmit\"\n",[649,4016,4017],{"class":651,"line":3795},[649,4018,4019],{"class":2040},"    },\n",[649,4021,4022,4025],{"class":651,"line":3801},[649,4023,4024],{"class":2044},"    \"dependencies\"",[649,4026,3747],{"class":2040},[649,4028,4029,4032,4034],{"class":651,"line":3807},[649,4030,4031],{"class":2044},"        \"@monospace\u002Fextension-kit\"",[649,4033,1729],{"class":2040},[649,4035,4036],{"class":659},"\"^0.3.0\"\n",[649,4038,4039],{"class":651,"line":3820},[649,4040,4019],{"class":2040},[649,4042,4043,4046],{"class":651,"line":3833},[649,4044,4045],{"class":2044},"    \"devDependencies\"",[649,4047,3747],{"class":2040},[649,4049,4050,4053,4055,4058],{"class":651,"line":3846},[649,4051,4052],{"class":2044},"        \"@monospace\u002Fcli\"",[649,4054,1729],{"class":2040},[649,4056,4057],{"class":659},"\"^0.2.1\"",[649,4059,3727],{"class":2040},[649,4061,4062,4065,4067,4070],{"class":651,"line":3859},[649,4063,4064],{"class":2044},"        \"rolldown\"",[649,4066,1729],{"class":2040},[649,4068,4069],{"class":659},"\"^1.2.0\"",[649,4071,3727],{"class":2040},[649,4073,4074,4077,4079],{"class":651,"line":3870},[649,4075,4076],{"class":2044},"        \"typescript\"",[649,4078,1729],{"class":2040},[649,4080,4081],{"class":659},"\"^6.0.3\"\n",[649,4083,4084],{"class":651,"line":3876},[649,4085,4086],{"class":2040},"    }\n",[649,4088,4089],{"class":651,"line":3882},[649,4090,2027],{"class":2040},[639,4092,4097],{"className":4093,"code":4094,"filename":4095,"language":4096,"meta":645,"style":645},"language-markdown shiki shiki-themes monospace-light monospace-light monospace-dark","# Art Institute of Chicago\n\nA Monospace data connector.\n\n## Build\n\n```sh\nnpm i\nnpm run build\nnpm run typecheck\n```\n\nEdit `src\u002Fdata-connectors\u002Fartic\u002Findex.ts` for connector handlers and\n`src\u002Fdata-connectors\u002Fartic\u002Fschema.ts` for its schema. Builds write\n`dist\u002Fexample\u002Fartic-connector.js` and `dist\u002Fmanifest.json`. They bundle without\nchecking types, so run `typecheck` too.\n\n## Install\n\n```sh\nnpx monospace extension build --install-to \u002Fpath\u002Fto\u002Fengine\u002Fextensions\n```\n\nReplace the path with your engine's extension directory: `.\u002Fextensions` beside the\nengine unless `MONOSPACE_EXTENSIONS__INSTALL_LOCATION` says otherwise. The engine loads\nextensions at startup; with `MONOSPACE_EXTENSIONS__AUTO_RELOAD=true` it also reloads them\nwhen they change, so adding `--watch` gives a live edit loop.\n\n## Configuration\n\nIn `extension.config.json`, `example\u002Fartic` identifies the installed bundle;\n`example\u002Fartic-connector` identifies the connector that data sources use.\nValidate data-source settings in `setup({ config })`.\n\n## Runtime\n\nConnectors run in a V8 isolate, not Node.js. Use web APIs such as `fetch`;\n`node:` imports are unavailable. Each entry builds into one self-contained\nmodule with its dependencies bundled.\n","README.md","markdown",[484,4098,4099,4104,4110,4115,4119,4124,4128,4133,4138,4142,4147,4152,4156,4161,4166,4171,4176,4180,4185,4189,4193,4198,4202,4207,4213,4219,4225,4231,4236,4242,4247,4253,4259,4265,4270,4276,4281,4287,4293],{"__ignoreMap":645},[649,4100,4101],{"class":651,"line":652},[649,4102,4103],{},"# Art Institute of Chicago\n",[649,4105,4106],{"class":651,"line":1793},[649,4107,4109],{"emptyLinePlaceholder":4108},true,"\n",[649,4111,4112],{"class":651,"line":2000},[649,4113,4114],{},"A Monospace data connector.\n",[649,4116,4117],{"class":651,"line":2006},[649,4118,4109],{"emptyLinePlaceholder":4108},[649,4120,4121],{"class":651,"line":2012},[649,4122,4123],{},"## Build\n",[649,4125,4126],{"class":651,"line":2018},[649,4127,4109],{"emptyLinePlaceholder":4108},[649,4129,4130],{"class":651,"line":2024},[649,4131,4132],{},"```sh\n",[649,4134,4135],{"class":651,"line":2397},[649,4136,4137],{},"npm i\n",[649,4139,4140],{"class":651,"line":3795},[649,4141,1044],{},[649,4143,4144],{"class":651,"line":3801},[649,4145,4146],{},"npm run typecheck\n",[649,4148,4149],{"class":651,"line":3807},[649,4150,4151],{},"```\n",[649,4153,4154],{"class":651,"line":3820},[649,4155,4109],{"emptyLinePlaceholder":4108},[649,4157,4158],{"class":651,"line":3833},[649,4159,4160],{},"Edit `src\u002Fdata-connectors\u002Fartic\u002Findex.ts` for connector handlers and\n",[649,4162,4163],{"class":651,"line":3846},[649,4164,4165],{},"`src\u002Fdata-connectors\u002Fartic\u002Fschema.ts` for its schema. Builds write\n",[649,4167,4168],{"class":651,"line":3859},[649,4169,4170],{},"`dist\u002Fexample\u002Fartic-connector.js` and `dist\u002Fmanifest.json`. They bundle without\n",[649,4172,4173],{"class":651,"line":3870},[649,4174,4175],{},"checking types, so run `typecheck` too.\n",[649,4177,4178],{"class":651,"line":3876},[649,4179,4109],{"emptyLinePlaceholder":4108},[649,4181,4182],{"class":651,"line":3882},[649,4183,4184],{},"## Install\n",[649,4186,4187],{"class":651,"line":3894},[649,4188,4109],{"emptyLinePlaceholder":4108},[649,4190,4191],{"class":651,"line":3907},[649,4192,4132],{},[649,4194,4195],{"class":651,"line":3919},[649,4196,4197],{},"npx monospace extension build --install-to \u002Fpath\u002Fto\u002Fengine\u002Fextensions\n",[649,4199,4200],{"class":651,"line":3929},[649,4201,4151],{},[649,4203,4205],{"class":651,"line":4204},23,[649,4206,4109],{"emptyLinePlaceholder":4108},[649,4208,4210],{"class":651,"line":4209},24,[649,4211,4212],{},"Replace the path with your engine's extension directory: `.\u002Fextensions` beside the\n",[649,4214,4216],{"class":651,"line":4215},25,[649,4217,4218],{},"engine unless `MONOSPACE_EXTENSIONS__INSTALL_LOCATION` says otherwise. The engine loads\n",[649,4220,4222],{"class":651,"line":4221},26,[649,4223,4224],{},"extensions at startup; with `MONOSPACE_EXTENSIONS__AUTO_RELOAD=true` it also reloads them\n",[649,4226,4228],{"class":651,"line":4227},27,[649,4229,4230],{},"when they change, so adding `--watch` gives a live edit loop.\n",[649,4232,4234],{"class":651,"line":4233},28,[649,4235,4109],{"emptyLinePlaceholder":4108},[649,4237,4239],{"class":651,"line":4238},29,[649,4240,4241],{},"## Configuration\n",[649,4243,4245],{"class":651,"line":4244},30,[649,4246,4109],{"emptyLinePlaceholder":4108},[649,4248,4250],{"class":651,"line":4249},31,[649,4251,4252],{},"In `extension.config.json`, `example\u002Fartic` identifies the installed bundle;\n",[649,4254,4256],{"class":651,"line":4255},32,[649,4257,4258],{},"`example\u002Fartic-connector` identifies the connector that data sources use.\n",[649,4260,4262],{"class":651,"line":4261},33,[649,4263,4264],{},"Validate data-source settings in `setup({ config })`.\n",[649,4266,4268],{"class":651,"line":4267},34,[649,4269,4109],{"emptyLinePlaceholder":4108},[649,4271,4273],{"class":651,"line":4272},35,[649,4274,4275],{},"## Runtime\n",[649,4277,4279],{"class":651,"line":4278},36,[649,4280,4109],{"emptyLinePlaceholder":4108},[649,4282,4284],{"class":651,"line":4283},37,[649,4285,4286],{},"Connectors run in a V8 isolate, not Node.js. Use web APIs such as `fetch`;\n",[649,4288,4290],{"class":651,"line":4289},38,[649,4291,4292],{},"`node:` imports are unavailable. Each entry builds into one self-contained\n",[649,4294,4296],{"class":651,"line":4295},39,[649,4297,4298],{},"module with its dependencies bundled.\n",[639,4300,4305],{"className":4301,"code":4302,"filename":4303,"language":4304,"meta":645,"style":645},"language-ts shiki shiki-themes monospace-light monospace-light monospace-dark","import type { Value } from '@monospace\u002Fextension-kit\u002Fdata-connector';\nimport { ConnectionFailed } from '@monospace\u002Fextension-kit\u002Fdata-connector';\n\nconst BASE_URL = 'https:\u002F\u002Fapi.artic.edu\u002Fapi\u002Fv1';\n\u002F** Monospace sets no time limit on `query` or `testConnection`, so each request sets its own. *\u002F\nconst TIMEOUT_MS = 10_000;\n\n\u002F** A request body for the search API, which takes Elasticsearch syntax. *\u002F\nexport type SearchBody = Record\u003Cstring, unknown>;\n\n\u002F** The fields of a search response the connector reads: the items, and the number of matches. *\u002F\ninterface SearchResponse {\n    data: Record\u003Cstring, Value>[];\n    pagination: { total: number };\n}\n\n\u002F** Converts a camelCase field name to the API's snake_case name, such as `artistId` to `artist_id`. *\u002F\nexport function apiFieldName(name: string): string {\n    return name.replaceAll(\u002F[A-Z]\u002Fgu, (letter) => `_${letter.toLowerCase()}`);\n}\n\n\u002F** Sends one search request. *\u002F\nexport async function search(collection: string, body: SearchBody): Promise\u003CSearchResponse> {\n    let response: Response;\n\n    try {\n        response = await fetch(`${BASE_URL}\u002F${collection}\u002Fsearch`, {\n            method: 'POST',\n            headers: { 'Content-Type': 'application\u002Fjson', 'AIC-User-Agent': 'monospace-artic-connector' },\n            body: JSON.stringify(body),\n            signal: AbortSignal.timeout(TIMEOUT_MS),\n        });\n    }\n    catch (error) {\n        \u002F\u002F Keep the original error as the `cause`. If the data source's permissions blocked the request,\n        \u002F\u002F Monospace finds the blocked request in the `cause` and reports a permission error, not a failed connection.\n        throw new ConnectionFailed('The Art Institute API did not answer.', { cause: error });\n    }\n\n    \u002F\u002F For a failed HTTP status, throw a plain `Error`, which Monospace reports as a failed query.\n    if (!response.ok) throw new Error(`The Art Institute API answered HTTP ${response.status}.`);\n\n    return (await response.json()) as SearchResponse;\n}\n","src\u002Fdata-connectors\u002Fartic\u002Fapi.ts","ts",[484,4306,4307,4335,4351,4355,4371,4377,4391,4395,4400,4429,4433,4438,4449,4467,4483,4487,4491,4496,4524,4581,4585,4589,4594,4635,4650,4654,4661,4694,4704,4730,4751,4771,4776,4780,4793,4798,4803,4827,4831,4835,4841,4887,4892,4918],{"__ignoreMap":645},[649,4308,4309,4313,4316,4319,4323,4326,4329,4332],{"class":651,"line":652},[649,4310,4312],{"class":4311},"sLVBU","import",[649,4314,4315],{"class":4311}," type",[649,4317,4318],{"class":2040}," { ",[649,4320,4322],{"class":4321},"sNJ9c","Value",[649,4324,4325],{"class":2040}," } ",[649,4327,4328],{"class":4311},"from",[649,4330,4331],{"class":659}," '@monospace\u002Fextension-kit\u002Fdata-connector'",[649,4333,4334],{"class":2040},";\n",[649,4336,4337,4339,4341,4343,4345,4347,4349],{"class":651,"line":1793},[649,4338,4312],{"class":4311},[649,4340,4318],{"class":2040},[649,4342,3035],{"class":4321},[649,4344,4325],{"class":2040},[649,4346,4328],{"class":4311},[649,4348,4331],{"class":659},[649,4350,4334],{"class":2040},[649,4352,4353],{"class":651,"line":2000},[649,4354,4109],{"emptyLinePlaceholder":4108},[649,4356,4357,4360,4363,4366,4369],{"class":651,"line":2006},[649,4358,4359],{"class":4311},"const",[649,4361,4362],{"class":655}," BASE_URL",[649,4364,4365],{"class":4311}," =",[649,4367,4368],{"class":659}," 'https:\u002F\u002Fapi.artic.edu\u002Fapi\u002Fv1'",[649,4370,4334],{"class":2040},[649,4372,4373],{"class":651,"line":2012},[649,4374,4376],{"class":4375},"seNfP","\u002F** Monospace sets no time limit on `query` or `testConnection`, so each request sets its own. *\u002F\n",[649,4378,4379,4381,4384,4386,4389],{"class":651,"line":2018},[649,4380,4359],{"class":4311},[649,4382,4383],{"class":655}," TIMEOUT_MS",[649,4385,4365],{"class":4311},[649,4387,4388],{"class":655}," 10_000",[649,4390,4334],{"class":2040},[649,4392,4393],{"class":651,"line":2024},[649,4394,4109],{"emptyLinePlaceholder":4108},[649,4396,4397],{"class":651,"line":2397},[649,4398,4399],{"class":4375},"\u002F** A request body for the search API, which takes Elasticsearch syntax. *\u002F\n",[649,4401,4402,4405,4407,4410,4412,4415,4418,4421,4423,4426],{"class":651,"line":3795},[649,4403,4404],{"class":4311},"export",[649,4406,4315],{"class":4311},[649,4408,4409],{"class":655}," SearchBody",[649,4411,4365],{"class":4311},[649,4413,4414],{"class":655}," Record",[649,4416,4417],{"class":2040},"\u003C",[649,4419,4420],{"class":2044},"string",[649,4422,482],{"class":2040},[649,4424,4425],{"class":2044},"unknown",[649,4427,4428],{"class":2040},">;\n",[649,4430,4431],{"class":651,"line":3801},[649,4432,4109],{"emptyLinePlaceholder":4108},[649,4434,4435],{"class":651,"line":3807},[649,4436,4437],{"class":4375},"\u002F** The fields of a search response the connector reads: the items, and the number of matches. *\u002F\n",[649,4439,4440,4443,4446],{"class":651,"line":3820},[649,4441,4442],{"class":4311},"interface",[649,4444,4445],{"class":655}," SearchResponse",[649,4447,4448],{"class":2040}," {\n",[649,4450,4451,4454,4456,4458,4460,4462,4464],{"class":651,"line":3833},[649,4452,4453],{"class":4311},"    data:",[649,4455,4414],{"class":655},[649,4457,4417],{"class":2040},[649,4459,4420],{"class":2044},[649,4461,482],{"class":2040},[649,4463,4322],{"class":655},[649,4465,4466],{"class":2040},">[];\n",[649,4468,4469,4472,4474,4477,4480],{"class":651,"line":3846},[649,4470,4471],{"class":4311},"    pagination:",[649,4473,4318],{"class":2040},[649,4475,4476],{"class":4311},"total:",[649,4478,4479],{"class":2044}," number",[649,4481,4482],{"class":2040}," };\n",[649,4484,4485],{"class":651,"line":3859},[649,4486,2027],{"class":2040},[649,4488,4489],{"class":651,"line":3870},[649,4490,4109],{"emptyLinePlaceholder":4108},[649,4492,4493],{"class":651,"line":3876},[649,4494,4495],{"class":4375},"\u002F** Converts a camelCase field name to the API's snake_case name, such as `artistId` to `artist_id`. *\u002F\n",[649,4497,4498,4500,4503,4506,4509,4512,4515,4518,4520,4522],{"class":651,"line":3882},[649,4499,4404],{"class":4311},[649,4501,4502],{"class":4311}," function",[649,4504,4505],{"class":655}," apiFieldName",[649,4507,4508],{"class":2040},"(",[649,4510,4511],{"class":4311},"name:",[649,4513,4514],{"class":2044}," string",[649,4516,4517],{"class":2040},")",[649,4519,2634],{"class":4311},[649,4521,4514],{"class":2044},[649,4523,4448],{"class":2040},[649,4525,4526,4529,4532,4534,4537,4539,4542,4545,4547,4550,4553,4556,4559,4562,4565,4567,4569,4572,4575,4578],{"class":651,"line":3894},[649,4527,4528],{"class":4311},"    return",[649,4530,4531],{"class":4321}," name",[649,4533,511],{"class":2040},[649,4535,4536],{"class":655},"replaceAll",[649,4538,4508],{"class":2040},[649,4540,4541],{"class":659},"\u002F",[649,4543,4544],{"class":655},"[A-Z]",[649,4546,4541],{"class":659},[649,4548,4549],{"class":4311},"gu",[649,4551,4552],{"class":2040},", (",[649,4554,4555],{"class":4311},"letter",[649,4557,4558],{"class":2040},") ",[649,4560,4561],{"class":4311},"=>",[649,4563,4564],{"class":659}," `_${",[649,4566,4555],{"class":4321},[649,4568,511],{"class":659},[649,4570,4571],{"class":655},"toLowerCase",[649,4573,4574],{"class":659},"()",[649,4576,4577],{"class":659},"}`",[649,4579,4580],{"class":2040},");\n",[649,4582,4583],{"class":651,"line":3907},[649,4584,2027],{"class":2040},[649,4586,4587],{"class":651,"line":3919},[649,4588,4109],{"emptyLinePlaceholder":4108},[649,4590,4591],{"class":651,"line":3929},[649,4592,4593],{"class":4375},"\u002F** Sends one search request. *\u002F\n",[649,4595,4596,4598,4601,4603,4606,4608,4611,4613,4615,4618,4620,4622,4624,4627,4629,4632],{"class":651,"line":4204},[649,4597,4404],{"class":4311},[649,4599,4600],{"class":4311}," async",[649,4602,4502],{"class":4311},[649,4604,4605],{"class":655}," search",[649,4607,4508],{"class":2040},[649,4609,4610],{"class":4311},"collection:",[649,4612,4514],{"class":2044},[649,4614,482],{"class":2040},[649,4616,4617],{"class":4311},"body:",[649,4619,4409],{"class":655},[649,4621,4517],{"class":2040},[649,4623,2634],{"class":4311},[649,4625,4626],{"class":655}," Promise",[649,4628,4417],{"class":2040},[649,4630,4631],{"class":655},"SearchResponse",[649,4633,4634],{"class":2040},"> {\n",[649,4636,4637,4640,4643,4645,4648],{"class":651,"line":4209},[649,4638,4639],{"class":4311},"    let",[649,4641,4642],{"class":4321}," response",[649,4644,2634],{"class":4311},[649,4646,4647],{"class":655}," Response",[649,4649,4334],{"class":2040},[649,4651,4652],{"class":651,"line":4215},[649,4653,4109],{"emptyLinePlaceholder":4108},[649,4655,4656,4659],{"class":651,"line":4221},[649,4657,4658],{"class":4311},"    try",[649,4660,4448],{"class":2040},[649,4662,4663,4666,4668,4671,4674,4676,4679,4682,4685,4688,4691],{"class":651,"line":4227},[649,4664,4665],{"class":4321},"        response",[649,4667,4365],{"class":4311},[649,4669,4670],{"class":4311}," await",[649,4672,4673],{"class":655}," fetch",[649,4675,4508],{"class":2040},[649,4677,4678],{"class":659},"`${",[649,4680,4681],{"class":655},"BASE_URL",[649,4683,4684],{"class":659},"}\u002F${",[649,4686,4687],{"class":4321},"collection",[649,4689,4690],{"class":659},"}\u002Fsearch`",[649,4692,4693],{"class":2040},", {\n",[649,4695,4696,4699,4702],{"class":651,"line":4233},[649,4697,4698],{"class":2040},"            method: ",[649,4700,4701],{"class":659},"'POST'",[649,4703,3727],{"class":2040},[649,4705,4706,4709,4712,4714,4717,4719,4722,4724,4727],{"class":651,"line":4238},[649,4707,4708],{"class":2040},"            headers: { ",[649,4710,4711],{"class":659},"'Content-Type'",[649,4713,1729],{"class":2040},[649,4715,4716],{"class":659},"'application\u002Fjson'",[649,4718,482],{"class":2040},[649,4720,4721],{"class":659},"'AIC-User-Agent'",[649,4723,1729],{"class":2040},[649,4725,4726],{"class":659},"'monospace-artic-connector'",[649,4728,4729],{"class":2040}," },\n",[649,4731,4732,4735,4738,4740,4743,4745,4748],{"class":651,"line":4244},[649,4733,4734],{"class":2040},"            body: ",[649,4736,4737],{"class":655},"JSON",[649,4739,511],{"class":2040},[649,4741,4742],{"class":655},"stringify",[649,4744,4508],{"class":2040},[649,4746,4747],{"class":4321},"body",[649,4749,4750],{"class":2040},"),\n",[649,4752,4753,4756,4759,4761,4764,4766,4769],{"class":651,"line":4249},[649,4754,4755],{"class":2040},"            signal: ",[649,4757,4758],{"class":4321},"AbortSignal",[649,4760,511],{"class":2040},[649,4762,4763],{"class":655},"timeout",[649,4765,4508],{"class":2040},[649,4767,4768],{"class":655},"TIMEOUT_MS",[649,4770,4750],{"class":2040},[649,4772,4773],{"class":651,"line":4255},[649,4774,4775],{"class":2040},"        });\n",[649,4777,4778],{"class":651,"line":4261},[649,4779,4086],{"class":2040},[649,4781,4782,4785,4787,4790],{"class":651,"line":4267},[649,4783,4784],{"class":4311},"    catch",[649,4786,1242],{"class":2040},[649,4788,4789],{"class":4321},"error",[649,4791,4792],{"class":2040},") {\n",[649,4794,4795],{"class":651,"line":4272},[649,4796,4797],{"class":4375},"        \u002F\u002F Keep the original error as the `cause`. If the data source's permissions blocked the request,\n",[649,4799,4800],{"class":651,"line":4278},[649,4801,4802],{"class":4375},"        \u002F\u002F Monospace finds the blocked request in the `cause` and reports a permission error, not a failed connection.\n",[649,4804,4805,4808,4811,4814,4816,4819,4822,4824],{"class":651,"line":4283},[649,4806,4807],{"class":4311},"        throw",[649,4809,4810],{"class":4311}," new",[649,4812,4813],{"class":655}," ConnectionFailed",[649,4815,4508],{"class":2040},[649,4817,4818],{"class":659},"'The Art Institute API did not answer.'",[649,4820,4821],{"class":2040},", { cause: ",[649,4823,4789],{"class":4321},[649,4825,4826],{"class":2040}," });\n",[649,4828,4829],{"class":651,"line":4289},[649,4830,4086],{"class":2040},[649,4832,4833],{"class":651,"line":4295},[649,4834,4109],{"emptyLinePlaceholder":4108},[649,4836,4838],{"class":651,"line":4837},40,[649,4839,4840],{"class":4375},"    \u002F\u002F For a failed HTTP status, throw a plain `Error`, which Monospace reports as a failed query.\n",[649,4842,4844,4847,4849,4852,4855,4857,4860,4862,4865,4867,4870,4872,4875,4877,4879,4882,4885],{"class":651,"line":4843},41,[649,4845,4846],{"class":4311},"    if",[649,4848,1242],{"class":2040},[649,4850,4851],{"class":4311},"!",[649,4853,4854],{"class":4321},"response",[649,4856,511],{"class":2040},[649,4858,4859],{"class":4321},"ok",[649,4861,4558],{"class":2040},[649,4863,4864],{"class":4311},"throw",[649,4866,4810],{"class":4311},[649,4868,4869],{"class":655}," Error",[649,4871,4508],{"class":2040},[649,4873,4874],{"class":659},"`The Art Institute API answered HTTP ${",[649,4876,4854],{"class":4321},[649,4878,511],{"class":659},[649,4880,4881],{"class":4321},"status",[649,4883,4884],{"class":659},"}.`",[649,4886,4580],{"class":2040},[649,4888,4890],{"class":651,"line":4889},42,[649,4891,4109],{"emptyLinePlaceholder":4108},[649,4893,4895,4897,4899,4902,4904,4906,4908,4911,4914,4916],{"class":651,"line":4894},43,[649,4896,4528],{"class":4311},[649,4898,1242],{"class":2040},[649,4900,4901],{"class":4311},"await",[649,4903,4642],{"class":4321},[649,4905,511],{"class":2040},[649,4907,2033],{"class":655},[649,4909,4910],{"class":2040},"()) ",[649,4912,4913],{"class":4311},"as",[649,4915,4445],{"class":655},[649,4917,4334],{"class":2040},[649,4919,4921],{"class":651,"line":4920},44,[649,4922,2027],{"class":2040},[639,4924,4926],{"className":4301,"code":4925,"filename":3121,"language":4304,"meta":645,"style":645},"import type { FilterSerialized } from '@monospace\u002Fextension-kit\u002Fdata-connector';\nimport { QueryRejected } from '@monospace\u002Fextension-kit\u002Fdata-connector';\nimport type { SearchBody } from '.\u002Fapi';\nimport { apiFieldName } from '.\u002Fapi';\n\n\u002F**\n * Translates a filter into an Elasticsearch query. Callers can send only what `schema.ts` declares,\n * but Monospace also joins a role's permission rules with `or`, so `or` is translated too. Any other\n * filter is rejected, never skipped: skipping part of a filter returns items the filter excludes.\n *\u002F\nexport function toQuery(filter: FilterSerialized): SearchBody {\n    if (filter.and !== undefined) {\n        return { bool: { filter: filter.and.map((child) => toQuery(child)) } };\n    }\n\n    if (filter.or !== undefined) {\n        return { bool: { should: filter.or.map((child) => toQuery(child)), minimum_should_match: 1 } };\n    }\n\n    if (filter.in?.field !== undefined && Array.isArray(filter.values)) {\n        \u002F\u002F The search API rejects `null` in `terms`, and `terms` never matches a missing value. So `null`\n        \u002F\u002F members are left out, and `in` never matches an item without a value.\n        return { terms: { [apiFieldName(filter.in.field)]: filter.values.filter((value) => value !== null) } };\n    }\n\n    if (filter.cmp === 'equals' && filter.left.field !== undefined && filter.right.value !== undefined) {\n        const name = apiFieldName(filter.left.field);\n        \u002F\u002F `field = null` means \"is null\": the search API's `exists` is false for a field without a value.\n        if (filter.right.value === null) return { bool: { must_not: { exists: { field: name } } } };\n        return { term: { [name]: filter.right.value } };\n    }\n\n    throw new QueryRejected('The Art Institute connector answers only `equals` and `in`, joined with `and` or `or`.');\n}\n",[484,4927,4928,4947,4963,4983,4999,5003,5008,5013,5018,5023,5028,5053,5074,5112,5116,5120,5138,5178,5182,5186,5231,5236,5241,5295,5299,5303,5359,5384,5389,5424,5448,5452,5456,5473],{"__ignoreMap":645},[649,4929,4930,4932,4934,4936,4939,4941,4943,4945],{"class":651,"line":652},[649,4931,4312],{"class":4311},[649,4933,4315],{"class":4311},[649,4935,4318],{"class":2040},[649,4937,4938],{"class":4321},"FilterSerialized",[649,4940,4325],{"class":2040},[649,4942,4328],{"class":4311},[649,4944,4331],{"class":659},[649,4946,4334],{"class":2040},[649,4948,4949,4951,4953,4955,4957,4959,4961],{"class":651,"line":1793},[649,4950,4312],{"class":4311},[649,4952,4318],{"class":2040},[649,4954,1677],{"class":4321},[649,4956,4325],{"class":2040},[649,4958,4328],{"class":4311},[649,4960,4331],{"class":659},[649,4962,4334],{"class":2040},[649,4964,4965,4967,4969,4971,4974,4976,4978,4981],{"class":651,"line":2000},[649,4966,4312],{"class":4311},[649,4968,4315],{"class":4311},[649,4970,4318],{"class":2040},[649,4972,4973],{"class":4321},"SearchBody",[649,4975,4325],{"class":2040},[649,4977,4328],{"class":4311},[649,4979,4980],{"class":659}," '.\u002Fapi'",[649,4982,4334],{"class":2040},[649,4984,4985,4987,4989,4991,4993,4995,4997],{"class":651,"line":2006},[649,4986,4312],{"class":4311},[649,4988,4318],{"class":2040},[649,4990,1754],{"class":4321},[649,4992,4325],{"class":2040},[649,4994,4328],{"class":4311},[649,4996,4980],{"class":659},[649,4998,4334],{"class":2040},[649,5000,5001],{"class":651,"line":2012},[649,5002,4109],{"emptyLinePlaceholder":4108},[649,5004,5005],{"class":651,"line":2018},[649,5006,5007],{"class":4375},"\u002F**\n",[649,5009,5010],{"class":651,"line":2024},[649,5011,5012],{"class":4375}," * Translates a filter into an Elasticsearch query. Callers can send only what `schema.ts` declares,\n",[649,5014,5015],{"class":651,"line":2397},[649,5016,5017],{"class":4375}," * but Monospace also joins a role's permission rules with `or`, so `or` is translated too. Any other\n",[649,5019,5020],{"class":651,"line":3795},[649,5021,5022],{"class":4375}," * filter is rejected, never skipped: skipping part of a filter returns items the filter excludes.\n",[649,5024,5025],{"class":651,"line":3801},[649,5026,5027],{"class":4375}," *\u002F\n",[649,5029,5030,5032,5034,5037,5039,5042,5045,5047,5049,5051],{"class":651,"line":3807},[649,5031,4404],{"class":4311},[649,5033,4502],{"class":4311},[649,5035,5036],{"class":655}," toQuery",[649,5038,4508],{"class":2040},[649,5040,5041],{"class":4311},"filter:",[649,5043,5044],{"class":655}," FilterSerialized",[649,5046,4517],{"class":2040},[649,5048,2634],{"class":4311},[649,5050,4409],{"class":655},[649,5052,4448],{"class":2040},[649,5054,5055,5057,5059,5062,5064,5066,5069,5072],{"class":651,"line":3820},[649,5056,4846],{"class":4311},[649,5058,1242],{"class":2040},[649,5060,5061],{"class":4321},"filter",[649,5063,511],{"class":2040},[649,5065,2160],{"class":4321},[649,5067,5068],{"class":4311}," !==",[649,5070,5071],{"class":655}," undefined",[649,5073,4792],{"class":2040},[649,5075,5076,5079,5082,5084,5086,5088,5090,5093,5096,5099,5101,5103,5105,5107,5109],{"class":651,"line":3833},[649,5077,5078],{"class":4311},"        return",[649,5080,5081],{"class":2040}," { bool: { filter: ",[649,5083,5061],{"class":4321},[649,5085,511],{"class":2040},[649,5087,2160],{"class":4321},[649,5089,511],{"class":2040},[649,5091,5092],{"class":655},"map",[649,5094,5095],{"class":2040},"((",[649,5097,5098],{"class":4311},"child",[649,5100,4558],{"class":2040},[649,5102,4561],{"class":4311},[649,5104,5036],{"class":655},[649,5106,4508],{"class":2040},[649,5108,5098],{"class":4321},[649,5110,5111],{"class":2040},")) } };\n",[649,5113,5114],{"class":651,"line":3846},[649,5115,4086],{"class":2040},[649,5117,5118],{"class":651,"line":3859},[649,5119,4109],{"emptyLinePlaceholder":4108},[649,5121,5122,5124,5126,5128,5130,5132,5134,5136],{"class":651,"line":3870},[649,5123,4846],{"class":4311},[649,5125,1242],{"class":2040},[649,5127,5061],{"class":4321},[649,5129,511],{"class":2040},[649,5131,2268],{"class":4321},[649,5133,5068],{"class":4311},[649,5135,5071],{"class":655},[649,5137,4792],{"class":2040},[649,5139,5140,5142,5145,5147,5149,5151,5153,5155,5157,5159,5161,5163,5165,5167,5169,5172,5175],{"class":651,"line":3876},[649,5141,5078],{"class":4311},[649,5143,5144],{"class":2040}," { bool: { should: ",[649,5146,5061],{"class":4321},[649,5148,511],{"class":2040},[649,5150,2268],{"class":4321},[649,5152,511],{"class":2040},[649,5154,5092],{"class":655},[649,5156,5095],{"class":2040},[649,5158,5098],{"class":4311},[649,5160,4558],{"class":2040},[649,5162,4561],{"class":4311},[649,5164,5036],{"class":655},[649,5166,4508],{"class":2040},[649,5168,5098],{"class":4321},[649,5170,5171],{"class":2040},")), minimum_should_match: ",[649,5173,5174],{"class":655},"1",[649,5176,5177],{"class":2040}," } };\n",[649,5179,5180],{"class":651,"line":3882},[649,5181,4086],{"class":2040},[649,5183,5184],{"class":651,"line":3894},[649,5185,4109],{"emptyLinePlaceholder":4108},[649,5187,5188,5190,5192,5194,5196,5198,5201,5204,5206,5208,5211,5214,5216,5219,5221,5223,5225,5228],{"class":651,"line":3907},[649,5189,4846],{"class":4311},[649,5191,1242],{"class":2040},[649,5193,5061],{"class":4321},[649,5195,511],{"class":2040},[649,5197,2151],{"class":4321},[649,5199,5200],{"class":2040},"?.",[649,5202,5203],{"class":4321},"field",[649,5205,5068],{"class":4311},[649,5207,5071],{"class":655},[649,5209,5210],{"class":4311}," &&",[649,5212,5213],{"class":4321}," Array",[649,5215,511],{"class":2040},[649,5217,5218],{"class":655},"isArray",[649,5220,4508],{"class":2040},[649,5222,5061],{"class":4321},[649,5224,511],{"class":2040},[649,5226,5227],{"class":4321},"values",[649,5229,5230],{"class":2040},")) {\n",[649,5232,5233],{"class":651,"line":3919},[649,5234,5235],{"class":4375},"        \u002F\u002F The search API rejects `null` in `terms`, and `terms` never matches a missing value. So `null`\n",[649,5237,5238],{"class":651,"line":3929},[649,5239,5240],{"class":4375},"        \u002F\u002F members are left out, and `in` never matches an item without a value.\n",[649,5242,5243,5245,5248,5250,5252,5254,5256,5258,5260,5262,5265,5267,5269,5271,5273,5275,5277,5280,5282,5284,5287,5289,5292],{"class":651,"line":4204},[649,5244,5078],{"class":4311},[649,5246,5247],{"class":2040}," { terms: { [",[649,5249,1754],{"class":655},[649,5251,4508],{"class":2040},[649,5253,5061],{"class":4321},[649,5255,511],{"class":2040},[649,5257,2151],{"class":4321},[649,5259,511],{"class":2040},[649,5261,5203],{"class":4321},[649,5263,5264],{"class":2040},")]: ",[649,5266,5061],{"class":4321},[649,5268,511],{"class":2040},[649,5270,5227],{"class":4321},[649,5272,511],{"class":2040},[649,5274,5061],{"class":655},[649,5276,5095],{"class":2040},[649,5278,5279],{"class":4311},"value",[649,5281,4558],{"class":2040},[649,5283,4561],{"class":4311},[649,5285,5286],{"class":4321}," value",[649,5288,5068],{"class":4311},[649,5290,5291],{"class":655}," null",[649,5293,5294],{"class":2040},") } };\n",[649,5296,5297],{"class":651,"line":4209},[649,5298,4086],{"class":2040},[649,5300,5301],{"class":651,"line":4215},[649,5302,4109],{"emptyLinePlaceholder":4108},[649,5304,5305,5307,5309,5311,5313,5316,5319,5322,5324,5327,5329,5332,5334,5336,5338,5340,5342,5344,5346,5349,5351,5353,5355,5357],{"class":651,"line":4221},[649,5306,4846],{"class":4311},[649,5308,1242],{"class":2040},[649,5310,5061],{"class":4321},[649,5312,511],{"class":2040},[649,5314,5315],{"class":4321},"cmp",[649,5317,5318],{"class":4311}," ===",[649,5320,5321],{"class":659}," 'equals'",[649,5323,5210],{"class":4311},[649,5325,5326],{"class":4321}," filter",[649,5328,511],{"class":2040},[649,5330,5331],{"class":4321},"left",[649,5333,511],{"class":2040},[649,5335,5203],{"class":4321},[649,5337,5068],{"class":4311},[649,5339,5071],{"class":655},[649,5341,5210],{"class":4311},[649,5343,5326],{"class":4321},[649,5345,511],{"class":2040},[649,5347,5348],{"class":4321},"right",[649,5350,511],{"class":2040},[649,5352,5279],{"class":4321},[649,5354,5068],{"class":4311},[649,5356,5071],{"class":655},[649,5358,4792],{"class":2040},[649,5360,5361,5364,5366,5368,5370,5372,5374,5376,5378,5380,5382],{"class":651,"line":4227},[649,5362,5363],{"class":4311},"        const",[649,5365,4531],{"class":655},[649,5367,4365],{"class":4311},[649,5369,4505],{"class":655},[649,5371,4508],{"class":2040},[649,5373,5061],{"class":4321},[649,5375,511],{"class":2040},[649,5377,5331],{"class":4321},[649,5379,511],{"class":2040},[649,5381,5203],{"class":4321},[649,5383,4580],{"class":2040},[649,5385,5386],{"class":651,"line":4233},[649,5387,5388],{"class":4375},"        \u002F\u002F `field = null` means \"is null\": the search API's `exists` is false for a field without a value.\n",[649,5390,5391,5394,5396,5398,5400,5402,5404,5406,5408,5410,5412,5415,5418,5421],{"class":651,"line":4238},[649,5392,5393],{"class":4311},"        if",[649,5395,1242],{"class":2040},[649,5397,5061],{"class":4321},[649,5399,511],{"class":2040},[649,5401,5348],{"class":4321},[649,5403,511],{"class":2040},[649,5405,5279],{"class":4321},[649,5407,5318],{"class":4311},[649,5409,5291],{"class":655},[649,5411,4558],{"class":2040},[649,5413,5414],{"class":4311},"return",[649,5416,5417],{"class":2040}," { bool: { must_not: { exists: { field: ",[649,5419,5420],{"class":4321},"name",[649,5422,5423],{"class":2040}," } } } };\n",[649,5425,5426,5428,5431,5433,5436,5438,5440,5442,5444,5446],{"class":651,"line":4244},[649,5427,5078],{"class":4311},[649,5429,5430],{"class":2040}," { term: { [",[649,5432,5420],{"class":4321},[649,5434,5435],{"class":2040},"]: ",[649,5437,5061],{"class":4321},[649,5439,511],{"class":2040},[649,5441,5348],{"class":4321},[649,5443,511],{"class":2040},[649,5445,5279],{"class":4321},[649,5447,5177],{"class":2040},[649,5449,5450],{"class":651,"line":4249},[649,5451,4086],{"class":2040},[649,5453,5454],{"class":651,"line":4255},[649,5455,4109],{"emptyLinePlaceholder":4108},[649,5457,5458,5461,5463,5466,5468,5471],{"class":651,"line":4261},[649,5459,5460],{"class":4311},"    throw",[649,5462,4810],{"class":4311},[649,5464,5465],{"class":655}," QueryRejected",[649,5467,4508],{"class":2040},[649,5469,5470],{"class":659},"'The Art Institute connector answers only `equals` and `in`, joined with `and` or `or`.'",[649,5472,4580],{"class":2040},[649,5474,5475],{"class":651,"line":4267},[649,5476,2027],{"class":2040},[639,5478,5480],{"className":4301,"code":5479,"filename":1665,"language":4304,"meta":645,"style":645},"import { defineDataConnector } from '@monospace\u002Fextension-kit\u002Fdata-connector';\nimport { search } from '.\u002Fapi';\nimport { readMany, readOne } from '.\u002Fread';\nimport { schema } from '.\u002Fschema';\n\nconst COLLECTIONS = new Set\u003Cstring>(schema.collections.map((collection) => collection.name));\n\nexport default defineDataConnector({\n    setup() {\n        return {\n            introspect() {\n                return schema.toSchemaDocument();\n            },\n\n            async query({ query }) {\n                \u002F\u002F Monospace sends only declared collections, and this connector declares no namespaces.\n                \u002F\u002F For any other collection, throw a plain `Error`.\n                if (query.namespace !== undefined || !COLLECTIONS.has(query.collection)) {\n                    throw new Error(`Unknown collection \\`${query.collection}\\`.`);\n                }\n\n                switch (query.op) {\n                    case 'readMany':\n                        return await readMany(query);\n                    case 'readOne':\n                        return await readOne(query);\n                    default:\n                        \u002F\u002F The schema declares no writes, so Monospace offers callers none.\n                        throw new Error('The Art Institute of Chicago API is read-only.');\n                }\n            },\n\n            async testConnection() {\n                await search('artworks', { size: 0 });\n                return { ok: true };\n            },\n        };\n    },\n});\n",[484,5481,5482,5498,5514,5535,5553,5557,5605,5609,5622,5630,5636,5643,5659,5663,5667,5683,5688,5693,5735,5771,5776,5780,5796,5807,5823,5832,5847,5854,5859,5875,5879,5883,5887,5896,5916,5927,5931,5936,5940],{"__ignoreMap":645},[649,5483,5484,5486,5488,5490,5492,5494,5496],{"class":651,"line":652},[649,5485,4312],{"class":4311},[649,5487,4318],{"class":2040},[649,5489,829],{"class":4321},[649,5491,4325],{"class":2040},[649,5493,4328],{"class":4311},[649,5495,4331],{"class":659},[649,5497,4334],{"class":2040},[649,5499,5500,5502,5504,5506,5508,5510,5512],{"class":651,"line":1793},[649,5501,4312],{"class":4311},[649,5503,4318],{"class":2040},[649,5505,1714],{"class":4321},[649,5507,4325],{"class":2040},[649,5509,4328],{"class":4311},[649,5511,4980],{"class":659},[649,5513,4334],{"class":2040},[649,5515,5516,5518,5520,5522,5524,5526,5528,5530,5533],{"class":651,"line":2000},[649,5517,4312],{"class":4311},[649,5519,4318],{"class":2040},[649,5521,892],{"class":4321},[649,5523,482],{"class":2040},[649,5525,2691],{"class":4321},[649,5527,4325],{"class":2040},[649,5529,4328],{"class":4311},[649,5531,5532],{"class":659}," '.\u002Fread'",[649,5534,4334],{"class":2040},[649,5536,5537,5539,5541,5544,5546,5548,5551],{"class":651,"line":2006},[649,5538,4312],{"class":4311},[649,5540,4318],{"class":2040},[649,5542,5543],{"class":4321},"schema",[649,5545,4325],{"class":2040},[649,5547,4328],{"class":4311},[649,5549,5550],{"class":659}," '.\u002Fschema'",[649,5552,4334],{"class":2040},[649,5554,5555],{"class":651,"line":2012},[649,5556,4109],{"emptyLinePlaceholder":4108},[649,5558,5559,5561,5564,5566,5568,5571,5573,5575,5578,5580,5582,5584,5586,5588,5590,5592,5594,5596,5598,5600,5602],{"class":651,"line":2018},[649,5560,4359],{"class":4311},[649,5562,5563],{"class":655}," COLLECTIONS",[649,5565,4365],{"class":4311},[649,5567,4810],{"class":4311},[649,5569,5570],{"class":655}," Set",[649,5572,4417],{"class":2040},[649,5574,4420],{"class":2044},[649,5576,5577],{"class":2040},">(",[649,5579,5543],{"class":4321},[649,5581,511],{"class":2040},[649,5583,481],{"class":4321},[649,5585,511],{"class":2040},[649,5587,5092],{"class":655},[649,5589,5095],{"class":2040},[649,5591,4687],{"class":4311},[649,5593,4558],{"class":2040},[649,5595,4561],{"class":4311},[649,5597,2856],{"class":4321},[649,5599,511],{"class":2040},[649,5601,5420],{"class":4321},[649,5603,5604],{"class":2040},"));\n",[649,5606,5607],{"class":651,"line":2024},[649,5608,4109],{"emptyLinePlaceholder":4108},[649,5610,5611,5613,5616,5619],{"class":651,"line":2397},[649,5612,4404],{"class":4311},[649,5614,5615],{"class":4311}," default",[649,5617,5618],{"class":655}," defineDataConnector",[649,5620,5621],{"class":2040},"({\n",[649,5623,5624,5627],{"class":651,"line":3795},[649,5625,5626],{"class":655},"    setup",[649,5628,5629],{"class":2040},"() {\n",[649,5631,5632,5634],{"class":651,"line":3801},[649,5633,5078],{"class":4311},[649,5635,4448],{"class":2040},[649,5637,5638,5641],{"class":651,"line":3807},[649,5639,5640],{"class":655},"            introspect",[649,5642,5629],{"class":2040},[649,5644,5645,5648,5651,5653,5656],{"class":651,"line":3820},[649,5646,5647],{"class":4311},"                return",[649,5649,5650],{"class":4321}," schema",[649,5652,511],{"class":2040},[649,5654,5655],{"class":655},"toSchemaDocument",[649,5657,5658],{"class":2040},"();\n",[649,5660,5661],{"class":651,"line":3833},[649,5662,3804],{"class":2040},[649,5664,5665],{"class":651,"line":3846},[649,5666,4109],{"emptyLinePlaceholder":4108},[649,5668,5669,5672,5675,5678,5680],{"class":651,"line":3859},[649,5670,5671],{"class":4311},"            async",[649,5673,5674],{"class":655}," query",[649,5676,5677],{"class":2040},"({ ",[649,5679,861],{"class":4311},[649,5681,5682],{"class":2040}," }) {\n",[649,5684,5685],{"class":651,"line":3870},[649,5686,5687],{"class":4375},"                \u002F\u002F Monospace sends only declared collections, and this connector declares no namespaces.\n",[649,5689,5690],{"class":651,"line":3876},[649,5691,5692],{"class":4375},"                \u002F\u002F For any other collection, throw a plain `Error`.\n",[649,5694,5695,5698,5700,5702,5704,5707,5709,5711,5714,5717,5720,5722,5725,5727,5729,5731,5733],{"class":651,"line":3882},[649,5696,5697],{"class":4311},"                if",[649,5699,1242],{"class":2040},[649,5701,861],{"class":4321},[649,5703,511],{"class":2040},[649,5705,5706],{"class":4321},"namespace",[649,5708,5068],{"class":4311},[649,5710,5071],{"class":655},[649,5712,5713],{"class":4311}," ||",[649,5715,5716],{"class":4311}," !",[649,5718,5719],{"class":655},"COLLECTIONS",[649,5721,511],{"class":2040},[649,5723,5724],{"class":655},"has",[649,5726,4508],{"class":2040},[649,5728,861],{"class":4321},[649,5730,511],{"class":2040},[649,5732,4687],{"class":4321},[649,5734,5230],{"class":2040},[649,5736,5737,5740,5742,5744,5746,5749,5752,5755,5757,5759,5761,5764,5766,5769],{"class":651,"line":3894},[649,5738,5739],{"class":4311},"                    throw",[649,5741,4810],{"class":4311},[649,5743,4869],{"class":655},[649,5745,4508],{"class":2040},[649,5747,5748],{"class":659},"`Unknown collection ",[649,5750,5751],{"class":655},"\\`",[649,5753,5754],{"class":659},"${",[649,5756,861],{"class":4321},[649,5758,511],{"class":659},[649,5760,4687],{"class":4321},[649,5762,5763],{"class":659},"}",[649,5765,5751],{"class":655},[649,5767,5768],{"class":659},".`",[649,5770,4580],{"class":2040},[649,5772,5773],{"class":651,"line":3907},[649,5774,5775],{"class":2040},"                }\n",[649,5777,5778],{"class":651,"line":3919},[649,5779,4109],{"emptyLinePlaceholder":4108},[649,5781,5782,5785,5787,5789,5791,5794],{"class":651,"line":3929},[649,5783,5784],{"class":4311},"                switch",[649,5786,1242],{"class":2040},[649,5788,861],{"class":4321},[649,5790,511],{"class":2040},[649,5792,5793],{"class":4321},"op",[649,5795,4792],{"class":2040},[649,5797,5798,5801,5804],{"class":651,"line":4204},[649,5799,5800],{"class":4311},"                    case",[649,5802,5803],{"class":659}," 'readMany'",[649,5805,5806],{"class":2040},":\n",[649,5808,5809,5812,5814,5817,5819,5821],{"class":651,"line":4209},[649,5810,5811],{"class":4311},"                        return",[649,5813,4670],{"class":4311},[649,5815,5816],{"class":655}," readMany",[649,5818,4508],{"class":2040},[649,5820,861],{"class":4321},[649,5822,4580],{"class":2040},[649,5824,5825,5827,5830],{"class":651,"line":4215},[649,5826,5800],{"class":4311},[649,5828,5829],{"class":659}," 'readOne'",[649,5831,5806],{"class":2040},[649,5833,5834,5836,5838,5841,5843,5845],{"class":651,"line":4221},[649,5835,5811],{"class":4311},[649,5837,4670],{"class":4311},[649,5839,5840],{"class":655}," readOne",[649,5842,4508],{"class":2040},[649,5844,861],{"class":4321},[649,5846,4580],{"class":2040},[649,5848,5849,5852],{"class":651,"line":4227},[649,5850,5851],{"class":4311},"                    default",[649,5853,5806],{"class":2040},[649,5855,5856],{"class":651,"line":4233},[649,5857,5858],{"class":4375},"                        \u002F\u002F The schema declares no writes, so Monospace offers callers none.\n",[649,5860,5861,5864,5866,5868,5870,5873],{"class":651,"line":4238},[649,5862,5863],{"class":4311},"                        throw",[649,5865,4810],{"class":4311},[649,5867,4869],{"class":655},[649,5869,4508],{"class":2040},[649,5871,5872],{"class":659},"'The Art Institute of Chicago API is read-only.'",[649,5874,4580],{"class":2040},[649,5876,5877],{"class":651,"line":4244},[649,5878,5775],{"class":2040},[649,5880,5881],{"class":651,"line":4249},[649,5882,3804],{"class":2040},[649,5884,5885],{"class":651,"line":4255},[649,5886,4109],{"emptyLinePlaceholder":4108},[649,5888,5889,5891,5894],{"class":651,"line":4261},[649,5890,5671],{"class":4311},[649,5892,5893],{"class":655}," testConnection",[649,5895,5629],{"class":2040},[649,5897,5898,5901,5903,5905,5908,5911,5914],{"class":651,"line":4267},[649,5899,5900],{"class":4311},"                await",[649,5902,4605],{"class":655},[649,5904,4508],{"class":2040},[649,5906,5907],{"class":659},"'artworks'",[649,5909,5910],{"class":2040},", { size: ",[649,5912,5913],{"class":655},"0",[649,5915,4826],{"class":2040},[649,5917,5918,5920,5923,5925],{"class":651,"line":4272},[649,5919,5647],{"class":4311},[649,5921,5922],{"class":2040}," { ok: ",[649,5924,3622],{"class":655},[649,5926,4482],{"class":2040},[649,5928,5929],{"class":651,"line":4278},[649,5930,3804],{"class":2040},[649,5932,5933],{"class":651,"line":4283},[649,5934,5935],{"class":2040},"        };\n",[649,5937,5938],{"class":651,"line":4289},[649,5939,4019],{"class":2040},[649,5941,5942],{"class":651,"line":4295},[649,5943,5944],{"class":2040},"});\n",[639,5946,5948],{"className":4301,"code":5947,"filename":3108,"language":4304,"meta":645,"style":645},"import type { MonospaceObject, QueryResultFor, QueryResultSerialized, ReadManyOperationSerialized, ReadOneOperationSerialized, SortItemSerialized, Value } from '@monospace\u002Fextension-kit\u002Fdata-connector';\nimport { QueryRejected } from '@monospace\u002Fextension-kit\u002Fdata-connector';\nimport { apiFieldName, search } from '.\u002Fapi';\nimport { toQuery } from '.\u002Ffilter';\n\n\u002F** The search API returns at most 100 items per request. *\u002F\nconst PAGE_SIZE = 100;\n\u002F** The search API rejects any request that reaches past its 1,000th result. *\u002F\nconst SEARCH_WINDOW = 1000;\n\n\u002F** Handles `readMany`, and returns the items in `records`. *\u002F\nexport async function readMany(query: ReadManyOperationSerialized): Promise\u003CQueryResultSerialized> {\n    \u002F\u002F The schema declares no count, so callers can't request one. A count request gets a plain `Error`.\n    if (query.count === true) throw new Error('The Art Institute connector doesn\\'t offer a count.');\n\n    \u002F\u002F Translate the filter and the sort first, so a failed translation sends no request.\n    const base = query.filter === undefined ? {} : { query: toQuery(query.filter) };\n    const sort = toSort(query.sort ?? []);\n    const offset = query.offset ?? 0;\n    let end = query.limit === undefined ? Infinity : offset + query.limit;\n\n    \u002F\u002F A read past the window still succeeds when fewer items match, so count the matches first and\n    \u002F\u002F end the read at the last match.\n    if (end > SEARCH_WINDOW) {\n        const { pagination } = await search(query.collection, { ...base, size: 0 });\n        end = Math.min(end, pagination.total);\n\n        if (end > SEARCH_WINDOW) {\n            \u002F\u002F The caller can narrow this read, so the message says how.\n            throw new QueryRejected(`The Art Institute search API returns only the first ${SEARCH_WINDOW} results. Narrow the filter or read an earlier page.`);\n        }\n    }\n\n    const select = query.select ?? [];\n    const body = { ...base, sort, fields: select.map(apiFieldName) };\n    const records: MonospaceObject[] = [];\n\n    for (let from = offset; from \u003C end; from += PAGE_SIZE) {\n        const size = Math.min(PAGE_SIZE, end - from);\n        const page = await search(query.collection, { ...body, from, size });\n        records.push(...page.data.map((apiItem) => toItem(apiItem, select)));\n        if (page.data.length \u003C size) break;\n    }\n\n    return { records };\n}\n\n\u002F**\n * Handles `readOne` with `readMany`: the key as a filter, any filter the caller adds, and a limit of\n * one item. Returns `record: null` when no item matches, and the caller gets `404`.\n *\u002F\nexport async function readOne(query: ReadOneOperationSerialized): Promise\u003CQueryResultFor\u003C'readOne'>> {\n    \u002F\u002F Monospace sends the key as `{ id }`. An ID that isn't a safe integer matches no item.\n    const { id } = query.key;\n    if (typeof id !== 'number' || !Number.isSafeInteger(id)) return { record: null };\n\n    const key = { cmp: 'equals', left: { field: 'id' }, right: { value: id } } as const;\n    const filter = query.filter === undefined ? key : { and: [key, query.filter] };\n    const { records = [] } = await readMany({ op: 'readMany', collection: query.collection, select: query.select, filter, limit: 1 });\n    return { record: records[0] ?? null };\n}\n\n\u002F**\n * Translates the caller's sort. Only `id` declares a sort, so a sort on any other field gets a plain\n * `Error`. `id` is never null, so `nulls` has no effect. Without a sort, pages still need a stable\n * order, so the default is `id` ascending.\n *\u002F\nfunction toSort(sort: readonly SortItemSerialized[]): { id: { order: 'asc' | 'desc' } }[] {\n    if (sort.length === 0) return [{ id: { order: 'asc' } }];\n\n    return sort.map(({ field, direction }) => {\n        if (field !== 'id') throw new Error(`The Art Institute connector doesn't offer sorting by \\`${field}\\`.`);\n        return { id: { order: direction === 'descending' ? 'desc' : 'asc' } };\n    });\n}\n\n\u002F**\n * Returns exactly the selected fields, with `null` where the API has no value (the API returns `null`\n * or leaves the field out). Monospace checks each value against the field's declared type.\n *\u002F\nfunction toItem(apiItem: Record\u003Cstring, Value>, select: readonly string[]): MonospaceObject {\n    const item: MonospaceObject = {};\n    for (const name of select) item[name] = apiItem[apiFieldName(name)] ?? null;\n    return item;\n}\n",[484,5949,5950,5998,6014,6034,6051,6055,6060,6074,6079,6093,6097,6102,6132,6137,6176,6180,6185,6229,6255,6277,6317,6321,6326,6331,6347,6389,6419,6423,6437,6442,6464,6468,6472,6476,6497,6531,6550,6554,6591,6622,6660,6708,6736,6740,6744,6756,6761,6766,6771,6777,6783,6788,6824,6830,6852,6898,6903,6940,6981,7036,7060,7065,7070,7075,7081,7087,7093,7098,7144,7174,7179,7207,7248,7273,7279,7284,7289,7294,7300,7306,7311,7351,7368,7416,7425],{"__ignoreMap":645},[649,5951,5952,5954,5956,5958,5961,5963,5966,5968,5971,5973,5976,5978,5981,5983,5986,5988,5990,5992,5994,5996],{"class":651,"line":652},[649,5953,4312],{"class":4311},[649,5955,4315],{"class":4311},[649,5957,4318],{"class":2040},[649,5959,5960],{"class":4321},"MonospaceObject",[649,5962,482],{"class":2040},[649,5964,5965],{"class":4321},"QueryResultFor",[649,5967,482],{"class":2040},[649,5969,5970],{"class":4321},"QueryResultSerialized",[649,5972,482],{"class":2040},[649,5974,5975],{"class":4321},"ReadManyOperationSerialized",[649,5977,482],{"class":2040},[649,5979,5980],{"class":4321},"ReadOneOperationSerialized",[649,5982,482],{"class":2040},[649,5984,5985],{"class":4321},"SortItemSerialized",[649,5987,482],{"class":2040},[649,5989,4322],{"class":4321},[649,5991,4325],{"class":2040},[649,5993,4328],{"class":4311},[649,5995,4331],{"class":659},[649,5997,4334],{"class":2040},[649,5999,6000,6002,6004,6006,6008,6010,6012],{"class":651,"line":1793},[649,6001,4312],{"class":4311},[649,6003,4318],{"class":2040},[649,6005,1677],{"class":4321},[649,6007,4325],{"class":2040},[649,6009,4328],{"class":4311},[649,6011,4331],{"class":659},[649,6013,4334],{"class":2040},[649,6015,6016,6018,6020,6022,6024,6026,6028,6030,6032],{"class":651,"line":2000},[649,6017,4312],{"class":4311},[649,6019,4318],{"class":2040},[649,6021,1754],{"class":4321},[649,6023,482],{"class":2040},[649,6025,1714],{"class":4321},[649,6027,4325],{"class":2040},[649,6029,4328],{"class":4311},[649,6031,4980],{"class":659},[649,6033,4334],{"class":2040},[649,6035,6036,6038,6040,6042,6044,6046,6049],{"class":651,"line":2006},[649,6037,4312],{"class":4311},[649,6039,4318],{"class":2040},[649,6041,2179],{"class":4321},[649,6043,4325],{"class":2040},[649,6045,4328],{"class":4311},[649,6047,6048],{"class":659}," '.\u002Ffilter'",[649,6050,4334],{"class":2040},[649,6052,6053],{"class":651,"line":2012},[649,6054,4109],{"emptyLinePlaceholder":4108},[649,6056,6057],{"class":651,"line":2018},[649,6058,6059],{"class":4375},"\u002F** The search API returns at most 100 items per request. *\u002F\n",[649,6061,6062,6064,6067,6069,6072],{"class":651,"line":2024},[649,6063,4359],{"class":4311},[649,6065,6066],{"class":655}," PAGE_SIZE",[649,6068,4365],{"class":4311},[649,6070,6071],{"class":655}," 100",[649,6073,4334],{"class":2040},[649,6075,6076],{"class":651,"line":2397},[649,6077,6078],{"class":4375},"\u002F** The search API rejects any request that reaches past its 1,000th result. *\u002F\n",[649,6080,6081,6083,6086,6088,6091],{"class":651,"line":3795},[649,6082,4359],{"class":4311},[649,6084,6085],{"class":655}," SEARCH_WINDOW",[649,6087,4365],{"class":4311},[649,6089,6090],{"class":655}," 1000",[649,6092,4334],{"class":2040},[649,6094,6095],{"class":651,"line":3801},[649,6096,4109],{"emptyLinePlaceholder":4108},[649,6098,6099],{"class":651,"line":3807},[649,6100,6101],{"class":4375},"\u002F** Handles `readMany`, and returns the items in `records`. *\u002F\n",[649,6103,6104,6106,6108,6110,6112,6114,6117,6120,6122,6124,6126,6128,6130],{"class":651,"line":3820},[649,6105,4404],{"class":4311},[649,6107,4600],{"class":4311},[649,6109,4502],{"class":4311},[649,6111,5816],{"class":655},[649,6113,4508],{"class":2040},[649,6115,6116],{"class":4311},"query:",[649,6118,6119],{"class":655}," ReadManyOperationSerialized",[649,6121,4517],{"class":2040},[649,6123,2634],{"class":4311},[649,6125,4626],{"class":655},[649,6127,4417],{"class":2040},[649,6129,5970],{"class":655},[649,6131,4634],{"class":2040},[649,6133,6134],{"class":651,"line":3833},[649,6135,6136],{"class":4375},"    \u002F\u002F The schema declares no count, so callers can't request one. A count request gets a plain `Error`.\n",[649,6138,6139,6141,6143,6145,6147,6150,6152,6155,6157,6159,6161,6163,6165,6168,6171,6174],{"class":651,"line":3846},[649,6140,4846],{"class":4311},[649,6142,1242],{"class":2040},[649,6144,861],{"class":4321},[649,6146,511],{"class":2040},[649,6148,6149],{"class":4321},"count",[649,6151,5318],{"class":4311},[649,6153,6154],{"class":655}," true",[649,6156,4558],{"class":2040},[649,6158,4864],{"class":4311},[649,6160,4810],{"class":4311},[649,6162,4869],{"class":655},[649,6164,4508],{"class":2040},[649,6166,6167],{"class":659},"'The Art Institute connector doesn",[649,6169,6170],{"class":655},"\\'",[649,6172,6173],{"class":659},"t offer a count.'",[649,6175,4580],{"class":2040},[649,6177,6178],{"class":651,"line":3859},[649,6179,4109],{"emptyLinePlaceholder":4108},[649,6181,6182],{"class":651,"line":3870},[649,6183,6184],{"class":4375},"    \u002F\u002F Translate the filter and the sort first, so a failed translation sends no request.\n",[649,6186,6187,6190,6193,6195,6197,6199,6201,6203,6205,6208,6211,6213,6216,6218,6220,6222,6224,6226],{"class":651,"line":3876},[649,6188,6189],{"class":4311},"    const",[649,6191,6192],{"class":655}," base",[649,6194,4365],{"class":4311},[649,6196,5674],{"class":4321},[649,6198,511],{"class":2040},[649,6200,5061],{"class":4321},[649,6202,5318],{"class":4311},[649,6204,5071],{"class":655},[649,6206,6207],{"class":4311}," ?",[649,6209,6210],{"class":2040}," {} ",[649,6212,2634],{"class":4311},[649,6214,6215],{"class":2040}," { query: ",[649,6217,2179],{"class":655},[649,6219,4508],{"class":2040},[649,6221,861],{"class":4321},[649,6223,511],{"class":2040},[649,6225,5061],{"class":4321},[649,6227,6228],{"class":2040},") };\n",[649,6230,6231,6233,6236,6238,6241,6243,6245,6247,6249,6252],{"class":651,"line":3882},[649,6232,6189],{"class":4311},[649,6234,6235],{"class":655}," sort",[649,6237,4365],{"class":4311},[649,6239,6240],{"class":655}," toSort",[649,6242,4508],{"class":2040},[649,6244,861],{"class":4321},[649,6246,511],{"class":2040},[649,6248,1896],{"class":4321},[649,6250,6251],{"class":4311}," ??",[649,6253,6254],{"class":2040}," []);\n",[649,6256,6257,6259,6262,6264,6266,6268,6270,6272,6275],{"class":651,"line":3894},[649,6258,6189],{"class":4311},[649,6260,6261],{"class":655}," offset",[649,6263,4365],{"class":4311},[649,6265,5674],{"class":4321},[649,6267,511],{"class":2040},[649,6269,1586],{"class":4321},[649,6271,6251],{"class":4311},[649,6273,6274],{"class":655}," 0",[649,6276,4334],{"class":2040},[649,6278,6279,6281,6284,6286,6288,6290,6292,6294,6296,6298,6301,6304,6306,6309,6311,6313,6315],{"class":651,"line":3907},[649,6280,4639],{"class":4311},[649,6282,6283],{"class":4321}," end",[649,6285,4365],{"class":4311},[649,6287,5674],{"class":4321},[649,6289,511],{"class":2040},[649,6291,1583],{"class":4321},[649,6293,5318],{"class":4311},[649,6295,5071],{"class":655},[649,6297,6207],{"class":4311},[649,6299,6300],{"class":655}," Infinity",[649,6302,6303],{"class":4311}," :",[649,6305,6261],{"class":4321},[649,6307,6308],{"class":4311}," +",[649,6310,5674],{"class":4321},[649,6312,511],{"class":2040},[649,6314,1583],{"class":4321},[649,6316,4334],{"class":2040},[649,6318,6319],{"class":651,"line":3919},[649,6320,4109],{"emptyLinePlaceholder":4108},[649,6322,6323],{"class":651,"line":3929},[649,6324,6325],{"class":4375},"    \u002F\u002F A read past the window still succeeds when fewer items match, so count the matches first and\n",[649,6327,6328],{"class":651,"line":4204},[649,6329,6330],{"class":4375},"    \u002F\u002F end the read at the last match.\n",[649,6332,6333,6335,6337,6340,6343,6345],{"class":651,"line":4209},[649,6334,4846],{"class":4311},[649,6336,1242],{"class":2040},[649,6338,6339],{"class":4321},"end",[649,6341,6342],{"class":4311}," >",[649,6344,6085],{"class":655},[649,6346,4792],{"class":2040},[649,6348,6349,6351,6353,6356,6358,6361,6363,6365,6367,6369,6371,6373,6376,6379,6382,6385,6387],{"class":651,"line":4215},[649,6350,5363],{"class":4311},[649,6352,4318],{"class":2040},[649,6354,6355],{"class":655},"pagination",[649,6357,4325],{"class":2040},[649,6359,6360],{"class":4311},"=",[649,6362,4670],{"class":4311},[649,6364,4605],{"class":655},[649,6366,4508],{"class":2040},[649,6368,861],{"class":4321},[649,6370,511],{"class":2040},[649,6372,4687],{"class":4321},[649,6374,6375],{"class":2040},", { ",[649,6377,6378],{"class":4311},"...",[649,6380,6381],{"class":4321},"base",[649,6383,6384],{"class":2040},", size: ",[649,6386,5913],{"class":655},[649,6388,4826],{"class":2040},[649,6390,6391,6394,6396,6399,6401,6404,6406,6408,6410,6412,6414,6417],{"class":651,"line":4221},[649,6392,6393],{"class":4321},"        end",[649,6395,4365],{"class":4311},[649,6397,6398],{"class":4321}," Math",[649,6400,511],{"class":2040},[649,6402,6403],{"class":655},"min",[649,6405,4508],{"class":2040},[649,6407,6339],{"class":4321},[649,6409,482],{"class":2040},[649,6411,6355],{"class":4321},[649,6413,511],{"class":2040},[649,6415,6416],{"class":4321},"total",[649,6418,4580],{"class":2040},[649,6420,6421],{"class":651,"line":4227},[649,6422,4109],{"emptyLinePlaceholder":4108},[649,6424,6425,6427,6429,6431,6433,6435],{"class":651,"line":4233},[649,6426,5393],{"class":4311},[649,6428,1242],{"class":2040},[649,6430,6339],{"class":4321},[649,6432,6342],{"class":4311},[649,6434,6085],{"class":655},[649,6436,4792],{"class":2040},[649,6438,6439],{"class":651,"line":4238},[649,6440,6441],{"class":4375},"            \u002F\u002F The caller can narrow this read, so the message says how.\n",[649,6443,6444,6447,6449,6451,6453,6456,6459,6462],{"class":651,"line":4244},[649,6445,6446],{"class":4311},"            throw",[649,6448,4810],{"class":4311},[649,6450,5465],{"class":655},[649,6452,4508],{"class":2040},[649,6454,6455],{"class":659},"`The Art Institute search API returns only the first ${",[649,6457,6458],{"class":655},"SEARCH_WINDOW",[649,6460,6461],{"class":659},"} results. Narrow the filter or read an earlier page.`",[649,6463,4580],{"class":2040},[649,6465,6466],{"class":651,"line":4249},[649,6467,3873],{"class":2040},[649,6469,6470],{"class":651,"line":4255},[649,6471,4086],{"class":2040},[649,6473,6474],{"class":651,"line":4261},[649,6475,4109],{"emptyLinePlaceholder":4108},[649,6477,6478,6480,6483,6485,6487,6489,6492,6494],{"class":651,"line":4267},[649,6479,6189],{"class":4311},[649,6481,6482],{"class":655}," select",[649,6484,4365],{"class":4311},[649,6486,5674],{"class":4321},[649,6488,511],{"class":2040},[649,6490,6491],{"class":4321},"select",[649,6493,6251],{"class":4311},[649,6495,6496],{"class":2040}," [];\n",[649,6498,6499,6501,6504,6506,6508,6510,6512,6514,6516,6519,6521,6523,6525,6527,6529],{"class":651,"line":4272},[649,6500,6189],{"class":4311},[649,6502,6503],{"class":655}," body",[649,6505,4365],{"class":4311},[649,6507,4318],{"class":2040},[649,6509,6378],{"class":4311},[649,6511,6381],{"class":4321},[649,6513,482],{"class":2040},[649,6515,1896],{"class":4321},[649,6517,6518],{"class":2040},", fields: ",[649,6520,6491],{"class":4321},[649,6522,511],{"class":2040},[649,6524,5092],{"class":655},[649,6526,4508],{"class":2040},[649,6528,1754],{"class":4321},[649,6530,6228],{"class":2040},[649,6532,6533,6535,6538,6540,6543,6546,6548],{"class":651,"line":4278},[649,6534,6189],{"class":4311},[649,6536,6537],{"class":655}," records",[649,6539,2634],{"class":4311},[649,6541,6542],{"class":655}," MonospaceObject",[649,6544,6545],{"class":2040},"[] ",[649,6547,6360],{"class":4311},[649,6549,6496],{"class":2040},[649,6551,6552],{"class":651,"line":4283},[649,6553,4109],{"emptyLinePlaceholder":4108},[649,6555,6556,6559,6561,6564,6567,6569,6571,6573,6575,6578,6580,6582,6584,6587,6589],{"class":651,"line":4289},[649,6557,6558],{"class":4311},"    for",[649,6560,1242],{"class":2040},[649,6562,6563],{"class":4311},"let",[649,6565,6566],{"class":4321}," from",[649,6568,4365],{"class":4311},[649,6570,6261],{"class":4321},[649,6572,924],{"class":2040},[649,6574,4328],{"class":4321},[649,6576,6577],{"class":4311}," \u003C",[649,6579,6283],{"class":4321},[649,6581,924],{"class":2040},[649,6583,4328],{"class":4321},[649,6585,6586],{"class":4311}," +=",[649,6588,6066],{"class":655},[649,6590,4792],{"class":2040},[649,6592,6593,6595,6598,6600,6602,6604,6606,6608,6611,6613,6615,6618,6620],{"class":651,"line":4295},[649,6594,5363],{"class":4311},[649,6596,6597],{"class":655}," size",[649,6599,4365],{"class":4311},[649,6601,6398],{"class":4321},[649,6603,511],{"class":2040},[649,6605,6403],{"class":655},[649,6607,4508],{"class":2040},[649,6609,6610],{"class":655},"PAGE_SIZE",[649,6612,482],{"class":2040},[649,6614,6339],{"class":4321},[649,6616,6617],{"class":4311}," -",[649,6619,6566],{"class":4321},[649,6621,4580],{"class":2040},[649,6623,6624,6626,6629,6631,6633,6635,6637,6639,6641,6643,6645,6647,6649,6651,6653,6655,6658],{"class":651,"line":4837},[649,6625,5363],{"class":4311},[649,6627,6628],{"class":655}," page",[649,6630,4365],{"class":4311},[649,6632,4670],{"class":4311},[649,6634,4605],{"class":655},[649,6636,4508],{"class":2040},[649,6638,861],{"class":4321},[649,6640,511],{"class":2040},[649,6642,4687],{"class":4321},[649,6644,6375],{"class":2040},[649,6646,6378],{"class":4311},[649,6648,4747],{"class":4321},[649,6650,482],{"class":2040},[649,6652,4328],{"class":4321},[649,6654,482],{"class":2040},[649,6656,6657],{"class":4321},"size",[649,6659,4826],{"class":2040},[649,6661,6662,6665,6667,6670,6672,6674,6677,6679,6681,6683,6685,6687,6690,6692,6694,6697,6699,6701,6703,6705],{"class":651,"line":4843},[649,6663,6664],{"class":4321},"        records",[649,6666,511],{"class":2040},[649,6668,6669],{"class":655},"push",[649,6671,4508],{"class":2040},[649,6673,6378],{"class":4311},[649,6675,6676],{"class":4321},"page",[649,6678,511],{"class":2040},[649,6680,1732],{"class":4321},[649,6682,511],{"class":2040},[649,6684,5092],{"class":655},[649,6686,5095],{"class":2040},[649,6688,6689],{"class":4311},"apiItem",[649,6691,4558],{"class":2040},[649,6693,4561],{"class":4311},[649,6695,6696],{"class":655}," toItem",[649,6698,4508],{"class":2040},[649,6700,6689],{"class":4321},[649,6702,482],{"class":2040},[649,6704,6491],{"class":4321},[649,6706,6707],{"class":2040},")));\n",[649,6709,6710,6712,6714,6716,6718,6720,6722,6725,6727,6729,6731,6734],{"class":651,"line":4889},[649,6711,5393],{"class":4311},[649,6713,1242],{"class":2040},[649,6715,6676],{"class":4321},[649,6717,511],{"class":2040},[649,6719,1732],{"class":4321},[649,6721,511],{"class":2040},[649,6723,6724],{"class":2044},"length",[649,6726,6577],{"class":4311},[649,6728,6597],{"class":4321},[649,6730,4558],{"class":2040},[649,6732,6733],{"class":4311},"break",[649,6735,4334],{"class":2040},[649,6737,6738],{"class":651,"line":4894},[649,6739,4086],{"class":2040},[649,6741,6742],{"class":651,"line":4920},[649,6743,4109],{"emptyLinePlaceholder":4108},[649,6745,6747,6749,6751,6754],{"class":651,"line":6746},45,[649,6748,4528],{"class":4311},[649,6750,4318],{"class":2040},[649,6752,6753],{"class":4321},"records",[649,6755,4482],{"class":2040},[649,6757,6759],{"class":651,"line":6758},46,[649,6760,2027],{"class":2040},[649,6762,6764],{"class":651,"line":6763},47,[649,6765,4109],{"emptyLinePlaceholder":4108},[649,6767,6769],{"class":651,"line":6768},48,[649,6770,5007],{"class":4375},[649,6772,6774],{"class":651,"line":6773},49,[649,6775,6776],{"class":4375}," * Handles `readOne` with `readMany`: the key as a filter, any filter the caller adds, and a limit of\n",[649,6778,6780],{"class":651,"line":6779},50,[649,6781,6782],{"class":4375}," * one item. Returns `record: null` when no item matches, and the caller gets `404`.\n",[649,6784,6786],{"class":651,"line":6785},51,[649,6787,5027],{"class":4375},[649,6789,6791,6793,6795,6797,6799,6801,6803,6806,6808,6810,6812,6814,6816,6818,6821],{"class":651,"line":6790},52,[649,6792,4404],{"class":4311},[649,6794,4600],{"class":4311},[649,6796,4502],{"class":4311},[649,6798,5840],{"class":655},[649,6800,4508],{"class":2040},[649,6802,6116],{"class":4311},[649,6804,6805],{"class":655}," ReadOneOperationSerialized",[649,6807,4517],{"class":2040},[649,6809,2634],{"class":4311},[649,6811,4626],{"class":655},[649,6813,4417],{"class":2040},[649,6815,5965],{"class":655},[649,6817,4417],{"class":2040},[649,6819,6820],{"class":659},"'readOne'",[649,6822,6823],{"class":2040},">> {\n",[649,6825,6827],{"class":651,"line":6826},53,[649,6828,6829],{"class":4375},"    \u002F\u002F Monospace sends the key as `{ id }`. An ID that isn't a safe integer matches no item.\n",[649,6831,6833,6835,6837,6839,6841,6843,6845,6847,6850],{"class":651,"line":6832},54,[649,6834,6189],{"class":4311},[649,6836,4318],{"class":2040},[649,6838,1563],{"class":655},[649,6840,4325],{"class":2040},[649,6842,6360],{"class":4311},[649,6844,5674],{"class":4321},[649,6846,511],{"class":2040},[649,6848,6849],{"class":4321},"key",[649,6851,4334],{"class":2040},[649,6853,6855,6857,6859,6862,6865,6867,6870,6872,6874,6877,6879,6882,6884,6886,6889,6891,6894,6896],{"class":651,"line":6854},55,[649,6856,4846],{"class":4311},[649,6858,1242],{"class":2040},[649,6860,6861],{"class":4311},"typeof",[649,6863,6864],{"class":4321}," id",[649,6866,5068],{"class":4311},[649,6868,6869],{"class":659}," 'number'",[649,6871,5713],{"class":4311},[649,6873,5716],{"class":4311},[649,6875,6876],{"class":4321},"Number",[649,6878,511],{"class":2040},[649,6880,6881],{"class":655},"isSafeInteger",[649,6883,4508],{"class":2040},[649,6885,1563],{"class":4321},[649,6887,6888],{"class":2040},")) ",[649,6890,5414],{"class":4311},[649,6892,6893],{"class":2040}," { record: ",[649,6895,1521],{"class":655},[649,6897,4482],{"class":2040},[649,6899,6901],{"class":651,"line":6900},56,[649,6902,4109],{"emptyLinePlaceholder":4108},[649,6904,6906,6908,6911,6913,6916,6919,6922,6925,6928,6930,6933,6935,6938],{"class":651,"line":6905},57,[649,6907,6189],{"class":4311},[649,6909,6910],{"class":655}," key",[649,6912,4365],{"class":4311},[649,6914,6915],{"class":2040}," { cmp: ",[649,6917,6918],{"class":659},"'equals'",[649,6920,6921],{"class":2040},", left: { field: ",[649,6923,6924],{"class":659},"'id'",[649,6926,6927],{"class":2040}," }, right: { value: ",[649,6929,1563],{"class":4321},[649,6931,6932],{"class":2040}," } } ",[649,6934,4913],{"class":4311},[649,6936,6937],{"class":4311}," const",[649,6939,4334],{"class":2040},[649,6941,6943,6945,6947,6949,6951,6953,6955,6957,6959,6961,6963,6965,6968,6970,6972,6974,6976,6978],{"class":651,"line":6942},58,[649,6944,6189],{"class":4311},[649,6946,5326],{"class":655},[649,6948,4365],{"class":4311},[649,6950,5674],{"class":4321},[649,6952,511],{"class":2040},[649,6954,5061],{"class":4321},[649,6956,5318],{"class":4311},[649,6958,5071],{"class":655},[649,6960,6207],{"class":4311},[649,6962,6910],{"class":4321},[649,6964,6303],{"class":4311},[649,6966,6967],{"class":2040}," { and: [",[649,6969,6849],{"class":4321},[649,6971,482],{"class":2040},[649,6973,861],{"class":4321},[649,6975,511],{"class":2040},[649,6977,5061],{"class":4321},[649,6979,6980],{"class":2040},"] };\n",[649,6982,6984,6986,6988,6990,6992,6995,6997,6999,7001,7004,7007,7010,7012,7014,7016,7019,7021,7023,7025,7027,7029,7032,7034],{"class":651,"line":6983},59,[649,6985,6189],{"class":4311},[649,6987,4318],{"class":2040},[649,6989,6753],{"class":655},[649,6991,4365],{"class":4311},[649,6993,6994],{"class":2040}," [] } ",[649,6996,6360],{"class":4311},[649,6998,4670],{"class":4311},[649,7000,5816],{"class":655},[649,7002,7003],{"class":2040},"({ op: ",[649,7005,7006],{"class":659},"'readMany'",[649,7008,7009],{"class":2040},", collection: ",[649,7011,861],{"class":4321},[649,7013,511],{"class":2040},[649,7015,4687],{"class":4321},[649,7017,7018],{"class":2040},", select: ",[649,7020,861],{"class":4321},[649,7022,511],{"class":2040},[649,7024,6491],{"class":4321},[649,7026,482],{"class":2040},[649,7028,5061],{"class":4321},[649,7030,7031],{"class":2040},", limit: ",[649,7033,5174],{"class":655},[649,7035,4826],{"class":2040},[649,7037,7039,7041,7043,7045,7048,7050,7053,7056,7058],{"class":651,"line":7038},60,[649,7040,4528],{"class":4311},[649,7042,6893],{"class":2040},[649,7044,6753],{"class":4321},[649,7046,7047],{"class":2040},"[",[649,7049,5913],{"class":655},[649,7051,7052],{"class":2040},"] ",[649,7054,7055],{"class":4311},"??",[649,7057,5291],{"class":655},[649,7059,4482],{"class":2040},[649,7061,7063],{"class":651,"line":7062},61,[649,7064,2027],{"class":2040},[649,7066,7068],{"class":651,"line":7067},62,[649,7069,4109],{"emptyLinePlaceholder":4108},[649,7071,7073],{"class":651,"line":7072},63,[649,7074,5007],{"class":4375},[649,7076,7078],{"class":651,"line":7077},64,[649,7079,7080],{"class":4375}," * Translates the caller's sort. Only `id` declares a sort, so a sort on any other field gets a plain\n",[649,7082,7084],{"class":651,"line":7083},65,[649,7085,7086],{"class":4375}," * `Error`. `id` is never null, so `nulls` has no effect. Without a sort, pages still need a stable\n",[649,7088,7090],{"class":651,"line":7089},66,[649,7091,7092],{"class":4375}," * order, so the default is `id` ascending.\n",[649,7094,7096],{"class":651,"line":7095},67,[649,7097,5027],{"class":4375},[649,7099,7101,7104,7106,7108,7111,7114,7117,7120,7122,7124,7127,7129,7132,7135,7138,7141],{"class":651,"line":7100},68,[649,7102,7103],{"class":4311},"function",[649,7105,6240],{"class":655},[649,7107,4508],{"class":2040},[649,7109,7110],{"class":4311},"sort:",[649,7112,7113],{"class":4311}," readonly",[649,7115,7116],{"class":655}," SortItemSerialized",[649,7118,7119],{"class":2040},"[])",[649,7121,2634],{"class":4311},[649,7123,4318],{"class":2040},[649,7125,7126],{"class":4311},"id:",[649,7128,4318],{"class":2040},[649,7130,7131],{"class":4311},"order:",[649,7133,7134],{"class":659}," 'asc'",[649,7136,7137],{"class":4311}," |",[649,7139,7140],{"class":659}," 'desc'",[649,7142,7143],{"class":2040}," } }[] {\n",[649,7145,7147,7149,7151,7153,7155,7157,7159,7161,7163,7165,7168,7171],{"class":651,"line":7146},69,[649,7148,4846],{"class":4311},[649,7150,1242],{"class":2040},[649,7152,1896],{"class":4321},[649,7154,511],{"class":2040},[649,7156,6724],{"class":2044},[649,7158,5318],{"class":4311},[649,7160,6274],{"class":655},[649,7162,4558],{"class":2040},[649,7164,5414],{"class":4311},[649,7166,7167],{"class":2040}," [{ id: { order: ",[649,7169,7170],{"class":659},"'asc'",[649,7172,7173],{"class":2040}," } }];\n",[649,7175,7177],{"class":651,"line":7176},70,[649,7178,4109],{"emptyLinePlaceholder":4108},[649,7180,7182,7184,7186,7188,7190,7193,7195,7197,7200,7203,7205],{"class":651,"line":7181},71,[649,7183,4528],{"class":4311},[649,7185,6235],{"class":4321},[649,7187,511],{"class":2040},[649,7189,5092],{"class":655},[649,7191,7192],{"class":2040},"(({ ",[649,7194,5203],{"class":4311},[649,7196,482],{"class":2040},[649,7198,7199],{"class":4311},"direction",[649,7201,7202],{"class":2040}," }) ",[649,7204,4561],{"class":4311},[649,7206,4448],{"class":2040},[649,7208,7210,7212,7214,7216,7218,7221,7223,7225,7227,7229,7231,7234,7236,7238,7240,7242,7244,7246],{"class":651,"line":7209},72,[649,7211,5393],{"class":4311},[649,7213,1242],{"class":2040},[649,7215,5203],{"class":4321},[649,7217,5068],{"class":4311},[649,7219,7220],{"class":659}," 'id'",[649,7222,4558],{"class":2040},[649,7224,4864],{"class":4311},[649,7226,4810],{"class":4311},[649,7228,4869],{"class":655},[649,7230,4508],{"class":2040},[649,7232,7233],{"class":659},"`The Art Institute connector doesn't offer sorting by ",[649,7235,5751],{"class":655},[649,7237,5754],{"class":659},[649,7239,5203],{"class":4321},[649,7241,5763],{"class":659},[649,7243,5751],{"class":655},[649,7245,5768],{"class":659},[649,7247,4580],{"class":2040},[649,7249,7251,7253,7256,7258,7260,7263,7265,7267,7269,7271],{"class":651,"line":7250},73,[649,7252,5078],{"class":4311},[649,7254,7255],{"class":2040}," { id: { order: ",[649,7257,7199],{"class":4321},[649,7259,5318],{"class":4311},[649,7261,7262],{"class":659}," 'descending'",[649,7264,6207],{"class":4311},[649,7266,7140],{"class":659},[649,7268,6303],{"class":4311},[649,7270,7134],{"class":659},[649,7272,5177],{"class":2040},[649,7274,7276],{"class":651,"line":7275},74,[649,7277,7278],{"class":2040},"    });\n",[649,7280,7282],{"class":651,"line":7281},75,[649,7283,2027],{"class":2040},[649,7285,7287],{"class":651,"line":7286},76,[649,7288,4109],{"emptyLinePlaceholder":4108},[649,7290,7292],{"class":651,"line":7291},77,[649,7293,5007],{"class":4375},[649,7295,7297],{"class":651,"line":7296},78,[649,7298,7299],{"class":4375}," * Returns exactly the selected fields, with `null` where the API has no value (the API returns `null`\n",[649,7301,7303],{"class":651,"line":7302},79,[649,7304,7305],{"class":4375}," * or leaves the field out). Monospace checks each value against the field's declared type.\n",[649,7307,7309],{"class":651,"line":7308},80,[649,7310,5027],{"class":4375},[649,7312,7314,7316,7318,7320,7323,7325,7327,7329,7331,7333,7336,7339,7341,7343,7345,7347,7349],{"class":651,"line":7313},81,[649,7315,7103],{"class":4311},[649,7317,6696],{"class":655},[649,7319,4508],{"class":2040},[649,7321,7322],{"class":4311},"apiItem:",[649,7324,4414],{"class":655},[649,7326,4417],{"class":2040},[649,7328,4420],{"class":2044},[649,7330,482],{"class":2040},[649,7332,4322],{"class":655},[649,7334,7335],{"class":2040},">, ",[649,7337,7338],{"class":4311},"select:",[649,7340,7113],{"class":4311},[649,7342,4514],{"class":2044},[649,7344,7119],{"class":2040},[649,7346,2634],{"class":4311},[649,7348,6542],{"class":655},[649,7350,4448],{"class":2040},[649,7352,7354,7356,7359,7361,7363,7365],{"class":651,"line":7353},82,[649,7355,6189],{"class":4311},[649,7357,7358],{"class":655}," item",[649,7360,2634],{"class":4311},[649,7362,6542],{"class":655},[649,7364,4365],{"class":4311},[649,7366,7367],{"class":2040}," {};\n",[649,7369,7371,7373,7375,7377,7379,7382,7384,7386,7388,7390,7392,7394,7396,7399,7401,7403,7405,7407,7410,7412,7414],{"class":651,"line":7370},83,[649,7372,6558],{"class":4311},[649,7374,1242],{"class":2040},[649,7376,4359],{"class":4311},[649,7378,4531],{"class":655},[649,7380,7381],{"class":4311}," of",[649,7383,6482],{"class":4321},[649,7385,4558],{"class":2040},[649,7387,495],{"class":4321},[649,7389,7047],{"class":2040},[649,7391,5420],{"class":4321},[649,7393,7052],{"class":2040},[649,7395,6360],{"class":4311},[649,7397,7398],{"class":4321}," apiItem",[649,7400,7047],{"class":2040},[649,7402,1754],{"class":655},[649,7404,4508],{"class":2040},[649,7406,5420],{"class":4321},[649,7408,7409],{"class":2040},")] ",[649,7411,7055],{"class":4311},[649,7413,5291],{"class":655},[649,7415,4334],{"class":2040},[649,7417,7419,7421,7423],{"class":651,"line":7418},84,[649,7420,4528],{"class":4311},[649,7422,7358],{"class":4321},[649,7424,4334],{"class":2040},[649,7426,7428],{"class":651,"line":7427},85,[649,7429,2027],{"class":2040},[639,7431,7433],{"className":4301,"code":7432,"filename":1295,"language":4304,"meta":645,"style":645},"import { defineCollection, defineRelation, defineSchema, field, fields, filter, index, paging, sort } from '@monospace\u002Fextension-kit\u002Fdata-connector\u002Fexperimental';\n\n\u002F\u002F The search API matches IDs exactly, so the ID fields accept `equals` and `in`, and `and` joins\n\u002F\u002F conditions. Monospace resolves a relation with `in` joined by `and`, so the relation needs both.\nconst exact = filter.field('equals', 'in');\nconst and = filter.logical('and');\n\n\u002F\u002F Callers can sort by `id`, ascending or descending.\nconst byId = { id: sort.field('ascending', 'descending') };\n\nconst artworkFilter = { fields: { id: exact, artistId: exact }, logicalOperators: and };\n\n\u002F\u002F The API's IDs fit in 32 bits, so the ID fields are `int32`, which travels as a JSON number.\n\u002F\u002F A 64-bit integer travels as a string. Neither collection declares a write, so both are read-only.\nexport const artworks = defineCollection({\n    name: 'artworks',\n    fields: {\n        id: field.int32(),\n        title: field.string({ nullable: true }),\n        artistId: field.int32({ nullable: true }),\n        dateDisplay: field.string({ nullable: true }),\n    },\n    indexes: { artworks_pkey: index.primary(['id']) },\n    operations: {\n        readMany: { filter: artworkFilter, sort: byId, limit: paging.limit(), offset: paging.offset(), output: fields.all() },\n        readOne: { filter: artworkFilter, output: fields.all() },\n    },\n});\n\nconst artistFilter = { fields: { id: exact }, logicalOperators: and };\n\nexport const artists = defineCollection({\n    name: 'artists',\n    fields: {\n        id: field.int32(),\n        title: field.string(),\n    },\n    indexes: { artists_pkey: index.primary(['id']) },\n    operations: {\n        readMany: { filter: artistFilter, sort: byId, limit: paging.limit(), offset: paging.offset(), output: fields.all() },\n        readOne: { filter: artistFilter, output: fields.all() },\n    },\n});\n\nexport const schema = defineSchema({\n    collections: [artworks, artists],\n    \u002F\u002F Monospace reads an artwork's `artist` with `id in […]`, and an artist's `artworks` with\n    \u002F\u002F `artistId in […]`. Both fields declare `in`, so callers can follow the relation both ways.\n    relations: [\n        defineRelation({\n            name: 'artworks_artist',\n            from: artworks,\n            to: artists,\n            on: [['artistId', 'id']],\n            names: { forward: 'artist', reverse: 'artworks' },\n        }),\n    ],\n});\n",[484,7434,7435,7489,7493,7498,7503,7529,7552,7556,7561,7591,7595,7622,7626,7631,7636,7652,7661,7666,7681,7700,7717,7734,7738,7758,7763,7806,7824,7828,7832,7836,7855,7859,7874,7883,7887,7899,7911,7915,7932,7936,7973,7989,7993,7997,8001,8016,8030,8035,8040,8045,8052,8062,8071,8080,8095,8110,8115,8119],{"__ignoreMap":645},[649,7436,7437,7439,7441,7444,7446,7449,7451,7454,7456,7458,7460,7462,7464,7466,7468,7471,7473,7476,7478,7480,7482,7484,7487],{"class":651,"line":652},[649,7438,4312],{"class":4311},[649,7440,4318],{"class":2040},[649,7442,7443],{"class":4321},"defineCollection",[649,7445,482],{"class":2040},[649,7447,7448],{"class":4321},"defineRelation",[649,7450,482],{"class":2040},[649,7452,7453],{"class":4321},"defineSchema",[649,7455,482],{"class":2040},[649,7457,5203],{"class":4321},[649,7459,482],{"class":2040},[649,7461,503],{"class":4321},[649,7463,482],{"class":2040},[649,7465,5061],{"class":4321},[649,7467,482],{"class":2040},[649,7469,7470],{"class":4321},"index",[649,7472,482],{"class":2040},[649,7474,7475],{"class":4321},"paging",[649,7477,482],{"class":2040},[649,7479,1896],{"class":4321},[649,7481,4325],{"class":2040},[649,7483,4328],{"class":4311},[649,7485,7486],{"class":659}," '@monospace\u002Fextension-kit\u002Fdata-connector\u002Fexperimental'",[649,7488,4334],{"class":2040},[649,7490,7491],{"class":651,"line":1793},[649,7492,4109],{"emptyLinePlaceholder":4108},[649,7494,7495],{"class":651,"line":2000},[649,7496,7497],{"class":4375},"\u002F\u002F The search API matches IDs exactly, so the ID fields accept `equals` and `in`, and `and` joins\n",[649,7499,7500],{"class":651,"line":2006},[649,7501,7502],{"class":4375},"\u002F\u002F conditions. Monospace resolves a relation with `in` joined by `and`, so the relation needs both.\n",[649,7504,7505,7507,7510,7512,7514,7516,7518,7520,7522,7524,7527],{"class":651,"line":2012},[649,7506,4359],{"class":4311},[649,7508,7509],{"class":655}," exact",[649,7511,4365],{"class":4311},[649,7513,5326],{"class":4321},[649,7515,511],{"class":2040},[649,7517,5203],{"class":655},[649,7519,4508],{"class":2040},[649,7521,6918],{"class":659},[649,7523,482],{"class":2040},[649,7525,7526],{"class":659},"'in'",[649,7528,4580],{"class":2040},[649,7530,7531,7533,7536,7538,7540,7542,7545,7547,7550],{"class":651,"line":2018},[649,7532,4359],{"class":4311},[649,7534,7535],{"class":655}," and",[649,7537,4365],{"class":4311},[649,7539,5326],{"class":4321},[649,7541,511],{"class":2040},[649,7543,7544],{"class":655},"logical",[649,7546,4508],{"class":2040},[649,7548,7549],{"class":659},"'and'",[649,7551,4580],{"class":2040},[649,7553,7554],{"class":651,"line":2024},[649,7555,4109],{"emptyLinePlaceholder":4108},[649,7557,7558],{"class":651,"line":2397},[649,7559,7560],{"class":4375},"\u002F\u002F Callers can sort by `id`, ascending or descending.\n",[649,7562,7563,7565,7568,7570,7573,7575,7577,7579,7581,7584,7586,7589],{"class":651,"line":3795},[649,7564,4359],{"class":4311},[649,7566,7567],{"class":655}," byId",[649,7569,4365],{"class":4311},[649,7571,7572],{"class":2040}," { id: ",[649,7574,1896],{"class":4321},[649,7576,511],{"class":2040},[649,7578,5203],{"class":655},[649,7580,4508],{"class":2040},[649,7582,7583],{"class":659},"'ascending'",[649,7585,482],{"class":2040},[649,7587,7588],{"class":659},"'descending'",[649,7590,6228],{"class":2040},[649,7592,7593],{"class":651,"line":3801},[649,7594,4109],{"emptyLinePlaceholder":4108},[649,7596,7597,7599,7602,7604,7607,7610,7613,7615,7618,7620],{"class":651,"line":3807},[649,7598,4359],{"class":4311},[649,7600,7601],{"class":655}," artworkFilter",[649,7603,4365],{"class":4311},[649,7605,7606],{"class":2040}," { fields: { id: ",[649,7608,7609],{"class":4321},"exact",[649,7611,7612],{"class":2040},", artistId: ",[649,7614,7609],{"class":4321},[649,7616,7617],{"class":2040}," }, logicalOperators: ",[649,7619,2160],{"class":4321},[649,7621,4482],{"class":2040},[649,7623,7624],{"class":651,"line":3820},[649,7625,4109],{"emptyLinePlaceholder":4108},[649,7627,7628],{"class":651,"line":3833},[649,7629,7630],{"class":4375},"\u002F\u002F The API's IDs fit in 32 bits, so the ID fields are `int32`, which travels as a JSON number.\n",[649,7632,7633],{"class":651,"line":3846},[649,7634,7635],{"class":4375},"\u002F\u002F A 64-bit integer travels as a string. Neither collection declares a write, so both are read-only.\n",[649,7637,7638,7640,7642,7645,7647,7650],{"class":651,"line":3859},[649,7639,4404],{"class":4311},[649,7641,6937],{"class":4311},[649,7643,7644],{"class":655}," artworks",[649,7646,4365],{"class":4311},[649,7648,7649],{"class":655}," defineCollection",[649,7651,5621],{"class":2040},[649,7653,7654,7657,7659],{"class":651,"line":3870},[649,7655,7656],{"class":2040},"    name: ",[649,7658,5907],{"class":659},[649,7660,3727],{"class":2040},[649,7662,7663],{"class":651,"line":3876},[649,7664,7665],{"class":2040},"    fields: {\n",[649,7667,7668,7671,7673,7675,7678],{"class":651,"line":3882},[649,7669,7670],{"class":2040},"        id: ",[649,7672,5203],{"class":4321},[649,7674,511],{"class":2040},[649,7676,7677],{"class":655},"int32",[649,7679,7680],{"class":2040},"(),\n",[649,7682,7683,7686,7688,7690,7692,7695,7697],{"class":651,"line":3894},[649,7684,7685],{"class":2040},"        title: ",[649,7687,5203],{"class":4321},[649,7689,511],{"class":2040},[649,7691,4420],{"class":655},[649,7693,7694],{"class":2040},"({ nullable: ",[649,7696,3622],{"class":655},[649,7698,7699],{"class":2040}," }),\n",[649,7701,7702,7705,7707,7709,7711,7713,7715],{"class":651,"line":3907},[649,7703,7704],{"class":2040},"        artistId: ",[649,7706,5203],{"class":4321},[649,7708,511],{"class":2040},[649,7710,7677],{"class":655},[649,7712,7694],{"class":2040},[649,7714,3622],{"class":655},[649,7716,7699],{"class":2040},[649,7718,7719,7722,7724,7726,7728,7730,7732],{"class":651,"line":3919},[649,7720,7721],{"class":2040},"        dateDisplay: ",[649,7723,5203],{"class":4321},[649,7725,511],{"class":2040},[649,7727,4420],{"class":655},[649,7729,7694],{"class":2040},[649,7731,3622],{"class":655},[649,7733,7699],{"class":2040},[649,7735,7736],{"class":651,"line":3929},[649,7737,4019],{"class":2040},[649,7739,7740,7743,7745,7747,7750,7753,7755],{"class":651,"line":4204},[649,7741,7742],{"class":2040},"    indexes: { artworks_pkey: ",[649,7744,7470],{"class":4321},[649,7746,511],{"class":2040},[649,7748,7749],{"class":655},"primary",[649,7751,7752],{"class":2040},"([",[649,7754,6924],{"class":659},[649,7756,7757],{"class":2040},"]) },\n",[649,7759,7760],{"class":651,"line":4209},[649,7761,7762],{"class":2040},"    operations: {\n",[649,7764,7765,7768,7771,7774,7776,7778,7780,7782,7784,7787,7789,7791,7793,7796,7798,7800,7803],{"class":651,"line":4215},[649,7766,7767],{"class":2040},"        readMany: { filter: ",[649,7769,7770],{"class":4321},"artworkFilter",[649,7772,7773],{"class":2040},", sort: ",[649,7775,1812],{"class":4321},[649,7777,7031],{"class":2040},[649,7779,7475],{"class":4321},[649,7781,511],{"class":2040},[649,7783,1583],{"class":655},[649,7785,7786],{"class":2040},"(), offset: ",[649,7788,7475],{"class":4321},[649,7790,511],{"class":2040},[649,7792,1586],{"class":655},[649,7794,7795],{"class":2040},"(), output: ",[649,7797,503],{"class":4321},[649,7799,511],{"class":2040},[649,7801,7802],{"class":655},"all",[649,7804,7805],{"class":2040},"() },\n",[649,7807,7808,7811,7813,7816,7818,7820,7822],{"class":651,"line":4221},[649,7809,7810],{"class":2040},"        readOne: { filter: ",[649,7812,7770],{"class":4321},[649,7814,7815],{"class":2040},", output: ",[649,7817,503],{"class":4321},[649,7819,511],{"class":2040},[649,7821,7802],{"class":655},[649,7823,7805],{"class":2040},[649,7825,7826],{"class":651,"line":4227},[649,7827,4019],{"class":2040},[649,7829,7830],{"class":651,"line":4233},[649,7831,5944],{"class":2040},[649,7833,7834],{"class":651,"line":4238},[649,7835,4109],{"emptyLinePlaceholder":4108},[649,7837,7838,7840,7843,7845,7847,7849,7851,7853],{"class":651,"line":4244},[649,7839,4359],{"class":4311},[649,7841,7842],{"class":655}," artistFilter",[649,7844,4365],{"class":4311},[649,7846,7606],{"class":2040},[649,7848,7609],{"class":4321},[649,7850,7617],{"class":2040},[649,7852,2160],{"class":4321},[649,7854,4482],{"class":2040},[649,7856,7857],{"class":651,"line":4249},[649,7858,4109],{"emptyLinePlaceholder":4108},[649,7860,7861,7863,7865,7868,7870,7872],{"class":651,"line":4255},[649,7862,4404],{"class":4311},[649,7864,6937],{"class":4311},[649,7866,7867],{"class":655}," artists",[649,7869,4365],{"class":4311},[649,7871,7649],{"class":655},[649,7873,5621],{"class":2040},[649,7875,7876,7878,7881],{"class":651,"line":4261},[649,7877,7656],{"class":2040},[649,7879,7880],{"class":659},"'artists'",[649,7882,3727],{"class":2040},[649,7884,7885],{"class":651,"line":4267},[649,7886,7665],{"class":2040},[649,7888,7889,7891,7893,7895,7897],{"class":651,"line":4272},[649,7890,7670],{"class":2040},[649,7892,5203],{"class":4321},[649,7894,511],{"class":2040},[649,7896,7677],{"class":655},[649,7898,7680],{"class":2040},[649,7900,7901,7903,7905,7907,7909],{"class":651,"line":4278},[649,7902,7685],{"class":2040},[649,7904,5203],{"class":4321},[649,7906,511],{"class":2040},[649,7908,4420],{"class":655},[649,7910,7680],{"class":2040},[649,7912,7913],{"class":651,"line":4283},[649,7914,4019],{"class":2040},[649,7916,7917,7920,7922,7924,7926,7928,7930],{"class":651,"line":4289},[649,7918,7919],{"class":2040},"    indexes: { artists_pkey: ",[649,7921,7470],{"class":4321},[649,7923,511],{"class":2040},[649,7925,7749],{"class":655},[649,7927,7752],{"class":2040},[649,7929,6924],{"class":659},[649,7931,7757],{"class":2040},[649,7933,7934],{"class":651,"line":4295},[649,7935,7762],{"class":2040},[649,7937,7938,7940,7943,7945,7947,7949,7951,7953,7955,7957,7959,7961,7963,7965,7967,7969,7971],{"class":651,"line":4837},[649,7939,7767],{"class":2040},[649,7941,7942],{"class":4321},"artistFilter",[649,7944,7773],{"class":2040},[649,7946,1812],{"class":4321},[649,7948,7031],{"class":2040},[649,7950,7475],{"class":4321},[649,7952,511],{"class":2040},[649,7954,1583],{"class":655},[649,7956,7786],{"class":2040},[649,7958,7475],{"class":4321},[649,7960,511],{"class":2040},[649,7962,1586],{"class":655},[649,7964,7795],{"class":2040},[649,7966,503],{"class":4321},[649,7968,511],{"class":2040},[649,7970,7802],{"class":655},[649,7972,7805],{"class":2040},[649,7974,7975,7977,7979,7981,7983,7985,7987],{"class":651,"line":4843},[649,7976,7810],{"class":2040},[649,7978,7942],{"class":4321},[649,7980,7815],{"class":2040},[649,7982,503],{"class":4321},[649,7984,511],{"class":2040},[649,7986,7802],{"class":655},[649,7988,7805],{"class":2040},[649,7990,7991],{"class":651,"line":4889},[649,7992,4019],{"class":2040},[649,7994,7995],{"class":651,"line":4894},[649,7996,5944],{"class":2040},[649,7998,7999],{"class":651,"line":4920},[649,8000,4109],{"emptyLinePlaceholder":4108},[649,8002,8003,8005,8007,8009,8011,8014],{"class":651,"line":6746},[649,8004,4404],{"class":4311},[649,8006,6937],{"class":4311},[649,8008,5650],{"class":655},[649,8010,4365],{"class":4311},[649,8012,8013],{"class":655}," defineSchema",[649,8015,5621],{"class":2040},[649,8017,8018,8021,8023,8025,8027],{"class":651,"line":6758},[649,8019,8020],{"class":2040},"    collections: [",[649,8022,486],{"class":4321},[649,8024,482],{"class":2040},[649,8026,490],{"class":4321},[649,8028,8029],{"class":2040},"],\n",[649,8031,8032],{"class":651,"line":6763},[649,8033,8034],{"class":4375},"    \u002F\u002F Monospace reads an artwork's `artist` with `id in […]`, and an artist's `artworks` with\n",[649,8036,8037],{"class":651,"line":6768},[649,8038,8039],{"class":4375},"    \u002F\u002F `artistId in […]`. Both fields declare `in`, so callers can follow the relation both ways.\n",[649,8041,8042],{"class":651,"line":6773},[649,8043,8044],{"class":2040},"    relations: [\n",[649,8046,8047,8050],{"class":651,"line":6779},[649,8048,8049],{"class":655},"        defineRelation",[649,8051,5621],{"class":2040},[649,8053,8054,8057,8060],{"class":651,"line":6785},[649,8055,8056],{"class":2040},"            name: ",[649,8058,8059],{"class":659},"'artworks_artist'",[649,8061,3727],{"class":2040},[649,8063,8064,8067,8069],{"class":651,"line":6790},[649,8065,8066],{"class":2040},"            from: ",[649,8068,486],{"class":4321},[649,8070,3727],{"class":2040},[649,8072,8073,8076,8078],{"class":651,"line":6826},[649,8074,8075],{"class":2040},"            to: ",[649,8077,490],{"class":4321},[649,8079,3727],{"class":2040},[649,8081,8082,8085,8088,8090,8092],{"class":651,"line":6832},[649,8083,8084],{"class":2040},"            on: [[",[649,8086,8087],{"class":659},"'artistId'",[649,8089,482],{"class":2040},[649,8091,6924],{"class":659},[649,8093,8094],{"class":2040},"]],\n",[649,8096,8097,8100,8103,8106,8108],{"class":651,"line":6854},[649,8098,8099],{"class":2040},"            names: { forward: ",[649,8101,8102],{"class":659},"'artist'",[649,8104,8105],{"class":2040},", reverse: ",[649,8107,5907],{"class":659},[649,8109,4729],{"class":2040},[649,8111,8112],{"class":651,"line":6900},[649,8113,8114],{"class":2040},"        }),\n",[649,8116,8117],{"class":651,"line":6905},[649,8118,3879],{"class":2040},[649,8120,8121],{"class":651,"line":6942},[649,8122,5944],{"class":2040},[639,8124,8127],{"className":2030,"code":8125,"filename":8126,"language":2033,"meta":645,"style":645},"{\n    \"compilerOptions\": {\n        \"target\": \"ES2023\",\n        \"module\": \"ESNext\",\n        \"moduleResolution\": \"bundler\",\n        \"strict\": true,\n        \"noEmit\": true,\n        \"verbatimModuleSyntax\": true\n    },\n    \"include\": [\n        \"src\"\n    ]\n}\n","tsconfig.json",[484,8128,8129,8133,8140,8152,8164,8176,8187,8198,8208,8212,8219,8224,8229],{"__ignoreMap":645},[649,8130,8131],{"class":651,"line":652},[649,8132,1997],{"class":2040},[649,8134,8135,8138],{"class":651,"line":1793},[649,8136,8137],{"class":2044},"    \"compilerOptions\"",[649,8139,3747],{"class":2040},[649,8141,8142,8145,8147,8150],{"class":651,"line":2000},[649,8143,8144],{"class":2044},"        \"target\"",[649,8146,1729],{"class":2040},[649,8148,8149],{"class":659},"\"ES2023\"",[649,8151,3727],{"class":2040},[649,8153,8154,8157,8159,8162],{"class":651,"line":2006},[649,8155,8156],{"class":2044},"        \"module\"",[649,8158,1729],{"class":2040},[649,8160,8161],{"class":659},"\"ESNext\"",[649,8163,3727],{"class":2040},[649,8165,8166,8169,8171,8174],{"class":651,"line":2012},[649,8167,8168],{"class":2044},"        \"moduleResolution\"",[649,8170,1729],{"class":2040},[649,8172,8173],{"class":659},"\"bundler\"",[649,8175,3727],{"class":2040},[649,8177,8178,8181,8183,8185],{"class":651,"line":2018},[649,8179,8180],{"class":2044},"        \"strict\"",[649,8182,1729],{"class":2040},[649,8184,3622],{"class":655},[649,8186,3727],{"class":2040},[649,8188,8189,8192,8194,8196],{"class":651,"line":2024},[649,8190,8191],{"class":2044},"        \"noEmit\"",[649,8193,1729],{"class":2040},[649,8195,3622],{"class":655},[649,8197,3727],{"class":2040},[649,8199,8200,8203,8205],{"class":651,"line":2397},[649,8201,8202],{"class":2044},"        \"verbatimModuleSyntax\"",[649,8204,1729],{"class":2040},[649,8206,8207],{"class":655},"true\n",[649,8209,8210],{"class":651,"line":3795},[649,8211,4019],{"class":2040},[649,8213,8214,8217],{"class":651,"line":3801},[649,8215,8216],{"class":2044},"    \"include\"",[649,8218,2048],{"class":2040},[649,8220,8221],{"class":651,"line":3807},[649,8222,8223],{"class":659},"        \"src\"\n",[649,8225,8226],{"class":651,"line":3820},[649,8227,8228],{"class":2040},"    ]\n",[649,8230,8231],{"class":651,"line":3833},[649,8232,2027],{"class":2040},[3695,8234,8236],{"id":8235},"what-you-learned","What You Learned",[521,8238,8239,8248,8257,8263,8269],{},[524,8240,8241,2332,8244,8247],{},[493,8242,8243],{},"Start from the scaffold.",[484,8245,8246],{},"monospace extension create"," writes a connector that builds; rename its entry and declare the hosts it calls.",[524,8249,8250,2332,8253,8256],{},[493,8251,8252],{},"Install and approve access.",[484,8254,8255],{},"build --install-to"," installs the extension. Approve access to the hosts its entry declares when you create a data source. Its collections then work in Studio and the API like any other collection.",[524,8258,8259,8262],{},[493,8260,8261],{},"Implement declared operations."," Monospace offers callers, Studio included, only the filters and sorts the schema declares. It rejects a caller's filter on a field or operator the schema doesn't declare before your code runs. Implement every filter, sort, and page you declare.",[524,8264,8265,8268],{},[493,8266,8267],{},"Send requests through one function."," That function gives every request to the external data source a time limit, and turns a failed request into an error.",[524,8270,8271,8274,8275,8277,8278,8280,8281,8283],{},[493,8272,8273],{},"Choose the error class by cause."," Throw ",[484,8276,1677],{}," with a message the caller can act on for a valid request the external data source can't serve. Return ",[484,8279,2819],{}," when a read by primary key finds no item; that isn't an error. Throw a plain ",[484,8282,1689],{}," for a collection, sort, or count the schema never offers.",[3695,8285,8287],{"id":8286},"what-this-connector-leaves-out","What This Connector Leaves Out",[462,8289,8290],{},"The full Art Institute connector and the linked guides add three defenses:",[521,8292,8293,8323,8333],{},[524,8294,8295,8298,8299,8301,8302,482,8304,8307,8308,8310,8311,8313,8314,487,8316,8318,8319,511],{},[493,8296,8297],{},"Check filters against the schema."," Monospace checks the filters callers send against the schema stored for the data source, which it imported from ",[484,8300,884],{}," when you created the data source. After you change ",[484,8303,884],{},[466,8305,8306],{"href":1440},"refresh the data source's schema"," so the checks match.",[3599,8309],{},"Monospace doesn't check the filter it hands to ",[484,8312,861],{},", and this connector translates ",[484,8315,2148],{},[484,8317,2151],{}," on any field it receives. The full connector also checks every filter against its declaration, and rejects a comparison it doesn't declare. See ",[466,8320,8322],{"href":8321},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-source-mapping#translate-a-rich-grammar","Translate a Rich Grammar",[524,8324,8325,8328,8329,511],{},[493,8326,8327],{},"Validate API responses."," This connector trusts the structure and values of the API's responses. Validate each value during conversion so API changes produce a clear error in your connector. See ",[466,8330,8332],{"href":8331},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-source-mapping#normalize-values","Normalize Values",[524,8334,8335,8338,8339,8341,8342,511],{},[493,8336,8337],{},"Pick an error class for each failure."," This connector reports every failed HTTP status as a plain ",[484,8340,1689],{},". Callers therefore can't distinguish a rate limit, a rejected credential, and an outage. See ",[466,8343,8345],{"href":8344},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Ferrors#_2-pick-a-class-for-each-failure","Pick a Class for Each Failure",[3695,8347,8349],{"id":8348},"next-steps","Next Steps",[521,8351,8352,8359,8365,8371,8377],{},[524,8353,8354,8358],{},[466,8355,8357],{"href":8356},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-sources","Manage Data Sources",": create data sources over the API, approve permissions, and update, recreate, or delete them when the extension changes",[524,8360,8361,8364],{},[466,8362,237],{"href":8363},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fruntime",": the sandbox your connector runs in, and what it can and can't use",[524,8366,8367,8370],{},[466,8368,256],{"href":8369},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Ftesting",": check a connector from unit tests to a running instance",[524,8372,8373,8376],{},[466,8374,246],{"href":8375},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-source-mapping",": decide which filters, sorts, and pages to declare, with the full Art Institute connector that this quickstart trims down",[524,8378,8379,8383],{},[466,8380,8382],{"href":8381},"\u002Fguides\u002Fdata-connectors\u002Fstripe","Build a Stripe Data Connector",": a Stripe test-mode connector with configuration and writes",[8385,8386,8387],"style",{},"html pre.shiki code .ssBNi, html code.shiki .ssBNi{--shiki-light:#1659E9;--shiki-default:#1659E9;--shiki-dark:#94B3F5}html pre.shiki code .suKVh, html code.shiki .suKVh{--shiki-light:#032F62;--shiki-default:#032F62;--shiki-dark:#F8FAFC}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sTMul, html code.shiki .sTMul{--shiki-light:#1F2937;--shiki-default:#1F2937;--shiki-dark:#94A3B8}html pre.shiki code .snHjA, html code.shiki .snHjA{--shiki-light:#124BC4;--shiki-default:#124BC4;--shiki-dark:#5B8EF4}html pre.shiki code .sLVBU, html code.shiki .sLVBU{--shiki-light:#0891B2;--shiki-default:#0891B2;--shiki-dark:#22D3EE}html pre.shiki code .sNJ9c, html code.shiki .sNJ9c{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E2E8F0}html pre.shiki code .seNfP, html code.shiki .seNfP{--shiki-light:#64748B;--shiki-default:#64748B;--shiki-dark:#94A3B8}",{"title":645,"searchDepth":1793,"depth":1793,"links":8389},[8390,8391,8392],{"id":8235,"depth":1793,"text":8236},{"id":8286,"depth":1793,"text":8287},{"id":8348,"depth":1793,"text":8349},"Build a read-only data connector extension for the Art Institute of Chicago API step by step, install it, and query it in Studio.","md",null,{"wide":4108},{"title":16,"icon":121},{"title":447,"description":8393},"a9e_HoqprtRm9BEAP4b5lXZR8UmZIh1EBQPTRZFT9RU",[8401,8403],{"title":108,"path":109,"stem":110,"description":8402,"icon":111,"children":-1},"Run several Monospace replicas against one shared system database.",{"title":123,"path":124,"stem":125,"description":8404,"icon":126,"children":-1},"Build a Stripe test-mode data connector extension with customers, products and prices, from probing the API to writes and tests.",1790840105223]