[{"data":1,"prerenderedAt":3079},["ShallowReactive",2],{"navigation_docs_en":3,"-en-developer-extensions-data-connectors-runtime":445,"-en-developer-extensions-data-connectors-runtime-surround":3074},[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":237,"body":447,"description":3067,"extension":3068,"links":3069,"meta":3070,"navigation":3071,"path":238,"seo":3072,"stem":239,"__hash__":3073},"docs_en\u002Fen\u002F5.developer\u002F3.extensions\u002F2.data-connectors\u002F2.runtime.md",{"type":448,"value":449,"toc":3044},"minimark",[450,453,457,461,464,482,485,489,564,568,571,574,641,656,660,663,674,810,816,821,840,1732,1736,1760,1773,2373,2431,2435,2444,2526,2544,2548,2557,2560,2598,2602,2605,2608,2637,2657,2661,2664,2754,2759,2762,2771,2818,2822,2902,2905,2934,2961,2965,2974,3000,3004,3040],[451,452],"preview",{},[454,455,143],"h2",{"id":456},"overview",[458,459,460],"p",{},"This page describes how the entries of a data connector extension run. Data connectors are the only extension entry type today, and the sandbox, lifecycle, and limits below apply to them specifically.",[458,462,463],{},"Engine runs each data connector extension inside a sandbox. Knowing its boundaries up front saves you from code that builds cleanly and then fails at runtime.",[458,465,466,467,471,472,477,478,481],{},"A ",[468,469,470],"strong",{},"data source"," is a connector configured in a ",[473,474,476],"a",{"href":475},"\u002Fconcepts\u002Forganization#glossary","workspace",". It points at the ",[468,479,480],{},"external data source",", the API, service, or database the connector reads and writes.",[458,483,484],{},"The model in one paragraph: every data source gets its own isolated Deno worker. The worker loads one self-contained JavaScript file and has web platform APIs but no Node APIs. It reaches only the hosts the data source was granted, and keeps nothing between restarts.",[454,486,488],{"id":487},"one-worker-per-data-source","One Worker per Data Source",[490,491,492,505],"table",{},[493,494,495],"thead",{},[496,497,498,502],"tr",{},[499,500,501],"th",{},"Property",[499,503,504],{},"Behavior",[506,507,508,517,525,538,549],"tbody",{},[496,509,510,514],{},[511,512,513],"td",{},"Isolation",[511,515,516],{},"Each data source runs in its own Deno worker. Two data sources from the same connector share no memory",[496,518,519,522],{},[511,520,521],{},"Code",[511,523,524],{},"One JavaScript file per entry, produced by the CLI build. The worker loads that file and nothing else",[496,526,527,530],{},[511,528,529],{},"State",[511,531,532,533,537],{},"Variables you create in ",[534,535,536],"code",{},"setup"," live as long as the worker. They are lost when the worker restarts",[496,539,540,543],{},[511,541,542],{},"Concurrency",[511,544,545,546,548],{},"One worker serves several requests at the same time. Treat shared state in ",[534,547,536],{}," as concurrently accessed",[496,550,551,554],{},[511,552,553],{},"Timing",[511,555,556,557,559,560],{},"Module evaluation and ",[534,558,536],{}," each run under a timeout. Calls to your handlers have no deadline. A worker whose code blocks the thread stops responding and gets replaced. See ",[473,561,563],{"href":562},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Flimits","Data Connector Runtime Limits",[454,565,567],{"id":566},"single-file-no-imports","Single File, No Imports",[458,569,570],{},"The worker refuses every module import. The CLI bundles your TypeScript and its dependencies into one file, and fails the build if the output still imports anything.",[458,572,573],{},"You can use npm packages that run on web APIs alone, because the build inlines them. You can't use packages that need Node built-ins.",[575,576,577,617],"code-group",{},[578,579,585],"pre",{"className":580,"code":581,"filename":582,"language":583,"meta":584,"style":584},"language-ts shiki shiki-themes monospace-light monospace-light monospace-dark","import { defineDataConnector } from '@monospace\u002Fextension-kit\u002Fdata-connector';\n","✅ bundled at build time","ts","",[534,586,587],{"__ignoreMap":584},[588,589,592,596,600,604,607,610,614],"span",{"class":590,"line":591},"line",1,[588,593,595],{"class":594},"sLVBU","import",[588,597,599],{"class":598},"sTMul"," { ",[588,601,603],{"class":602},"sNJ9c","defineDataConnector",[588,605,606],{"class":598}," } ",[588,608,609],{"class":594},"from",[588,611,613],{"class":612},"suKVh"," '@monospace\u002Fextension-kit\u002Fdata-connector'",[588,615,616],{"class":598},";\n",[578,618,621],{"className":580,"code":619,"filename":620,"language":583,"meta":584,"style":584},"import { readFileSync } from 'node:fs';\n","❌ fails the build",[534,622,623],{"__ignoreMap":584},[588,624,625,627,629,632,634,636,639],{"class":590,"line":591},[588,626,595],{"class":594},[588,628,599],{"class":598},[588,630,631],{"class":602},"readFileSync",[588,633,606],{"class":598},[588,635,609],{"class":594},[588,637,638],{"class":612}," 'node:fs'",[588,640,616],{"class":598},[458,642,643,644,647,648,651,652,655],{},"A build that still imports a module fails with ",[534,645,646],{},"extension.built_not_self_contained",". A file that bypasses the CLI and imports a module fails to load with ",[534,649,650],{},"an extension cannot import …",". A dynamic ",[534,653,654],{},"import()"," fails with the same message when it runs.",[454,657,659],{"id":658},"available-apis","Available APIs",[458,661,662],{},"The worker exposes the web platform APIs of the Deno runtime, and nothing that reaches outside the sandbox.",[664,665,666,667,673],"tip",{},"Need a Node.js-compatible API? ",[473,668,672],{"href":669,"rel":670},"https:\u002F\u002Ffeedback.monospace.io\u002Frequest?request=new",[671],"nofollow","Let us know",".",[490,675,676,686],{},[493,677,678],{},[496,679,680,683],{},[499,681,682],{},"Available",[499,684,685],{},"Not available",[506,687,688,716,729,745,761,774,784,791],{},[496,689,690,705],{},[511,691,692,695,696,695,699,695,702],{},[534,693,694],{},"fetch",", ",[534,697,698],{},"Request",[534,700,701],{},"Response",[534,703,704],{},"Headers",[511,706,707,708,711,712,715],{},"Node APIs (",[534,709,710],{},"node:*"," modules, ",[534,713,714],{},"require",")",[496,717,718,726],{},[511,719,720,695,723],{},[534,721,722],{},"URL",[534,724,725],{},"URLSearchParams",[511,727,728],{},"npm packages resolved at runtime",[496,730,731,742],{},[511,732,733,695,736,695,739],{},[534,734,735],{},"crypto",[534,737,738],{},"TextEncoder",[534,740,741],{},"TextDecoder",[511,743,744],{},"Filesystem reads and writes",[496,746,747,758],{},[511,748,749,695,752,695,755],{},[534,750,751],{},"AbortController",[534,753,754],{},"AbortSignal.timeout",[534,756,757],{},"setTimeout",[511,759,760],{},"Environment variables",[496,762,763,771],{},[511,764,765,695,768],{},[534,766,767],{},"ReadableStream",[534,769,770],{},"structuredClone",[511,772,773],{},"Subprocesses",[496,775,776,781],{},[511,777,778],{},[534,779,780],{},"console",[511,782,783],{},"Web workers",[496,785,786,788],{},[511,787],{},[511,789,790],{},"Persistent storage of any kind",[496,792,793,795],{},[511,794],{},[511,796,797,798,801,802,805,806,809],{},"Engine's stdin, stdout, and stderr. ",[534,799,800],{},"Deno.stdin"," reads nothing, and writes to ",[534,803,804],{},"Deno.stdout"," and ",[534,807,808],{},"Deno.stderr"," are discarded",[458,811,812,813,673],{},"Filesystem, environment, and subprocess calls throw ",[534,814,815],{},"Deno.errors.NotCapable",[817,818,820],"h3",{"id":819},"configuration-not-environment-variables","Configuration, Not Environment Variables",[458,822,823,824,828,829,831,832,835,836,839],{},"A connector gets its settings and credentials from the data source's configuration, never from the environment. The Stripe connector from ",[473,825,827],{"href":826},"\u002Fguides\u002Fdata-connectors\u002Fstripe","Build a Stripe Data Connector"," parses its configuration in ",[534,830,536],{},". Its ",[534,833,834],{},"parseConfig"," throws ",[534,837,838],{},"InvalidConfiguration"," when the configuration is invalid:",[575,841,842,1696],{},[578,843,846],{"className":580,"code":844,"filename":845,"language":583,"meta":584,"style":584},"import { defineDataConnector } from '@monospace\u002Fextension-kit\u002Fdata-connector';\nimport { StripeClient } from '.\u002Fclient';\nimport { schemaDocument } from '.\u002Fcollections';\nimport { parseConfig } from '.\u002Fconfig';\nimport { readMany, readOne } from '.\u002Fread';\nimport { findResource } from '.\u002Fresources';\nimport { create, deleteMany, deleteOne, updateMany, updateOne } from '.\u002Fwrite';\n\nexport default defineDataConnector\u003Cunknown>({\n    setup({ config: rawConfig }) {\n        const config = parseConfig(rawConfig);\n        const context = { client: new StripeClient(config.apiKey), config };\n\n        return {\n            introspect() {\n                return schemaDocument(config.enableWrites);\n            },\n\n            async query({ query }) {\n                \u002F\u002F Engine sends only declared collections, and this connector declares no namespaces.\n                \u002F\u002F For anything else, throw a plain error.\n                const resource = query.namespace === undefined ? findResource(query.collection) : undefined;\n                if (resource === undefined) throw new Error(`Unknown collection \\`${query.collection}\\`.`);\n\n                switch (query.op) {\n                    case 'readMany': return await readMany(context, resource, query);\n                    case 'readOne': return await readOne(context, resource, query);\n                    case 'create': return await create(context, resource, query);\n                    case 'updateMany': return await updateMany(context, resource, query);\n                    case 'updateOne': return await updateOne(context, resource, query);\n                    case 'deleteMany': return await deleteMany(context, resource, query);\n                    case 'deleteOne': return await deleteOne(context, resource, query);\n                    default: {\n                        \u002F\u002F `query` is `never` here, so an operation added to the kit fails to compile until it's handled.\n                        const unhandled: never = query;\n                        throw new Error('The Stripe connector received an operation it doesn\\'t handle.', { cause: unhandled });\n                    }\n                }\n            },\n\n            async testConnection() {\n                await context.client.ping();\n                return { ok: true };\n            },\n        };\n    },\n});\n","✅ read configuration in setup",[534,847,848,864,883,902,920,944,963,1002,1009,1032,1053,1076,1112,1117,1126,1135,1155,1161,1166,1182,1189,1195,1244,1298,1303,1321,1356,1387,1418,1449,1480,1511,1542,1551,1557,1577,1607,1613,1619,1624,1629,1639,1660,1673,1678,1684,1690],{"__ignoreMap":584},[588,849,850,852,854,856,858,860,862],{"class":590,"line":591},[588,851,595],{"class":594},[588,853,599],{"class":598},[588,855,603],{"class":602},[588,857,606],{"class":598},[588,859,609],{"class":594},[588,861,613],{"class":612},[588,863,616],{"class":598},[588,865,867,869,871,874,876,878,881],{"class":590,"line":866},2,[588,868,595],{"class":594},[588,870,599],{"class":598},[588,872,873],{"class":602},"StripeClient",[588,875,606],{"class":598},[588,877,609],{"class":594},[588,879,880],{"class":612}," '.\u002Fclient'",[588,882,616],{"class":598},[588,884,886,888,890,893,895,897,900],{"class":590,"line":885},3,[588,887,595],{"class":594},[588,889,599],{"class":598},[588,891,892],{"class":602},"schemaDocument",[588,894,606],{"class":598},[588,896,609],{"class":594},[588,898,899],{"class":612}," '.\u002Fcollections'",[588,901,616],{"class":598},[588,903,905,907,909,911,913,915,918],{"class":590,"line":904},4,[588,906,595],{"class":594},[588,908,599],{"class":598},[588,910,834],{"class":602},[588,912,606],{"class":598},[588,914,609],{"class":594},[588,916,917],{"class":612}," '.\u002Fconfig'",[588,919,616],{"class":598},[588,921,923,925,927,930,932,935,937,939,942],{"class":590,"line":922},5,[588,924,595],{"class":594},[588,926,599],{"class":598},[588,928,929],{"class":602},"readMany",[588,931,695],{"class":598},[588,933,934],{"class":602},"readOne",[588,936,606],{"class":598},[588,938,609],{"class":594},[588,940,941],{"class":612}," '.\u002Fread'",[588,943,616],{"class":598},[588,945,947,949,951,954,956,958,961],{"class":590,"line":946},6,[588,948,595],{"class":594},[588,950,599],{"class":598},[588,952,953],{"class":602},"findResource",[588,955,606],{"class":598},[588,957,609],{"class":594},[588,959,960],{"class":612}," '.\u002Fresources'",[588,962,616],{"class":598},[588,964,966,968,970,973,975,978,980,983,985,988,990,993,995,997,1000],{"class":590,"line":965},7,[588,967,595],{"class":594},[588,969,599],{"class":598},[588,971,972],{"class":602},"create",[588,974,695],{"class":598},[588,976,977],{"class":602},"deleteMany",[588,979,695],{"class":598},[588,981,982],{"class":602},"deleteOne",[588,984,695],{"class":598},[588,986,987],{"class":602},"updateMany",[588,989,695],{"class":598},[588,991,992],{"class":602},"updateOne",[588,994,606],{"class":598},[588,996,609],{"class":594},[588,998,999],{"class":612}," '.\u002Fwrite'",[588,1001,616],{"class":598},[588,1003,1005],{"class":590,"line":1004},8,[588,1006,1008],{"emptyLinePlaceholder":1007},true,"\n",[588,1010,1012,1015,1018,1022,1025,1029],{"class":590,"line":1011},9,[588,1013,1014],{"class":594},"export",[588,1016,1017],{"class":594}," default",[588,1019,1021],{"class":1020},"ssBNi"," defineDataConnector",[588,1023,1024],{"class":598},"\u003C",[588,1026,1028],{"class":1027},"snHjA","unknown",[588,1030,1031],{"class":598},">({\n",[588,1033,1035,1038,1041,1044,1047,1050],{"class":590,"line":1034},10,[588,1036,1037],{"class":1020},"    setup",[588,1039,1040],{"class":598},"({ ",[588,1042,1043],{"class":594},"config",[588,1045,1046],{"class":598},": ",[588,1048,1049],{"class":594},"rawConfig",[588,1051,1052],{"class":598}," }) {\n",[588,1054,1056,1059,1062,1065,1068,1071,1073],{"class":590,"line":1055},11,[588,1057,1058],{"class":594},"        const",[588,1060,1061],{"class":1020}," config",[588,1063,1064],{"class":594}," =",[588,1066,1067],{"class":1020}," parseConfig",[588,1069,1070],{"class":598},"(",[588,1072,1049],{"class":602},[588,1074,1075],{"class":598},");\n",[588,1077,1079,1081,1084,1086,1089,1092,1095,1097,1099,1101,1104,1107,1109],{"class":590,"line":1078},12,[588,1080,1058],{"class":594},[588,1082,1083],{"class":1020}," context",[588,1085,1064],{"class":594},[588,1087,1088],{"class":598}," { client: ",[588,1090,1091],{"class":594},"new",[588,1093,1094],{"class":1020}," StripeClient",[588,1096,1070],{"class":598},[588,1098,1043],{"class":602},[588,1100,673],{"class":598},[588,1102,1103],{"class":602},"apiKey",[588,1105,1106],{"class":598},"), ",[588,1108,1043],{"class":602},[588,1110,1111],{"class":598}," };\n",[588,1113,1115],{"class":590,"line":1114},13,[588,1116,1008],{"emptyLinePlaceholder":1007},[588,1118,1120,1123],{"class":590,"line":1119},14,[588,1121,1122],{"class":594},"        return",[588,1124,1125],{"class":598}," {\n",[588,1127,1129,1132],{"class":590,"line":1128},15,[588,1130,1131],{"class":1020},"            introspect",[588,1133,1134],{"class":598},"() {\n",[588,1136,1138,1141,1144,1146,1148,1150,1153],{"class":590,"line":1137},16,[588,1139,1140],{"class":594},"                return",[588,1142,1143],{"class":1020}," schemaDocument",[588,1145,1070],{"class":598},[588,1147,1043],{"class":602},[588,1149,673],{"class":598},[588,1151,1152],{"class":602},"enableWrites",[588,1154,1075],{"class":598},[588,1156,1158],{"class":590,"line":1157},17,[588,1159,1160],{"class":598},"            },\n",[588,1162,1164],{"class":590,"line":1163},18,[588,1165,1008],{"emptyLinePlaceholder":1007},[588,1167,1169,1172,1175,1177,1180],{"class":590,"line":1168},19,[588,1170,1171],{"class":594},"            async",[588,1173,1174],{"class":1020}," query",[588,1176,1040],{"class":598},[588,1178,1179],{"class":594},"query",[588,1181,1052],{"class":598},[588,1183,1185],{"class":590,"line":1184},20,[588,1186,1188],{"class":1187},"seNfP","                \u002F\u002F Engine sends only declared collections, and this connector declares no namespaces.\n",[588,1190,1192],{"class":590,"line":1191},21,[588,1193,1194],{"class":1187},"                \u002F\u002F For anything else, throw a plain error.\n",[588,1196,1198,1201,1204,1206,1208,1210,1213,1216,1219,1222,1225,1227,1229,1231,1234,1237,1240,1242],{"class":590,"line":1197},22,[588,1199,1200],{"class":594},"                const",[588,1202,1203],{"class":1020}," resource",[588,1205,1064],{"class":594},[588,1207,1174],{"class":602},[588,1209,673],{"class":598},[588,1211,1212],{"class":602},"namespace",[588,1214,1215],{"class":594}," ===",[588,1217,1218],{"class":1020}," undefined",[588,1220,1221],{"class":594}," ?",[588,1223,1224],{"class":1020}," findResource",[588,1226,1070],{"class":598},[588,1228,1179],{"class":602},[588,1230,673],{"class":598},[588,1232,1233],{"class":602},"collection",[588,1235,1236],{"class":598},") ",[588,1238,1239],{"class":594},":",[588,1241,1218],{"class":1020},[588,1243,616],{"class":598},[588,1245,1247,1250,1253,1256,1258,1260,1262,1265,1268,1271,1273,1276,1279,1282,1284,1286,1288,1291,1293,1296],{"class":590,"line":1246},23,[588,1248,1249],{"class":594},"                if",[588,1251,1252],{"class":598}," (",[588,1254,1255],{"class":602},"resource",[588,1257,1215],{"class":594},[588,1259,1218],{"class":1020},[588,1261,1236],{"class":598},[588,1263,1264],{"class":594},"throw",[588,1266,1267],{"class":594}," new",[588,1269,1270],{"class":1020}," Error",[588,1272,1070],{"class":598},[588,1274,1275],{"class":612},"`Unknown collection ",[588,1277,1278],{"class":1020},"\\`",[588,1280,1281],{"class":612},"${",[588,1283,1179],{"class":602},[588,1285,673],{"class":612},[588,1287,1233],{"class":602},[588,1289,1290],{"class":612},"}",[588,1292,1278],{"class":1020},[588,1294,1295],{"class":612},".`",[588,1297,1075],{"class":598},[588,1299,1301],{"class":590,"line":1300},24,[588,1302,1008],{"emptyLinePlaceholder":1007},[588,1304,1306,1309,1311,1313,1315,1318],{"class":590,"line":1305},25,[588,1307,1308],{"class":594},"                switch",[588,1310,1252],{"class":598},[588,1312,1179],{"class":602},[588,1314,673],{"class":598},[588,1316,1317],{"class":602},"op",[588,1319,1320],{"class":598},") {\n",[588,1322,1324,1327,1330,1332,1335,1338,1341,1343,1346,1348,1350,1352,1354],{"class":590,"line":1323},26,[588,1325,1326],{"class":594},"                    case",[588,1328,1329],{"class":612}," 'readMany'",[588,1331,1046],{"class":598},[588,1333,1334],{"class":594},"return",[588,1336,1337],{"class":594}," await",[588,1339,1340],{"class":1020}," readMany",[588,1342,1070],{"class":598},[588,1344,1345],{"class":602},"context",[588,1347,695],{"class":598},[588,1349,1255],{"class":602},[588,1351,695],{"class":598},[588,1353,1179],{"class":602},[588,1355,1075],{"class":598},[588,1357,1359,1361,1364,1366,1368,1370,1373,1375,1377,1379,1381,1383,1385],{"class":590,"line":1358},27,[588,1360,1326],{"class":594},[588,1362,1363],{"class":612}," 'readOne'",[588,1365,1046],{"class":598},[588,1367,1334],{"class":594},[588,1369,1337],{"class":594},[588,1371,1372],{"class":1020}," readOne",[588,1374,1070],{"class":598},[588,1376,1345],{"class":602},[588,1378,695],{"class":598},[588,1380,1255],{"class":602},[588,1382,695],{"class":598},[588,1384,1179],{"class":602},[588,1386,1075],{"class":598},[588,1388,1390,1392,1395,1397,1399,1401,1404,1406,1408,1410,1412,1414,1416],{"class":590,"line":1389},28,[588,1391,1326],{"class":594},[588,1393,1394],{"class":612}," 'create'",[588,1396,1046],{"class":598},[588,1398,1334],{"class":594},[588,1400,1337],{"class":594},[588,1402,1403],{"class":1020}," create",[588,1405,1070],{"class":598},[588,1407,1345],{"class":602},[588,1409,695],{"class":598},[588,1411,1255],{"class":602},[588,1413,695],{"class":598},[588,1415,1179],{"class":602},[588,1417,1075],{"class":598},[588,1419,1421,1423,1426,1428,1430,1432,1435,1437,1439,1441,1443,1445,1447],{"class":590,"line":1420},29,[588,1422,1326],{"class":594},[588,1424,1425],{"class":612}," 'updateMany'",[588,1427,1046],{"class":598},[588,1429,1334],{"class":594},[588,1431,1337],{"class":594},[588,1433,1434],{"class":1020}," updateMany",[588,1436,1070],{"class":598},[588,1438,1345],{"class":602},[588,1440,695],{"class":598},[588,1442,1255],{"class":602},[588,1444,695],{"class":598},[588,1446,1179],{"class":602},[588,1448,1075],{"class":598},[588,1450,1452,1454,1457,1459,1461,1463,1466,1468,1470,1472,1474,1476,1478],{"class":590,"line":1451},30,[588,1453,1326],{"class":594},[588,1455,1456],{"class":612}," 'updateOne'",[588,1458,1046],{"class":598},[588,1460,1334],{"class":594},[588,1462,1337],{"class":594},[588,1464,1465],{"class":1020}," updateOne",[588,1467,1070],{"class":598},[588,1469,1345],{"class":602},[588,1471,695],{"class":598},[588,1473,1255],{"class":602},[588,1475,695],{"class":598},[588,1477,1179],{"class":602},[588,1479,1075],{"class":598},[588,1481,1483,1485,1488,1490,1492,1494,1497,1499,1501,1503,1505,1507,1509],{"class":590,"line":1482},31,[588,1484,1326],{"class":594},[588,1486,1487],{"class":612}," 'deleteMany'",[588,1489,1046],{"class":598},[588,1491,1334],{"class":594},[588,1493,1337],{"class":594},[588,1495,1496],{"class":1020}," deleteMany",[588,1498,1070],{"class":598},[588,1500,1345],{"class":602},[588,1502,695],{"class":598},[588,1504,1255],{"class":602},[588,1506,695],{"class":598},[588,1508,1179],{"class":602},[588,1510,1075],{"class":598},[588,1512,1514,1516,1519,1521,1523,1525,1528,1530,1532,1534,1536,1538,1540],{"class":590,"line":1513},32,[588,1515,1326],{"class":594},[588,1517,1518],{"class":612}," 'deleteOne'",[588,1520,1046],{"class":598},[588,1522,1334],{"class":594},[588,1524,1337],{"class":594},[588,1526,1527],{"class":1020}," deleteOne",[588,1529,1070],{"class":598},[588,1531,1345],{"class":602},[588,1533,695],{"class":598},[588,1535,1255],{"class":602},[588,1537,695],{"class":598},[588,1539,1179],{"class":602},[588,1541,1075],{"class":598},[588,1543,1545,1548],{"class":590,"line":1544},33,[588,1546,1547],{"class":594},"                    default",[588,1549,1550],{"class":598},": {\n",[588,1552,1554],{"class":590,"line":1553},34,[588,1555,1556],{"class":1187},"                        \u002F\u002F `query` is `never` here, so an operation added to the kit fails to compile until it's handled.\n",[588,1558,1560,1563,1566,1568,1571,1573,1575],{"class":590,"line":1559},35,[588,1561,1562],{"class":594},"                        const",[588,1564,1565],{"class":1020}," unhandled",[588,1567,1239],{"class":594},[588,1569,1570],{"class":1027}," never",[588,1572,1064],{"class":594},[588,1574,1174],{"class":602},[588,1576,616],{"class":598},[588,1578,1580,1583,1585,1587,1589,1592,1595,1598,1601,1604],{"class":590,"line":1579},36,[588,1581,1582],{"class":594},"                        throw",[588,1584,1267],{"class":594},[588,1586,1270],{"class":1020},[588,1588,1070],{"class":598},[588,1590,1591],{"class":612},"'The Stripe connector received an operation it doesn",[588,1593,1594],{"class":1020},"\\'",[588,1596,1597],{"class":612},"t handle.'",[588,1599,1600],{"class":598},", { cause: ",[588,1602,1603],{"class":602},"unhandled",[588,1605,1606],{"class":598}," });\n",[588,1608,1610],{"class":590,"line":1609},37,[588,1611,1612],{"class":598},"                    }\n",[588,1614,1616],{"class":590,"line":1615},38,[588,1617,1618],{"class":598},"                }\n",[588,1620,1622],{"class":590,"line":1621},39,[588,1623,1160],{"class":598},[588,1625,1627],{"class":590,"line":1626},40,[588,1628,1008],{"emptyLinePlaceholder":1007},[588,1630,1632,1634,1637],{"class":590,"line":1631},41,[588,1633,1171],{"class":594},[588,1635,1636],{"class":1020}," testConnection",[588,1638,1134],{"class":598},[588,1640,1642,1645,1647,1649,1652,1654,1657],{"class":590,"line":1641},42,[588,1643,1644],{"class":594},"                await",[588,1646,1083],{"class":602},[588,1648,673],{"class":598},[588,1650,1651],{"class":602},"client",[588,1653,673],{"class":598},[588,1655,1656],{"class":1020},"ping",[588,1658,1659],{"class":598},"();\n",[588,1661,1663,1665,1668,1671],{"class":590,"line":1662},43,[588,1664,1140],{"class":594},[588,1666,1667],{"class":598}," { ok: ",[588,1669,1670],{"class":1020},"true",[588,1672,1111],{"class":598},[588,1674,1676],{"class":590,"line":1675},44,[588,1677,1160],{"class":598},[588,1679,1681],{"class":590,"line":1680},45,[588,1682,1683],{"class":598},"        };\n",[588,1685,1687],{"class":590,"line":1686},46,[588,1688,1689],{"class":598},"    },\n",[588,1691,1693],{"class":590,"line":1692},47,[588,1694,1695],{"class":598},"});\n",[578,1697,1700],{"className":580,"code":1698,"filename":1699,"language":583,"meta":584,"style":584},"const apiKey = Deno.env.get('STRIPE_API_KEY');\n","❌ throws NotCapable",[534,1701,1702],{"__ignoreMap":584},[588,1703,1704,1707,1710,1712,1715,1717,1720,1722,1725,1727,1730],{"class":590,"line":591},[588,1705,1706],{"class":594},"const",[588,1708,1709],{"class":1020}," apiKey",[588,1711,1064],{"class":594},[588,1713,1714],{"class":602}," Deno",[588,1716,673],{"class":598},[588,1718,1719],{"class":602},"env",[588,1721,673],{"class":598},[588,1723,1724],{"class":1020},"get",[588,1726,1070],{"class":598},[588,1728,1729],{"class":612},"'STRIPE_API_KEY'",[588,1731,1075],{"class":598},[817,1733,1735],{"id":1734},"http-through-fetch","HTTP Through fetch",[458,1737,1738,1739,1741,1742,1745,1746,1749,1750,695,1752,1755,1756,1759],{},"Use ",[534,1740,694],{}," for every call to the external data source. It sends a ",[534,1743,1744],{},"Monospace\u002F\u003Cversion>"," user agent unless you set ",[534,1747,1748],{},"User-Agent"," yourself. Engine sets no deadline on ",[534,1751,1179],{},[534,1753,1754],{},"introspect"," or ",[534,1757,1758],{},"testConnection",", so a request that never answers holds the caller's request open until the caller gives up. Give every outgoing request a timeout. It bounds that one request, not the whole operation: a read that pages sends several requests, each with its own deadline.",[458,1761,1762,1763,1766,1767,805,1770,1239],{},"This excerpt from the full Art Institute of Chicago connector, from ",[473,1764,246],{"href":1765},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-source-mapping",", sends one request with a 10-second deadline. It leaves out the imports, the types, and the helpers ",[534,1768,1769],{},"retryAfter",[534,1771,1772],{},"parseSearchResult",[578,1774,1777],{"className":580,"code":1775,"filename":1776,"language":583,"meta":584,"style":584},"const BASE_URL = 'https:\u002F\u002Fapi.artic.edu\u002Fapi\u002Fv1';\n\u002F** Engine sets no deadline on `query` or `testConnection`, so every request carries its own. *\u002F\nconst TIMEOUT_MS = 10_000;\n\u002F\u002F …\n\u002F**\n * Sends one search request, and classifies every failure. Only an error's code and message leave the\n * connector, so the message names the API and the status, never the response body.\n *\u002F\nexport async function search(collection: string, body: SearchBody): Promise\u003CSearchResult> {\n    let response: Response;\n    let text: string;\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            \u002F\u002F The deadline covers reading the body too.\n            signal: AbortSignal.timeout(TIMEOUT_MS),\n        });\n        text = await response.text();\n    }\n    catch (error) {\n        const isTimeout = error instanceof Error && error.name === 'TimeoutError';\n        const reason = isTimeout ? `did not answer within ${TIMEOUT_MS \u002F 1000} seconds` : 'could not be reached';\n        \u002F\u002F Keep the rejection as the `cause`: when the data source's permissions refused the request,\n        \u002F\u002F Engine finds that there and reports a permission error instead of a failed connection.\n        throw new ConnectionFailed(`The Art Institute API ${reason}.`, { cause: error });\n    }\n\n    if (response.status === 429) {\n        throw new RateLimited(`The Art Institute API rate limited the connector.${retryAfter(response)}`);\n    }\n\n    \u002F\u002F Treat a server error as an outage: a later request may work.\n    if (response.status >= 500) {\n        throw new ConnectionFailed(`The Art Institute API answered HTTP ${response.status}.`);\n    }\n\n    \u002F\u002F Any other failed status means the connector sent a request the API refuses.\n    if (!response.ok) {\n        throw new Error(`The Art Institute API answered HTTP ${response.status}.`);\n    }\n\n    return parseSearchResult(text);\n}\n","src\u002Fdata-connectors\u002Fartic\u002Fsearch.ts",[534,1778,1779,1793,1798,1812,1817,1822,1827,1832,1837,1881,1896,1909,1913,1920,1951,1962,1988,2009,2014,2034,2039,2057,2062,2074,2108,2143,2148,2153,2180,2184,2188,2210,2237,2241,2245,2250,2270,2293,2297,2301,2306,2324,2346,2350,2354,2368],{"__ignoreMap":584},[588,1780,1781,1783,1786,1788,1791],{"class":590,"line":591},[588,1782,1706],{"class":594},[588,1784,1785],{"class":1020}," BASE_URL",[588,1787,1064],{"class":594},[588,1789,1790],{"class":612}," 'https:\u002F\u002Fapi.artic.edu\u002Fapi\u002Fv1'",[588,1792,616],{"class":598},[588,1794,1795],{"class":590,"line":866},[588,1796,1797],{"class":1187},"\u002F** Engine sets no deadline on `query` or `testConnection`, so every request carries its own. *\u002F\n",[588,1799,1800,1802,1805,1807,1810],{"class":590,"line":885},[588,1801,1706],{"class":594},[588,1803,1804],{"class":1020}," TIMEOUT_MS",[588,1806,1064],{"class":594},[588,1808,1809],{"class":1020}," 10_000",[588,1811,616],{"class":598},[588,1813,1814],{"class":590,"line":904},[588,1815,1816],{"class":1187},"\u002F\u002F …\n",[588,1818,1819],{"class":590,"line":922},[588,1820,1821],{"class":1187},"\u002F**\n",[588,1823,1824],{"class":590,"line":946},[588,1825,1826],{"class":1187}," * Sends one search request, and classifies every failure. Only an error's code and message leave the\n",[588,1828,1829],{"class":590,"line":965},[588,1830,1831],{"class":1187}," * connector, so the message names the API and the status, never the response body.\n",[588,1833,1834],{"class":590,"line":1004},[588,1835,1836],{"class":1187}," *\u002F\n",[588,1838,1839,1841,1844,1847,1850,1852,1855,1858,1860,1863,1866,1868,1870,1873,1875,1878],{"class":590,"line":1011},[588,1840,1014],{"class":594},[588,1842,1843],{"class":594}," async",[588,1845,1846],{"class":594}," function",[588,1848,1849],{"class":1020}," search",[588,1851,1070],{"class":598},[588,1853,1854],{"class":594},"collection:",[588,1856,1857],{"class":1027}," string",[588,1859,695],{"class":598},[588,1861,1862],{"class":594},"body:",[588,1864,1865],{"class":1020}," SearchBody",[588,1867,715],{"class":598},[588,1869,1239],{"class":594},[588,1871,1872],{"class":1020}," Promise",[588,1874,1024],{"class":598},[588,1876,1877],{"class":1020},"SearchResult",[588,1879,1880],{"class":598},"> {\n",[588,1882,1883,1886,1889,1891,1894],{"class":590,"line":1034},[588,1884,1885],{"class":594},"    let",[588,1887,1888],{"class":602}," response",[588,1890,1239],{"class":594},[588,1892,1893],{"class":1020}," Response",[588,1895,616],{"class":598},[588,1897,1898,1900,1903,1905,1907],{"class":590,"line":1055},[588,1899,1885],{"class":594},[588,1901,1902],{"class":602}," text",[588,1904,1239],{"class":594},[588,1906,1857],{"class":1027},[588,1908,616],{"class":598},[588,1910,1911],{"class":590,"line":1078},[588,1912,1008],{"emptyLinePlaceholder":1007},[588,1914,1915,1918],{"class":590,"line":1114},[588,1916,1917],{"class":594},"    try",[588,1919,1125],{"class":598},[588,1921,1922,1925,1927,1929,1932,1934,1937,1940,1943,1945,1948],{"class":590,"line":1119},[588,1923,1924],{"class":602},"        response",[588,1926,1064],{"class":594},[588,1928,1337],{"class":594},[588,1930,1931],{"class":1020}," fetch",[588,1933,1070],{"class":598},[588,1935,1936],{"class":612},"`${",[588,1938,1939],{"class":1020},"BASE_URL",[588,1941,1942],{"class":612},"}\u002F${",[588,1944,1233],{"class":602},[588,1946,1947],{"class":612},"}\u002Fsearch`",[588,1949,1950],{"class":598},", {\n",[588,1952,1953,1956,1959],{"class":590,"line":1128},[588,1954,1955],{"class":598},"            method: ",[588,1957,1958],{"class":612},"'POST'",[588,1960,1961],{"class":598},",\n",[588,1963,1964,1967,1970,1972,1975,1977,1980,1982,1985],{"class":590,"line":1137},[588,1965,1966],{"class":598},"            headers: { ",[588,1968,1969],{"class":612},"'Content-Type'",[588,1971,1046],{"class":598},[588,1973,1974],{"class":612},"'application\u002Fjson'",[588,1976,695],{"class":598},[588,1978,1979],{"class":612},"'AIC-User-Agent'",[588,1981,1046],{"class":598},[588,1983,1984],{"class":612},"'monospace-artic-connector'",[588,1986,1987],{"class":598}," },\n",[588,1989,1990,1993,1996,1998,2001,2003,2006],{"class":590,"line":1157},[588,1991,1992],{"class":598},"            body: ",[588,1994,1995],{"class":1020},"JSON",[588,1997,673],{"class":598},[588,1999,2000],{"class":1020},"stringify",[588,2002,1070],{"class":598},[588,2004,2005],{"class":602},"body",[588,2007,2008],{"class":598},"),\n",[588,2010,2011],{"class":590,"line":1163},[588,2012,2013],{"class":1187},"            \u002F\u002F The deadline covers reading the body too.\n",[588,2015,2016,2019,2022,2024,2027,2029,2032],{"class":590,"line":1168},[588,2017,2018],{"class":598},"            signal: ",[588,2020,2021],{"class":602},"AbortSignal",[588,2023,673],{"class":598},[588,2025,2026],{"class":1020},"timeout",[588,2028,1070],{"class":598},[588,2030,2031],{"class":1020},"TIMEOUT_MS",[588,2033,2008],{"class":598},[588,2035,2036],{"class":590,"line":1184},[588,2037,2038],{"class":598},"        });\n",[588,2040,2041,2044,2046,2048,2050,2052,2055],{"class":590,"line":1191},[588,2042,2043],{"class":602},"        text",[588,2045,1064],{"class":594},[588,2047,1337],{"class":594},[588,2049,1888],{"class":602},[588,2051,673],{"class":598},[588,2053,2054],{"class":1020},"text",[588,2056,1659],{"class":598},[588,2058,2059],{"class":590,"line":1197},[588,2060,2061],{"class":598},"    }\n",[588,2063,2064,2067,2069,2072],{"class":590,"line":1246},[588,2065,2066],{"class":594},"    catch",[588,2068,1252],{"class":598},[588,2070,2071],{"class":602},"error",[588,2073,1320],{"class":598},[588,2075,2076,2078,2081,2083,2086,2089,2091,2094,2096,2098,2101,2103,2106],{"class":590,"line":1300},[588,2077,1058],{"class":594},[588,2079,2080],{"class":1020}," isTimeout",[588,2082,1064],{"class":594},[588,2084,2085],{"class":602}," error",[588,2087,2088],{"class":594}," instanceof",[588,2090,1270],{"class":1020},[588,2092,2093],{"class":594}," &&",[588,2095,2085],{"class":602},[588,2097,673],{"class":598},[588,2099,2100],{"class":602},"name",[588,2102,1215],{"class":594},[588,2104,2105],{"class":612}," 'TimeoutError'",[588,2107,616],{"class":598},[588,2109,2110,2112,2115,2117,2119,2121,2124,2126,2129,2132,2135,2138,2141],{"class":590,"line":1305},[588,2111,1058],{"class":594},[588,2113,2114],{"class":1020}," reason",[588,2116,1064],{"class":594},[588,2118,2080],{"class":602},[588,2120,1221],{"class":594},[588,2122,2123],{"class":612}," `did not answer within ${",[588,2125,2031],{"class":1020},[588,2127,2128],{"class":594}," \u002F",[588,2130,2131],{"class":1020}," 1000",[588,2133,2134],{"class":612},"} seconds`",[588,2136,2137],{"class":594}," :",[588,2139,2140],{"class":612}," 'could not be reached'",[588,2142,616],{"class":598},[588,2144,2145],{"class":590,"line":1323},[588,2146,2147],{"class":1187},"        \u002F\u002F Keep the rejection as the `cause`: when the data source's permissions refused the request,\n",[588,2149,2150],{"class":590,"line":1358},[588,2151,2152],{"class":1187},"        \u002F\u002F Engine finds that there and reports a permission error instead of a failed connection.\n",[588,2154,2155,2158,2160,2163,2165,2168,2171,2174,2176,2178],{"class":590,"line":1389},[588,2156,2157],{"class":594},"        throw",[588,2159,1267],{"class":594},[588,2161,2162],{"class":1020}," ConnectionFailed",[588,2164,1070],{"class":598},[588,2166,2167],{"class":612},"`The Art Institute API ${",[588,2169,2170],{"class":602},"reason",[588,2172,2173],{"class":612},"}.`",[588,2175,1600],{"class":598},[588,2177,2071],{"class":602},[588,2179,1606],{"class":598},[588,2181,2182],{"class":590,"line":1420},[588,2183,2061],{"class":598},[588,2185,2186],{"class":590,"line":1451},[588,2187,1008],{"emptyLinePlaceholder":1007},[588,2189,2190,2193,2195,2198,2200,2203,2205,2208],{"class":590,"line":1482},[588,2191,2192],{"class":594},"    if",[588,2194,1252],{"class":598},[588,2196,2197],{"class":602},"response",[588,2199,673],{"class":598},[588,2201,2202],{"class":602},"status",[588,2204,1215],{"class":594},[588,2206,2207],{"class":1020}," 429",[588,2209,1320],{"class":598},[588,2211,2212,2214,2216,2219,2221,2224,2226,2228,2230,2232,2235],{"class":590,"line":1513},[588,2213,2157],{"class":594},[588,2215,1267],{"class":594},[588,2217,2218],{"class":1020}," RateLimited",[588,2220,1070],{"class":598},[588,2222,2223],{"class":612},"`The Art Institute API rate limited the connector.${",[588,2225,1769],{"class":1020},[588,2227,1070],{"class":612},[588,2229,2197],{"class":602},[588,2231,715],{"class":612},[588,2233,2234],{"class":612},"}`",[588,2236,1075],{"class":598},[588,2238,2239],{"class":590,"line":1544},[588,2240,2061],{"class":598},[588,2242,2243],{"class":590,"line":1553},[588,2244,1008],{"emptyLinePlaceholder":1007},[588,2246,2247],{"class":590,"line":1559},[588,2248,2249],{"class":1187},"    \u002F\u002F Treat a server error as an outage: a later request may work.\n",[588,2251,2252,2254,2256,2258,2260,2262,2265,2268],{"class":590,"line":1579},[588,2253,2192],{"class":594},[588,2255,1252],{"class":598},[588,2257,2197],{"class":602},[588,2259,673],{"class":598},[588,2261,2202],{"class":602},[588,2263,2264],{"class":594}," >=",[588,2266,2267],{"class":1020}," 500",[588,2269,1320],{"class":598},[588,2271,2272,2274,2276,2278,2280,2283,2285,2287,2289,2291],{"class":590,"line":1609},[588,2273,2157],{"class":594},[588,2275,1267],{"class":594},[588,2277,2162],{"class":1020},[588,2279,1070],{"class":598},[588,2281,2282],{"class":612},"`The Art Institute API answered HTTP ${",[588,2284,2197],{"class":602},[588,2286,673],{"class":612},[588,2288,2202],{"class":602},[588,2290,2173],{"class":612},[588,2292,1075],{"class":598},[588,2294,2295],{"class":590,"line":1615},[588,2296,2061],{"class":598},[588,2298,2299],{"class":590,"line":1621},[588,2300,1008],{"emptyLinePlaceholder":1007},[588,2302,2303],{"class":590,"line":1626},[588,2304,2305],{"class":1187},"    \u002F\u002F Any other failed status means the connector sent a request the API refuses.\n",[588,2307,2308,2310,2312,2315,2317,2319,2322],{"class":590,"line":1631},[588,2309,2192],{"class":594},[588,2311,1252],{"class":598},[588,2313,2314],{"class":594},"!",[588,2316,2197],{"class":602},[588,2318,673],{"class":598},[588,2320,2321],{"class":602},"ok",[588,2323,1320],{"class":598},[588,2325,2326,2328,2330,2332,2334,2336,2338,2340,2342,2344],{"class":590,"line":1641},[588,2327,2157],{"class":594},[588,2329,1267],{"class":594},[588,2331,1270],{"class":1020},[588,2333,1070],{"class":598},[588,2335,2282],{"class":612},[588,2337,2197],{"class":602},[588,2339,673],{"class":612},[588,2341,2202],{"class":602},[588,2343,2173],{"class":612},[588,2345,1075],{"class":598},[588,2347,2348],{"class":590,"line":1662},[588,2349,2061],{"class":598},[588,2351,2352],{"class":590,"line":1675},[588,2353,1008],{"emptyLinePlaceholder":1007},[588,2355,2356,2359,2362,2364,2366],{"class":590,"line":1680},[588,2357,2358],{"class":594},"    return",[588,2360,2361],{"class":1020}," parseSearchResult",[588,2363,1070],{"class":598},[588,2365,2054],{"class":602},[588,2367,1075],{"class":598},[588,2369,2370],{"class":590,"line":1686},[588,2371,2372],{"class":598},"}\n",[2374,2375,2376,2391,2400],"ul",{},[2377,2378,2379,2384,2385,2387,2388,673],"li",{},[468,2380,2381],{},[534,2382,2383],{},"AbortSignal.timeout(TIMEOUT_MS)"," gives the request its deadline. When it passes, ",[534,2386,694],{}," rejects with an error named ",[534,2389,2390],{},"TimeoutError",[2377,2392,2393,2399],{},[468,2394,2395,2396,673],{},"Read the body inside the same ",[534,2397,2398],{},"try"," The signal also aborts reading the body, so the deadline covers the whole response.",[2377,2401,2402,2408,2409,2412,2413,2415,2416,2419,2420,2423,2424,2426,2427,673],{},[468,2403,2404,2405,673],{},"Keep the rejection as the ",[534,2406,2407],{},"cause"," A request to a host outside the data source's grant rejects with an error named ",[534,2410,2411],{},"NotCapable",". Engine looks for it along the thrown error's ",[534,2414,2407],{}," chain, so ",[534,2417,2418],{},"ConnectionFailed"," with ",[534,2421,2422],{},"{ cause: error }"," still reaches the caller as a permissions error, with your message as the innermost one. Without ",[534,2425,2407],{},", the denial reads as a failed connection. See ",[473,2428,2430],{"href":2429},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fpermissions#handle-a-denied-request","Handle a Denied Request",[817,2432,2434],{"id":2433},"logging","Logging",[458,2436,2437,2438,2440,2441,2443],{},"Write logs with ",[534,2439,780],{},". Engine discards stdout and stderr, so anything written there never appears. This logs the status of the ",[534,2442,694],{}," response above:",[575,2445,2446,2476],{},[578,2447,2450],{"className":580,"code":2448,"filename":2449,"language":583,"meta":584,"style":584},"console.info('fetched artworks page', response.status);\n","✅ goes to the Engine log",[534,2451,2452],{"__ignoreMap":584},[588,2453,2454,2456,2458,2461,2463,2466,2468,2470,2472,2474],{"class":590,"line":591},[588,2455,780],{"class":602},[588,2457,673],{"class":598},[588,2459,2460],{"class":1020},"info",[588,2462,1070],{"class":598},[588,2464,2465],{"class":612},"'fetched artworks page'",[588,2467,695],{"class":598},[588,2469,2197],{"class":602},[588,2471,673],{"class":598},[588,2473,2202],{"class":602},[588,2475,1075],{"class":598},[578,2477,2480],{"className":580,"code":2478,"filename":2479,"language":583,"meta":584,"style":584},"await Deno.stdout.write(new TextEncoder().encode('fetched page\\n'));\n","❌ discarded",[534,2481,2482],{"__ignoreMap":584},[588,2483,2484,2487,2489,2491,2494,2496,2499,2501,2503,2506,2509,2512,2514,2517,2520,2523],{"class":590,"line":591},[588,2485,2486],{"class":594},"await",[588,2488,1714],{"class":602},[588,2490,673],{"class":598},[588,2492,2493],{"class":602},"stdout",[588,2495,673],{"class":598},[588,2497,2498],{"class":1020},"write",[588,2500,1070],{"class":598},[588,2502,1091],{"class":594},[588,2504,2505],{"class":1020}," TextEncoder",[588,2507,2508],{"class":598},"().",[588,2510,2511],{"class":1020},"encode",[588,2513,1070],{"class":598},[588,2515,2516],{"class":612},"'fetched page",[588,2518,2519],{"class":1020},"\\n",[588,2521,2522],{"class":612},"'",[588,2524,2525],{"class":598},"));\n",[458,2527,2528,2529,2531,2532,2535,2536,2539,2540,2543],{},"Every ",[534,2530,780],{}," call lands in the Engine log at info level, tagged with the data source and the connector id. Engine also exposes ",[534,2533,2534],{},"monospace.log(message, fields)",". It logs ",[534,2537,2538],{},"fields"," as JSON in a single ",[534,2541,2542],{},"params"," attribute instead of formatting them into the message.",[817,2545,2547],{"id":2546},"no-persistence","No Persistence",[458,2549,2550,2551,2553,2554,2556],{},"The worker has nowhere to store data. Keep API clients, tokens, and caches in variables that ",[534,2552,536],{}," creates, like the Stripe connector's ",[534,2555,1345],{}," above. Expect to rebuild them after a restart.",[458,2558,2559],{},"Writing to disk throws instead:",[578,2561,2563],{"className":580,"code":2562,"filename":1699,"language":583,"meta":584,"style":584},"await Deno.writeTextFile('.\u002Fcursor.json', JSON.stringify({ offset: 100 }));\n",[534,2564,2565],{"__ignoreMap":584},[588,2566,2567,2569,2571,2573,2576,2578,2581,2583,2585,2587,2589,2592,2595],{"class":590,"line":591},[588,2568,2486],{"class":594},[588,2570,1714],{"class":602},[588,2572,673],{"class":598},[588,2574,2575],{"class":1020},"writeTextFile",[588,2577,1070],{"class":598},[588,2579,2580],{"class":612},"'.\u002Fcursor.json'",[588,2582,695],{"class":598},[588,2584,1995],{"class":1020},[588,2586,673],{"class":598},[588,2588,2000],{"class":1020},[588,2590,2591],{"class":598},"({ offset: ",[588,2593,2594],{"class":1020},"100",[588,2596,2597],{"class":598}," }));\n",[454,2599,2601],{"id":2600},"network-access","Network Access",[458,2603,2604],{},"A worker reaches only the hosts its data source was granted. An empty grant means no network at all.",[458,2606,2607],{},"The connector declares the hosts it needs in two places:",[2374,2609,2610,2628],{},[2377,2611,2612,2615,2616,2619,2620,2623,2624,2627],{},[468,2613,2614],{},"Fixed hosts"," go in ",[534,2617,2618],{},"extension.config.json"," as ",[534,2621,2622],{},"net:"," permissions with a reason (e.g., ",[534,2625,2626],{},"net:api.stripe.com",").",[2377,2629,2630,2633,2634,673],{},[468,2631,2632],{},"Hosts that depend on configuration",", such as a configurable base URL, come from the connector's optional ",[534,2635,2636],{},"preflight",[458,2638,2639,2640,2642,2643,2645,2646,2648,2649,2652,2653,2656],{},"Whoever creates the data source approves the combined set. A ",[534,2641,694],{}," to any other host rejects with Deno's ",[534,2644,2411],{}," error, and so does a redirect from a granted host to one outside the grant. Keep it as the ",[534,2647,2407],{}," when you wrap it, as ",[473,2650,1735],{"href":2651},"#http-through-fetch"," shows. See ",[473,2654,432],{"href":2655},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fpermissions"," for the format and the approval flow.",[454,2658,2660],{"id":2659},"data-source-lifecycle","Data Source Lifecycle",[458,2662,2663],{},"Engine starts a data source's worker when it first needs it. Every start walks the same sequence, from load to setup. Connection tests and schema previews start a temporary worker of their own, with the same sequence.",[2665,2666,2667,2671,2674,2677,2694,2698,2704,2707,2717,2721],"steps",{},[817,2668,2670],{"id":2669},"load","Load",[458,2672,2673],{},"Engine evaluates the connector file. Code at module scope runs here, under the load timeout, with the network permissions the data source was granted. Keep network calls out of module scope: this step runs before the permission check, so a call to a host the sent grant lacks fails the start before Engine can report the permissions the connector requires.",[817,2675,2676],{"id":2636},"Preflight",[458,2678,2679,2680,2683,2684,2686,2687,2689,2690,673],{},"If the connector defines ",[534,2681,2682],{},"preflight({ config })",", Engine calls it to collect the network permissions the configuration implies. ",[534,2685,2636],{}," is synchronous and returns permissions only. It has no timeout of its own: a ",[534,2688,2636],{}," that blocks falls under the ",[473,2691,2693],{"href":2692},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Flimits#liveness-check","liveness check",[817,2695,2697],{"id":2696},"permission-check","Permission Check",[458,2699,2700,2701,2703],{},"Engine compares the data source's granted permissions with the manifest's permissions plus those from ",[534,2702,2636],{},". The two sets must contain exactly the same hosts, ports, and wildcards. Reasons aren't compared. If the sets differ in either direction, the worker stops here.",[817,2705,2706],{"id":536},"Setup",[458,2708,2709,2710,2713,2714,2716],{},"Engine calls ",[534,2711,2712],{},"setup({ config })"," under the setup timeout. ",[534,2715,536],{}," validates the configuration, builds the client for the external data source, and returns the handlers.",[817,2718,2720],{"id":2719},"serve","Serve",[458,2722,2723,2724,2727,2728,2731,2732,2735,2736,2738,2739,2742,2743,2745,2746,2749,2750,2753],{},"Once set up, the worker answers calls on demand. Engine calls ",[534,2725,2726],{},"introspect()"," when it needs the schema, such as when a data source is created, previewed, or reintrospected. It calls ",[534,2729,2730],{},"query(request)"," for each operation. It calls the optional ",[534,2733,2734],{},"testConnection()"," when a connection test is requested, and before it creates a data source or previews a schema: a ",[534,2737,1758],{}," that throws or answers ",[534,2740,2741],{},"{ ok: false }"," stops both. Without ",[534,2744,1758],{},", a connection test answers ",[534,2747,2748],{},"422"," with code ",[534,2751,2752],{},"7002",", and creating a data source still works.",[458,2755,2756,2758],{},[534,2757,536],{}," runs once per worker, not once per request. Anything it creates is shared by every request that worker serves.",[817,2760,266],{"id":2761},"configuration",[458,2763,2764,2765,2767,2768,673],{},"A data source's configuration is the JSON object you enter when you create it. In Studio, that's a raw JSON editor. Through the REST API, it's the request's ",[534,2766,1043],{}," object, sent next to the approved ",[534,2769,2770],{},"permissions",[490,2772,2773,2781],{},[493,2774,2775],{},[496,2776,2777,2779],{},[499,2778,501],{},[499,2780,504],{},[506,2782,2783,2797,2805],{},[496,2784,2785,2788],{},[511,2786,2787],{},"Validation",[511,2789,2790,2791,2793,2794,2796],{},"Engine doesn't validate configuration. The connector parses it in ",[534,2792,536],{}," and throws ",[534,2795,838],{}," when it's wrong",[496,2798,2799,2802],{},[511,2800,2801],{},"Storage",[511,2803,2804],{},"Engine stores the configuration and the granted permissions encrypted",[496,2806,2807,2810],{},[511,2808,2809],{},"Changes",[511,2811,2812,2813,2817],{},"No API updates an existing data source's configuration or permissions. ",[473,2814,2816],{"href":2815},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-sources#recreate-a-data-source","Recreate the data source"," to change them",[817,2819,2821],{"id":2820},"restarts-and-failures","Restarts and Failures",[490,2823,2824,2834],{},[493,2825,2826],{},[496,2827,2828,2831],{},[499,2829,2830],{},"Event",[499,2832,2833],{},"What happens",[506,2835,2836,2847,2855,2878,2888],{},[496,2837,2838,2841],{},[511,2839,2840],{},"The worker crashes or stops responding",[511,2842,2843,2844,2846],{},"Requests in flight fail. With none in flight, the first request sent to it fails. The next request starts a new worker, and ",[534,2845,536],{}," runs again. Failed requests aren't replayed",[496,2848,2849,2852],{},[511,2850,2851],{},"A new worker is starting",[511,2853,2854],{},"Other requests to the data source fail instead of waiting",[496,2856,2857,2875],{},[511,2858,2859,835,2861,1755,2863,2866,2867,2869,2870,1755,2872,2874],{},[534,2860,536],{},[534,2862,838],{},[534,2864,2865],{},"AccessDenied",", a request it sends is refused by the data source's permissions (uncaught, or kept as the ",[534,2868,2407],{},"), or it returns no ",[534,2871,1754],{},[534,2873,1179],{}," handler",[511,2876,2877],{},"The data source stays stopped until the extension is reloaded",[496,2879,2880,2886],{},[511,2881,2882,2883,2885],{},"The file fails to load, ",[534,2884,2636],{}," returns malformed permissions, or the granted permissions don't match the required ones",[511,2887,2877],{},[496,2889,2890,2899],{},[511,2891,2892,2893,2895,2896,2898],{},"Loading or ",[534,2894,536],{}," times out, or ",[534,2897,536],{}," throws another kit error class or a plain error",[511,2900,2901],{},"The request fails, and the next request tries to start the worker again",[458,2903,2904],{},"The table describes a data source's own worker. A connection test or schema preview runs in a temporary worker, so a failure there, including one that deactivates it, doesn't affect the data source or the next test.",[458,2906,2907,2908,2910,2911,695,2913,1755,2915,2917,2918,2922,2923,2926,2927,2930,2931,2933],{},"A thrown error inside ",[534,2909,1179],{}," fails that request only. A ",[534,2912,934],{},[534,2914,992],{},[534,2916,982],{}," that finds no matching ",[473,2919,2921],{"href":2920},"\u002Fconcepts\u002Fdata-model#collections","item"," (a single data object in a collection) answers ",[534,2924,2925],{},"{ record: null }"," instead of throwing. Unhandled promise rejections are logged and don't stop the worker. A rejection message longer than 4,096 UTF-16 code units is cut there and ends with ",[534,2928,2929],{},"…",". ",[534,2932,780],{}," output isn't cut.",[458,2935,2936,2937,2941,2942,695,2944,1755,2946,2948,2949,2952,2953,2956,2957,673],{},"A handler that resolves can still fail the request. Engine checks the answer after the handler returns: an item missing a ",[473,2938,2940],{"href":2939},"\u002Fconcepts\u002Fdata-model#fields","field"," the request selects, a value Engine can't convert to its field type, or a ",[534,2943,934],{},[534,2945,992],{},[534,2947,982],{}," that answers ",[534,2950,2951],{},"records"," instead of ",[534,2954,2955],{},"record"," fails the request. For a write, the external data source has already applied the change, and Engine can't roll it back. See ",[473,2958,2960],{"href":2959},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fapi#answer-a-query","Answer a Query",[454,2962,2964],{"id":2963},"install-and-reload","Install and Reload",[458,2966,2967,2968,2973],{},"Engine loads connector code from the extensions in its install location, at startup and, with ",[2969,2970],"env-var",{"name":2971,"section":2972},"extensions__auto_reload","extensions"," on, whenever an installed extension changes. After a reload, each data source whose entry id is still in the new build switches to the new code on the next request that reaches its connector. A data source whose entry was removed or renamed keeps running the old code until its worker restarts.",[458,2975,2976,2977,2981,2982,2985,2986,2990,2991,2995,2996,2999],{},"A reload swaps code only. Each data source keeps the schema it was created with, its configuration, its granted permissions, and the ",[473,2978,2980],{"href":2979},"\u002Freference\u002Fextensions\u002Fmanifest#capabilities","query capabilities"," its workspace was built with. A reloaded build that changes the entry's capabilities deactivates its existing data sources: requests that reach their connector fail with ",[534,2983,2984],{},"503"," until the instance restarts or the workspace is rebuilt. See ",[473,2987,2989],{"href":2988},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Foperations#when-the-capabilities-change","When the Capabilities Change",". See ",[473,2992,2994],{"href":2993},"\u002Fdeveloper\u002Fextensions\u002Fdata-connectors\u002Fdata-sources#update-data-sources-after-an-extension-update","Update Data Sources After an Extension Update"," for what to do after each kind of change, and ",[473,2997,227],{"href":2998},"\u002Fdeveloper\u002Fextensions\u002Finstall"," for the install location and reload settings.",[454,3001,3003],{"id":3002},"see-also","See Also",[2374,3005,3006,3011,3016,3026,3033],{},[2377,3007,3008,3010],{},[473,3009,563],{"href":562},": timeouts and other hard numbers",[2377,3012,3013,3015],{},[473,3014,432],{"href":2655},": declare and approve the hosts a connector reaches",[2377,3017,3018,1046,3021,695,3023,3025],{},[473,3019,410],{"href":3020},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Fapi",[534,3022,2636],{},[534,3024,536],{},", and the handlers",[2377,3027,3028,3032],{},[473,3029,3031],{"href":3030},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Ferrors","Data Connector Errors",": the error classes and when to throw them",[2377,3034,3035,3039],{},[473,3036,3038],{"href":3037},"\u002Freference\u002Fextensions\u002Fdata-connectors\u002Flimitations","Data Connector Limitations",": what a connector can't do today",[3041,3042,3043],"style",{},"html pre.shiki code .sLVBU, html code.shiki .sLVBU{--shiki-light:#0891B2;--shiki-default:#0891B2;--shiki-dark:#22D3EE}html pre.shiki code .sTMul, html code.shiki .sTMul{--shiki-light:#1F2937;--shiki-default:#1F2937;--shiki-dark:#94A3B8}html pre.shiki code .sNJ9c, html code.shiki .sNJ9c{--shiki-light:#24292E;--shiki-default:#24292E;--shiki-dark:#E2E8F0}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 .ssBNi, html code.shiki .ssBNi{--shiki-light:#1659E9;--shiki-default:#1659E9;--shiki-dark:#94B3F5}html pre.shiki code .snHjA, html code.shiki .snHjA{--shiki-light:#124BC4;--shiki-default:#124BC4;--shiki-dark:#5B8EF4}html pre.shiki code .seNfP, html code.shiki .seNfP{--shiki-light:#64748B;--shiki-default:#64748B;--shiki-dark:#94A3B8}",{"title":584,"searchDepth":866,"depth":866,"links":3045},[3046,3047,3048,3049,3055,3056,3065,3066],{"id":456,"depth":866,"text":143},{"id":487,"depth":866,"text":488},{"id":566,"depth":866,"text":567},{"id":658,"depth":866,"text":659,"children":3050},[3051,3052,3053,3054],{"id":819,"depth":885,"text":820},{"id":1734,"depth":885,"text":1735},{"id":2433,"depth":885,"text":2434},{"id":2546,"depth":885,"text":2547},{"id":2600,"depth":866,"text":2601},{"id":2659,"depth":866,"text":2660,"children":3057},[3058,3059,3060,3061,3062,3063,3064],{"id":2669,"depth":885,"text":2670},{"id":2636,"depth":885,"text":2676},{"id":2696,"depth":885,"text":2697},{"id":536,"depth":885,"text":2706},{"id":2719,"depth":885,"text":2720},{"id":2761,"depth":885,"text":266},{"id":2820,"depth":885,"text":2821},{"id":2963,"depth":866,"text":2964},{"id":3002,"depth":866,"text":3003},"Learn where data connector code runs, what it can use, how it reaches the network, and how data sources start, reload, and restart.","md",null,{},{"icon":240},{"title":237,"description":3067},"tgDPiEZ0qJtEXQt7bMAP3L9v2MdEVsApGLiMaDKC630",[3075,3077],{"title":143,"path":232,"stem":233,"description":3076,"icon":114,"children":-1},"Understand how data connector extensions serve live queries, what their operations contract promises, and whether your external data source fits.",{"title":242,"path":243,"stem":244,"description":3078,"icon":42,"children":-1},"Learn how to create, update, recreate, and delete the data sources that use a data connector extension.",1790840121662]