1"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[716],{228388:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>d,contentTitle:()=>i,default:()=>p,frontMatter:()=>o,metadata:()=>c,toc:()=>u});var r=t(785893),s=t(511151),l=t(374866),a=t(685162);const o={title:"Compatability",description:"Understand what environments the Tableland SDK supports.",keywords:["node polyfills","node fetch","ethers","nodejs"]},i=void 0,c={id:"sdk/reference/compatability",title:"Compatability",description:"Understand what environments the Tableland SDK supports.",source:"@site/docs/sdk/reference/compatability.md",sourceDirName:"sdk/reference",slug:"/sdk/reference/compatability",permalink:"/sdk/reference/compatability",draft:!1,unlisted:!1,editUrl:"https://github.com/tablelandnetwork/docs/tree/main/docs/sdk/reference/compatability.md",tags:[],version:"current",lastUpdatedBy:"Dan Buchholz",lastUpdatedAt:1715119661e3,frontMatter:{title:"Compatability",description:"Understand what environments the Tableland SDK supports.",keywords:["node polyfills","node fetch","ethers","nodejs"]},sidebar:"sdk",previous:{title:"Type conversion",permalink:"/sdk/reference/type-conversion"}},d={},u=[{value:"Synopsis",id:"synopsis",level:2},{value:"Build systems",id:"build-systems",level:2},{value:"Node polyfills",id:"node-polyfills",level:2},{value:"Installation",id:"installation",level:3},{value:"Add the polyfill",id:"add-the-polyfill",level:3}];function h(e){const n={a:"a",code:"code",h2:"h2",h3:"h3",li:"li",p:"p",pre:"pre",ul:"ul",...(0,s.a)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsx)(n.p,{children:"The Tableland SDK has certain dependencies and requirements that you'll need to be aware of before you can use it in your project. This page provides a reference for what you can use and some workarounds, where applicable."}),"\n",(0,r.jsx)(n.h2,{id:"synopsis",children:"Synopsis"}),"\n",(0,r.jsxs)(n.p,{children:["The ",(0,r.jsx)(n.code,{children:"@tableland/sdk"})," can support the following environments or dependencies:"]}),"\n",(0,r.jsxs)(n.ul,{children:["\n",(0,r.jsx)(n.li,{children:"Node.js 18.x+."}),"\n",(0,r.jsx)(n.li,{children:"Both ESM and CommonJS modules are supported."}),"\n",(0,r.jsxs)(n.li,{children:[(0,r.jsx)(n.code,{children:"ethers"})," v6.x, specifically, ",(0,r.jsx)(n.code,{children:"[email protected]"}),"."]}),"\n"]}),"\n",(0,r.jsx)(n.h2,{id:"build-systems",children:"Build systems"}),"\n",(0,r.jsxs)(n.p,{children:["The Tableland SDK uses an optimized WASM build of our ",(0,r.jsx)(n.a,{href:"/sdk/walkthroughs/sql-parser",children:"SQL parser"})," under the hood. Unfortunately, some build systems such as ",(0,r.jsx)(n.a,{href:"https://vitejs.dev",children:"Vite"})," require an adjustment to their configuration to support this feature. To temporarily work around this issue, simply add ",(0,r.jsx)(n.code,{children:"@tableland/sqlparser"})," to the ",(0,r.jsx)(n.code,{children:"excluded"})," list under ",(0,r.jsx)(n.code,{children:"optimizeDeps"})," in your ",(0,r.jsx)(n.code,{children:"vite.config.ts"})," file:"]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-ts",metastring:'title="vite.config.ts"',children:'// ...\noptimizeDeps: {\n exclude: ["@tableland/sqlparser"];\n}\n// ...\n'})}),"\n",(0,r.jsx)(n.h2,{id:"node-polyfills",children:"Node polyfills"}),"\n",(0,r.jsxs)(n.p,{children:["The Tableland SDK makes use of the ",(0,r.jsx)(n.code,{children:"fetch"})," API as well as ",(0,r.jsx)(n.code,{children:"Headers"}),". If you're using a version of Node that came before the current ",(0,r.jsx)(n.a,{href:"https://github.com/nodejs/release#release-schedule",children:"LTS"})," 18.x version. Any version prior to Node 18 might need to implement polyfills."]}),"\n",(0,r.jsx)(n.h3,{id:"installation",children:"Installation"}),"\n",(0,r.jsxs)(n.p,{children:["To use a polyfill, you'll first need to install ",(0,r.jsx)(n.a,{href:"https://github.com/node-fetch/node-fetch",children:(0,r.jsx)(n.code,{children:"node-fetch"})}),"."]}),"\n",(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-npm2yarn",children:"npm install node-fetch\n"})}),"\n",(0,r.jsxs)(n.p,{children:["Starting with ",(0,r.jsx)(n.code,{children:"node-fetch"})," v3, it is an ESM-only module; you are not able to import it with ",(0,r.jsx)(n.code,{children:"require()"}),". If you cannot switch to ESM and need CommonJS (CJS) support, you could use v2 (",(0,r.jsx)(n.code,{children:"node-fetch@2"}),")\u2014or choose to use an async ",(0,r.jsx)(n.code,{children:"import()"}),"."]}),"\n",(0,r.jsx)(n.h3,{id:"add-the-polyfill",children:"Add the polyfill"}),"\n",(0,r.jsxs)(n.p,{children:["In your source file, import ",(0,r.jsx)(n.code,{children:"fetch"}),", ",(0,r.jsx)(n.code,{children:"Headers"}),", ",(0,r.jsx)(n.code,{children:"Request"}),", and ",(0,r.jsx)(n.code,{children:"Response"})," from ",(0,r.jsx)(n.code,{children:"node-fetch"}),". Then, you'll patch the global object in Node (",(0,r.jsx)(n.a,{href:"https://developer.mozilla.org/en-US/docs/Glossary/Global_object",children:(0,r.jsx)(n.code,{children:"globalThis"})}
1),"), thus, enabling Tableland SDK compatability."]}),"\n",(0,r.jsxs)(l.Z,{children:[(0,r.jsx)(a.Z,{value:"esm",label:"ESM",default:!0,children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'import fetch, { Headers, Request, Response } from "node-fetch";\n\nif (!globalThis.fetch) {\n globalThis.fetch = fetch;\n globalThis.Headers = Headers;\n globalThis.Request = Request;\n globalThis.Response = Response;\n}\n'})})}),(0,r.jsx)(a.Z,{value:"cjs",label:"CJS",children:(0,r.jsx)(n.pre,{children:(0,r.jsx)(n.code,{className:"language-js",children:'const fetch = (...args) =>\n import("node-fetch").then(({ default: fetch }) => fetch(...args));\n'})})})]}),"\n",(0,r.jsxs)(n.p,{children:["Note that if you're using TypeScript, you can just declare ",(0,r.jsx)(n.code,{children:"globalThis as any"})," in the ESM example declarations above (i.e., add a type to all of the references to ",(0,r.jsx)(n.code,{children:"globalThis"}),")."]})]})}function p(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,r.jsx)(n,{...e,children:(0,r.jsx)(h,{...e})}):h(e)}},685162:(e,n,t)=>{t.d(n,{Z:()=>a});t(667294);var r=t(490512);const s={tabItem:"tabItem_Ymn6"};var l=t(785893);function a(e){let{children:n,hidden:t,className:a}=e;return(0,l.jsx)("div",{role:"tabpanel",className:(0,r.Z)(s.tabItem,a),hidden:t,children:n})}},374866:(e,n,t)=>{t.d(n,{Z:()=>T});var r=t(667294),s=t(490512),l=t(212466),a=t(616550),o=t(120469),i=t(191980),c=t(867392),d=t(20812);function u(e){return r.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,r.isValidElement)(e)&&function(e){const{props:n}=e;return!!n&&"object"==typeof n&&"value"in n}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function h(e){const{values:n,children:t}=e;return(0,r.useMemo)((()=>{const e=n??function(e){return u(e).map((e=>{let{props:{value:n,label:t,attributes:r,default:s}}=e;return{value:n,label:t,attributes:r,default:s}}))}(t);return function(e){const n=(0,c.l)(e,((e,n)=>e.value===n.value));if(n.length>0)throw new Error(`Docusaurus error: Duplicate values "${n.map((e=>e.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e}),[n,t])}function p(e){let{value:n,tabValues:t}=e;return t.some((e=>e.value===n))}function f(e){let{queryString:n=!1,groupId:t}=e;const s=(0,a.k6)(),l=function(e){let{queryString:n=!1,groupId:t}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!t)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return t??null}({queryString:n,groupId:t});return[(0,i._X)(l),(0,r.useCallback)((e=>{if(!l)return;const n=new URLSearchParams(s.location.search);n.set(l,e),s.replace({...s.location,search:n.toString()})}),[l,s])]}function m(e){const{defaultValue:n,queryString:t=!1,groupId:s}=e,l=h(e),[a,i]=(0,r.useState)((()=>function(e){let{defaultValue:n,tabValues:t}=e;if(0===t.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(n){if(!p({value:n,tabValues:t}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${t.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const r=t.find((e=>e.default))??t[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:n,tabValues:l}))),[c,u]=f({queryString:t,groupId:s}),[m,b]=function(e){let{groupId:n}=e;const t=function(e){return e?`docusaurus.tab.${e}`:null}(n),[s,l]=(0,d.Nk)(t);return[s,(0,r.useCallback)((e=>{t&&l.set(e)}),[t,l])]}({groupId:s}),y=(()=>{const e=c??m;return p({value:e,tabValues:l})?e:null})();(0,o.Z)((()=>{y&&i(y)}),[y]);return{selectedValue:a,selectValue:(0,r.useCallback)((e=>{if(!p({value:e,tabValues:l}))throw new Error(`Can't select invalid tab value=${e}`);i(e),u(e),b(e)}),[u,b,l]),tabValues:l}}var b=t(972389);const y={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var j=t(785893);function x(e){let{className:n,block:t,selectedValue:r,selectValue:a,tabValues:o}=e;const i=[],{blockElementScrollPositionUntilNextRender:c}=(0,l.o5)(),d=e=>{const n=e.currentTarget,t=i.indexOf(n),s=o[t].value;s!==r&&(c(n),a(s))},u=e=>{let n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const t=i.indexOf(e.currentTarget)+1;n=i[t]??i[0];break}case"ArrowLeft":{const t=i.indexOf(e.currentTarget)-1;n=i[t]??i[i.length-1];break}}n?.focus()};return(0,j.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.Z)("tabs",{"tabs--block":t},n),children:o.map((e=>{let{value:n,label:t,attributes:l}=e;return(0,j.jsx)("li",{role:"tab",tabIndex:r===n?0:-1,"aria-selected":r===n,ref:e=>i.push(e),onKeyDown:u,onClick:d,...l,className:(0,s.Z)("tabs__item",y.tabItem,l?.className,{"tabs__item--active":r===n}),children:t??n},n)}))})}function v(e){let{lazy:n,children:t,selectedValue:s}=e;
1const l=(Array.isArray(t)?t:[t]).filter(Boolean);if(n){const e=l.find((e=>e.props.value===s));return e?(0,r.cloneElement)(e,{className:"margin-top--md"}):null}return(0,j.jsx)("div",{className:"margin-top--md",children:l.map(((e,n)=>(0,r.cloneElement)(e,{key:n,hidden:e.props.value!==s})))})}function g(e){const n=m(e);return(0,j.jsxs)("div",{className:(0,s.Z)("tabs-container",y.tabList),children:[(0,j.jsx)(x,{...n,...e}),(0,j.jsx)(v,{...n,...e})]})}function T(e){const n=(0,b.Z)();return(0,j.jsx)(g,{...e,children:u(e.children)},String(n))}},511151:(e,n,t)=>{t.d(n,{Z:()=>o,a:()=>a});var r=t(667294);const s={},l=r.createContext(s);function a(e){const n=r.useContext(l);return r.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function o(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),r.createElement(l.Provider,{value:n},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.