diff --git a/404.html b/404.html index 885e1e99..4f335e08 100644 --- a/404.html +++ b/404.html @@ -13,7 +13,7 @@ - + diff --git a/assets/js/50ac8df9.3f905d6d.js b/assets/js/50ac8df9.300fecc8.js similarity index 98% rename from assets/js/50ac8df9.3f905d6d.js rename to assets/js/50ac8df9.300fecc8.js index 11e86e1a..f3be5553 100644 --- a/assets/js/50ac8df9.3f905d6d.js +++ b/assets/js/50ac8df9.300fecc8.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5180],{13146:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>r,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>a});var o=t(11527),i=t(63883);const s={},l="Relations",c={id:"composedb/guides/data-modeling/relations",title:"Relations",description:"Define queryable relationships between models and other models or accounts.",source:"@site/docs/composedb/guides/data-modeling/relations.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/relations",permalink:"/docs/composedb/guides/data-modeling/relations",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Schemas",permalink:"/docs/composedb/guides/data-modeling/schemas"},next:{title:"Composites",permalink:"/docs/composedb/guides/data-modeling/composites"}},r={},a=[{value:"Types of Relations",id:"types-of-relations",level:2},{value:"Account to Model",id:"account-to-model",level:2},{value:"Example: Simple Profile",id:"example-simple-profile",level:3},{value:"Model to Account",id:"model-to-account",level:2},{value:"Example: Direct message (DM)",id:"example-direct-message-dm",level:3},{value:"Model to Model",id:"model-to-model",level:2},{value:"Example: Post with comments and likes",id:"example-post-with-comments-and-likes",level:3},{value:"Using interfaces",id:"using-interfaces",level:3},{value:"Account to Account",id:"account-to-account",level:2},{value:"Next Steps",id:"next-steps",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"relations",children:"Relations"}),"\n",(0,o.jsx)(n.p,{children:"Define queryable relationships between models and other models or accounts."}),"\n",(0,o.jsx)(n.h2,{id:"types-of-relations",children:"Types of Relations"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"There are a few primary forms of relations currently supported by ComposeDB:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-model",children:"Account to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-account",children:"Model to account relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-model",children:"Model to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-account",children:"Account to account relations"})}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-model",children:"Account to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Account to model relations enable linking and querying data to the account that created it. By default the ",(0,o.jsx)(n.code,{children:"@createmodel"})," directive (used when creating a new model) requires that every model must specify a relation to its author\u2019s account. This was covered in ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"}),"."]}),"\n",(0,o.jsx)(n.h3,{id:"example-simple-profile",children:"Example: Simple Profile"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a very simple user profile that can be queried based on the author:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Define simple profile model\n# Relate it to the author\'s account\n# Limit to one profile per account\n# Enable queries based on author\n\ntype SimpleProfile @createModel(accountRelation: SINGLE, description: "Very basic profile") {\n displayName: String! @string(minLength: 3, maxLength: 50)\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the profile to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"SINGLE"})," limits to one profile per account"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-account",children:"Model to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Model to account relations enable you to link data to and query data from an account other than the data\u2019s author. When using this type of relation, you need to define a model field that stores an account (e.g. a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/composedb-client/user-sessions",children:"DID"}),"), then add the ",(0,o.jsx)(n.code,{children:"@accountReference"})," directive to make it queryable."]}),"\n",(0,o.jsx)(n.h3,{id:"example-direct-message-dm",children:"Example: Direct message (DM)"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a user-to-user message that can be queried based on the recipient:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:"# Define message model\n# Relate it to author's account\n# Allow unlimited sent messages\n# Store reference to recipient's account\n# Enable queries based on recipient\n\ntype Message @createModel(accountRelation: LIST, description: \"Direct message model\") {\n recipient: DID! @accountReference\n directMessage: String! @string(minLength: 1, maxLength: 200)\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the message to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"LIST"})," allows unlimited messages"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"recipient"})," references the recipient\u2019s account by storing its ",(0,o.jsx)(n.code,{children:"DID!"}),", using ",(0,o.jsx)(n.code,{children:"@accountReference"})]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-model",children:"Model to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"Model to model relations enable you to link data to and query data from another piece of data. These relations can be uni-directional (e.g. query a post from a comment) or bi-directional (e.g. query a post from a comment and query all comments from a post)."}),"\n",(0,o.jsxs)(n.p,{children:["There is type of model-to-model relation that includes the user as part of the relationship. This is achieved by using the ",(0,o.jsx)(n.code,{children:"SET"})," account relation type, which allows users to enforce a constraint where each user account (or DID) can create only one instance of a model for a specific record of another model."]}),"\n",(0,o.jsx)(n.h3,{id:"example-post-with-comments-and-likes",children:"Example: Post with comments and likes"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model that allows many comments from the same or different account to be made on a single post. It supports unlimited comments per user, and bi-directional queries from any comment or like to the original post and from the original post to all of its comments and likes. The model schema also creates a relation between posts and likes enabling a single like per post by an account, meaning a single account will only be able to like the post once"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load post model (using streamID)\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96") {\n id: ID!\n}\n\n# New comment model\n# Set reference to original post\n# Enable querying comment to get original post\n\ntype Comment @createModel(accountRelation: LIST, description: "A comment on a Post") {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n text: String! @string(maxLength: 500)\n}\n\n# New like model\n# Set relationship to original post\n# Enable querying comment to get original post\ntype Like @createModel(description: "A like on a post", accountRelation: SET, accountRelationFields: ["postID"]) {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Relations can also be created between models loaded from known streamIDs"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load comment model\n\ntype Comment @loadModel(id: "kjzl6hvfrbw6c9oo2ync09y6z5c9mas9u49lfzcowepuzxmcn3pzztvzd0c7gh0") {\n id: ID!\n}\n\n# Load post model\n# Extend post model with comments and likes\n# Set relationships to all comments and likes\n# Enable querying post to get all comments and likes\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96") {\n comments: [Comment] @relationFrom(model: "Comment", property: "postID")\n likes: [Like] @relationFrom(model: "Like", property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"id"})," is a simple placeholder, since empty types are not allowed"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"postID"})," defines the relationship from a comment to the original post, using ",(0,o.jsx)(n.code,{children:"@documentReference"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"post"})," allows accessing the original post from the comment, using ",(0,o.jsx)(n.code,{children:"@relationDocument"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"text"})," defines a string for the comment"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"comments"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Comment"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"likes"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Like"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"using-interfaces",children:"Using interfaces"}),"\n",(0,o.jsx)(n.p,{children:"When defining relations, it is possible to reference model interfaces to allow for a wider range of documents in the relations set, for example to create a collection of documents using different models implementing the same interface:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'interface TextContent @createModel(description: "Required text content interface") {\n text: String! @string(maxLength: 10000)\n}\n\ntype Page implements TextContent @createModel(description: "Page model") {\n title: String @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n}\n\ntype Post implements TextContent @createModel(description: "Post model") {\n title: String! @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n createdAt: DateTime!\n}\n\ntype ContentCollectionItem\n @createModel(description: "Association between a collection and an item") {\n # The Node interface is used here instead of ContentCollection, see warning below\n collectionID: StreamID! @documentReference(model: "Node")\n collection: Node! @relationDocument(property: "collectionID")\n itemID: StreamID! @documentReference(model: "TextContent")\n item: TextContent! @relationDocument(property: "itemID")\n}\n\ntype ContentCollection @createModel(description: "Collection of text contents") {\n name: String @string(maxLength: 50)\n items: [ContentCollectionItem]!\n @relationFrom(model: "ContentCollectionItem", property: "collectionID")\n}\n'})}),"\n",(0,o.jsxs)(n.admonition,{title:"Circular references",type:"caution",children:[(0,o.jsxs)(n.p,{children:["ComposeDB does not support creating relations with circular references, such as ",(0,o.jsx)(n.code,{children:"ContentCollection"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollection"})," in the example above."]}),(0,o.jsxs)(n.p,{children:["To work around this limitation, it is possible to use the ",(0,o.jsx)(n.code,{children:"Node"})," interface as a placeholder for any model. The example above uses the ",(0,o.jsx)(n.code,{children:"Node"})," interface instead of ",(0,o.jsx)(n.code,{children:"ContentCollection"})," to reference the collection in the ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," in order to avoid creating a circular reference."]})]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-account",children:"Account to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsx)(n.p,{children:"Account to account relations are on the roadmap, but not yet supported."})}),"\n",(0,o.jsx)(n.p,{children:"Account to account relations enable you to define a relationship between an account and a different account, and query both ways based on that relationship. This is useful for creating structures such as social graphs where the relationship represents a follow."}),"\n",(0,o.jsx)(n.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Now that you understand the fundamentals of creating models with different types of relations, let's create a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/composites",children:(0,o.jsx)(n.strong,{children:"composite"})})," so we can use it in our app."]})]})}function m(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},63883:(e,n,t)=>{t.d(n,{Z:()=>c,a:()=>l});var o=t(50959);const i={},s=o.createContext(i);function l(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[5180],{13146:(e,n,t)=>{t.r(n),t.d(n,{assets:()=>r,contentTitle:()=>l,default:()=>m,frontMatter:()=>s,metadata:()=>c,toc:()=>a});var o=t(11527),i=t(63883);const s={},l="Relations",c={id:"composedb/guides/data-modeling/relations",title:"Relations",description:"Define queryable relationships between models and other models or accounts.",source:"@site/docs/composedb/guides/data-modeling/relations.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/relations",permalink:"/docs/composedb/guides/data-modeling/relations",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Schemas",permalink:"/docs/composedb/guides/data-modeling/schemas"},next:{title:"Composites",permalink:"/docs/composedb/guides/data-modeling/composites"}},r={},a=[{value:"Types of Relations",id:"types-of-relations",level:2},{value:"Account to Model",id:"account-to-model",level:2},{value:"Example: Simple Profile",id:"example-simple-profile",level:3},{value:"Model to Account",id:"model-to-account",level:2},{value:"Example: Direct message (DM)",id:"example-direct-message-dm",level:3},{value:"Model to Model",id:"model-to-model",level:2},{value:"Example: Post with comments and likes",id:"example-post-with-comments-and-likes",level:3},{value:"Using interfaces",id:"using-interfaces",level:3},{value:"Account to Account",id:"account-to-account",level:2},{value:"Next Steps",id:"next-steps",level:2}];function d(e){const n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.a)(),...e.components};return(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"relations",children:"Relations"}),"\n",(0,o.jsx)(n.p,{children:"Define queryable relationships between models and other models or accounts."}),"\n",(0,o.jsx)(n.h2,{id:"types-of-relations",children:"Types of Relations"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"There are a few primary forms of relations currently supported by ComposeDB:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-model",children:"Account to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-account",children:"Model to account relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#model-to-model",children:"Model to model relations"})}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"#account-to-account",children:"Account to account relations"})}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-model",children:"Account to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Account to model relations enable linking and querying data to the account that created it. By default the ",(0,o.jsx)(n.code,{children:"@createmodel"})," directive (used when creating a new model) requires that every model must specify a relation to its author\u2019s account. This was covered in ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"}),"."]}),"\n",(0,o.jsx)(n.h3,{id:"example-simple-profile",children:"Example: Simple Profile"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a very simple user profile that can be queried based on the author:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Define simple profile model\n# Relate it to the author\'s account\n# Limit to one profile per account\n# Enable queries based on author\n\ntype SimpleProfile @createModel(accountRelation: SINGLE, description: "Very basic profile") {\n displayName: String! @string(minLength: 3, maxLength: 50)\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the profile to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"SINGLE"})," limits to one profile per account"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-account",children:"Model to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Model to account relations enable you to link data to and query data from an account other than the data\u2019s author. When using this type of relation, you need to define a model field that stores an account (e.g. a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/composedb-client/user-sessions",children:"DID"}),"), then add the ",(0,o.jsx)(n.code,{children:"@accountReference"})," directive to make it queryable."]}),"\n",(0,o.jsx)(n.h3,{id:"example-direct-message-dm",children:"Example: Direct message (DM)"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model for a user-to-user message that can be queried based on the recipient:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:"# Define message model\n# Relate it to author's account\n# Allow unlimited sent messages\n# Store reference to recipient's account\n# Enable queries based on recipient\n\ntype Message @createModel(accountRelation: LIST, description: \"Direct message model\") {\n recipient: DID! @accountReference\n directMessage: String! @string(minLength: 1, maxLength: 200)\n}\n"})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"accountRelation"})," relates the message to the author\u2019s account"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"LIST"})," allows unlimited messages"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"recipient"})," references the recipient\u2019s account by storing its ",(0,o.jsx)(n.code,{children:"DID!"}),", using ",(0,o.jsx)(n.code,{children:"@accountReference"})]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"model-to-model",children:"Model to Model"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.p,{children:"Model to model relations enable you to link data to and query data from another piece of data. These relations can be uni-directional (e.g. query a post from a comment) or bi-directional (e.g. query a post from a comment and query all comments from a post)."}),"\n",(0,o.jsxs)(n.p,{children:["There is type of model-to-model relation that includes the user as part of the relationship. This is achieved by using the ",(0,o.jsx)(n.code,{children:"SET"})," account relation type, which allows users to enforce a constraint where each user account (or DID) can create only one instance of a model for a specific record of another model."]}),"\n",(0,o.jsx)(n.h3,{id:"example-post-with-comments-and-likes",children:"Example: Post with comments and likes"}),"\n",(0,o.jsx)(n.p,{children:"Here\u2019s a model that allows many comments from the same or different account to be made on a single post. It supports unlimited comments per user, and bi-directional queries from any comment or like to the original post and from the original post to all of its comments and likes. The model schema also creates a relation between posts and likes enabling a single like per post by an account, meaning a single account will only be able to like the post once"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load post model (using streamID)\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy") {\n id: ID!\n}\n\n# New comment model\n# Set reference to original post\n# Enable querying comment to get original post\n\ntype Comment @createModel(accountRelation: LIST, description: "A comment on a Post") {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n text: String! @string(maxLength: 500)\n}\n\n# New like model\n# Set relationship to original post\n# Enable querying comment to get original post\ntype Like @createModel(description: "A like on a post", accountRelation: SET, accountRelationFields: ["postID"]) {\n postID: StreamID! @documentReference(model: "Post")\n post: Post! @relationDocument(property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Relations can also be created between models loaded from known streamIDs"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'# Load comment model\n\ntype Comment @loadModel(id: "kjzl6hvfrbw6c9oo2ync09y6z5c9mas9u49lfzcowepuzxmcn3pzztvzd0c7gh0") {\n id: ID!\n}\n\n# Load post model\n# Extend post model with comments and likes\n# Set relationships to all comments and likes\n# Enable querying post to get all comments and likes\n\ntype Post @loadModel(id: "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy") {\n comments: [Comment] @relationFrom(model: "Comment", property: "postID")\n likes: [Like] @relationFrom(model: "Like", property: "postID")\n}\n'})}),"\n",(0,o.jsx)(n.p,{children:"Where:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"id"})," is a simple placeholder, since empty types are not allowed"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"postID"})," defines the relationship from a comment to the original post, using ",(0,o.jsx)(n.code,{children:"@documentReference"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"post"})," allows accessing the original post from the comment, using ",(0,o.jsx)(n.code,{children:"@relationDocument"})]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"text"})," defines a string for the comment"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"comments"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Comment"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"likes"})," defines the relationships from a post to a collection of comments, using ",(0,o.jsx)(n.code,{children:"@relationFrom"}),"; requires specifying the model relation (",(0,o.jsx)(n.code,{children:"Like"}),") and the specific property that stores the relation (",(0,o.jsx)(n.code,{children:"postID"}),")"]}),"\n"]}),"\n",(0,o.jsx)(n.h3,{id:"using-interfaces",children:"Using interfaces"}),"\n",(0,o.jsx)(n.p,{children:"When defining relations, it is possible to reference model interfaces to allow for a wider range of documents in the relations set, for example to create a collection of documents using different models implementing the same interface:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-graphql",children:'interface TextContent @createModel(description: "Required text content interface") {\n text: String! @string(maxLength: 10000)\n}\n\ntype Page implements TextContent @createModel(description: "Page model") {\n title: String @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n}\n\ntype Post implements TextContent @createModel(description: "Post model") {\n title: String! @string(maxLength: 100)\n text: String! @string(maxLength: 10000)\n createdAt: DateTime!\n}\n\ntype ContentCollectionItem\n @createModel(description: "Association between a collection and an item") {\n # The Node interface is used here instead of ContentCollection, see warning below\n collectionID: StreamID! @documentReference(model: "Node")\n collection: Node! @relationDocument(property: "collectionID")\n itemID: StreamID! @documentReference(model: "TextContent")\n item: TextContent! @relationDocument(property: "itemID")\n}\n\ntype ContentCollection @createModel(description: "Collection of text contents") {\n name: String @string(maxLength: 50)\n items: [ContentCollectionItem]!\n @relationFrom(model: "ContentCollectionItem", property: "collectionID")\n}\n'})}),"\n",(0,o.jsxs)(n.admonition,{title:"Circular references",type:"caution",children:[(0,o.jsxs)(n.p,{children:["ComposeDB does not support creating relations with circular references, such as ",(0,o.jsx)(n.code,{children:"ContentCollection"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," -> ",(0,o.jsx)(n.code,{children:"ContentCollection"})," in the example above."]}),(0,o.jsxs)(n.p,{children:["To work around this limitation, it is possible to use the ",(0,o.jsx)(n.code,{children:"Node"})," interface as a placeholder for any model. The example above uses the ",(0,o.jsx)(n.code,{children:"Node"})," interface instead of ",(0,o.jsx)(n.code,{children:"ContentCollection"})," to reference the collection in the ",(0,o.jsx)(n.code,{children:"ContentCollectionItem"})," in order to avoid creating a circular reference."]})]}),"\n",(0,o.jsx)(n.h2,{id:"account-to-account",children:"Account to Account"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsx)(n.p,{children:"Account to account relations are on the roadmap, but not yet supported."})}),"\n",(0,o.jsx)(n.p,{children:"Account to account relations enable you to define a relationship between an account and a different account, and query both ways based on that relationship. This is useful for creating structures such as social graphs where the relationship represents a follow."}),"\n",(0,o.jsx)(n.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsxs)(n.p,{children:["Now that you understand the fundamentals of creating models with different types of relations, let's create a ",(0,o.jsx)(n.a,{href:"/docs/composedb/guides/data-modeling/composites",children:(0,o.jsx)(n.strong,{children:"composite"})})," so we can use it in our app."]})]})}function m(e={}){const{wrapper:n}={...(0,i.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(d,{...e})}):d(e)}},63883:(e,n,t)=>{t.d(n,{Z:()=>c,a:()=>l});var o=t(50959);const i={},s=o.createContext(i);function l(e){const n=o.useContext(s);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function c(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:l(e.components),o.createElement(s.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9501b78f.4ee046de.js b/assets/js/9501b78f.4ee046de.js deleted file mode 100644 index 67ccf1a0..00000000 --- a/assets/js/9501b78f.4ee046de.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4533],{41608:(e,o,s)=>{s.r(o),s.d(o,{assets:()=>d,contentTitle:()=>c,default:()=>u,frontMatter:()=>a,metadata:()=>l,toc:()=>m});var n=s(11527),t=s(63883),i=s(37421),r=s(81779);const a={},c="Composites",l={id:"composedb/guides/data-modeling/composites",title:"Composites",description:"Guides for creating, deploying, and using composites.",source:"@site/docs/composedb/guides/data-modeling/composites.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/composites",permalink:"/docs/composedb/guides/data-modeling/composites",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Relations",permalink:"/docs/composedb/guides/data-modeling/relations"},next:{title:"ComposeDB Client",permalink:"/docs/composedb/guides/composedb-client/"}},d={},m=[{value:"Overview",id:"overview",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Basic Usage",id:"basic-usage",level:2},{value:"Creating composites",id:"creating-composites",level:3},{value:"Deploying composites",id:"deploying-composites",level:3},{value:"Compiling composites",id:"compiling-composites",level:3},{value:"Advanced",id:"advanced",level:2},{value:"Merging composites",id:"merging-composites",level:3},{value:"Extracting composites",id:"extracting-composites",level:3},{value:"Inspecting composites",id:"inspecting-composites",level:3},{value:"Aliasing composites",id:"aliasing-composites",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Related Guides",id:"related-guides",level:2}];function p(e){const o={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(o.h1,{id:"composites",children:"Composites"}),"\n",(0,n.jsx)(o.p,{children:"Guides for creating, deploying, and using composites."}),"\n",(0,n.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsx)(o.p,{children:"In order to start using a model in your app, you\u2019ll have to include it in a composite. Composites are collections of one or more models and represent the complete GraphQL schema for your app. For basic usage, follow these steps:"}),"\n",(0,n.jsxs)(o.ol,{children:["\n",(0,n.jsx)(o.li,{children:"Create a composite containing one or more models"}),"\n",(0,n.jsx)(o.li,{children:"Deploy the composite to your ComposeDB server"}),"\n",(0,n.jsx)(o.li,{children:"Compile the composite for usage by your ComposeDB client"}),"\n"]}),"\n",(0,n.jsx)(o.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsxs)(o.ul,{children:["\n",(0,n.jsx)(o.li,{children:"If you want to manage your composites from the CLI, you will need to have it installed"}),"\n",(0,n.jsxs)(o.li,{children:["If you want to manage your composites from JavaScript, you will need to install the\xa0",(0,n.jsx)(o.a,{href:"https://composedb.js.org/docs/0.5.x/api/modules/devtools",children:(0,n.jsx)(o.code,{children:"@composedb/devtools"})}),"\xa0library"]}),"\n",(0,n.jsxs)(o.li,{children:["One or more ",(0,n.jsx)(o.code,{children:".graphql"})," files containing your models"]}),"\n"]}),"\n",(0,n.jsx)(o.h2,{id:"basic-usage",children:"Basic Usage"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsx)(o.h3,{id:"creating-composites",children:"Creating composites"}),"\n",(0,n.jsxs)(o.p,{children:["Let\u2019s say you have a model written in a ",(0,n.jsx)(o.code,{children:"my-schema.graphql"})," file. To convert this schema into a composite, run the following:"]}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:create my-schema.graphql --output=my-composite.json --did-private-key=your-private-key\n"})})}),(0,n.jsx)(r.Z,{value:"js",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { DID } from 'dids'\nimport { Ed25519Provider } from 'key-did-provider-ed25519'\nimport { getResolver } from 'key-did-resolver'\nimport { fromString } from 'uint8arrays/from-string'\n\n// Import the devtool node package\nimport { createComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\n// Hexadecimal-encoded private key for a DID having admin access to the target Ceramic node\n// Replace the example key here by your admin private key\nconst privateKey = fromString('b0cb[...]515f', 'base16')\n\nconst did = new DID({\n resolver: getResolver(),\n provider: new Ed25519Provider(privateKey),\n})\nawait did.authenticate()\n\n// Replace by the URL of the Ceramic node you want to deploy the Models to\nconst ceramic = new CeramicClient('http://localhost:7007')\n// An authenticated DID with admin access must be set on the Ceramic instance\nceramic.did = did\n\n// Replace by the path to the source schema file\nconst composite = await createComposite(ceramic, './source-schema.graphql')\n\n// Replace by the path to the encoded composite file\nawait writeEncodedComposite(composite, './my-composite.json')\n"})})})]}),"\n",(0,n.jsxs)(o.p,{children:["This will create a file called ",(0,n.jsx)(o.code,{children:"my-composite.json"})," which contains the composite in JSON."]}),"\n",(0,n.jsx)(o.h3,{id:"deploying-composites",children:"Deploying composites"}),"\n",(0,n.jsx)(o.p,{children:"After creating the composite, deploy it to your local node:"}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:deploy my-composite.json --ceramic-url=http://localhost:7007 --did-private-key=your-private-key\n"})})}),(0,n.jsx)(r.Z,{value:"js",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { DID } from 'dids'\nimport { Ed25519Provider } from 'key-did-provider-ed25519'\nimport { getResolver } from 'key-did-resolver'\nimport { fromString } from 'uint8arrays/from-string'\n\nimport { readEncodedComposite } from '@composedb/devtools-node'\n\n// Hexadecimal-encoded private key for a DID having admin access to the target Ceramic node\n// Replace the example key here by your admin private key\nconst privateKey = fromString('b0cb[...]515f', 'base16')\n\nconst did = new DID({\n resolver: getResolver(),\n provider: new Ed25519Provider(privateKey),\n})\nawait did.authenticate()\n\n// Replace by the URL of the Ceramic node you want to deploy the Models to\nconst ceramic = new CeramicClient('http://localhost:7007')\n// An authenticated DID with admin access must be set on the Ceramic instance\nceramic.did = did\n\n// Replace by the path to the local encoded composite file\nconst composite = await readEncodedComposite(ceramic, 'my-first-composite.json')\n\n// Notify the Ceramic node to index the models present in the composite\nawait composite.startIndexingOn(ceramic)\n"})})})]}),"\n",(0,n.jsx)(o.admonition,{type:"tip",children:(0,n.jsxs)(o.p,{children:["This will also automatically add all models contained in the composite to the ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"}),"."]})}),"\n",(0,n.jsx)(o.h3,{id:"compiling-composites",children:"Compiling composites"}),"\n",(0,n.jsxs)(o.p,{children:["After deploying your composite, compile it so you can start perform ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-interactions/",children:"data interactions"})," using the ComposeDB client."]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:compile my-first-composite.json runtime-composite.json\n"})}),"\n",(0,n.jsx)(o.h2,{id:"advanced",children:"Advanced"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsx)(o.h3,{id:"merging-composites",children:"Merging composites"}),"\n",(0,n.jsx)(o.p,{children:"If you have more than one composite, you need to merge them into a single composite for use in your app. This may apply when:"}),"\n",(0,n.jsxs)(o.ul,{children:["\n",(0,n.jsxs)(o.li,{children:["You want to use multiple models from the ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog#using-multiple-models",children:"catalog"})]}),"\n",(0,n.jsx)(o.li,{children:"You want to use a model from the catalog and one or more models you created"}),"\n",(0,n.jsx)(o.li,{children:"You create multiple models and store their schemas in different GraphQL files"}),"\n"]}),"\n",(0,n.jsxs)(o.p,{children:["Let\u2019s say you have two composites where ",(0,n.jsx)(o.code,{children:"simple-profile-composite.json"})," contains the model for a profile model and ",(0,n.jsx)(o.code,{children:"post-composite.json"})," contains the model for a post. To merge, reference both composite JSON files and specify an output file path for the merged composite."]}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:merge simple-profile-composite.json post-composite.json --output=merged-composite.json\n"})})}),(0,n.jsxs)(r.Z,{value:"js",children:[(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\n\nconst loadSources = [\n 'simple-profile-composite.json',\n 'post-composite.json',\n].map(async (path) => await readEncodedComposite(ceramic, path))\nconst sourceComposites = await Promise.all(loadSources)\nconst mergedComposite = Composite.from(sourceComposites)\n\nawait writeEncodedComposite(mergedComposite, 'merged-composite.json')\n"})}),(0,n.jsxs)(o.admonition,{type:"caution",children:[(0,n.jsxs)(o.p,{children:[(0,n.jsx)(o.em,{children:(0,n.jsx)(o.strong,{children:"Note:"})})," To run the code above, you need a Ceramic JS HTTP client library installed on your machine to connect your app to a Ceramic node. Ceramic JS HTTP client can be installed by running the following command:"]}),(0,n.jsx)(o.p,{children:(0,n.jsx)(o.code,{children:"pnpm install @ceramicnetwork/http-client"})})]})]})]}),"\n",(0,n.jsxs)(o.p,{children:["The output of either example is a new file named ",(0,n.jsx)(o.code,{children:"merged-composite.json"})," which contains the models of both merged composites. From here you need to ",(0,n.jsx)(o.a,{href:"#deploying-composites",children:"deploy"})," the composite to your node, then ",(0,n.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it."]}),"\n",(0,n.jsx)(o.h3,{id:"extracting-composites",children:"Extracting composites"}),"\n",(0,n.jsx)(o.p,{children:"In cases where your composite contain models not needed by your application, or in other cases where you generally want to separate models in your composite, you can extract models into a separate composite."}),"\n",(0,n.jsxs)(o.p,{children:["As an example, let\u2019s reuse the ",(0,n.jsx)(o.code,{children:"merged-composite.json"})," file from the previous section and assume you want to extract the profile model into a separate composite. To do this, load the ",(0,n.jsx)(o.code,{children:"merged-composite.json"})," file and specify which model(s) you\u2019d like to extract into a new composite file."]}),"\n",(0,n.jsxs)(i.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,n.jsx)(r.Z,{value:"cli",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-bash",children:"composedb composite:extract-model merged-composite.json kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc --output=new-composite.json\n"})})}),(0,n.jsx)(r.Z,{value:"js",children:(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\nconst sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')\n\nconst mergedComposite = sourceComposite.copy(['kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc'])\nawait writeEncodedComposite(mergedComposite, 'new-composite.json')\n"})})})]}),"\n",(0,n.jsxs)(o.p,{children:["This will create a file called ",(0,n.jsx)(o.code,{children:"new-composite.json"})," with your profile model in it. From here you need to deploy the composite to your node, then ",(0,n.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it."]}),"\n",(0,n.jsx)(o.h3,{id:"inspecting-composites",children:"Inspecting composites"}),"\n",(0,n.jsx)(o.p,{children:"If you want to check what models are included in a specific composite, follow the steps below:"}),"\n",(0,n.jsxs)(o.ol,{children:["\n",(0,n.jsxs)(o.li,{children:["\n",(0,n.jsxs)(o.p,{children:["Compile the composite:\n",(0,n.jsx)(o.code,{children:"composedb composite:compile my-first-composite.json runtime-composite.json"})]}),"\n"]}),"\n",(0,n.jsxs)(o.li,{children:["\n",(0,n.jsxs)(o.p,{children:["View the GraphQL schema of the composite:\n",(0,n.jsx)(o.a,{href:"https://composedb.js.org/docs/0.5.x/api/commands/cli.graphql",children:(0,n.jsx)(o.code,{children:"composedb graphql:schema runtime-composite.json --output=schema.graphql"})})]}),"\n"]}),"\n"]}),"\n",(0,n.jsx)(o.h3,{id:"aliasing-composites",children:"Aliasing composites"}),"\n",(0,n.jsx)(o.p,{children:"In general, models are referenced using their unique model streamIDs which are not memorable. Models can be more easily referenced by aliasing them to your preferred names."}),"\n",(0,n.jsxs)(o.p,{children:["To manually set aliases for your models, add the following section to your composite JSON file. In this case we will use the aliases ",(0,n.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,n.jsx)(o.code,{children:"Post"}),"."]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:'"aliases":{\n "kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc":"SimpleProfile",\n "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96":"Post"\n }\n'})}),"\n",(0,n.jsxs)(o.p,{children:["To do aliases programmatically, use the ComposeDB Devtools library. Here\u2019s an example script that loads a composite JSON file and assigns ",(0,n.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,n.jsx)(o.code,{children:"Post"}),":"]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\nconst sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')\n\nconst newComposite = sourceComposite.setAliases({\n 'kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc': 'SimpleProfile',\n 'kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96': 'Post',\n})\nawait writeEncodedComposite(newComposite, 'new-composite.json')\n"})}),"\n",(0,n.jsxs)(o.p,{children:["This script will create a file named ",(0,n.jsx)(o.code,{children:"new-composite.json"})," including model aliases:"]}),"\n",(0,n.jsx)(o.pre,{children:(0,n.jsx)(o.code,{className:"language-jsx",children:'"aliases":{\n "kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc":"SimpleProfile",\n "kjzl6hvfrbw6c99mdfpjx1z3fue7sesgua6gsl1vu97229lq56344zu9bawnf96":"Post"\n }\n'})}),"\n",(0,n.jsxs)(o.p,{children:["From here you need to ",(0,n.jsx)(o.a,{href:"#deploying-composites",children:"deploy"})," the composite to your node, then ",(0,n.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it. When interacting with the models inside your app, you can refer to them using their human-readable aliases rather than their streamIDs."]}),"\n",(0,n.jsx)(o.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsxs)(o.p,{children:["Set up your ",(0,n.jsx)(o.a,{href:"/docs/composedb/guides/composedb-client/",children:(0,n.jsx)(o.strong,{children:"ComposeDB Client"})})]}),"\n",(0,n.jsx)(o.h2,{id:"related-guides",children:"Related Guides"}),"\n",(0,n.jsx)(o.hr,{}),"\n",(0,n.jsxs)(o.ul,{children:["\n",(0,n.jsx)(o.li,{children:(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"})}),"\n",(0,n.jsx)(o.li,{children:(0,n.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"})}),"\n"]})]})}function u(e={}){const{wrapper:o}={...(0,t.a)(),...e.components};return o?(0,n.jsx)(o,{...e,children:(0,n.jsx)(p,{...e})}):p(e)}},81779:(e,o,s)=>{s.d(o,{Z:()=>r});s(50959);var n=s(45924);const t={tabItem:"tabItem_e7Wc"};var i=s(11527);function r(e){let{children:o,hidden:s,className:r}=e;return(0,i.jsx)("div",{role:"tabpanel",className:(0,n.Z)(t.tabItem,r),hidden:s,children:o})}},37421:(e,o,s)=>{s.d(o,{Z:()=>w});var n=s(50959),t=s(45924),i=s(71988),r=s(28903),a=s(739),c=s(99965),l=s(43251),d=s(76698);function m(e){return n.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,n.isValidElement)(e)&&function(e){const{props:o}=e;return!!o&&"object"==typeof o&&"value"in o}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function p(e){const{values:o,children:s}=e;return(0,n.useMemo)((()=>{const e=o??function(e){return m(e).map((e=>{let{props:{value:o,label:s,attributes:n,default:t}}=e;return{value:o,label:s,attributes:n,default:t}}))}(s);return function(e){const o=(0,l.l)(e,((e,o)=>e.value===o.value));if(o.length>0)throw new Error(`Docusaurus error: Duplicate values "${o.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[o,s])}function u(e){let{value:o,tabValues:s}=e;return s.some((e=>e.value===o))}function h(e){let{queryString:o=!1,groupId:s}=e;const t=(0,r.k6)(),i=function(e){let{queryString:o=!1,groupId:s}=e;if("string"==typeof o)return o;if(!1===o)return null;if(!0===o&&!s)throw new Error('Docusaurus error: The 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 s??null}({queryString:o,groupId:s});return[(0,c._X)(i),(0,n.useCallback)((e=>{if(!i)return;const o=new URLSearchParams(t.location.search);o.set(i,e),t.replace({...t.location,search:o.toString()})}),[i,t])]}function g(e){const{defaultValue:o,queryString:s=!1,groupId:t}=e,i=p(e),[r,c]=(0,n.useState)((()=>function(e){let{defaultValue:o,tabValues:s}=e;if(0===s.length)throw new Error("Docusaurus error: the component requires at least one children component");if(o){if(!u({value:o,tabValues:s}))throw new Error(`Docusaurus error: The has a defaultValue "${o}" but none of its children has the corresponding value. Available values are: ${s.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return o}const n=s.find((e=>e.default))??s[0];if(!n)throw new Error("Unexpected error: 0 tabValues");return n.value}({defaultValue:o,tabValues:i}))),[l,m]=h({queryString:s,groupId:t}),[g,f]=function(e){let{groupId:o}=e;const s=function(e){return e?`docusaurus.tab.${e}`:null}(o),[t,i]=(0,d.Nk)(s);return[t,(0,n.useCallback)((e=>{s&&i.set(e)}),[s,i])]}({groupId:t}),j=(()=>{const e=l??g;return u({value:e,tabValues:i})?e:null})();(0,a.Z)((()=>{j&&c(j)}),[j]);return{selectedValue:r,selectValue:(0,n.useCallback)((e=>{if(!u({value:e,tabValues:i}))throw new Error(`Can't select invalid tab value=${e}`);c(e),m(e),f(e)}),[m,f,i]),tabValues:i}}var f=s(12049);const j={tabList:"tabList_c3am",tabItem:"tabItem_iDuG"};var x=s(11527);function v(e){let{className:o,block:s,selectedValue:n,selectValue:r,tabValues:a}=e;const c=[],{blockElementScrollPositionUntilNextRender:l}=(0,i.o5)(),d=e=>{const o=e.currentTarget,s=c.indexOf(o),t=a[s].value;t!==n&&(l(o),r(t))},m=e=>{let o=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const s=c.indexOf(e.currentTarget)+1;o=c[s]??c[0];break}case"ArrowLeft":{const s=c.indexOf(e.currentTarget)-1;o=c[s]??c[c.length-1];break}}o?.focus()};return(0,x.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,t.Z)("tabs",{"tabs--block":s},o),children:a.map((e=>{let{value:o,label:s,attributes:i}=e;return(0,x.jsx)("li",{role:"tab",tabIndex:n===o?0:-1,"aria-selected":n===o,ref:e=>c.push(e),onKeyDown:m,onClick:d,...i,className:(0,t.Z)("tabs__item",j.tabItem,i?.className,{"tabs__item--active":n===o}),children:s??o},o)}))})}function b(e){let{lazy:o,children:s,selectedValue:t}=e;const i=(Array.isArray(s)?s:[s]).filter(Boolean);if(o){const e=i.find((e=>e.props.value===t));return e?(0,n.cloneElement)(e,{className:"margin-top--md"}):null}return(0,x.jsx)("div",{className:"margin-top--md",children:i.map(((e,o)=>(0,n.cloneElement)(e,{key:o,hidden:e.props.value!==t})))})}function y(e){const o=g(e);return(0,x.jsxs)("div",{className:(0,t.Z)("tabs-container",j.tabList),children:[(0,x.jsx)(v,{...e,...o}),(0,x.jsx)(b,{...e,...o})]})}function w(e){const o=(0,f.Z)();return(0,x.jsx)(y,{...e,children:m(e.children)},String(o))}},63883:(e,o,s)=>{s.d(o,{Z:()=>a,a:()=>r});var n=s(50959);const t={},i=n.createContext(t);function r(e){const o=n.useContext(i);return n.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function a(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:r(e.components),n.createElement(i.Provider,{value:o},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/9501b78f.a765143f.js b/assets/js/9501b78f.a765143f.js new file mode 100644 index 00000000..102e0bf5 --- /dev/null +++ b/assets/js/9501b78f.a765143f.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[4533],{41608:(e,o,s)=>{s.r(o),s.d(o,{assets:()=>d,contentTitle:()=>l,default:()=>u,frontMatter:()=>a,metadata:()=>c,toc:()=>m});var t=s(11527),i=s(63883),n=s(37421),r=s(81779);const a={},l="Composites",c={id:"composedb/guides/data-modeling/composites",title:"Composites",description:"Guides for creating, deploying, and using composites.",source:"@site/docs/composedb/guides/data-modeling/composites.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/composites",permalink:"/docs/composedb/guides/data-modeling/composites",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Relations",permalink:"/docs/composedb/guides/data-modeling/relations"},next:{title:"ComposeDB Client",permalink:"/docs/composedb/guides/composedb-client/"}},d={},m=[{value:"Overview",id:"overview",level:2},{value:"Prerequisites",id:"prerequisites",level:2},{value:"Basic Usage",id:"basic-usage",level:2},{value:"Creating composites",id:"creating-composites",level:3},{value:"Deploying composites",id:"deploying-composites",level:3},{value:"Compiling composites",id:"compiling-composites",level:3},{value:"Advanced",id:"advanced",level:2},{value:"Merging composites",id:"merging-composites",level:3},{value:"Extracting composites",id:"extracting-composites",level:3},{value:"Inspecting composites",id:"inspecting-composites",level:3},{value:"Aliasing composites",id:"aliasing-composites",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Related Guides",id:"related-guides",level:2}];function p(e){const o={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(o.h1,{id:"composites",children:"Composites"}),"\n",(0,t.jsx)(o.p,{children:"Guides for creating, deploying, and using composites."}),"\n",(0,t.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsx)(o.p,{children:"In order to start using a model in your app, you\u2019ll have to include it in a composite. Composites are collections of one or more models and represent the complete GraphQL schema for your app. For basic usage, follow these steps:"}),"\n",(0,t.jsxs)(o.ol,{children:["\n",(0,t.jsx)(o.li,{children:"Create a composite containing one or more models"}),"\n",(0,t.jsx)(o.li,{children:"Deploy the composite to your ComposeDB server"}),"\n",(0,t.jsx)(o.li,{children:"Compile the composite for usage by your ComposeDB client"}),"\n"]}),"\n",(0,t.jsx)(o.h2,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsxs)(o.ul,{children:["\n",(0,t.jsx)(o.li,{children:"If you want to manage your composites from the CLI, you will need to have it installed"}),"\n",(0,t.jsxs)(o.li,{children:["If you want to manage your composites from JavaScript, you will need to install the\xa0",(0,t.jsx)(o.a,{href:"https://composedb.js.org/docs/0.5.x/api/modules/devtools",children:(0,t.jsx)(o.code,{children:"@composedb/devtools"})}),"\xa0library"]}),"\n",(0,t.jsxs)(o.li,{children:["One or more ",(0,t.jsx)(o.code,{children:".graphql"})," files containing your models"]}),"\n"]}),"\n",(0,t.jsx)(o.h2,{id:"basic-usage",children:"Basic Usage"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsx)(o.h3,{id:"creating-composites",children:"Creating composites"}),"\n",(0,t.jsxs)(o.p,{children:["Let\u2019s say you have a model written in a ",(0,t.jsx)(o.code,{children:"my-schema.graphql"})," file. To convert this schema into a composite, run the following:"]}),"\n",(0,t.jsxs)(n.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,t.jsx)(r.Z,{value:"cli",children:(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:create my-schema.graphql --output=my-composite.json --did-private-key=your-private-key\n"})})}),(0,t.jsx)(r.Z,{value:"js",children:(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { DID } from 'dids'\nimport { Ed25519Provider } from 'key-did-provider-ed25519'\nimport { getResolver } from 'key-did-resolver'\nimport { fromString } from 'uint8arrays/from-string'\n\n// Import the devtool node package\nimport { createComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\n// Hexadecimal-encoded private key for a DID having admin access to the target Ceramic node\n// Replace the example key here by your admin private key\nconst privateKey = fromString('b0cb[...]515f', 'base16')\n\nconst did = new DID({\n resolver: getResolver(),\n provider: new Ed25519Provider(privateKey),\n})\nawait did.authenticate()\n\n// Replace by the URL of the Ceramic node you want to deploy the Models to\nconst ceramic = new CeramicClient('http://localhost:7007')\n// An authenticated DID with admin access must be set on the Ceramic instance\nceramic.did = did\n\n// Replace by the path to the source schema file\nconst composite = await createComposite(ceramic, './source-schema.graphql')\n\n// Replace by the path to the encoded composite file\nawait writeEncodedComposite(composite, './my-composite.json')\n"})})})]}),"\n",(0,t.jsxs)(o.p,{children:["This will create a file called ",(0,t.jsx)(o.code,{children:"my-composite.json"})," which contains the composite in JSON."]}),"\n",(0,t.jsx)(o.h3,{id:"deploying-composites",children:"Deploying composites"}),"\n",(0,t.jsx)(o.p,{children:"After creating the composite, deploy it to your local node:"}),"\n",(0,t.jsxs)(n.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,t.jsx)(r.Z,{value:"cli",children:(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:deploy my-composite.json --ceramic-url=http://localhost:7007 --did-private-key=your-private-key\n"})})}),(0,t.jsx)(r.Z,{value:"js",children:(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { DID } from 'dids'\nimport { Ed25519Provider } from 'key-did-provider-ed25519'\nimport { getResolver } from 'key-did-resolver'\nimport { fromString } from 'uint8arrays/from-string'\n\nimport { readEncodedComposite } from '@composedb/devtools-node'\n\n// Hexadecimal-encoded private key for a DID having admin access to the target Ceramic node\n// Replace the example key here by your admin private key\nconst privateKey = fromString('b0cb[...]515f', 'base16')\n\nconst did = new DID({\n resolver: getResolver(),\n provider: new Ed25519Provider(privateKey),\n})\nawait did.authenticate()\n\n// Replace by the URL of the Ceramic node you want to deploy the Models to\nconst ceramic = new CeramicClient('http://localhost:7007')\n// An authenticated DID with admin access must be set on the Ceramic instance\nceramic.did = did\n\n// Replace by the path to the local encoded composite file\nconst composite = await readEncodedComposite(ceramic, 'my-first-composite.json')\n\n// Notify the Ceramic node to index the models present in the composite\nawait composite.startIndexingOn(ceramic)\n"})})})]}),"\n",(0,t.jsx)(o.admonition,{type:"tip",children:(0,t.jsxs)(o.p,{children:["This will also automatically add all models contained in the composite to the ",(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"}),"."]})}),"\n",(0,t.jsx)(o.h3,{id:"compiling-composites",children:"Compiling composites"}),"\n",(0,t.jsxs)(o.p,{children:["After deploying your composite, compile it so you can start perform ",(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-interactions/",children:"data interactions"})," using the ComposeDB client."]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:compile my-first-composite.json runtime-composite.json\n"})}),"\n",(0,t.jsx)(o.h2,{id:"advanced",children:"Advanced"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsx)(o.h3,{id:"merging-composites",children:"Merging composites"}),"\n",(0,t.jsx)(o.p,{children:"If you have more than one composite, you need to merge them into a single composite for use in your app. This may apply when:"}),"\n",(0,t.jsxs)(o.ul,{children:["\n",(0,t.jsxs)(o.li,{children:["You want to use multiple models from the ",(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog#using-multiple-models",children:"catalog"})]}),"\n",(0,t.jsx)(o.li,{children:"You want to use a model from the catalog and one or more models you created"}),"\n",(0,t.jsx)(o.li,{children:"You create multiple models and store their schemas in different GraphQL files"}),"\n"]}),"\n",(0,t.jsxs)(o.p,{children:["Let\u2019s say you have two composites where ",(0,t.jsx)(o.code,{children:"simple-profile-composite.json"})," contains the model for a profile model and ",(0,t.jsx)(o.code,{children:"post-composite.json"})," contains the model for a post. To merge, reference both composite JSON files and specify an output file path for the merged composite."]}),"\n",(0,t.jsxs)(n.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,t.jsx)(r.Z,{value:"cli",children:(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:merge simple-profile-composite.json post-composite.json --output=merged-composite.json\n"})})}),(0,t.jsxs)(r.Z,{value:"js",children:[(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\n\nconst loadSources = [\n 'simple-profile-composite.json',\n 'post-composite.json',\n].map(async (path) => await readEncodedComposite(ceramic, path))\nconst sourceComposites = await Promise.all(loadSources)\nconst mergedComposite = Composite.from(sourceComposites)\n\nawait writeEncodedComposite(mergedComposite, 'merged-composite.json')\n"})}),(0,t.jsxs)(o.admonition,{type:"caution",children:[(0,t.jsxs)(o.p,{children:[(0,t.jsx)(o.em,{children:(0,t.jsx)(o.strong,{children:"Note:"})})," To run the code above, you need a Ceramic JS HTTP client library installed on your machine to connect your app to a Ceramic node. Ceramic JS HTTP client can be installed by running the following command:"]}),(0,t.jsx)(o.p,{children:(0,t.jsx)(o.code,{children:"pnpm install @ceramicnetwork/http-client"})})]})]})]}),"\n",(0,t.jsxs)(o.p,{children:["The output of either example is a new file named ",(0,t.jsx)(o.code,{children:"merged-composite.json"})," which contains the models of both merged composites. From here you need to ",(0,t.jsx)(o.a,{href:"#deploying-composites",children:"deploy"})," the composite to your node, then ",(0,t.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it."]}),"\n",(0,t.jsx)(o.h3,{id:"extracting-composites",children:"Extracting composites"}),"\n",(0,t.jsx)(o.p,{children:"In cases where your composite contain models not needed by your application, or in other cases where you generally want to separate models in your composite, you can extract models into a separate composite."}),"\n",(0,t.jsxs)(o.p,{children:["As an example, let\u2019s reuse the ",(0,t.jsx)(o.code,{children:"merged-composite.json"})," file from the previous section and assume you want to extract the profile model into a separate composite. To do this, load the ",(0,t.jsx)(o.code,{children:"merged-composite.json"})," file and specify which model(s) you\u2019d like to extract into a new composite file."]}),"\n",(0,t.jsxs)(n.Z,{defaultValue:"cli",groupId:"cli-or-js",values:[{label:"CLI",value:"cli"},{label:"JavaScript",value:"js"}],children:[(0,t.jsx)(r.Z,{value:"cli",children:(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:extract-model merged-composite.json kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 --output=new-composite.json\n"})})}),(0,t.jsx)(r.Z,{value:"js",children:(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\nconst sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')\n\nconst mergedComposite = sourceComposite.copy(['kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65'])\nawait writeEncodedComposite(mergedComposite, 'new-composite.json')\n"})})})]}),"\n",(0,t.jsxs)(o.p,{children:["This will create a file called ",(0,t.jsx)(o.code,{children:"new-composite.json"})," with your profile model in it. From here you need to deploy the composite to your node, then ",(0,t.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it."]}),"\n",(0,t.jsx)(o.h3,{id:"inspecting-composites",children:"Inspecting composites"}),"\n",(0,t.jsx)(o.p,{children:"If you want to check what models are included in a specific composite, follow the steps below:"}),"\n",(0,t.jsxs)(o.ol,{children:["\n",(0,t.jsxs)(o.li,{children:["\n",(0,t.jsxs)(o.p,{children:["Compile the composite:\n",(0,t.jsx)(o.code,{children:"composedb composite:compile my-first-composite.json runtime-composite.json"})]}),"\n"]}),"\n",(0,t.jsxs)(o.li,{children:["\n",(0,t.jsxs)(o.p,{children:["View the GraphQL schema of the composite:\n",(0,t.jsx)(o.a,{href:"https://composedb.js.org/docs/0.5.x/api/commands/cli.graphql",children:(0,t.jsx)(o.code,{children:"composedb graphql:schema runtime-composite.json --output=schema.graphql"})})]}),"\n"]}),"\n"]}),"\n",(0,t.jsx)(o.h3,{id:"aliasing-composites",children:"Aliasing composites"}),"\n",(0,t.jsx)(o.p,{children:"In general, models are referenced using their unique model streamIDs which are not memorable. Models can be more easily referenced by aliasing them to your preferred names."}),"\n",(0,t.jsxs)(o.p,{children:["To manually set aliases for your models, add the following section to your composite JSON file. In this case we will use the aliases ",(0,t.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,t.jsx)(o.code,{children:"Post"}),"."]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-jsx",children:'"aliases":{\n "kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65":"SimpleProfile",\n "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy":"Post"\n }\n'})}),"\n",(0,t.jsxs)(o.p,{children:["To do aliases programmatically, use the ComposeDB Devtools library. Here\u2019s an example script that loads a composite JSON file and assigns ",(0,t.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,t.jsx)(o.code,{children:"Post"}),":"]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-jsx",children:"import { CeramicClient } from '@ceramicnetwork/http-client'\nimport { Composite } from '@composedb/devtools'\nimport { readEncodedComposite, writeEncodedComposite } from '@composedb/devtools-node'\n\nconst ceramic = new CeramicClient('http://localhost:7007')\nconst sourceComposite = await readEncodedComposite(ceramic, 'merged-composite.json')\n\nconst newComposite = sourceComposite.setAliases({\n 'kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65': 'SimpleProfile',\n 'kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy': 'Post',\n})\nawait writeEncodedComposite(newComposite, 'new-composite.json')\n"})}),"\n",(0,t.jsxs)(o.p,{children:["This script will create a file named ",(0,t.jsx)(o.code,{children:"new-composite.json"})," including model aliases:"]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-jsx",children:'"aliases":{\n "kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65":"SimpleProfile",\n "kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy":"Post"\n }\n'})}),"\n",(0,t.jsxs)(o.p,{children:["From here you need to ",(0,t.jsx)(o.a,{href:"#deploying-composites",children:"deploy"})," the composite to your node, then ",(0,t.jsx)(o.a,{href:"#compiling-composites",children:"compile"})," the composite to start using it. When interacting with the models inside your app, you can refer to them using their human-readable aliases rather than their streamIDs."]}),"\n",(0,t.jsx)(o.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsxs)(o.p,{children:["Set up your ",(0,t.jsx)(o.a,{href:"/docs/composedb/guides/composedb-client/",children:(0,t.jsx)(o.strong,{children:"ComposeDB Client"})})]}),"\n",(0,t.jsx)(o.h2,{id:"related-guides",children:"Related Guides"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsxs)(o.ul,{children:["\n",(0,t.jsx)(o.li,{children:(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"})}),"\n",(0,t.jsx)(o.li,{children:(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"})}),"\n"]})]})}function u(e={}){const{wrapper:o}={...(0,i.a)(),...e.components};return o?(0,t.jsx)(o,{...e,children:(0,t.jsx)(p,{...e})}):p(e)}},81779:(e,o,s)=>{s.d(o,{Z:()=>r});s(50959);var t=s(45924);const i={tabItem:"tabItem_e7Wc"};var n=s(11527);function r(e){let{children:o,hidden:s,className:r}=e;return(0,n.jsx)("div",{role:"tabpanel",className:(0,t.Z)(i.tabItem,r),hidden:s,children:o})}},37421:(e,o,s)=>{s.d(o,{Z:()=>w});var t=s(50959),i=s(45924),n=s(71988),r=s(28903),a=s(739),l=s(99965),c=s(43251),d=s(76698);function m(e){return t.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,t.isValidElement)(e)&&function(e){const{props:o}=e;return!!o&&"object"==typeof o&&"value"in o}(e))return e;throw new Error(`Docusaurus error: Bad child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function p(e){const{values:o,children:s}=e;return(0,t.useMemo)((()=>{const e=o??function(e){return m(e).map((e=>{let{props:{value:o,label:s,attributes:t,default:i}}=e;return{value:o,label:s,attributes:t,default:i}}))}(s);return function(e){const o=(0,c.l)(e,((e,o)=>e.value===o.value));if(o.length>0)throw new Error(`Docusaurus error: Duplicate values "${o.map((e=>e.value)).join(", ")}" found in . Every value needs to be unique.`)}(e),e}),[o,s])}function u(e){let{value:o,tabValues:s}=e;return s.some((e=>e.value===o))}function h(e){let{queryString:o=!1,groupId:s}=e;const i=(0,r.k6)(),n=function(e){let{queryString:o=!1,groupId:s}=e;if("string"==typeof o)return o;if(!1===o)return null;if(!0===o&&!s)throw new Error('Docusaurus error: The 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 s??null}({queryString:o,groupId:s});return[(0,l._X)(n),(0,t.useCallback)((e=>{if(!n)return;const o=new URLSearchParams(i.location.search);o.set(n,e),i.replace({...i.location,search:o.toString()})}),[n,i])]}function g(e){const{defaultValue:o,queryString:s=!1,groupId:i}=e,n=p(e),[r,l]=(0,t.useState)((()=>function(e){let{defaultValue:o,tabValues:s}=e;if(0===s.length)throw new Error("Docusaurus error: the component requires at least one children component");if(o){if(!u({value:o,tabValues:s}))throw new Error(`Docusaurus error: The has a defaultValue "${o}" but none of its children has the corresponding value. Available values are: ${s.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return o}const t=s.find((e=>e.default))??s[0];if(!t)throw new Error("Unexpected error: 0 tabValues");return t.value}({defaultValue:o,tabValues:n}))),[c,m]=h({queryString:s,groupId:i}),[g,j]=function(e){let{groupId:o}=e;const s=function(e){return e?`docusaurus.tab.${e}`:null}(o),[i,n]=(0,d.Nk)(s);return[i,(0,t.useCallback)((e=>{s&&n.set(e)}),[s,n])]}({groupId:i}),f=(()=>{const e=c??g;return u({value:e,tabValues:n})?e:null})();(0,a.Z)((()=>{f&&l(f)}),[f]);return{selectedValue:r,selectValue:(0,t.useCallback)((e=>{if(!u({value:e,tabValues:n}))throw new Error(`Can't select invalid tab value=${e}`);l(e),m(e),j(e)}),[m,j,n]),tabValues:n}}var j=s(12049);const f={tabList:"tabList_c3am",tabItem:"tabItem_iDuG"};var x=s(11527);function v(e){let{className:o,block:s,selectedValue:t,selectValue:r,tabValues:a}=e;const l=[],{blockElementScrollPositionUntilNextRender:c}=(0,n.o5)(),d=e=>{const o=e.currentTarget,s=l.indexOf(o),i=a[s].value;i!==t&&(c(o),r(i))},m=e=>{let o=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const s=l.indexOf(e.currentTarget)+1;o=l[s]??l[0];break}case"ArrowLeft":{const s=l.indexOf(e.currentTarget)-1;o=l[s]??l[l.length-1];break}}o?.focus()};return(0,x.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,i.Z)("tabs",{"tabs--block":s},o),children:a.map((e=>{let{value:o,label:s,attributes:n}=e;return(0,x.jsx)("li",{role:"tab",tabIndex:t===o?0:-1,"aria-selected":t===o,ref:e=>l.push(e),onKeyDown:m,onClick:d,...n,className:(0,i.Z)("tabs__item",f.tabItem,n?.className,{"tabs__item--active":t===o}),children:s??o},o)}))})}function y(e){let{lazy:o,children:s,selectedValue:i}=e;const n=(Array.isArray(s)?s:[s]).filter(Boolean);if(o){const e=n.find((e=>e.props.value===i));return e?(0,t.cloneElement)(e,{className:"margin-top--md"}):null}return(0,x.jsx)("div",{className:"margin-top--md",children:n.map(((e,o)=>(0,t.cloneElement)(e,{key:o,hidden:e.props.value!==i})))})}function b(e){const o=g(e);return(0,x.jsxs)("div",{className:(0,i.Z)("tabs-container",f.tabList),children:[(0,x.jsx)(v,{...e,...o}),(0,x.jsx)(y,{...e,...o})]})}function w(e){const o=(0,j.Z)();return(0,x.jsx)(b,{...e,children:m(e.children)},String(o))}},63883:(e,o,s)=>{s.d(o,{Z:()=>a,a:()=>r});var t=s(50959);const i={},n=t.createContext(i);function r(e){const o=t.useContext(n);return t.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function a(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:r(e.components),t.createElement(n.Provider,{value:o},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c9154a8c.a7aee102.js b/assets/js/c9154a8c.a7aee102.js deleted file mode 100644 index 82fdd6e6..00000000 --- a/assets/js/c9154a8c.a7aee102.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1563],{1509:(e,o,s)=>{s.r(o),s.d(o,{assets:()=>c,contentTitle:()=>l,default:()=>h,frontMatter:()=>i,metadata:()=>d,toc:()=>a});var t=s(11527),n=s(63883);const i={},l="Create your composite",d={id:"composedb/create-your-composite",title:"Create your composite",description:"Create your composite to serve as your graph database schema. In this guide, we will create your first composite.",source:"@site/docs/composedb/create-your-composite.mdx",sourceDirName:"composedb",slug:"/composedb/create-your-composite",permalink:"/docs/composedb/create-your-composite",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Quickstart",permalink:"/docs/composedb/set-up-your-environment"},next:{title:"Interact with data",permalink:"/docs/composedb/interact-with-data"}},c={},a=[{value:"Overview",id:"overview",level:2},{value:"Data Model Catalog",id:"data-model-catalog",level:2},{value:"List all models",id:"list-all-models",level:3},{value:"Creating the composite",id:"creating-the-composite",level:2},{value:"Using a single model",id:"using-a-single-model",level:3},{value:"Using multiple models",id:"using-multiple-models",level:3},{value:"Using the composite",id:"using-the-composite",level:2},{value:"Deploying the composite",id:"deploying-the-composite",level:3},{value:"Compiling the composite",id:"compiling-the-composite",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Related Guides",id:"related-guides",level:2}];function r(e){const o={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,n.a)(),...e.components};return(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)(o.h1,{id:"create-your-composite",children:"Create your composite"}),"\n",(0,t.jsx)(o.p,{children:"Create your composite to serve as your graph database schema. In this guide, we will create your first composite."}),"\n",(0,t.jsx)(o.admonition,{type:"tip",children:(0,t.jsxs)(o.p,{children:["Before continuing, you must have ",(0,t.jsx)(o.a,{href:"/docs/composedb/set-up-your-environment",children:"set up your environment"})," in the previous step"]})}),"\n",(0,t.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsx)(o.p,{children:"A composite is your database schema for ComposeDB, which includes a collection of data models. Once created, your composite instructs your node which models to index and also allows your client to perform queries and mutations on these models."}),"\n",(0,t.jsx)(o.h2,{id:"data-model-catalog",children:"Data Model Catalog"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsxs)(o.p,{children:["The ",(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"})," contains all models created by other ComposeDB developers. By creating or reusing models within the model catalog in your composite, you can instantly share and sync data with other applications. This brings native app data composability to Web3 -- no more API integrations."]}),"\n",(0,t.jsx)(o.h3,{id:"list-all-models",children:"List all models"}),"\n",(0,t.jsx)(o.p,{children:"To list all models in the model catalog, run the following command:"}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb model:list --table\n"})}),"\n",(0,t.jsxs)(o.p,{children:["Here, the flag ",(0,t.jsx)(o.code,{children:"--table"})," will display the output in an organized table view and provide more details about each model\u2019s functionality. By default, this command lists models in production on mainnet. To see models being developed on clay testnet, specify ",(0,t.jsx)(o.code,{children:"--network=testnet-clay"}),":"]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb model:list --network=testnet-clay --table\n"})}),"\n",(0,t.jsx)(o.p,{children:(0,t.jsx)(o.img,{alt:"Data Model Table",src:s(50150).Z+"",width:"2824",height:"1422"})}),"\n",(0,t.jsx)(o.p,{children:"Notice each model has the following properties:"}),"\n",(0,t.jsxs)(o.ul,{children:["\n",(0,t.jsxs)(o.li,{children:[(0,t.jsx)(o.code,{children:"Name"})," - model name"]}),"\n",(0,t.jsxs)(o.li,{children:[(0,t.jsx)(o.code,{children:"Unique ID"})," - unique identifier (stream ID) for the model"]}),"\n",(0,t.jsxs)(o.li,{children:[(0,t.jsx)(o.code,{children:"Description"})," - description of the model\u2019s functionality"]}),"\n"]}),"\n",(0,t.jsx)(o.h2,{id:"creating-the-composite",children:"Creating the composite"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsx)(o.p,{children:"In this section we will show how to create a composite by downloading models from the model catalog."}),"\n",(0,t.jsx)(o.h3,{id:"using-a-single-model",children:"Using a single model"}),"\n",(0,t.jsxs)(o.p,{children:["You can fetch any existing model from the catalog by referencing the model\u2019s unique ID. For example, for your basic social media app, use the existing model ",(0,t.jsx)(o.code,{children:"SimpleProfile"}),". To fetch the model, to your working directory, take note of the model stream ID in the table above and run the following command:"]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:from-model kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep --ceramic-url=http://localhost:7007 --output=my-first-composite.json\n"})}),"\n",(0,t.jsx)(o.p,{children:"You should see the following output in your terminal:"}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"\u2714 Creating a composite from models... Composite was created and its encoded representation was saved in my-first-composite.json\n"})}),"\n",(0,t.jsxs)(o.p,{children:["This output means that you now have the ",(0,t.jsx)(o.code,{children:"SimpleProfile"})," model stored locally in a file called ",(0,t.jsx)(o.code,{children:"my-first-composite.json"}),"."]}),"\n",(0,t.jsx)(o.h3,{id:"using-multiple-models",children:"Using multiple models"}),"\n",(0,t.jsxs)(o.p,{children:["If your application needs multiple models, for example the ",(0,t.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,t.jsx)(o.code,{children:"Post"})," models, you can. To fetch them, take note of the model stream IDs and provide them in a ComposeDB CLI command as follows:"]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:from-model kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep kjzl6hvfrbw6c7gkodzmqq5s031yfo5xdllvcr1z0tumwl7kpml4gfe5gbwh2bg --ceramic-url=http://localhost:7007 --output=my-first-composite.json\n"})}),"\n",(0,t.jsxs)(o.p,{children:["The output of this command will be a composite file named ",(0,t.jsx)(o.code,{children:"my-first-composite.json"}),"."]}),"\n",(0,t.jsx)(o.h2,{id:"using-the-composite",children:"Using the composite"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsx)(o.h3,{id:"deploying-the-composite",children:"Deploying the composite"}),"\n",(0,t.jsxs)(o.p,{children:["You will have to deploy the composite with fetched models to your local Ceramic node so that they can be used when building and running your applications. This can be achieved by using ComposeDB CLI and referencing the composite file of fetched models in your local environment as shown below. Note that you have to provide ",(0,t.jsx)(o.a,{href:"./set-up-your-environment#generate-your-private-key",children:"your did private key"})," to deploy the model:"]}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:deploy my-first-composite.json --ceramic-url=http://localhost:7007 --did-private-key=your-private-key\n"})}),"\n",(0,t.jsx)(o.p,{children:"You should see the output similar to the one below:"}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:'\u2139 Using DID did:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu\n\u2714 Deploying the composite... Done!\n["kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep"]\n'})}),"\n",(0,t.jsx)(o.p,{children:"Whenever composites are deployed, the models will be automatically indexed. This also means that these models are shared across the network (at the moment, only Clay testnet). If you check the output produced by the terminal that runs your Ceramic local node, you should see a similar output:"}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"IMPORTANT: Starting indexing for Model kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep\nIMPORTANT: Starting indexing for Model kjzl6hvfrbw6c7gkodzmqq5s031yfo5xdllvcr1z0tumwl7kpml4gfe5gbwh2bg\nIMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c5bf2jmwo9scp1ctkqvs5nru1jfjb1dgqqnf90sycptlztjdfep\nIMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c7gkodzmqq5s031yfo5xdllvcr1z0tumwl7kpml4gfe5gbwh2bg\n"})}),"\n",(0,t.jsx)(o.p,{children:"This means that the composite was deployed and the models were indexed on your local node successfully! \ud83c\udf89"}),"\n",(0,t.jsx)(o.h3,{id:"compiling-the-composite",children:"Compiling the composite"}),"\n",(0,t.jsx)(o.p,{children:"The last step left is compiling the composite. This is necessary to interact with the data in the next step of this guide:"}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"composedb composite:compile my-first-composite.json runtime-composite.json\n"})}),"\n",(0,t.jsx)(o.p,{children:"You should see the following output in your terminal:"}),"\n",(0,t.jsx)(o.pre,{children:(0,t.jsx)(o.code,{className:"language-bash",children:"\u2714 Compiling the composite... Done!\nruntime-composite.json\n"})}),"\n",(0,t.jsxs)(o.p,{children:["The output of this command will be a json file called ",(0,t.jsx)(o.code,{children:"runtime-composite.json"})]}),"\n",(0,t.jsx)(o.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,t.jsx)(o.hr,{}),"\n",(0,t.jsxs)(o.p,{children:["Now that you have created your composite, you are ready to use it: ",(0,t.jsx)(o.strong,{children:(0,t.jsx)(o.a,{href:"/docs/composedb/interact-with-data",children:"Interact with data \u2192"})})]}),"\n",(0,t.jsx)(o.h2,{id:"related-guides",children:"Related Guides"}),"\n",(0,t.jsxs)(o.ul,{children:["\n",(0,t.jsxs)(o.li,{children:["\n",(0,t.jsx)(o.p,{children:(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/",children:"Intro to Modeling"})}),"\n"]}),"\n",(0,t.jsxs)(o.li,{children:["\n",(0,t.jsx)(o.p,{children:(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"})}),"\n"]}),"\n",(0,t.jsxs)(o.li,{children:["\n",(0,t.jsx)(o.p,{children:(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"})}),"\n"]}),"\n",(0,t.jsxs)(o.li,{children:["\n",(0,t.jsx)(o.p,{children:(0,t.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/composites",children:"Composites"})}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:o}={...(0,n.a)(),...e.components};return o?(0,t.jsx)(o,{...e,children:(0,t.jsx)(r,{...e})}):r(e)}},50150:(e,o,s)=>{s.d(o,{Z:()=>t});const t=s.p+"assets/images/data-model-table-9edfb95dc33320c39c7c54bf99facad5.png"},63883:(e,o,s)=>{s.d(o,{Z:()=>d,a:()=>l});var t=s(50959);const n={},i=t.createContext(n);function l(e){const o=t.useContext(i);return t.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function d(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(n):e.components||n:l(e.components),t.createElement(i.Provider,{value:o},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/c9154a8c.b0f62f6e.js b/assets/js/c9154a8c.b0f62f6e.js new file mode 100644 index 00000000..dba14600 --- /dev/null +++ b/assets/js/c9154a8c.b0f62f6e.js @@ -0,0 +1 @@ +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[1563],{1509:(e,o,s)=>{s.r(o),s.d(o,{assets:()=>a,contentTitle:()=>l,default:()=>h,frontMatter:()=>n,metadata:()=>d,toc:()=>c});var i=s(11527),t=s(63883);const n={},l="Create your composite",d={id:"composedb/create-your-composite",title:"Create your composite",description:"Create your composite to serve as your graph database schema. In this guide, we will create your first composite.",source:"@site/docs/composedb/create-your-composite.mdx",sourceDirName:"composedb",slug:"/composedb/create-your-composite",permalink:"/docs/composedb/create-your-composite",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Quickstart",permalink:"/docs/composedb/set-up-your-environment"},next:{title:"Interact with data",permalink:"/docs/composedb/interact-with-data"}},a={},c=[{value:"Overview",id:"overview",level:2},{value:"Data Model Catalog",id:"data-model-catalog",level:2},{value:"List all models",id:"list-all-models",level:3},{value:"Creating the composite",id:"creating-the-composite",level:2},{value:"Using a single model",id:"using-a-single-model",level:3},{value:"Using multiple models",id:"using-multiple-models",level:3},{value:"Using the composite",id:"using-the-composite",level:2},{value:"Deploying the composite",id:"deploying-the-composite",level:3},{value:"Compiling the composite",id:"compiling-the-composite",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Related Guides",id:"related-guides",level:2}];function r(e){const o={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",img:"img",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,t.a)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(o.h1,{id:"create-your-composite",children:"Create your composite"}),"\n",(0,i.jsx)(o.p,{children:"Create your composite to serve as your graph database schema. In this guide, we will create your first composite."}),"\n",(0,i.jsx)(o.admonition,{type:"tip",children:(0,i.jsxs)(o.p,{children:["Before continuing, you must have ",(0,i.jsx)(o.a,{href:"/docs/composedb/set-up-your-environment",children:"set up your environment"})," in the previous step"]})}),"\n",(0,i.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,i.jsx)(o.hr,{}),"\n",(0,i.jsx)(o.p,{children:"A composite is your database schema for ComposeDB, which includes a collection of data models. Once created, your composite instructs your node which models to index and also allows your client to perform queries and mutations on these models."}),"\n",(0,i.jsx)(o.h2,{id:"data-model-catalog",children:"Data Model Catalog"}),"\n",(0,i.jsx)(o.hr,{}),"\n",(0,i.jsxs)(o.p,{children:["The ",(0,i.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"})," contains all models created by other ComposeDB developers. By creating or reusing models within the model catalog in your composite, you can instantly share and sync data with other applications. This brings native app data composability to Web3 -- no more API integrations."]}),"\n",(0,i.jsx)(o.h3,{id:"list-all-models",children:"List all models"}),"\n",(0,i.jsx)(o.p,{children:"To list all models in the model catalog, run the following command:"}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"composedb model:list --table\n"})}),"\n",(0,i.jsxs)(o.p,{children:["Here, the flag ",(0,i.jsx)(o.code,{children:"--table"})," will display the output in an organized table view and provide more details about each model\u2019s functionality. By default, this command lists models in production on mainnet. To see models being developed on clay testnet, specify ",(0,i.jsx)(o.code,{children:"--network=testnet-clay"}),":"]}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"composedb model:list --network=testnet-clay --table\n"})}),"\n",(0,i.jsx)(o.p,{children:(0,i.jsx)(o.img,{alt:"Data Model Table",src:s(50150).Z+"",width:"2824",height:"1422"})}),"\n",(0,i.jsx)(o.p,{children:"Notice each model has the following properties:"}),"\n",(0,i.jsxs)(o.ul,{children:["\n",(0,i.jsxs)(o.li,{children:[(0,i.jsx)(o.code,{children:"Name"})," - model name"]}),"\n",(0,i.jsxs)(o.li,{children:[(0,i.jsx)(o.code,{children:"Unique ID"})," - unique identifier (stream ID) for the model"]}),"\n",(0,i.jsxs)(o.li,{children:[(0,i.jsx)(o.code,{children:"Description"})," - description of the model\u2019s functionality"]}),"\n"]}),"\n",(0,i.jsx)(o.h2,{id:"creating-the-composite",children:"Creating the composite"}),"\n",(0,i.jsx)(o.hr,{}),"\n",(0,i.jsx)(o.p,{children:"In this section we will show how to create a composite by downloading models from the model catalog."}),"\n",(0,i.jsx)(o.h3,{id:"using-a-single-model",children:"Using a single model"}),"\n",(0,i.jsxs)(o.p,{children:["You can fetch any existing model from the catalog by referencing the model\u2019s unique ID. For example, for your basic social media app, use the existing model ",(0,i.jsx)(o.code,{children:"SimpleProfile"}),". To fetch the model, to your working directory, take note of the model stream ID in the table above and run the following command:"]}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"composedb composite:from-model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 --ceramic-url=http://localhost:7007 --output=my-first-composite.json\n"})}),"\n",(0,i.jsx)(o.p,{children:"You should see the following output in your terminal:"}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"\u2714 Creating a composite from models... Composite was created and its encoded representation was saved in my-first-composite.json\n"})}),"\n",(0,i.jsxs)(o.p,{children:["This output means that you now have the ",(0,i.jsx)(o.code,{children:"SimpleProfile"})," model stored locally in a file called ",(0,i.jsx)(o.code,{children:"my-first-composite.json"}),"."]}),"\n",(0,i.jsx)(o.h3,{id:"using-multiple-models",children:"Using multiple models"}),"\n",(0,i.jsxs)(o.p,{children:["If your application needs multiple models, for example the ",(0,i.jsx)(o.code,{children:"SimpleProfile"})," and ",(0,i.jsx)(o.code,{children:"Post"})," models, you can. To fetch them, take note of the model stream IDs and provide them in a ComposeDB CLI command as follows:"]}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"composedb composite:from-model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy --ceramic-url=http://localhost:7007 --output=my-first-composite.json\n"})}),"\n",(0,i.jsxs)(o.p,{children:["The output of this command will be a composite file named ",(0,i.jsx)(o.code,{children:"my-first-composite.json"}),"."]}),"\n",(0,i.jsx)(o.h2,{id:"using-the-composite",children:"Using the composite"}),"\n",(0,i.jsx)(o.hr,{}),"\n",(0,i.jsx)(o.h3,{id:"deploying-the-composite",children:"Deploying the composite"}),"\n",(0,i.jsxs)(o.p,{children:["You will have to deploy the composite with fetched models to your local Ceramic node so that they can be used when building and running your applications. This can be achieved by using ComposeDB CLI and referencing the composite file of fetched models in your local environment as shown below. Note that you have to provide ",(0,i.jsx)(o.a,{href:"./set-up-your-environment#generate-your-private-key",children:"your did private key"})," to deploy the model:"]}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"composedb composite:deploy my-first-composite.json --ceramic-url=http://localhost:7007 --did-private-key=your-private-key\n"})}),"\n",(0,i.jsx)(o.p,{children:"You should see the output similar to the one below:"}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:'\u2139 Using DID did:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu\n\u2714 Deploying the composite... Done!\n["kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65"]\n'})}),"\n",(0,i.jsx)(o.p,{children:"Whenever composites are deployed, the models will be automatically indexed. This also means that these models are shared across the network (at the moment, only Clay testnet). If you check the output produced by the terminal that runs your Ceramic local node, you should see a similar output:"}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"IMPORTANT: Starting indexing for Model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65\nIMPORTANT: Starting indexing for Model kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy\nIMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65\nIMPORTANT: Creating ComposeDB Indexing table for model: kjzl6hvfrbw6c822s0cj1ug59spj648ml8a6mbqaz91wx8zx3mlwi76tfh3u1dy\n"})}),"\n",(0,i.jsx)(o.p,{children:"This means that the composite was deployed and the models were indexed on your local node successfully! \ud83c\udf89"}),"\n",(0,i.jsx)(o.h3,{id:"compiling-the-composite",children:"Compiling the composite"}),"\n",(0,i.jsx)(o.p,{children:"The last step left is compiling the composite. This is necessary to interact with the data in the next step of this guide:"}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"composedb composite:compile my-first-composite.json runtime-composite.json\n"})}),"\n",(0,i.jsx)(o.p,{children:"You should see the following output in your terminal:"}),"\n",(0,i.jsx)(o.pre,{children:(0,i.jsx)(o.code,{className:"language-bash",children:"\u2714 Compiling the composite... Done!\nruntime-composite.json\n"})}),"\n",(0,i.jsxs)(o.p,{children:["The output of this command will be a json file called ",(0,i.jsx)(o.code,{children:"runtime-composite.json"})]}),"\n",(0,i.jsx)(o.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,i.jsx)(o.hr,{}),"\n",(0,i.jsxs)(o.p,{children:["Now that you have created your composite, you are ready to use it: ",(0,i.jsx)(o.strong,{children:(0,i.jsx)(o.a,{href:"/docs/composedb/interact-with-data",children:"Interact with data \u2192"})})]}),"\n",(0,i.jsx)(o.h2,{id:"related-guides",children:"Related Guides"}),"\n",(0,i.jsxs)(o.ul,{children:["\n",(0,i.jsxs)(o.li,{children:["\n",(0,i.jsx)(o.p,{children:(0,i.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/",children:"Intro to Modeling"})}),"\n"]}),"\n",(0,i.jsxs)(o.li,{children:["\n",(0,i.jsx)(o.p,{children:(0,i.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/model-catalog",children:"Model Catalog"})}),"\n"]}),"\n",(0,i.jsxs)(o.li,{children:["\n",(0,i.jsx)(o.p,{children:(0,i.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"})}),"\n"]}),"\n",(0,i.jsxs)(o.li,{children:["\n",(0,i.jsx)(o.p,{children:(0,i.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/composites",children:"Composites"})}),"\n"]}),"\n"]})]})}function h(e={}){const{wrapper:o}={...(0,t.a)(),...e.components};return o?(0,i.jsx)(o,{...e,children:(0,i.jsx)(r,{...e})}):r(e)}},50150:(e,o,s)=>{s.d(o,{Z:()=>i});const i=s.p+"assets/images/data-model-table-9edfb95dc33320c39c7c54bf99facad5.png"},63883:(e,o,s)=>{s.d(o,{Z:()=>d,a:()=>l});var i=s(50959);const t={},n=i.createContext(t);function l(e){const o=i.useContext(n);return i.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function d(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(t):e.components||t:l(e.components),i.createElement(n.Provider,{value:o},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/ce565fec.b8e471b2.js b/assets/js/ce565fec.94828a0a.js similarity index 99% rename from assets/js/ce565fec.b8e471b2.js rename to assets/js/ce565fec.94828a0a.js index 08b35606..17af0aa9 100644 --- a/assets/js/ce565fec.b8e471b2.js +++ b/assets/js/ce565fec.94828a0a.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6448],{47054:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>t,metadata:()=>c,toc:()=>h});var o=r(11527),s=r(63883),i=r(37421),a=r(81779);const t={},l="Quickstart",c={id:"composedb/set-up-your-environment",title:"Quickstart",description:"The first step to build with ComposeDB is setting up your development environment. This Quickstart guide will walk you through the process of setting up your local development environment from scratch.",source:"@site/docs/composedb/set-up-your-environment.mdx",sourceDirName:"composedb",slug:"/composedb/set-up-your-environment",permalink:"/docs/composedb/set-up-your-environment",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Scaffold a new Ceramic app",permalink:"/docs/composedb/create-ceramic-app"},next:{title:"Create your composite",permalink:"/docs/composedb/create-your-composite"}},d={},h=[{value:"1. Prerequisites",id:"1-prerequisites",level:2},{value:"2. Installation",id:"2-installation",level:2},{value:"2a. Installation using create-ceramic-app",id:"2a-installation-using-create-ceramic-app",level:3},{value:"2b. Installation using Wheel",id:"2b-installation-using-wheel",level:3},{value:"Install the dependencies",id:"install-the-dependencies",level:4},{value:"Configure the development environment",id:"configure-the-development-environment",level:4},{value:"2c. Installation using JavaScript package managers",id:"2c-installation-using-javascript-package-managers",level:3},{value:"Install the dependencies",id:"install-the-dependencies-1",level:4},{value:"Setup",id:"setup",level:4},{value:"Developer Account",id:"developer-account",level:4},{value:"Using your account",id:"using-your-account",level:4},{value:"Confirmation",id:"confirmation",level:4},{value:"3. Frequently Asked Questions",id:"3-frequently-asked-questions",level:2},{value:"4. Next Steps",id:"4-next-steps",level:2}];function u(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components},{Details:r}=n;return r||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"quickstart",children:"Quickstart"}),"\n",(0,o.jsx)(n.p,{children:"The first step to build with ComposeDB is setting up your development environment. This Quickstart guide will walk you through the process of setting up your local development environment from scratch."}),"\n",(0,o.jsx)(n.p,{children:"By the end of this guide you'll have a good understanding of how to get started building with ComposeDB."}),"\n",(0,o.jsx)(n.h2,{id:"1-prerequisites",children:"1. Prerequisites"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["Operating system: ",(0,o.jsx)(n.strong,{children:"Linux, Mac, or Windows"})," (only ",(0,o.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/windows/wsl/install",children:"WSL2"}),")"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Node.js v20"})," - If you are using a different version, please use ",(0,o.jsx)(n.code,{children:"nvm"})," to install Node.js v20 for best results."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"npm v10"})," - Installed automatically with NodeJS v20"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"2-installation",children:"2. Installation"}),"\n",(0,o.jsx)(n.p,{children:"There are a few ways to set up your environment. Choose the one that best fits your needs:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsxs)(n.a,{href:"#installation-using-create-ceramic-app",children:["Using ",(0,o.jsx)(n.code,{children:"create-ceramic-app"})]})," - get up and running quickly with a basic ComposeDB application with one command. Good for the first quick experience with Ceramic and ComposeDB."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"#installation-using-wheel",children:"Using the Wheel"})," - the recommended and the easiest way to configure your full working environment and install the necessary dependencies."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"#installation-using-javascript-package-managers",children:"Using JavaScript package managers"})," - an alternative, more manual, way to configure your working environment which supports ",(0,o.jsx)(n.code,{children:"npm"}),", ",(0,o.jsx)(n.code,{children:"pnpm"})," and ",(0,o.jsx)(n.code,{children:"yarn"}),"."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsxs)(n.strong,{children:["Install and start the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary"]})}),"\n",(0,o.jsxs)(n.p,{children:["All of the configuration options listed above ",(0,o.jsxs)(n.strong,{children:["require a ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running"]}),", which provides a data network access. You can run ",(0,o.jsx)(n.code,{children:"ceramic-one"})," on your\nlocal machine using two simple steps listed below."]}),"\n",(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The instructions below cover the steps for the MacOS-based systems. If you are running on a Linux-based system, you can find the\ninstructions ",(0,o.jsx)(n.a,{href:"https://github.com/ceramicnetwork/rust-ceramic?tab=readme-ov-file#linux---debian-based-distributions",children:"here"}),"."]})}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:["Install the component using ",(0,o.jsx)(n.a,{href:"https://brew.sh/",children:"Homebrew"}),":"]}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"brew install ceramicnetwork/tap/ceramic-one\n"})}),"\n",(0,o.jsxs)(n.ol,{start:"2",children:["\n",(0,o.jsxs)(n.li,{children:["Start the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," using the following command:"]}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ceramic-one daemon \n"})}),"\n",(0,o.jsxs)(n.admonition,{type:"note",children:[(0,o.jsxs)(n.p,{children:["By default, the command above will spin off a node which connects to a ",(0,o.jsx)(n.code,{children:"clay-testnet"})," network. You can change this behaviour by providing a ",(0,o.jsx)(n.code,{children:"--network"})," flag and specifying a network of your choice. For example:"]}),(0,o.jsx)(n.p,{children:(0,o.jsx)(n.code,{children:"ceramic-one daemon --network clay-testnet"})})]}),"\n",(0,o.jsxs)(n.p,{children:["By default ",(0,o.jsx)(n.code,{children:"ceramic-one"})," will store its data in the current directory. You can configure this behaviour by\nspecifying the ",(0,o.jsx)(n.code,{children:"--store-dir"}),"and ",(0,o.jsx)(n.code,{children:"--p2p-key-dir"})," arguments. For example:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ceramic-one daemon --store-dir ~/.ceramic-one --p2p-key-dir ~/.ceramic-one\n"})}),"\n",(0,o.jsxs)(n.p,{children:["With ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running you can move on with the ComposeDB installation and configuration method of your choice."]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h3,{id:"2a-installation-using-create-ceramic-app",children:"2a. Installation using create-ceramic-app"}),"\n",(0,o.jsxs)("table",{children:[(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"When to use"})}),(0,o.jsx)("td",{children:"When you want to get up and running quickly with a basic ComposeDB application with one command."})]}),(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"Time to install"})}),(0,o.jsx)("td",{children:"Less than 2 minutes"})]})]}),"\n",(0,o.jsx)(n.p,{children:"Just run the command below and follow the instructions:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"npm",groupId:"package-manager",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"},{label:"bun",value:"bun"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npx create-ceramic-app\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpx create-ceramic-app\n"})})}),(0,o.jsxs)(a.Z,{value:"yarn",children:[(0,o.jsxs)(n.admonition,{type:"tip",children:[(0,o.jsxs)(n.p,{children:["You need at least yarn 2.x to use the ",(0,o.jsx)(n.code,{children:"yarn dlx"})," command. If you have an older version, upgrade it by running ",(0,o.jsx)(n.code,{children:"yarn set version stable"})," and ",(0,o.jsx)(n.code,{children:"yarn install"}),"."]}),(0,o.jsx)(n.p,{children:"Then you can run the following command to create a new Ceramic app using yarn 2.x"})]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn dlx create-ceramic-app\n"})})]}),(0,o.jsx)(a.Z,{value:"bun",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"bunx create-ceramic-app\n"})})})]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h3,{id:"2b-installation-using-wheel",children:"2b. Installation using Wheel"}),"\n",(0,o.jsxs)("table",{children:[(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"When to use"})}),(0,o.jsx)("td",{children:"When you want to configure full working environment and start working on your own app."})]}),(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"Time to install"})}),(0,o.jsx)("td",{children:"5 minutes"})]})]}),"\n",(0,o.jsxs)(n.p,{children:["The easiest and recommended way to configure your full local development environment is by using ",(0,o.jsx)(n.a,{href:"https://github.com/ceramicstudio/wheel.git",children:"Wheel"})," - a CLI starter tool for Ceramic that makes it easy to install necessary dependencies and run a Ceramic node enabled with ComposeDB. The installation instructions below are also covered in a video tutorial that you can follow:"]}),"\n",(0,o.jsx)("iframe",{width:"660",height:"415",src:"https://www.youtube.com/embed/r68FXBTCBZ4?si=FRolthOjecS9Ys2_",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0}),"\n",(0,o.jsx)(n.h4,{id:"install-the-dependencies",children:"Install the dependencies"}),"\n",(0,o.jsx)(n.p,{children:"In order to use Wheel, you\u2019ll have to install a few dependencies:"}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Node.js"})]}),"\n",(0,o.jsx)(n.p,{children:"If you don\u2019t already have them installed, you will need to install at least:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://nodejs.org/en/",children:(0,o.jsx)(n.strong,{children:"NodeJS v20"})})," - If you are using a different version, please use ",(0,o.jsx)(n.code,{children:"nvm"})," to install Node.js v20 for best results."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"npm v10"})," - Installed automatically with NodeJS v20."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Make sure you have the correct versions installed."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"node -v\nnpm -v\n"})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"jq"})]}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.code,{children:"jq"})," is a lightweight and flexible command-line JSON processor. The installation method depends on your operating system. Install it using one of the methods defined in\nthe ",(0,o.jsx)(n.a,{href:"https://stedolan.github.io/jq/download/",children:"official tutorial here"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"PostgreSQL"})," (optional)"]}),"\n",(0,o.jsx)(n.p,{children:"PostgreSQL is only required for a production configuration on the Mainnet. If you are new to ComposeDB on Ceramic and would like to quickly test it out, you can skip the PostgreSQL installation and come back to it once you are ready to scale your project. You will need Postgres installed on your machine to store indexed data."}),"\n",(0,o.jsxs)(n.p,{children:["To install Postgres, follow ",(0,o.jsx)(n.a,{href:"https://www.postgresql.org/download/",children:"instructions provided on official Postgres documentation"}),".\nOnce installed, open Postgres in your command line:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"psql postgres\n"})}),"\n",(0,o.jsx)(n.p,{children:"Configure your database using the following commands:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-SQL",children:"CREATE DATABASE ceramic;\nCREATE ROLE ceramic WITH PASSWORD 'password' LOGIN;\nGRANT ALL PRIVILEGES ON DATABASE \"ceramic\" to ceramic;\n"})}),"\n",(0,o.jsx)(n.h4,{id:"configure-the-development-environment",children:"Configure the development environment"}),"\n",(0,o.jsxs)(n.p,{children:["Make sure you have the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running. To do that, follow the steps listed ",(0,o.jsx)(n.a,{href:"#2-installation",children:"here"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"Now you can use Wheel to install all of the dependencies needed to run Ceramic and ComposeDB as well as configure the working environment\nfor your project."}),"\n",(0,o.jsx)(n.p,{children:"To download Wheel, run the command below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/ceramicstudio/wheel/main/wheel.sh | bash\n"})}),"\n",(0,o.jsx)(n.p,{children:"Once Wheel is downloaded, you are good to start configuring your project working directory. To kick it off, run the command below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"./wheel\n"})}),"\n",(0,o.jsx)(n.p,{children:"Wheel will ask you a few questions, allowing you to configure your entire working environment - from what Ceramic dependencies you\u2019d like to install to how your Ceramic node should be configured."}),"\n",(0,o.jsx)(n.p,{children:"You can run the following command to learn more about available Wheel commands and options:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"./wheel --help\n"})}),"\n",(0,o.jsxs)(n.p,{children:["For developers who are completely new to Ceramic, we highly recommend starting the configuration with all the default options. This will install the Ceramic and ComposeDB dependencies and spin up a local node running ",(0,o.jsx)(n.code,{children:"InMemory"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"At the end of configuration, this option will also give you an option to set up an example web3 social app for you to interact with and test ComposeDB features."}),"\n",(0,o.jsx)(n.admonition,{type:"important",children:(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.a,{href:"/docs/composedb/guides/composedb-server/access-mainnet",children:"Ceramic Anchor Service (CAS)"})," is used to anchor Ceramic streams on a blockchain.\nCAS is require for ",(0,o.jsx)(n.code,{children:"dev"}),", ",(0,o.jsx)(n.code,{children:"testnet-clay"})," and ",(0,o.jsx)(n.code,{children:"mainnet"})," networks. Since ",(0,o.jsx)(n.code,{children:"InMemory"})," option doesn\u2019t use CAS, data generated for your project will not be persisted."]})}),"\n",(0,o.jsxs)(n.p,{children:["If you are ready to dive into a more advanced configuration, head to ",(0,o.jsx)(n.a,{href:"/docs/wheel/wheel-reference",children:(0,o.jsx)(n.strong,{children:"Wheel reference"})})," page to learn more details about each parameter you can configure."]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h3,{id:"2c-installation-using-javascript-package-managers",children:"2c. Installation using JavaScript package managers"}),"\n",(0,o.jsxs)("table",{children:[(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"When to use"})}),(0,o.jsx)("td",{children:"When you want more control and a manual way to configure your working environment."})]}),(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"Time to install"})}),(0,o.jsx)("td",{children:"5-10 minutes"})]})]}),"\n",(0,o.jsxs)(n.p,{children:["Another way to install the dependencies and configure Ceramic is using JavaScript package managers. This option requires more manual steps. The guide below covers this\nprocess step-by-step. If you have followed the ",(0,o.jsx)(n.a,{href:"#installation-using-wheel",children:"Wheel installation"})," guide above, you can skip this section."]}),"\n",(0,o.jsx)(n.h4,{id:"install-the-dependencies-1",children:"Install the dependencies"}),"\n",(0,o.jsx)(n.p,{children:"Start with creating the project directory. Here you\u2019ll store all your app\u2019s local files:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"mkdir my-project #creates a new directory\ncd my-project #targets the created directory\n"})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Node.js"})]}),"\n",(0,o.jsxs)(n.p,{children:["If you don\u2019t already have them installed, you will need to install Node.js v20 and a package manager. We primarily use ",(0,o.jsx)(n.code,{children:"pnpm"}),", but ",(0,o.jsx)(n.code,{children:"npm"})," and ",(0,o.jsx)(n.code,{children:"yarn"})," are supported as well."]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://nodejs.org/en/",children:(0,o.jsx)(n.strong,{children:"NodeJS v20"})})," - If you are using a different version, please use ",(0,o.jsx)(n.code,{children:"nvm"})," to install Node.js v20 for best results."]}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://pnpm.io/installation",children:(0,o.jsx)(n.strong,{children:"pnpm v10"})})}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Make sure you have the correct versions installed."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"node -v\npnpm -v\n"})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"ceramic-one"})]}),"\n",(0,o.jsxs)(n.p,{children:["Make sure you have the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running. To do that, follow the steps listed ",(0,o.jsx)(n.a,{href:"#2-installation",children:"here"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Ceramic"})]}),"\n",(0,o.jsxs)(n.p,{children:["ComposeDB runs on Ceramic, so you will need to run a Ceramic node. To get started, we recommend running a local Ceramic node. If you're interested in running the production node, you can follow one of the ",(0,o.jsx)(n.a,{href:"./guides/composedb-server/",children:"guides here"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"Ceramic CLI provides a set of commands that make it easier to run and manage Ceramic nodes. Start by installing the Ceramic CLI:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"npm-or-pnpm-or-yarnr",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npm install --location=global @ceramicnetwork/cli\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm install -g @ceramicnetwork/cli\n"})})}),(0,o.jsxs)(a.Z,{value:"yarn",children:[(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsxs)(n.p,{children:["Global packages are only supported for yarn 2.x and older. For yarn 3.x and newer, use ",(0,o.jsx)(n.code,{children:"yarn dlx"})," to run composedb cli commands"]})}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn global add @ceramicnetwork/cli\n"})})]})]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"ComposeDB"})]}),"\n",(0,o.jsx)(n.p,{children:"Next install the ComposeDB CLI, which enables you to interact with ComposeDB data from your terminal:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"npm-or-pnpm-or-yarnr",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npm install --location=global @composedb/cli\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm add -g @composedb/cli\n"})})}),(0,o.jsxs)(a.Z,{value:"yarn",children:[(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsxs)(n.p,{children:["Global packages are only supported for yarn 2.x and older. For yarn 3.x and newer, use ",(0,o.jsx)(n.code,{children:"yarn dlx"})," to run composedb cli commands"]})}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn global add @composedb/cli\n"})})]})]}),"\n",(0,o.jsxs)(n.admonition,{type:"tip",children:[(0,o.jsxs)(n.p,{children:["The command above will install the latest version of the ComposeDB CLI. If you need to install a specific version, you\ncan specify it by adding ",(0,o.jsx)(n.code,{children:"@version-number"})," at the end of this command. You can also prefix the version number with ",(0,o.jsx)(n.code,{children:"^"})," to\ninstall the latest patch. For example, if you'd like to install the latest patched version of ComposeDB 0.6.x you can run the command:"]}),(0,o.jsx)(n.p,{children:(0,o.jsx)(n.code,{children:"npm install --location=global @composedb/cli@^0.6.x"})})]}),"\n",(0,o.jsx)(n.p,{children:"ComposeDB provides two additional libraries that support development:"}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://composedb.js.org/docs/0.5.x/api/modules/devtools",children:"@composedb/devtools"})," containing utilities related to managing composites"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://composedb.js.org/docs/0.5.x/api/modules/devtools_node",children:"@composedb/devtools-node"})," which contains utilities for interacting with the local file system and starting a local HTTP server."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"To install the development packages, run:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"package-manager",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npm install -D @composedb/devtools @composedb/devtools-node\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm add -D @composedb/devtools @composedb/devtools-node\n"})})}),(0,o.jsx)(a.Z,{value:"yarn",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn add -D @composedb/devtools@^0.5.0 @composedb/devtools-node@^0.5.0\n"})})})]}),"\n",(0,o.jsx)(n.h4,{id:"setup",children:"Setup"}),"\n",(0,o.jsx)(n.p,{children:"All dependencies are installed. Now you can start setting up your project. The first step is to run a local Ceramic node."}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Run a Ceramic node"})]}),"\n",(0,o.jsx)(n.p,{children:"You can check that everything was installed correctly by spinning up a Ceramic node. Running the command below will start the Ceramic node in local mode and connect to Clay testnet.\nIndexing is a key component of ComposeDB, which syncs data across nodes. Enable indexing by toggling:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"package-manager",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npx @ceramicnetwork/cli daemon\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm dlx @ceramicnetwork/cli daemon\n"})})}),(0,o.jsx)(a.Z,{value:"yarn",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn dlx @ceramicnetwork/cli daemon\n"})})})]}),"\n",(0,o.jsx)(n.p,{children:"You should see the following output in your terminal. This means you have successfully started a local node and connected to Clay testnet \ud83d\ude80"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"IMPORTANT: Ceramic API running on 0.0.0.0:7007\n"})}),"\n",(0,o.jsx)(n.h4,{id:"developer-account",children:"Developer Account"}),"\n",(0,o.jsxs)(n.p,{children:["Now, that you have installed everything successfully and are able to run the node, let's create a developer account. You can stop\nthe node for now by using the keyboard combination ",(0,o.jsx)(n.code,{children:"Control+C"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Generate your private key"})]}),"\n",(0,o.jsx)(n.p,{children:"You will need a private key for authorizing ComposeDB CLI commands in the later stages of development. You can generate it using the command below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"composedb did:generate-private-key\n"})}),"\n",(0,o.jsx)(n.p,{children:"You should see the output similar to the one below. Keep in mind that the key generated for your will be unique and will different from the example shown below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"\u2714 Generating random private key... Done!\n5c7d2fa8ebc488f2fe008e5ed1db7f1f95c203434bbcbeb703491c405f6f31f0\n"})}),"\n",(0,o.jsx)(n.p,{children:"Copy and save this key securely for later use."}),"\n",(0,o.jsx)(n.admonition,{type:"important",children:(0,o.jsx)(n.p,{children:"Store your private key securely - the key allows changes to be made to your app. In addition, you will need it throughout the app development process."})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Generate your account"})]}),"\n",(0,o.jsxs)(n.p,{children:["Indexing is one of the key features of ComposeDB. In order to notify the Ceramic node which models have to be indexed, the ComposeDB tools have to interact with the restricted Admin API. Calling the API requires an authenticated Decentralized Identifier (DID) to be provided in the node configuration file. Create a DID by running the following command, using the private key generated previously instead of the placeholder variable ",(0,o.jsx)(n.code,{children:"your-private-key"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"composedb did:from-private-key your-private-key\n"})}),"\n",(0,o.jsx)(n.p,{children:"You should see the output similar to the one below. Here again, the DID created for you will be unique and will differ from the one shown below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"\u2714 Creating DID... Done!\ndid:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu\n"})}),"\n",(0,o.jsx)(n.p,{children:"This key will be used to configure your node in the later steps of this guide."}),"\n",(0,o.jsx)(n.admonition,{type:"important",children:(0,o.jsx)(n.p,{children:"Copy this authenticated DID key and store it in a secure place, just like with your private key above. This DID key will have to be provided in your Ceramic node\u2019s configuration file which will ensure that only authorized users can make changes to your application, e.g. deploy models on your Ceramic node."})}),"\n",(0,o.jsx)(n.h4,{id:"using-your-account",children:"Using your account"}),"\n",(0,o.jsxs)(n.p,{children:["The very first time you spin up a Ceramic node, a node configuration file is automatically created for you where you can configure how your node is operated. Here you have to provide the DID key which is authorised to interact with the Admin API.\nThe Ceramic node configuration file will be created inside of the automatically created directory ",(0,o.jsx)(n.code,{children:"./ceramic"})," in your home directory (usually ",(0,o.jsx)(n.code,{children:"/home/USERNAME/"})," on Linux or ",(0,o.jsx)(n.code,{children:"/Users/USERNAME/"})," on Mac). This directory can be accessed using the following command:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"cd ~/.ceramic\n"})}),"\n",(0,o.jsx)(n.p,{children:"Inside of this directory you should find the following files:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"daemon.config.json"})," - your Ceramic node configuration file"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"statestore"})," - a local directory for ",(0,o.jsx)(n.a,{href:"../protocol/js-ceramic/guides/ceramic-nodes/running-cloud#ceramic-state-store",children:"persisting the data"})]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["Open the ",(0,o.jsx)(n.code,{children:"daemon.config.json"})," file using your preferred code editor and provide the authenticated DID, generated in the ",(0,o.jsx)(n.a,{href:"#generate-your-account",children:"generate your account"})," step of this guide, in the ",(0,o.jsx)(n.code,{children:"admin-dids"})," section of the file as shown in the example below:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-json",children:'{\n ...\n "http-api": {\n ...\n "admin-dids": ["did:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu"]\n },\n "indexing": {\n ...\n "allow-queries-before-historical-sync": true\n }\n}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Save this file and start your Ceramic node again by following the steps in the ",(0,o.jsx)(n.a,{href:"#confirmation",children:"Confirmation"})," section of this guide."]}),"\n",(0,o.jsx)(n.h4,{id:"confirmation",children:"Confirmation"}),"\n",(0,o.jsx)(n.p,{children:"As a final test, spin up the Ceramic local node:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"ceramic daemon --network=testnet-clay\n"})}),"\n",(0,o.jsx)(n.p,{children:"Once again, you should see your local Ceramic node up and running as follows:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"IMPORTANT: Ceramic API running on 0.0.0.0:7007\n"})}),"\n",(0,o.jsx)(n.p,{children:"By this point you should have your development environment and all configurations in place to get started working on your application."}),"\n",(0,o.jsx)(n.p,{children:"Congratulations!"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h2,{id:"3-frequently-asked-questions",children:"3. Frequently Asked Questions"}),"\n",(0,o.jsx)(n.p,{children:"Some questions and issues come up more often than others. We've compiled a list of the most common ones here."}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Which setup method is better: Wheel or JavaScript package managers?"}),(0,o.jsx)("div",{children:(0,o.jsxs)("div",{children:[(0,o.jsxs)("p",{children:[(0,o.jsx)(n.strong,{children:"create-ceramic-app"})," is the fastest. Good for your first interaction with ComposeDB."]}),(0,o.jsx)("p",{children:(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Wheel"})," is the recommended and the easiest way to configure your working environment and install all the\nnecessary dependencies. We highly recommended going with Wheel if you are just starting out with Ceramic.\nEverything will be taken care of for you."]})}),(0,o.jsx)("p",{children:(0,o.jsxs)(n.p,{children:["You might consider using ",(0,o.jsx)(n.strong,{children:"JavaScript package managers"})," if you are already familiar with Ceramic and need more\nmanual configuration and control over your working environment."]})})]})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Which operating systems are supported?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"It's best to run Ceramic and ComposeDB on Linux or a Mac. You can also run it on Windows but you'll have to use\nWSL2 (Windows Subsystem for Linux). See the supported operating systems section at the top."})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Which Node.js version is preferred?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"We have seen the best results using Node.js v20. Earlier versions are no longer supported, later versions can\ncause issues for some users. While we're working on eliminating the issues, it's best to use Node v20 for now."})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"How long does it take to install the packages?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"Installing everything (either with Wheel or JavaScript packages) takes usually between 2 and 10 minutes.\nThroughout the guide above you can find what kind of output you should be looking for to know that everything was\ninstalled correctly."})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Where in the system do I run all of the commands?"}),(0,o.jsxs)("div",{children:[(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"Sometimes, especially when using JavaScript package managers to install Ceramic and ComposeDB, it's easy to forget\nthat you need to run all of the commands in the app's directory. This directory is either automatically created\nfor you when using Wheel, or you create it manually when using JavaScript package managers."})}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"When installing with JavaScript package managers you need to open 2-3 terminal windows and run different commands,\nso it's easy to miss that you can be in a wrong directory. Please make sure you run all the commands where they're\nsupposed to run."})})]})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Where can I find a Ceramic node configuration file, daemon.config.json?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsxs)(n.p,{children:["When installing ComposeDB with JavaScript package managers, at some point you need to edit your Ceramic node\nconfig file. By default, it's in your home directory, in .ceramic folder (",(0,o.jsx)(n.em,{children:"not"})," in the app directory). It's easy\nto miss this detail so please check the path. This command should take you to the right directory: cd ~/.ceramic"]})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"How to restart a node after stopping it?"}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"When you use Wheel to install Ceramic and ComposeDB, it takes care of the whole installation process. But please\nnote that Wheel is just an installer, not a node launcher. If you want to launch Ceramic and ComposeDB again, after\nyou have stopped it, you need to launch Ceramic daemon again and then launch ComposeDB."})}),(0,o.jsx)("div",{children:"You can launch Ceramic daemon by running the following command: ceramic daeomn --network=InMemory"}),(0,o.jsx)("div",{children:"You can launch ComposeDB by running the command: composedb"}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:'More on all of the composedb command options can be found in "2. Create your composite" section of this Getting\nStarted guide.'})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"How do I interact with the data once Ceramic node is running?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:'The easiest way to interact with data is through a GraphQL Server. You can find all the details on how to set it\nup, launch, and interact with your data in section of this guide, "3. Interact with data"'})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:(0,o.jsxs)(n.p,{children:["Error when creating a composite: \u2716 request to ",(0,o.jsx)(n.a,{href:"http://localhost:7007/(",children:"http://localhost:7007/("}),"...) failed, reason: connect ECONNREFUSED\n::1:7007"]})}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:"The most likely cause is using Node.js v18. Please try using Node.js v20."})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Error: npm ERR! code EACCESS"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:"The most likely cause is read/write access on your system. Try running the command with sudo privileges."})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"What if my question is not answered on this page?"}),(0,o.jsxs)("div",{children:[(0,o.jsx)("div",{}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"If your question is not answered in this guide, we recommend visiting our Community Forum (see the link in the\nfooter). There, you can ask your question and get help from our community of developers and users. It's great to\nask anything: from beginner to expert questions. The community and our developers are there to help you."})})]})]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h2,{id:"4-next-steps",children:"4. Next Steps"}),"\n",(0,o.jsx)(n.p,{children:"In this Quickstart guide, you have learned how to get started with ComposeDB. You have set up your development environment and are ready to start building your application. The next steps are:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./create-your-composite",children:(0,o.jsx)(n.strong,{children:"Create your composite"})})," - Learn how to create your first composite, a reusable data model that can be used across different applications."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./interact-with-data",children:(0,o.jsx)(n.strong,{children:"Interact with data"})})," - Learn how to interact with data in ComposeDB, from creating, reading, updating, and deleting data to running complex queries."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./core-concepts",children:(0,o.jsx)(n.strong,{children:"Core ComposeDB concepts"})})," - Learn about the core concepts of ComposeDB, such as composites, schemas, and queries."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./guides/composedb-server/running-in-the-cloud",children:(0,o.jsx)(n.strong,{children:"Running in the cloud"})})," - Ready to upgrade from a local node to production? Learn how to deploy your app."]}),"\n"]})]})}function p(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(u,{...e})}):u(e)}},81779:(e,n,r)=>{r.d(n,{Z:()=>a});r(50959);var o=r(45924);const s={tabItem:"tabItem_e7Wc"};var i=r(11527);function a(e){let{children:n,hidden:r,className:a}=e;return(0,i.jsx)("div",{role:"tabpanel",className:(0,o.Z)(s.tabItem,a),hidden:r,children:n})}},37421:(e,n,r)=>{r.d(n,{Z:()=>b});var o=r(50959),s=r(45924),i=r(71988),a=r(28903),t=r(739),l=r(99965),c=r(43251),d=r(76698);function h(e){return o.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,o.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 child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function u(e){const{values:n,children:r}=e;return(0,o.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:r,attributes:o,default:s}}=e;return{value:n,label:r,attributes:o,default:s}}))}(r);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 . Every value needs to be unique.`)}(e),e}),[n,r])}function p(e){let{value:n,tabValues:r}=e;return r.some((e=>e.value===n))}function m(e){let{queryString:n=!1,groupId:r}=e;const s=(0,a.k6)(),i=function(e){let{queryString:n=!1,groupId:r}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!r)throw new Error('Docusaurus error: The 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 r??null}({queryString:n,groupId:r});return[(0,l._X)(i),(0,o.useCallback)((e=>{if(!i)return;const n=new URLSearchParams(s.location.search);n.set(i,e),s.replace({...s.location,search:n.toString()})}),[i,s])]}function x(e){const{defaultValue:n,queryString:r=!1,groupId:s}=e,i=u(e),[a,l]=(0,o.useState)((()=>function(e){let{defaultValue:n,tabValues:r}=e;if(0===r.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!p({value:n,tabValues:r}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${r.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const o=r.find((e=>e.default))??r[0];if(!o)throw new Error("Unexpected error: 0 tabValues");return o.value}({defaultValue:n,tabValues:i}))),[c,h]=m({queryString:r,groupId:s}),[x,g]=function(e){let{groupId:n}=e;const r=function(e){return e?`docusaurus.tab.${e}`:null}(n),[s,i]=(0,d.Nk)(r);return[s,(0,o.useCallback)((e=>{r&&i.set(e)}),[r,i])]}({groupId:s}),j=(()=>{const e=c??x;return p({value:e,tabValues:i})?e:null})();(0,t.Z)((()=>{j&&l(j)}),[j]);return{selectedValue:a,selectValue:(0,o.useCallback)((e=>{if(!p({value:e,tabValues:i}))throw new Error(`Can't select invalid tab value=${e}`);l(e),h(e),g(e)}),[h,g,i]),tabValues:i}}var g=r(12049);const j={tabList:"tabList_c3am",tabItem:"tabItem_iDuG"};var y=r(11527);function f(e){let{className:n,block:r,selectedValue:o,selectValue:a,tabValues:t}=e;const l=[],{blockElementScrollPositionUntilNextRender:c}=(0,i.o5)(),d=e=>{const n=e.currentTarget,r=l.indexOf(n),s=t[r].value;s!==o&&(c(n),a(s))},h=e=>{let n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const r=l.indexOf(e.currentTarget)+1;n=l[r]??l[0];break}case"ArrowLeft":{const r=l.indexOf(e.currentTarget)-1;n=l[r]??l[l.length-1];break}}n?.focus()};return(0,y.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.Z)("tabs",{"tabs--block":r},n),children:t.map((e=>{let{value:n,label:r,attributes:i}=e;return(0,y.jsx)("li",{role:"tab",tabIndex:o===n?0:-1,"aria-selected":o===n,ref:e=>l.push(e),onKeyDown:h,onClick:d,...i,className:(0,s.Z)("tabs__item",j.tabItem,i?.className,{"tabs__item--active":o===n}),children:r??n},n)}))})}function v(e){let{lazy:n,children:r,selectedValue:s}=e;const i=(Array.isArray(r)?r:[r]).filter(Boolean);if(n){const e=i.find((e=>e.props.value===s));return e?(0,o.cloneElement)(e,{className:"margin-top--md"}):null}return(0,y.jsx)("div",{className:"margin-top--md",children:i.map(((e,n)=>(0,o.cloneElement)(e,{key:n,hidden:e.props.value!==s})))})}function w(e){const n=x(e);return(0,y.jsxs)("div",{className:(0,s.Z)("tabs-container",j.tabList),children:[(0,y.jsx)(f,{...e,...n}),(0,y.jsx)(v,{...e,...n})]})}function b(e){const n=(0,g.Z)();return(0,y.jsx)(w,{...e,children:h(e.children)},String(n))}},63883:(e,n,r)=>{r.d(n,{Z:()=>t,a:()=>a});var o=r(50959);const s={},i=o.createContext(s);function a(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[6448],{47054:(e,n,r)=>{r.r(n),r.d(n,{assets:()=>d,contentTitle:()=>l,default:()=>p,frontMatter:()=>t,metadata:()=>c,toc:()=>h});var o=r(11527),s=r(63883),i=r(37421),a=r(81779);const t={},l="Quickstart",c={id:"composedb/set-up-your-environment",title:"Quickstart",description:"The first step to build with ComposeDB is setting up your development environment. This Quickstart guide will walk you through the process of setting up your local development environment from scratch.",source:"@site/docs/composedb/set-up-your-environment.mdx",sourceDirName:"composedb",slug:"/composedb/set-up-your-environment",permalink:"/docs/composedb/set-up-your-environment",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Scaffold a new Ceramic app",permalink:"/docs/composedb/create-ceramic-app"},next:{title:"Create your composite",permalink:"/docs/composedb/create-your-composite"}},d={},h=[{value:"1. Prerequisites",id:"1-prerequisites",level:2},{value:"2. Installation",id:"2-installation",level:2},{value:"2a. Installation using create-ceramic-app",id:"2a-installation-using-create-ceramic-app",level:3},{value:"2b. Installation using Wheel",id:"2b-installation-using-wheel",level:3},{value:"Install the dependencies",id:"install-the-dependencies",level:4},{value:"Configure the development environment",id:"configure-the-development-environment",level:4},{value:"2c. Installation using JavaScript package managers",id:"2c-installation-using-javascript-package-managers",level:3},{value:"Install the dependencies",id:"install-the-dependencies-1",level:4},{value:"Setup",id:"setup",level:4},{value:"Developer Account",id:"developer-account",level:4},{value:"Using your account",id:"using-your-account",level:4},{value:"Confirmation",id:"confirmation",level:4},{value:"3. Frequently Asked Questions",id:"3-frequently-asked-questions",level:2},{value:"4. Next Steps",id:"4-next-steps",level:2}];function u(e){const n={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",h3:"h3",h4:"h4",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,s.a)(),...e.components},{Details:r}=n;return r||function(e,n){throw new Error("Expected "+(n?"component":"object")+" `"+e+"` to be defined: you likely forgot to import, pass, or provide it.")}("Details",!0),(0,o.jsxs)(o.Fragment,{children:[(0,o.jsx)(n.h1,{id:"quickstart",children:"Quickstart"}),"\n",(0,o.jsx)(n.p,{children:"The first step to build with ComposeDB is setting up your development environment. This Quickstart guide will walk you through the process of setting up your local development environment from scratch."}),"\n",(0,o.jsx)(n.p,{children:"By the end of this guide you'll have a good understanding of how to get started building with ComposeDB."}),"\n",(0,o.jsx)(n.h2,{id:"1-prerequisites",children:"1. Prerequisites"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:["Operating system: ",(0,o.jsx)(n.strong,{children:"Linux, Mac, or Windows"})," (only ",(0,o.jsx)(n.a,{href:"https://learn.microsoft.com/en-us/windows/wsl/install",children:"WSL2"}),")"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"Node.js v20"})," - If you are using a different version, please use ",(0,o.jsx)(n.code,{children:"nvm"})," to install Node.js v20 for best results."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"npm v10"})," - Installed automatically with NodeJS v20"]}),"\n"]}),"\n",(0,o.jsx)(n.h2,{id:"2-installation",children:"2. Installation"}),"\n",(0,o.jsx)(n.p,{children:"There are a few ways to set up your environment. Choose the one that best fits your needs:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsxs)(n.a,{href:"#installation-using-create-ceramic-app",children:["Using ",(0,o.jsx)(n.code,{children:"create-ceramic-app"})]})," - get up and running quickly with a basic ComposeDB application with one command. Good for the first quick experience with Ceramic and ComposeDB."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"#installation-using-wheel",children:"Using the Wheel"})," - the recommended and the easiest way to configure your full working environment and install the necessary dependencies."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"#installation-using-javascript-package-managers",children:"Using JavaScript package managers"})," - an alternative, more manual, way to configure your working environment which supports ",(0,o.jsx)(n.code,{children:"npm"}),", ",(0,o.jsx)(n.code,{children:"pnpm"})," and ",(0,o.jsx)(n.code,{children:"yarn"}),"."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:(0,o.jsxs)(n.strong,{children:["Install and start the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary"]})}),"\n",(0,o.jsxs)(n.p,{children:["All of the configuration options listed above ",(0,o.jsxs)(n.strong,{children:["require a ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running"]}),", which provides a data network access. You can run ",(0,o.jsx)(n.code,{children:"ceramic-one"})," on your\nlocal machine using two simple steps listed below."]}),"\n",(0,o.jsx)(n.admonition,{type:"note",children:(0,o.jsxs)(n.p,{children:["The instructions below cover the steps for the MacOS-based systems. If you are running on a Linux-based system, you can find the\ninstructions ",(0,o.jsx)(n.a,{href:"https://github.com/ceramicnetwork/rust-ceramic?tab=readme-ov-file#linux---debian-based-distributions",children:"here"}),"."]})}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:["Install the component using ",(0,o.jsx)(n.a,{href:"https://brew.sh/",children:"Homebrew"}),":"]}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"brew install ceramicnetwork/tap/ceramic-one\n"})}),"\n",(0,o.jsxs)(n.ol,{start:"2",children:["\n",(0,o.jsxs)(n.li,{children:["Start the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," using the following command:"]}),"\n"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ceramic-one daemon \n"})}),"\n",(0,o.jsxs)(n.admonition,{type:"note",children:[(0,o.jsxs)(n.p,{children:["By default, the command above will spin off a node which connects to a ",(0,o.jsx)(n.code,{children:"testnet-clay"})," network. You can change this behaviour by providing a ",(0,o.jsx)(n.code,{children:"--network"})," flag and specifying a network of your choice. For example:"]}),(0,o.jsx)(n.p,{children:(0,o.jsx)(n.code,{children:"ceramic-one daemon --network testnet-clay"})})]}),"\n",(0,o.jsxs)(n.p,{children:["By default ",(0,o.jsx)(n.code,{children:"ceramic-one"})," will store its data in the current directory. You can configure this behaviour by\nspecifying the ",(0,o.jsx)(n.code,{children:"--store-dir"}),"and ",(0,o.jsx)(n.code,{children:"--p2p-key-dir"})," arguments. For example:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"ceramic-one daemon --store-dir ~/.ceramic-one --p2p-key-dir ~/.ceramic-one\n"})}),"\n",(0,o.jsxs)(n.p,{children:["With ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running you can move on with the ComposeDB installation and configuration method of your choice."]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h3,{id:"2a-installation-using-create-ceramic-app",children:"2a. Installation using create-ceramic-app"}),"\n",(0,o.jsxs)("table",{children:[(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"When to use"})}),(0,o.jsx)("td",{children:"When you want to get up and running quickly with a basic ComposeDB application with one command."})]}),(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"Time to install"})}),(0,o.jsx)("td",{children:"Less than 2 minutes"})]})]}),"\n",(0,o.jsx)(n.p,{children:"Just run the command below and follow the instructions:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"npm",groupId:"package-manager",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"},{label:"bun",value:"bun"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npx create-ceramic-app\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpx create-ceramic-app\n"})})}),(0,o.jsxs)(a.Z,{value:"yarn",children:[(0,o.jsxs)(n.admonition,{type:"tip",children:[(0,o.jsxs)(n.p,{children:["You need at least yarn 2.x to use the ",(0,o.jsx)(n.code,{children:"yarn dlx"})," command. If you have an older version, upgrade it by running ",(0,o.jsx)(n.code,{children:"yarn set version stable"})," and ",(0,o.jsx)(n.code,{children:"yarn install"}),"."]}),(0,o.jsx)(n.p,{children:"Then you can run the following command to create a new Ceramic app using yarn 2.x"})]}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn dlx create-ceramic-app\n"})})]}),(0,o.jsx)(a.Z,{value:"bun",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"bunx create-ceramic-app\n"})})})]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h3,{id:"2b-installation-using-wheel",children:"2b. Installation using Wheel"}),"\n",(0,o.jsxs)("table",{children:[(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"When to use"})}),(0,o.jsx)("td",{children:"When you want to configure full working environment and start working on your own app."})]}),(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"Time to install"})}),(0,o.jsx)("td",{children:"5 minutes"})]})]}),"\n",(0,o.jsxs)(n.p,{children:["The easiest and recommended way to configure your full local development environment is by using ",(0,o.jsx)(n.a,{href:"https://github.com/ceramicstudio/wheel.git",children:"Wheel"})," - a CLI starter tool for Ceramic that makes it easy to install necessary dependencies and run a Ceramic node enabled with ComposeDB. The installation instructions below are also covered in a video tutorial that you can follow:"]}),"\n",(0,o.jsx)("iframe",{width:"660",height:"415",src:"https://www.youtube.com/embed/r68FXBTCBZ4?si=FRolthOjecS9Ys2_",frameborder:"0",allow:"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture",allowfullscreen:!0}),"\n",(0,o.jsx)(n.h4,{id:"install-the-dependencies",children:"Install the dependencies"}),"\n",(0,o.jsx)(n.p,{children:"In order to use Wheel, you\u2019ll have to install a few dependencies:"}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Node.js"})]}),"\n",(0,o.jsx)(n.p,{children:"If you don\u2019t already have them installed, you will need to install at least:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://nodejs.org/en/",children:(0,o.jsx)(n.strong,{children:"NodeJS v20"})})," - If you are using a different version, please use ",(0,o.jsx)(n.code,{children:"nvm"})," to install Node.js v20 for best results."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.strong,{children:"npm v10"})," - Installed automatically with NodeJS v20."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Make sure you have the correct versions installed."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"node -v\nnpm -v\n"})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"jq"})]}),"\n",(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.code,{children:"jq"})," is a lightweight and flexible command-line JSON processor. The installation method depends on your operating system. Install it using one of the methods defined in\nthe ",(0,o.jsx)(n.a,{href:"https://stedolan.github.io/jq/download/",children:"official tutorial here"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"PostgreSQL"})," (optional)"]}),"\n",(0,o.jsx)(n.p,{children:"PostgreSQL is only required for a production configuration on the Mainnet. If you are new to ComposeDB on Ceramic and would like to quickly test it out, you can skip the PostgreSQL installation and come back to it once you are ready to scale your project. You will need Postgres installed on your machine to store indexed data."}),"\n",(0,o.jsxs)(n.p,{children:["To install Postgres, follow ",(0,o.jsx)(n.a,{href:"https://www.postgresql.org/download/",children:"instructions provided on official Postgres documentation"}),".\nOnce installed, open Postgres in your command line:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"psql postgres\n"})}),"\n",(0,o.jsx)(n.p,{children:"Configure your database using the following commands:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-SQL",children:"CREATE DATABASE ceramic;\nCREATE ROLE ceramic WITH PASSWORD 'password' LOGIN;\nGRANT ALL PRIVILEGES ON DATABASE \"ceramic\" to ceramic;\n"})}),"\n",(0,o.jsx)(n.h4,{id:"configure-the-development-environment",children:"Configure the development environment"}),"\n",(0,o.jsxs)(n.p,{children:["Make sure you have the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running. To do that, follow the steps listed ",(0,o.jsx)(n.a,{href:"#2-installation",children:"here"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"Now you can use Wheel to install all of the dependencies needed to run Ceramic and ComposeDB as well as configure the working environment\nfor your project."}),"\n",(0,o.jsx)(n.p,{children:"To download Wheel, run the command below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"curl --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/ceramicstudio/wheel/main/wheel.sh | bash\n"})}),"\n",(0,o.jsx)(n.p,{children:"Once Wheel is downloaded, you are good to start configuring your project working directory. To kick it off, run the command below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"./wheel\n"})}),"\n",(0,o.jsx)(n.p,{children:"Wheel will ask you a few questions, allowing you to configure your entire working environment - from what Ceramic dependencies you\u2019d like to install to how your Ceramic node should be configured."}),"\n",(0,o.jsx)(n.p,{children:"You can run the following command to learn more about available Wheel commands and options:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"./wheel --help\n"})}),"\n",(0,o.jsxs)(n.p,{children:["For developers who are completely new to Ceramic, we highly recommend starting the configuration with all the default options. This will install the Ceramic and ComposeDB dependencies and spin up a local node running ",(0,o.jsx)(n.code,{children:"InMemory"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"At the end of configuration, this option will also give you an option to set up an example web3 social app for you to interact with and test ComposeDB features."}),"\n",(0,o.jsx)(n.admonition,{type:"important",children:(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.a,{href:"/docs/composedb/guides/composedb-server/access-mainnet",children:"Ceramic Anchor Service (CAS)"})," is used to anchor Ceramic streams on a blockchain.\nCAS is require for ",(0,o.jsx)(n.code,{children:"dev"}),", ",(0,o.jsx)(n.code,{children:"testnet-clay"})," and ",(0,o.jsx)(n.code,{children:"mainnet"})," networks. Since ",(0,o.jsx)(n.code,{children:"InMemory"})," option doesn\u2019t use CAS, data generated for your project will not be persisted."]})}),"\n",(0,o.jsxs)(n.p,{children:["If you are ready to dive into a more advanced configuration, head to ",(0,o.jsx)(n.a,{href:"/docs/wheel/wheel-reference",children:(0,o.jsx)(n.strong,{children:"Wheel reference"})})," page to learn more details about each parameter you can configure."]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h3,{id:"2c-installation-using-javascript-package-managers",children:"2c. Installation using JavaScript package managers"}),"\n",(0,o.jsxs)("table",{children:[(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"When to use"})}),(0,o.jsx)("td",{children:"When you want more control and a manual way to configure your working environment."})]}),(0,o.jsxs)("tr",{children:[(0,o.jsx)("td",{children:(0,o.jsx)(n.strong,{children:"Time to install"})}),(0,o.jsx)("td",{children:"5-10 minutes"})]})]}),"\n",(0,o.jsxs)(n.p,{children:["Another way to install the dependencies and configure Ceramic is using JavaScript package managers. This option requires more manual steps. The guide below covers this\nprocess step-by-step. If you have followed the ",(0,o.jsx)(n.a,{href:"#installation-using-wheel",children:"Wheel installation"})," guide above, you can skip this section."]}),"\n",(0,o.jsx)(n.h4,{id:"install-the-dependencies-1",children:"Install the dependencies"}),"\n",(0,o.jsx)(n.p,{children:"Start with creating the project directory. Here you\u2019ll store all your app\u2019s local files:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"mkdir my-project #creates a new directory\ncd my-project #targets the created directory\n"})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Node.js"})]}),"\n",(0,o.jsxs)(n.p,{children:["If you don\u2019t already have them installed, you will need to install Node.js v20 and a package manager. We primarily use ",(0,o.jsx)(n.code,{children:"pnpm"}),", but ",(0,o.jsx)(n.code,{children:"npm"})," and ",(0,o.jsx)(n.code,{children:"yarn"})," are supported as well."]}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://nodejs.org/en/",children:(0,o.jsx)(n.strong,{children:"NodeJS v20"})})," - If you are using a different version, please use ",(0,o.jsx)(n.code,{children:"nvm"})," to install Node.js v20 for best results."]}),"\n",(0,o.jsx)(n.li,{children:(0,o.jsx)(n.a,{href:"https://pnpm.io/installation",children:(0,o.jsx)(n.strong,{children:"pnpm v10"})})}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"Make sure you have the correct versions installed."}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"node -v\npnpm -v\n"})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"ceramic-one"})]}),"\n",(0,o.jsxs)(n.p,{children:["Make sure you have the ",(0,o.jsx)(n.code,{children:"ceramic-one"})," binary up and running. To do that, follow the steps listed ",(0,o.jsx)(n.a,{href:"#2-installation",children:"here"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Ceramic"})]}),"\n",(0,o.jsxs)(n.p,{children:["ComposeDB runs on Ceramic, so you will need to run a Ceramic node. To get started, we recommend running a local Ceramic node. If you're interested in running the production node, you can follow one of the ",(0,o.jsx)(n.a,{href:"./guides/composedb-server/",children:"guides here"}),"."]}),"\n",(0,o.jsx)(n.p,{children:"Ceramic CLI provides a set of commands that make it easier to run and manage Ceramic nodes. Start by installing the Ceramic CLI:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"npm-or-pnpm-or-yarnr",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npm install --location=global @ceramicnetwork/cli\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm install -g @ceramicnetwork/cli\n"})})}),(0,o.jsxs)(a.Z,{value:"yarn",children:[(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsxs)(n.p,{children:["Global packages are only supported for yarn 2.x and older. For yarn 3.x and newer, use ",(0,o.jsx)(n.code,{children:"yarn dlx"})," to run composedb cli commands"]})}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn global add @ceramicnetwork/cli\n"})})]})]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"ComposeDB"})]}),"\n",(0,o.jsx)(n.p,{children:"Next install the ComposeDB CLI, which enables you to interact with ComposeDB data from your terminal:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"npm-or-pnpm-or-yarnr",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npm install --location=global @composedb/cli\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm add -g @composedb/cli\n"})})}),(0,o.jsxs)(a.Z,{value:"yarn",children:[(0,o.jsx)(n.admonition,{type:"caution",children:(0,o.jsxs)(n.p,{children:["Global packages are only supported for yarn 2.x and older. For yarn 3.x and newer, use ",(0,o.jsx)(n.code,{children:"yarn dlx"})," to run composedb cli commands"]})}),(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn global add @composedb/cli\n"})})]})]}),"\n",(0,o.jsxs)(n.admonition,{type:"tip",children:[(0,o.jsxs)(n.p,{children:["The command above will install the latest version of the ComposeDB CLI. If you need to install a specific version, you\ncan specify it by adding ",(0,o.jsx)(n.code,{children:"@version-number"})," at the end of this command. You can also prefix the version number with ",(0,o.jsx)(n.code,{children:"^"})," to\ninstall the latest patch. For example, if you'd like to install the latest patched version of ComposeDB 0.6.x you can run the command:"]}),(0,o.jsx)(n.p,{children:(0,o.jsx)(n.code,{children:"npm install --location=global @composedb/cli@^0.6.x"})})]}),"\n",(0,o.jsx)(n.p,{children:"ComposeDB provides two additional libraries that support development:"}),"\n",(0,o.jsxs)(n.ol,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://composedb.js.org/docs/0.5.x/api/modules/devtools",children:"@composedb/devtools"})," containing utilities related to managing composites"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"https://composedb.js.org/docs/0.5.x/api/modules/devtools_node",children:"@composedb/devtools-node"})," which contains utilities for interacting with the local file system and starting a local HTTP server."]}),"\n"]}),"\n",(0,o.jsx)(n.p,{children:"To install the development packages, run:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"package-manager",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npm install -D @composedb/devtools @composedb/devtools-node\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm add -D @composedb/devtools @composedb/devtools-node\n"})})}),(0,o.jsx)(a.Z,{value:"yarn",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn add -D @composedb/devtools@^0.5.0 @composedb/devtools-node@^0.5.0\n"})})})]}),"\n",(0,o.jsx)(n.h4,{id:"setup",children:"Setup"}),"\n",(0,o.jsx)(n.p,{children:"All dependencies are installed. Now you can start setting up your project. The first step is to run a local Ceramic node."}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Run a Ceramic node"})]}),"\n",(0,o.jsx)(n.p,{children:"You can check that everything was installed correctly by spinning up a Ceramic node. Running the command below will start the Ceramic node in local mode and connect to Clay testnet.\nIndexing is a key component of ComposeDB, which syncs data across nodes. Enable indexing by toggling:"}),"\n",(0,o.jsxs)(i.Z,{defaultValue:"pnpm",groupId:"package-manager",values:[{label:"npm",value:"npm"},{label:"pnpm",value:"pnpm"},{label:"yarn",value:"yarn"}],children:[(0,o.jsx)(a.Z,{value:"npm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"npx @ceramicnetwork/cli daemon\n"})})}),(0,o.jsx)(a.Z,{value:"pnpm",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"pnpm dlx @ceramicnetwork/cli daemon\n"})})}),(0,o.jsx)(a.Z,{value:"yarn",children:(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"yarn dlx @ceramicnetwork/cli daemon\n"})})})]}),"\n",(0,o.jsx)(n.p,{children:"You should see the following output in your terminal. This means you have successfully started a local node and connected to Clay testnet \ud83d\ude80"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"IMPORTANT: Ceramic API running on 0.0.0.0:7007\n"})}),"\n",(0,o.jsx)(n.h4,{id:"developer-account",children:"Developer Account"}),"\n",(0,o.jsxs)(n.p,{children:["Now, that you have installed everything successfully and are able to run the node, let's create a developer account. You can stop\nthe node for now by using the keyboard combination ",(0,o.jsx)(n.code,{children:"Control+C"}),"."]}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Generate your private key"})]}),"\n",(0,o.jsx)(n.p,{children:"You will need a private key for authorizing ComposeDB CLI commands in the later stages of development. You can generate it using the command below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"composedb did:generate-private-key\n"})}),"\n",(0,o.jsx)(n.p,{children:"You should see the output similar to the one below. Keep in mind that the key generated for your will be unique and will different from the example shown below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"\u2714 Generating random private key... Done!\n5c7d2fa8ebc488f2fe008e5ed1db7f1f95c203434bbcbeb703491c405f6f31f0\n"})}),"\n",(0,o.jsx)(n.p,{children:"Copy and save this key securely for later use."}),"\n",(0,o.jsx)(n.admonition,{type:"important",children:(0,o.jsx)(n.p,{children:"Store your private key securely - the key allows changes to be made to your app. In addition, you will need it throughout the app development process."})}),"\n",(0,o.jsxs)(n.p,{children:["\u2192 ",(0,o.jsx)(n.strong,{children:"Generate your account"})]}),"\n",(0,o.jsxs)(n.p,{children:["Indexing is one of the key features of ComposeDB. In order to notify the Ceramic node which models have to be indexed, the ComposeDB tools have to interact with the restricted Admin API. Calling the API requires an authenticated Decentralized Identifier (DID) to be provided in the node configuration file. Create a DID by running the following command, using the private key generated previously instead of the placeholder variable ",(0,o.jsx)(n.code,{children:"your-private-key"}),":"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"composedb did:from-private-key your-private-key\n"})}),"\n",(0,o.jsx)(n.p,{children:"You should see the output similar to the one below. Here again, the DID created for you will be unique and will differ from the one shown below:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-bash",children:"\u2714 Creating DID... Done!\ndid:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu\n"})}),"\n",(0,o.jsx)(n.p,{children:"This key will be used to configure your node in the later steps of this guide."}),"\n",(0,o.jsx)(n.admonition,{type:"important",children:(0,o.jsx)(n.p,{children:"Copy this authenticated DID key and store it in a secure place, just like with your private key above. This DID key will have to be provided in your Ceramic node\u2019s configuration file which will ensure that only authorized users can make changes to your application, e.g. deploy models on your Ceramic node."})}),"\n",(0,o.jsx)(n.h4,{id:"using-your-account",children:"Using your account"}),"\n",(0,o.jsxs)(n.p,{children:["The very first time you spin up a Ceramic node, a node configuration file is automatically created for you where you can configure how your node is operated. Here you have to provide the DID key which is authorised to interact with the Admin API.\nThe Ceramic node configuration file will be created inside of the automatically created directory ",(0,o.jsx)(n.code,{children:"./ceramic"})," in your home directory (usually ",(0,o.jsx)(n.code,{children:"/home/USERNAME/"})," on Linux or ",(0,o.jsx)(n.code,{children:"/Users/USERNAME/"})," on Mac). This directory can be accessed using the following command:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"cd ~/.ceramic\n"})}),"\n",(0,o.jsx)(n.p,{children:"Inside of this directory you should find the following files:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"daemon.config.json"})," - your Ceramic node configuration file"]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.code,{children:"statestore"})," - a local directory for ",(0,o.jsx)(n.a,{href:"../protocol/js-ceramic/guides/ceramic-nodes/running-cloud#ceramic-state-store",children:"persisting the data"})]}),"\n"]}),"\n",(0,o.jsxs)(n.p,{children:["Open the ",(0,o.jsx)(n.code,{children:"daemon.config.json"})," file using your preferred code editor and provide the authenticated DID, generated in the ",(0,o.jsx)(n.a,{href:"#generate-your-account",children:"generate your account"})," step of this guide, in the ",(0,o.jsx)(n.code,{children:"admin-dids"})," section of the file as shown in the example below:"]}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-json",children:'{\n ...\n "http-api": {\n ...\n "admin-dids": ["did:key:z6MkoDgemAx51v8w692aZRLPdwP6UPKj3EgUhBTvbL7hCwLu"]\n },\n "indexing": {\n ...\n "allow-queries-before-historical-sync": true\n }\n}\n'})}),"\n",(0,o.jsxs)(n.p,{children:["Save this file and start your Ceramic node again by following the steps in the ",(0,o.jsx)(n.a,{href:"#confirmation",children:"Confirmation"})," section of this guide."]}),"\n",(0,o.jsx)(n.h4,{id:"confirmation",children:"Confirmation"}),"\n",(0,o.jsx)(n.p,{children:"As a final test, spin up the Ceramic local node:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"ceramic daemon --network=testnet-clay\n"})}),"\n",(0,o.jsx)(n.p,{children:"Once again, you should see your local Ceramic node up and running as follows:"}),"\n",(0,o.jsx)(n.pre,{children:(0,o.jsx)(n.code,{className:"language-powershell",children:"IMPORTANT: Ceramic API running on 0.0.0.0:7007\n"})}),"\n",(0,o.jsx)(n.p,{children:"By this point you should have your development environment and all configurations in place to get started working on your application."}),"\n",(0,o.jsx)(n.p,{children:"Congratulations!"}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h2,{id:"3-frequently-asked-questions",children:"3. Frequently Asked Questions"}),"\n",(0,o.jsx)(n.p,{children:"Some questions and issues come up more often than others. We've compiled a list of the most common ones here."}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Which setup method is better: Wheel or JavaScript package managers?"}),(0,o.jsx)("div",{children:(0,o.jsxs)("div",{children:[(0,o.jsxs)("p",{children:[(0,o.jsx)(n.strong,{children:"create-ceramic-app"})," is the fastest. Good for your first interaction with ComposeDB."]}),(0,o.jsx)("p",{children:(0,o.jsxs)(n.p,{children:[(0,o.jsx)(n.strong,{children:"Wheel"})," is the recommended and the easiest way to configure your working environment and install all the\nnecessary dependencies. We highly recommended going with Wheel if you are just starting out with Ceramic.\nEverything will be taken care of for you."]})}),(0,o.jsx)("p",{children:(0,o.jsxs)(n.p,{children:["You might consider using ",(0,o.jsx)(n.strong,{children:"JavaScript package managers"})," if you are already familiar with Ceramic and need more\nmanual configuration and control over your working environment."]})})]})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Which operating systems are supported?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"It's best to run Ceramic and ComposeDB on Linux or a Mac. You can also run it on Windows but you'll have to use\nWSL2 (Windows Subsystem for Linux). See the supported operating systems section at the top."})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Which Node.js version is preferred?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"We have seen the best results using Node.js v20. Earlier versions are no longer supported, later versions can\ncause issues for some users. While we're working on eliminating the issues, it's best to use Node v20 for now."})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"How long does it take to install the packages?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"Installing everything (either with Wheel or JavaScript packages) takes usually between 2 and 10 minutes.\nThroughout the guide above you can find what kind of output you should be looking for to know that everything was\ninstalled correctly."})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Where in the system do I run all of the commands?"}),(0,o.jsxs)("div",{children:[(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"Sometimes, especially when using JavaScript package managers to install Ceramic and ComposeDB, it's easy to forget\nthat you need to run all of the commands in the app's directory. This directory is either automatically created\nfor you when using Wheel, or you create it manually when using JavaScript package managers."})}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"When installing with JavaScript package managers you need to open 2-3 terminal windows and run different commands,\nso it's easy to miss that you can be in a wrong directory. Please make sure you run all the commands where they're\nsupposed to run."})})]})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Where can I find a Ceramic node configuration file, daemon.config.json?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsxs)(n.p,{children:["When installing ComposeDB with JavaScript package managers, at some point you need to edit your Ceramic node\nconfig file. By default, it's in your home directory, in .ceramic folder (",(0,o.jsx)(n.em,{children:"not"})," in the app directory). It's easy\nto miss this detail so please check the path. This command should take you to the right directory: cd ~/.ceramic"]})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"How to restart a node after stopping it?"}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"When you use Wheel to install Ceramic and ComposeDB, it takes care of the whole installation process. But please\nnote that Wheel is just an installer, not a node launcher. If you want to launch Ceramic and ComposeDB again, after\nyou have stopped it, you need to launch Ceramic daemon again and then launch ComposeDB."})}),(0,o.jsx)("div",{children:"You can launch Ceramic daemon by running the following command: ceramic daeomn --network=InMemory"}),(0,o.jsx)("div",{children:"You can launch ComposeDB by running the command: composedb"}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:'More on all of the composedb command options can be found in "2. Create your composite" section of this Getting\nStarted guide.'})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"How do I interact with the data once Ceramic node is running?"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:'The easiest way to interact with data is through a GraphQL Server. You can find all the details on how to set it\nup, launch, and interact with your data in section of this guide, "3. Interact with data"'})})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:(0,o.jsxs)(n.p,{children:["Error when creating a composite: \u2716 request to ",(0,o.jsx)(n.a,{href:"http://localhost:7007/(",children:"http://localhost:7007/("}),"...) failed, reason: connect ECONNREFUSED\n::1:7007"]})}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:"The most likely cause is using Node.js v18. Please try using Node.js v20."})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"Error: npm ERR! code EACCESS"}),(0,o.jsx)("div",{children:(0,o.jsx)("div",{children:"The most likely cause is read/write access on your system. Try running the command with sudo privileges."})})]}),"\n",(0,o.jsxs)(r,{children:[(0,o.jsx)("summary",{children:"What if my question is not answered on this page?"}),(0,o.jsxs)("div",{children:[(0,o.jsx)("div",{}),(0,o.jsx)("div",{children:(0,o.jsx)(n.p,{children:"If your question is not answered in this guide, we recommend visiting our Community Forum (see the link in the\nfooter). There, you can ask your question and get help from our community of developers and users. It's great to\nask anything: from beginner to expert questions. The community and our developers are there to help you."})})]})]}),"\n",(0,o.jsx)(n.hr,{}),"\n",(0,o.jsx)(n.h2,{id:"4-next-steps",children:"4. Next Steps"}),"\n",(0,o.jsx)(n.p,{children:"In this Quickstart guide, you have learned how to get started with ComposeDB. You have set up your development environment and are ready to start building your application. The next steps are:"}),"\n",(0,o.jsxs)(n.ul,{children:["\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./create-your-composite",children:(0,o.jsx)(n.strong,{children:"Create your composite"})})," - Learn how to create your first composite, a reusable data model that can be used across different applications."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./interact-with-data",children:(0,o.jsx)(n.strong,{children:"Interact with data"})})," - Learn how to interact with data in ComposeDB, from creating, reading, updating, and deleting data to running complex queries."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./core-concepts",children:(0,o.jsx)(n.strong,{children:"Core ComposeDB concepts"})})," - Learn about the core concepts of ComposeDB, such as composites, schemas, and queries."]}),"\n",(0,o.jsxs)(n.li,{children:[(0,o.jsx)(n.a,{href:"./guides/composedb-server/running-in-the-cloud",children:(0,o.jsx)(n.strong,{children:"Running in the cloud"})})," - Ready to upgrade from a local node to production? Learn how to deploy your app."]}),"\n"]})]})}function p(e={}){const{wrapper:n}={...(0,s.a)(),...e.components};return n?(0,o.jsx)(n,{...e,children:(0,o.jsx)(u,{...e})}):u(e)}},81779:(e,n,r)=>{r.d(n,{Z:()=>a});r(50959);var o=r(45924);const s={tabItem:"tabItem_e7Wc"};var i=r(11527);function a(e){let{children:n,hidden:r,className:a}=e;return(0,i.jsx)("div",{role:"tabpanel",className:(0,o.Z)(s.tabItem,a),hidden:r,children:n})}},37421:(e,n,r)=>{r.d(n,{Z:()=>b});var o=r(50959),s=r(45924),i=r(71988),a=r(28903),t=r(739),l=r(99965),c=r(43251),d=r(76698);function h(e){return o.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,o.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 child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the component should be , and every should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function u(e){const{values:n,children:r}=e;return(0,o.useMemo)((()=>{const e=n??function(e){return h(e).map((e=>{let{props:{value:n,label:r,attributes:o,default:s}}=e;return{value:n,label:r,attributes:o,default:s}}))}(r);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 . Every value needs to be unique.`)}(e),e}),[n,r])}function p(e){let{value:n,tabValues:r}=e;return r.some((e=>e.value===n))}function m(e){let{queryString:n=!1,groupId:r}=e;const s=(0,a.k6)(),i=function(e){let{queryString:n=!1,groupId:r}=e;if("string"==typeof n)return n;if(!1===n)return null;if(!0===n&&!r)throw new Error('Docusaurus error: The 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 r??null}({queryString:n,groupId:r});return[(0,l._X)(i),(0,o.useCallback)((e=>{if(!i)return;const n=new URLSearchParams(s.location.search);n.set(i,e),s.replace({...s.location,search:n.toString()})}),[i,s])]}function x(e){const{defaultValue:n,queryString:r=!1,groupId:s}=e,i=u(e),[a,l]=(0,o.useState)((()=>function(e){let{defaultValue:n,tabValues:r}=e;if(0===r.length)throw new Error("Docusaurus error: the component requires at least one children component");if(n){if(!p({value:n,tabValues:r}))throw new Error(`Docusaurus error: The has a defaultValue "${n}" but none of its children has the corresponding value. Available values are: ${r.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return n}const o=r.find((e=>e.default))??r[0];if(!o)throw new Error("Unexpected error: 0 tabValues");return o.value}({defaultValue:n,tabValues:i}))),[c,h]=m({queryString:r,groupId:s}),[x,g]=function(e){let{groupId:n}=e;const r=function(e){return e?`docusaurus.tab.${e}`:null}(n),[s,i]=(0,d.Nk)(r);return[s,(0,o.useCallback)((e=>{r&&i.set(e)}),[r,i])]}({groupId:s}),j=(()=>{const e=c??x;return p({value:e,tabValues:i})?e:null})();(0,t.Z)((()=>{j&&l(j)}),[j]);return{selectedValue:a,selectValue:(0,o.useCallback)((e=>{if(!p({value:e,tabValues:i}))throw new Error(`Can't select invalid tab value=${e}`);l(e),h(e),g(e)}),[h,g,i]),tabValues:i}}var g=r(12049);const j={tabList:"tabList_c3am",tabItem:"tabItem_iDuG"};var y=r(11527);function f(e){let{className:n,block:r,selectedValue:o,selectValue:a,tabValues:t}=e;const l=[],{blockElementScrollPositionUntilNextRender:c}=(0,i.o5)(),d=e=>{const n=e.currentTarget,r=l.indexOf(n),s=t[r].value;s!==o&&(c(n),a(s))},h=e=>{let n=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const r=l.indexOf(e.currentTarget)+1;n=l[r]??l[0];break}case"ArrowLeft":{const r=l.indexOf(e.currentTarget)-1;n=l[r]??l[l.length-1];break}}n?.focus()};return(0,y.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,s.Z)("tabs",{"tabs--block":r},n),children:t.map((e=>{let{value:n,label:r,attributes:i}=e;return(0,y.jsx)("li",{role:"tab",tabIndex:o===n?0:-1,"aria-selected":o===n,ref:e=>l.push(e),onKeyDown:h,onClick:d,...i,className:(0,s.Z)("tabs__item",j.tabItem,i?.className,{"tabs__item--active":o===n}),children:r??n},n)}))})}function v(e){let{lazy:n,children:r,selectedValue:s}=e;const i=(Array.isArray(r)?r:[r]).filter(Boolean);if(n){const e=i.find((e=>e.props.value===s));return e?(0,o.cloneElement)(e,{className:"margin-top--md"}):null}return(0,y.jsx)("div",{className:"margin-top--md",children:i.map(((e,n)=>(0,o.cloneElement)(e,{key:n,hidden:e.props.value!==s})))})}function w(e){const n=x(e);return(0,y.jsxs)("div",{className:(0,s.Z)("tabs-container",j.tabList),children:[(0,y.jsx)(f,{...e,...n}),(0,y.jsx)(v,{...e,...n})]})}function b(e){const n=(0,g.Z)();return(0,y.jsx)(w,{...e,children:h(e.children)},String(n))}},63883:(e,n,r)=>{r.d(n,{Z:()=>t,a:()=>a});var o=r(50959);const s={},i=o.createContext(s);function a(e){const n=o.useContext(i);return o.useMemo((function(){return"function"==typeof e?e(n):{...n,...e}}),[n,e])}function t(e){let n;return n=e.disableParentContext?"function"==typeof e.components?e.components(s):e.components||s:a(e.components),o.createElement(i.Provider,{value:n},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/f62bb520.98436485.js b/assets/js/f62bb520.b0344cc6.js similarity index 98% rename from assets/js/f62bb520.98436485.js rename to assets/js/f62bb520.b0344cc6.js index 1d3d38ae..975111b0 100644 --- a/assets/js/f62bb520.98436485.js +++ b/assets/js/f62bb520.b0344cc6.js @@ -1 +1 @@ -"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2096],{12346:(e,o,s)=>{s.r(o),s.d(o,{assets:()=>a,contentTitle:()=>d,default:()=>m,frontMatter:()=>n,metadata:()=>t,toc:()=>r});var l=s(11527),i=s(63883);const n={},d="Model Catalog",t={id:"composedb/guides/data-modeling/model-catalog",title:"Model Catalog",description:"Discover, share, and reuse data models.",source:"@site/docs/composedb/guides/data-modeling/model-catalog.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/model-catalog",permalink:"/docs/composedb/guides/data-modeling/model-catalog",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Data Modeling",permalink:"/docs/composedb/guides/data-modeling/"},next:{title:"Writing Models",permalink:"/docs/composedb/guides/data-modeling/writing-models"}},a={},r=[{value:"Overview",id:"overview",level:2},{value:"Use Cases",id:"use-cases",level:3},{value:"Adding models to the catalog",id:"adding-models-to-the-catalog",level:2},{value:"Using models from the catalog",id:"using-models-from-the-catalog",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"List all models",id:"list-all-models",level:3},{value:"Using a single model",id:"using-a-single-model",level:3},{value:"Using multiple models",id:"using-multiple-models",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Related Guides",id:"related-guides",level:2}];function c(e){const o={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,i.a)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(o.h1,{id:"model-catalog",children:"Model Catalog"}),"\n",(0,l.jsx)(o.p,{children:"Discover, share, and reuse data models."}),"\n",(0,l.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.p,{children:"The catalog is a free and open source repository of all data models created by the ComposeDB developer community. The catalog aims to make it as easy as possible for developers to discover, share, and reuse each others models and underlying data."}),"\n",(0,l.jsx)(o.p,{children:(0,l.jsx)(o.img,{alt:"Data Model Table",src:s(50150).Z+"",width:"2824",height:"1422"})}),"\n",(0,l.jsx)(o.h3,{id:"use-cases",children:"Use Cases"}),"\n",(0,l.jsxs)(o.ul,{children:["\n",(0,l.jsx)(o.li,{children:"Discover high-quality models for your app"}),"\n",(0,l.jsx)(o.li,{children:"Share and distribute your models to others"}),"\n"]}),"\n",(0,l.jsx)(o.h2,{id:"adding-models-to-the-catalog",children:"Adding models to the catalog"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.p,{children:"Models in all deployed composites are automatically available on the catalog."}),"\n",(0,l.jsx)(o.p,{children:"How it works:"}),"\n",(0,l.jsxs)(o.ol,{children:["\n",(0,l.jsxs)(o.li,{children:["A developer deploys a ",(0,l.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/composites",children:"composite"})," containing models to testnet or mainnet"]}),"\n",(0,l.jsx)(o.li,{children:"An indexer builds a catalog of all deployed models and exposes it via API"}),"\n",(0,l.jsx)(o.li,{children:"The catalog is automatically available on various interfaces, including ComposeDB CLI"}),"\n"]}),"\n",(0,l.jsx)(o.h2,{id:"using-models-from-the-catalog",children:"Using models from the catalog"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.h3,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,l.jsxs)(o.p,{children:["You need a running instance of ComposeDB server and CLI to use the catalog. See ",(0,l.jsx)(o.a,{href:"/docs/composedb/set-up-your-environment",children:"set up your environment"})," to get started."]}),"\n",(0,l.jsx)(o.h3,{id:"list-all-models",children:"List all models"}),"\n",(0,l.jsx)(o.p,{children:"Using ComposeDB CLI, run the following command to list all models:"}),"\n",(0,l.jsx)(o.pre,{children:(0,l.jsx)(o.code,{className:"language-sh",children:"composedb model:list --table\n"})}),"\n",(0,l.jsx)(o.p,{children:"You will see a table where each model has the following metadata properties:"}),"\n",(0,l.jsxs)(o.ul,{children:["\n",(0,l.jsxs)(o.li,{children:[(0,l.jsx)(o.code,{children:"Name"})," - name of the model"]}),"\n",(0,l.jsxs)(o.li,{children:[(0,l.jsx)(o.code,{children:"ID"})," - unique identifier (streamID) of the model"]}),"\n",(0,l.jsxs)(o.li,{children:[(0,l.jsx)(o.code,{children:"Description"})," - description of the model"]}),"\n"]}),"\n",(0,l.jsx)(o.h3,{id:"using-a-single-model",children:"Using a single model"}),"\n",(0,l.jsx)(o.p,{children:"Fetch a single model from the catalog and convert it into a composite, using its model ID:"}),"\n",(0,l.jsx)(o.pre,{children:(0,l.jsx)(o.code,{className:"language-sh",children:"composedb composite:from-model kjzl6hvfrbw6c7keo17n66rxyo21nqqaa9lh491jz16od43nokz7ksfcvzi6bwc --output=my-composite.json\n"})}),"\n",(0,l.jsx)(o.h3,{id:"using-multiple-models",children:"Using multiple models"}),"\n",(0,l.jsxs)(o.p,{children:["Run the ",(0,l.jsx)(o.code,{children:"composite:from-model"})," command depicted above for each model you want to use in your application. Remember to change the composite file name to avoid collisions. After you have multiple composite files, merge them. See Merging Composites."]}),"\n",(0,l.jsx)(o.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.p,{children:"To use your newly created composite in your app, you will need to deploy and compile your composite."}),"\n",(0,l.jsx)(o.h2,{id:"related-guides",children:"Related Guides"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsxs)(o.p,{children:["Can\u2019t find what you\u2019re looking for in the catalog? See ",(0,l.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"})," to learn how to write your own models."]})]})}function m(e={}){const{wrapper:o}={...(0,i.a)(),...e.components};return o?(0,l.jsx)(o,{...e,children:(0,l.jsx)(c,{...e})}):c(e)}},50150:(e,o,s)=>{s.d(o,{Z:()=>l});const l=s.p+"assets/images/data-model-table-9edfb95dc33320c39c7c54bf99facad5.png"},63883:(e,o,s)=>{s.d(o,{Z:()=>t,a:()=>d});var l=s(50959);const i={},n=l.createContext(i);function d(e){const o=l.useContext(n);return l.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function t(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),l.createElement(n.Provider,{value:o},e.children)}}}]); \ No newline at end of file +"use strict";(self.webpackChunkdocs=self.webpackChunkdocs||[]).push([[2096],{12346:(e,o,s)=>{s.r(o),s.d(o,{assets:()=>a,contentTitle:()=>d,default:()=>m,frontMatter:()=>n,metadata:()=>t,toc:()=>r});var l=s(11527),i=s(63883);const n={},d="Model Catalog",t={id:"composedb/guides/data-modeling/model-catalog",title:"Model Catalog",description:"Discover, share, and reuse data models.",source:"@site/docs/composedb/guides/data-modeling/model-catalog.mdx",sourceDirName:"composedb/guides/data-modeling",slug:"/composedb/guides/data-modeling/model-catalog",permalink:"/docs/composedb/guides/data-modeling/model-catalog",draft:!1,unlisted:!1,tags:[],version:"current",frontMatter:{},sidebar:"composedb",previous:{title:"Data Modeling",permalink:"/docs/composedb/guides/data-modeling/"},next:{title:"Writing Models",permalink:"/docs/composedb/guides/data-modeling/writing-models"}},a={},r=[{value:"Overview",id:"overview",level:2},{value:"Use Cases",id:"use-cases",level:3},{value:"Adding models to the catalog",id:"adding-models-to-the-catalog",level:2},{value:"Using models from the catalog",id:"using-models-from-the-catalog",level:2},{value:"Prerequisites",id:"prerequisites",level:3},{value:"List all models",id:"list-all-models",level:3},{value:"Using a single model",id:"using-a-single-model",level:3},{value:"Using multiple models",id:"using-multiple-models",level:3},{value:"Next Steps",id:"next-steps",level:2},{value:"Related Guides",id:"related-guides",level:2}];function c(e){const o={a:"a",code:"code",h1:"h1",h2:"h2",h3:"h3",hr:"hr",img:"img",li:"li",ol:"ol",p:"p",pre:"pre",ul:"ul",...(0,i.a)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(o.h1,{id:"model-catalog",children:"Model Catalog"}),"\n",(0,l.jsx)(o.p,{children:"Discover, share, and reuse data models."}),"\n",(0,l.jsx)(o.h2,{id:"overview",children:"Overview"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.p,{children:"The catalog is a free and open source repository of all data models created by the ComposeDB developer community. The catalog aims to make it as easy as possible for developers to discover, share, and reuse each others models and underlying data."}),"\n",(0,l.jsx)(o.p,{children:(0,l.jsx)(o.img,{alt:"Data Model Table",src:s(50150).Z+"",width:"2824",height:"1422"})}),"\n",(0,l.jsx)(o.h3,{id:"use-cases",children:"Use Cases"}),"\n",(0,l.jsxs)(o.ul,{children:["\n",(0,l.jsx)(o.li,{children:"Discover high-quality models for your app"}),"\n",(0,l.jsx)(o.li,{children:"Share and distribute your models to others"}),"\n"]}),"\n",(0,l.jsx)(o.h2,{id:"adding-models-to-the-catalog",children:"Adding models to the catalog"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.p,{children:"Models in all deployed composites are automatically available on the catalog."}),"\n",(0,l.jsx)(o.p,{children:"How it works:"}),"\n",(0,l.jsxs)(o.ol,{children:["\n",(0,l.jsxs)(o.li,{children:["A developer deploys a ",(0,l.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/composites",children:"composite"})," containing models to testnet or mainnet"]}),"\n",(0,l.jsx)(o.li,{children:"An indexer builds a catalog of all deployed models and exposes it via API"}),"\n",(0,l.jsx)(o.li,{children:"The catalog is automatically available on various interfaces, including ComposeDB CLI"}),"\n"]}),"\n",(0,l.jsx)(o.h2,{id:"using-models-from-the-catalog",children:"Using models from the catalog"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.h3,{id:"prerequisites",children:"Prerequisites"}),"\n",(0,l.jsxs)(o.p,{children:["You need a running instance of ComposeDB server and CLI to use the catalog. See ",(0,l.jsx)(o.a,{href:"/docs/composedb/set-up-your-environment",children:"set up your environment"})," to get started."]}),"\n",(0,l.jsx)(o.h3,{id:"list-all-models",children:"List all models"}),"\n",(0,l.jsx)(o.p,{children:"Using ComposeDB CLI, run the following command to list all models:"}),"\n",(0,l.jsx)(o.pre,{children:(0,l.jsx)(o.code,{className:"language-sh",children:"composedb model:list --table\n"})}),"\n",(0,l.jsx)(o.p,{children:"You will see a table where each model has the following metadata properties:"}),"\n",(0,l.jsxs)(o.ul,{children:["\n",(0,l.jsxs)(o.li,{children:[(0,l.jsx)(o.code,{children:"Name"})," - name of the model"]}),"\n",(0,l.jsxs)(o.li,{children:[(0,l.jsx)(o.code,{children:"ID"})," - unique identifier (streamID) of the model"]}),"\n",(0,l.jsxs)(o.li,{children:[(0,l.jsx)(o.code,{children:"Description"})," - description of the model"]}),"\n"]}),"\n",(0,l.jsx)(o.h3,{id:"using-a-single-model",children:"Using a single model"}),"\n",(0,l.jsx)(o.p,{children:"Fetch a single model from the catalog and convert it into a composite, using its model ID:"}),"\n",(0,l.jsx)(o.pre,{children:(0,l.jsx)(o.code,{className:"language-sh",children:"composedb composite:from-model kjzl6hvfrbw6c5i55ks5m4hhyuh0jylw4g7x0asndu97i7luts4dfzvm35oev65 --output=my-composite.json\n"})}),"\n",(0,l.jsx)(o.h3,{id:"using-multiple-models",children:"Using multiple models"}),"\n",(0,l.jsxs)(o.p,{children:["Run the ",(0,l.jsx)(o.code,{children:"composite:from-model"})," command depicted above for each model you want to use in your application. Remember to change the composite file name to avoid collisions. After you have multiple composite files, merge them. See Merging Composites."]}),"\n",(0,l.jsx)(o.h2,{id:"next-steps",children:"Next Steps"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsx)(o.p,{children:"To use your newly created composite in your app, you will need to deploy and compile your composite."}),"\n",(0,l.jsx)(o.h2,{id:"related-guides",children:"Related Guides"}),"\n",(0,l.jsx)(o.hr,{}),"\n",(0,l.jsxs)(o.p,{children:["Can\u2019t find what you\u2019re looking for in the catalog? See ",(0,l.jsx)(o.a,{href:"/docs/composedb/guides/data-modeling/writing-models",children:"Writing Models"})," to learn how to write your own models."]})]})}function m(e={}){const{wrapper:o}={...(0,i.a)(),...e.components};return o?(0,l.jsx)(o,{...e,children:(0,l.jsx)(c,{...e})}):c(e)}},50150:(e,o,s)=>{s.d(o,{Z:()=>l});const l=s.p+"assets/images/data-model-table-9edfb95dc33320c39c7c54bf99facad5.png"},63883:(e,o,s)=>{s.d(o,{Z:()=>t,a:()=>d});var l=s(50959);const i={},n=l.createContext(i);function d(e){const o=l.useContext(n);return l.useMemo((function(){return"function"==typeof e?e(o):{...o,...e}}),[o,e])}function t(e){let o;return o=e.disableParentContext?"function"==typeof e.components?e.components(i):e.components||i:d(e.components),l.createElement(n.Provider,{value:o},e.children)}}}]); \ No newline at end of file diff --git a/assets/js/runtime~main.f8f59563.js b/assets/js/runtime~main.38676fb0.js similarity index 95% rename from assets/js/runtime~main.f8f59563.js rename to assets/js/runtime~main.38676fb0.js index 58014490..8a84f250 100644 --- a/assets/js/runtime~main.f8f59563.js +++ b/assets/js/runtime~main.38676fb0.js @@ -1 +1 @@ -(()=>{"use strict";var e,a,d,f,c,b={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var d=t[e]={id:e,loaded:!1,exports:{}};return b[e].call(d.exports,d,d.exports,r),d.loaded=!0,d.exports}r.m=b,r.amdO={},e=[],r.O=(a,d,f,c)=>{if(!d){var b=1/0;for(i=0;i=c)&&Object.keys(r.O).every((e=>r.O[e](d[o])))?d.splice(o--,1):(t=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[d,f,c]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var c=Object.create(null);r.r(c);var b={};a=a||[null,d({}),d([]),d(d)];for(var t=2&f&&e;"object"==typeof t&&!~a.indexOf(t);t=d(t))Object.getOwnPropertyNames(t).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,r.d(c,b),c},r.d=(e,a)=>{for(var d in a)r.o(a,d)&&!r.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:a[d]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,d)=>(r.f[d](e,a),a)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",78:"7e11ed3f",81:"aff15e2c",123:"291cea97",214:"3e79c00b",282:"ba3f6249",479:"f4efe5df",534:"ceeb2b4c",1032:"e6be3d8d",1338:"d259cc28",1563:"c9154a8c",1613:"25ce1775",1629:"8ce4b383",1693:"ce6e997c",1708:"4a4bd56d",1797:"c9a78a7a",1949:"f3dd1d93",2096:"f62bb520",2138:"338e03eb",2416:"01a9496d",2439:"710ba772",2731:"aa0f1462",2920:"645a40c9",2921:"f24b2b48",3085:"1f391b9e",3091:"b270863b",3133:"15f296da",3204:"c716af53",3235:"5395834c",3281:"4b6678a8",3299:"6c6412b8",3526:"3f1108f7",3605:"89d63585",3867:"8a67f073",3939:"d4116bca",4183:"d05820b1",4195:"c4f5d8e4",4209:"099b0b93",4236:"c2945dd9",4278:"150e3322",4315:"dd095bbf",4331:"ee43cb92",4354:"de911483",4368:"a94703ab",4477:"bce0453e",4492:"39e7b47c",4506:"35d5cb5a",4533:"9501b78f",4559:"0c1e5038",4571:"4a5609e3",4644:"3d8c81e5",4654:"70664883",4912:"cb1aa78b",5080:"2aa4703d",5180:"50ac8df9",5300:"ddae1884",5579:"f70d46ff",5747:"72d73ab2",5925:"7926ff25",5938:"5f51428e",6106:"38c62372",6222:"e04d35f3",6322:"273faaa4",6334:"56263542",6376:"26f80a59",6381:"c1a66efd",6448:"ce565fec",6565:"694ea443",6677:"d49c56fb",6782:"6c1d9ad5",7412:"146626bd",7414:"393be207",7457:"eb3e7197",7786:"2f85ee40",7794:"ea61a43e",7918:"17896441",7920:"1a4e3797",7935:"25c8d778",8068:"658e741e",8213:"28eff070",8463:"88efdd69",8478:"cb57f702",8518:"a7bd4aaa",8547:"7937e713",8606:"f613eb11",8950:"00a9185c",9106:"592feb7b",9146:"3ed8e140",9175:"ab942642",9240:"6897c3e9",9267:"19a9fad3",9268:"afee21f6",9424:"3ed9d3dd",9428:"7c046a56",9495:"01709c1f",9540:"ed53dec9",9661:"5e95c892",9728:"dce36073",9798:"78a5e76b",9896:"9362b507",9930:"c65b14c4"}[e]||e)+"."+{53:"3a424b8c",78:"99b58050",81:"0efae874",123:"003ee5ce",214:"21dedcd0",282:"292acd00",479:"3b9b2218",534:"7a5e1202",1032:"66aa35f2",1090:"03489973",1142:"bccb8c89",1338:"b64344b9",1474:"8d846b5f",1549:"03851758",1563:"a7aee102",1595:"9bd42bfb",1613:"d7721ce6",1629:"be9f8463",1693:"7cd44b64",1708:"08bb08c4",1797:"043b62a4",1949:"f0485e1d",2096:"98436485",2138:"db8be613",2416:"4efcdaf7",2439:"b26a515e",2508:"e808cebe",2542:"85a28d2c",2622:"c6af7613",2731:"34b566f1",2920:"93f59ecf",2921:"2b614ce3",3076:"b459935d",3085:"5a63db22",3091:"e7794033",3133:"b5e99075",3204:"4452f8fb",3235:"bb316e2b",3241:"5dc1cc36",3281:"8aa8c905",3299:"ce19160f",3526:"7bad267a",3544:"dc458fd5",3605:"bd26d889",3867:"ecfafa3a",3939:"ee97628e",4015:"e35ae8d0",4061:"1bd77c9a",4183:"1352a88b",4195:"21bad148",4209:"7b4a5c44",4236:"7bc6690d",4257:"1d41b759",4278:"0ea94b3e",4291:"44ddbbff",4315:"0be7468b",4331:"441a12eb",4354:"3f466acc",4368:"9efb7069",4399:"d9940d2f",4477:"b53ac0a5",4492:"a638cd2c",4506:"1dedea6b",4533:"4ee046de",4559:"fd560ea0",4571:"6762f67e",4579:"86df400c",4644:"344ca2b5",4653:"f6671511",4654:"cd11e5c6",4912:"a6b7111d",5080:"fbf985b1",5180:"3f905d6d",5297:"0d530261",5300:"5fd1e49e",5579:"dcceaf6a",5703:"c120a798",5727:"ae545876",5747:"8ea27ce9",5902:"c83b7144",5925:"eedb3bfd",5938:"0b27ca41",6106:"cb626a00",6142:"3a77b229",6222:"8a275b9a",6270:"acd6c8af",6322:"06f69951",6334:"5de5c142",6376:"d0bddf30",6381:"e32d038b",6448:"b8e471b2",6487:"e3e92d18",6560:"bf490696",6565:"33b3e12e",6677:"d8c3e03e",6782:"7bae9687",7147:"4d2c78ff",7412:"94970fe1",7414:"83dcf5ed",7439:"875151a5",7457:"b37239e4",7786:"fbc899c1",7794:"040ff102",7918:"2127455d",7920:"7cbd2130",7935:"972830d8",8068:"223fc679",8134:"b5028f03",8213:"0f9989ac",8463:"861dc452",8478:"a99f9c95",8518:"bfd594d2",8547:"eeb345c8",8606:"50f2f900",8613:"19a8b0d0",8950:"ca27cc7d",9106:"ba604b61",9146:"c54dba5e",9175:"3e42bd3b",9240:"24a2cc5b",9267:"56ddab8a",9268:"3aebfb1e",9424:"aab7e91b",9428:"47cc4add",9475:"811b55ba",9495:"e96620f6",9540:"1ba16b69",9661:"0dd244cc",9728:"e0ddf4d0",9798:"2e176f38",9896:"e8f8b5b0",9930:"a4ec967e"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},c="docs:",r.l=(e,a,d,b)=>{if(f[e])f[e].push(a);else{var t,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var c=f[e];if(delete f[e],t.parentNode&&t.parentNode.removeChild(t),c&&c.forEach((e=>e(d))),a)return a(d)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=u.bind(null,t.onerror),t.onload=u.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),r.p="/",r.gca=function(e){return e={17896441:"7918",56263542:"6334",70664883:"4654","935f2afb":"53","7e11ed3f":"78",aff15e2c:"81","291cea97":"123","3e79c00b":"214",ba3f6249:"282",f4efe5df:"479",ceeb2b4c:"534",e6be3d8d:"1032",d259cc28:"1338",c9154a8c:"1563","25ce1775":"1613","8ce4b383":"1629",ce6e997c:"1693","4a4bd56d":"1708",c9a78a7a:"1797",f3dd1d93:"1949",f62bb520:"2096","338e03eb":"2138","01a9496d":"2416","710ba772":"2439",aa0f1462:"2731","645a40c9":"2920",f24b2b48:"2921","1f391b9e":"3085",b270863b:"3091","15f296da":"3133",c716af53:"3204","5395834c":"3235","4b6678a8":"3281","6c6412b8":"3299","3f1108f7":"3526","89d63585":"3605","8a67f073":"3867",d4116bca:"3939",d05820b1:"4183",c4f5d8e4:"4195","099b0b93":"4209",c2945dd9:"4236","150e3322":"4278",dd095bbf:"4315",ee43cb92:"4331",de911483:"4354",a94703ab:"4368",bce0453e:"4477","39e7b47c":"4492","35d5cb5a":"4506","9501b78f":"4533","0c1e5038":"4559","4a5609e3":"4571","3d8c81e5":"4644",cb1aa78b:"4912","2aa4703d":"5080","50ac8df9":"5180",ddae1884:"5300",f70d46ff:"5579","72d73ab2":"5747","7926ff25":"5925","5f51428e":"5938","38c62372":"6106",e04d35f3:"6222","273faaa4":"6322","26f80a59":"6376",c1a66efd:"6381",ce565fec:"6448","694ea443":"6565",d49c56fb:"6677","6c1d9ad5":"6782","146626bd":"7412","393be207":"7414",eb3e7197:"7457","2f85ee40":"7786",ea61a43e:"7794","1a4e3797":"7920","25c8d778":"7935","658e741e":"8068","28eff070":"8213","88efdd69":"8463",cb57f702:"8478",a7bd4aaa:"8518","7937e713":"8547",f613eb11:"8606","00a9185c":"8950","592feb7b":"9106","3ed8e140":"9146",ab942642:"9175","6897c3e9":"9240","19a9fad3":"9267",afee21f6:"9268","3ed9d3dd":"9424","7c046a56":"9428","01709c1f":"9495",ed53dec9:"9540","5e95c892":"9661",dce36073:"9728","78a5e76b":"9798","9362b507":"9896",c65b14c4:"9930"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,d)=>{var f=r.o(e,a)?e[a]:void 0;if(0!==f)if(f)d.push(f[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var c=new Promise(((d,c)=>f=e[a]=[d,c]));d.push(f[2]=c);var b=r.p+r.u(a),t=new Error;r.l(b,(d=>{if(r.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var c=d&&("load"===d.type?"missing":d.type),b=d&&d.target&&d.target.src;t.message="Loading chunk "+a+" failed.\n("+c+": "+b+")",t.name="ChunkLoadError",t.type=c,t.request=b,f[1](t)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,d)=>{var f,c,b=d[0],t=d[1],o=d[2],n=0;if(b.some((a=>0!==e[a]))){for(f in t)r.o(t,f)&&(r.m[f]=t[f]);if(o)var i=o(r)}for(a&&a(d);n{"use strict";var e,a,d,f,c,b={},t={};function r(e){var a=t[e];if(void 0!==a)return a.exports;var d=t[e]={id:e,loaded:!1,exports:{}};return b[e].call(d.exports,d,d.exports,r),d.loaded=!0,d.exports}r.m=b,r.amdO={},e=[],r.O=(a,d,f,c)=>{if(!d){var b=1/0;for(i=0;i=c)&&Object.keys(r.O).every((e=>r.O[e](d[o])))?d.splice(o--,1):(t=!1,c0&&e[i-1][2]>c;i--)e[i]=e[i-1];e[i]=[d,f,c]},r.n=e=>{var a=e&&e.__esModule?()=>e.default:()=>e;return r.d(a,{a:a}),a},d=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__,r.t=function(e,f){if(1&f&&(e=this(e)),8&f)return e;if("object"==typeof e&&e){if(4&f&&e.__esModule)return e;if(16&f&&"function"==typeof e.then)return e}var c=Object.create(null);r.r(c);var b={};a=a||[null,d({}),d([]),d(d)];for(var t=2&f&&e;"object"==typeof t&&!~a.indexOf(t);t=d(t))Object.getOwnPropertyNames(t).forEach((a=>b[a]=()=>e[a]));return b.default=()=>e,r.d(c,b),c},r.d=(e,a)=>{for(var d in a)r.o(a,d)&&!r.o(e,d)&&Object.defineProperty(e,d,{enumerable:!0,get:a[d]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce(((a,d)=>(r.f[d](e,a),a)),[])),r.u=e=>"assets/js/"+({53:"935f2afb",78:"7e11ed3f",81:"aff15e2c",123:"291cea97",214:"3e79c00b",282:"ba3f6249",479:"f4efe5df",534:"ceeb2b4c",1032:"e6be3d8d",1338:"d259cc28",1563:"c9154a8c",1613:"25ce1775",1629:"8ce4b383",1693:"ce6e997c",1708:"4a4bd56d",1797:"c9a78a7a",1949:"f3dd1d93",2096:"f62bb520",2138:"338e03eb",2416:"01a9496d",2439:"710ba772",2731:"aa0f1462",2920:"645a40c9",2921:"f24b2b48",3085:"1f391b9e",3091:"b270863b",3133:"15f296da",3204:"c716af53",3235:"5395834c",3281:"4b6678a8",3299:"6c6412b8",3526:"3f1108f7",3605:"89d63585",3867:"8a67f073",3939:"d4116bca",4183:"d05820b1",4195:"c4f5d8e4",4209:"099b0b93",4236:"c2945dd9",4278:"150e3322",4315:"dd095bbf",4331:"ee43cb92",4354:"de911483",4368:"a94703ab",4477:"bce0453e",4492:"39e7b47c",4506:"35d5cb5a",4533:"9501b78f",4559:"0c1e5038",4571:"4a5609e3",4644:"3d8c81e5",4654:"70664883",4912:"cb1aa78b",5080:"2aa4703d",5180:"50ac8df9",5300:"ddae1884",5579:"f70d46ff",5747:"72d73ab2",5925:"7926ff25",5938:"5f51428e",6106:"38c62372",6222:"e04d35f3",6322:"273faaa4",6334:"56263542",6376:"26f80a59",6381:"c1a66efd",6448:"ce565fec",6565:"694ea443",6677:"d49c56fb",6782:"6c1d9ad5",7412:"146626bd",7414:"393be207",7457:"eb3e7197",7786:"2f85ee40",7794:"ea61a43e",7918:"17896441",7920:"1a4e3797",7935:"25c8d778",8068:"658e741e",8213:"28eff070",8463:"88efdd69",8478:"cb57f702",8518:"a7bd4aaa",8547:"7937e713",8606:"f613eb11",8950:"00a9185c",9106:"592feb7b",9146:"3ed8e140",9175:"ab942642",9240:"6897c3e9",9267:"19a9fad3",9268:"afee21f6",9424:"3ed9d3dd",9428:"7c046a56",9495:"01709c1f",9540:"ed53dec9",9661:"5e95c892",9728:"dce36073",9798:"78a5e76b",9896:"9362b507",9930:"c65b14c4"}[e]||e)+"."+{53:"3a424b8c",78:"99b58050",81:"0efae874",123:"003ee5ce",214:"21dedcd0",282:"292acd00",479:"3b9b2218",534:"7a5e1202",1032:"66aa35f2",1090:"03489973",1142:"bccb8c89",1338:"b64344b9",1474:"8d846b5f",1549:"03851758",1563:"b0f62f6e",1595:"9bd42bfb",1613:"d7721ce6",1629:"be9f8463",1693:"7cd44b64",1708:"08bb08c4",1797:"043b62a4",1949:"f0485e1d",2096:"b0344cc6",2138:"db8be613",2416:"4efcdaf7",2439:"b26a515e",2508:"e808cebe",2542:"85a28d2c",2622:"c6af7613",2731:"34b566f1",2920:"93f59ecf",2921:"2b614ce3",3076:"b459935d",3085:"5a63db22",3091:"e7794033",3133:"b5e99075",3204:"4452f8fb",3235:"bb316e2b",3241:"5dc1cc36",3281:"8aa8c905",3299:"ce19160f",3526:"7bad267a",3544:"dc458fd5",3605:"bd26d889",3867:"ecfafa3a",3939:"ee97628e",4015:"e35ae8d0",4061:"1bd77c9a",4183:"1352a88b",4195:"21bad148",4209:"7b4a5c44",4236:"7bc6690d",4257:"1d41b759",4278:"0ea94b3e",4291:"44ddbbff",4315:"0be7468b",4331:"441a12eb",4354:"3f466acc",4368:"9efb7069",4399:"d9940d2f",4477:"b53ac0a5",4492:"a638cd2c",4506:"1dedea6b",4533:"a765143f",4559:"fd560ea0",4571:"6762f67e",4579:"86df400c",4644:"344ca2b5",4653:"f6671511",4654:"cd11e5c6",4912:"a6b7111d",5080:"fbf985b1",5180:"300fecc8",5297:"0d530261",5300:"5fd1e49e",5579:"dcceaf6a",5703:"c120a798",5727:"ae545876",5747:"8ea27ce9",5902:"c83b7144",5925:"eedb3bfd",5938:"0b27ca41",6106:"cb626a00",6142:"3a77b229",6222:"8a275b9a",6270:"acd6c8af",6322:"06f69951",6334:"5de5c142",6376:"d0bddf30",6381:"e32d038b",6448:"94828a0a",6487:"e3e92d18",6560:"bf490696",6565:"33b3e12e",6677:"d8c3e03e",6782:"7bae9687",7147:"4d2c78ff",7412:"94970fe1",7414:"83dcf5ed",7439:"875151a5",7457:"b37239e4",7786:"fbc899c1",7794:"040ff102",7918:"2127455d",7920:"7cbd2130",7935:"972830d8",8068:"223fc679",8134:"b5028f03",8213:"0f9989ac",8463:"861dc452",8478:"a99f9c95",8518:"bfd594d2",8547:"eeb345c8",8606:"50f2f900",8613:"19a8b0d0",8950:"ca27cc7d",9106:"ba604b61",9146:"c54dba5e",9175:"3e42bd3b",9240:"24a2cc5b",9267:"56ddab8a",9268:"3aebfb1e",9424:"aab7e91b",9428:"47cc4add",9475:"811b55ba",9495:"e96620f6",9540:"1ba16b69",9661:"0dd244cc",9728:"e0ddf4d0",9798:"2e176f38",9896:"e8f8b5b0",9930:"a4ec967e"}[e]+".js",r.miniCssF=e=>{},r.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),r.o=(e,a)=>Object.prototype.hasOwnProperty.call(e,a),f={},c="docs:",r.l=(e,a,d,b)=>{if(f[e])f[e].push(a);else{var t,o;if(void 0!==d)for(var n=document.getElementsByTagName("script"),i=0;i{t.onerror=t.onload=null,clearTimeout(s);var c=f[e];if(delete f[e],t.parentNode&&t.parentNode.removeChild(t),c&&c.forEach((e=>e(d))),a)return a(d)},s=setTimeout(u.bind(null,void 0,{type:"timeout",target:t}),12e4);t.onerror=u.bind(null,t.onerror),t.onload=u.bind(null,t.onload),o&&document.head.appendChild(t)}},r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),r.p="/",r.gca=function(e){return e={17896441:"7918",56263542:"6334",70664883:"4654","935f2afb":"53","7e11ed3f":"78",aff15e2c:"81","291cea97":"123","3e79c00b":"214",ba3f6249:"282",f4efe5df:"479",ceeb2b4c:"534",e6be3d8d:"1032",d259cc28:"1338",c9154a8c:"1563","25ce1775":"1613","8ce4b383":"1629",ce6e997c:"1693","4a4bd56d":"1708",c9a78a7a:"1797",f3dd1d93:"1949",f62bb520:"2096","338e03eb":"2138","01a9496d":"2416","710ba772":"2439",aa0f1462:"2731","645a40c9":"2920",f24b2b48:"2921","1f391b9e":"3085",b270863b:"3091","15f296da":"3133",c716af53:"3204","5395834c":"3235","4b6678a8":"3281","6c6412b8":"3299","3f1108f7":"3526","89d63585":"3605","8a67f073":"3867",d4116bca:"3939",d05820b1:"4183",c4f5d8e4:"4195","099b0b93":"4209",c2945dd9:"4236","150e3322":"4278",dd095bbf:"4315",ee43cb92:"4331",de911483:"4354",a94703ab:"4368",bce0453e:"4477","39e7b47c":"4492","35d5cb5a":"4506","9501b78f":"4533","0c1e5038":"4559","4a5609e3":"4571","3d8c81e5":"4644",cb1aa78b:"4912","2aa4703d":"5080","50ac8df9":"5180",ddae1884:"5300",f70d46ff:"5579","72d73ab2":"5747","7926ff25":"5925","5f51428e":"5938","38c62372":"6106",e04d35f3:"6222","273faaa4":"6322","26f80a59":"6376",c1a66efd:"6381",ce565fec:"6448","694ea443":"6565",d49c56fb:"6677","6c1d9ad5":"6782","146626bd":"7412","393be207":"7414",eb3e7197:"7457","2f85ee40":"7786",ea61a43e:"7794","1a4e3797":"7920","25c8d778":"7935","658e741e":"8068","28eff070":"8213","88efdd69":"8463",cb57f702:"8478",a7bd4aaa:"8518","7937e713":"8547",f613eb11:"8606","00a9185c":"8950","592feb7b":"9106","3ed8e140":"9146",ab942642:"9175","6897c3e9":"9240","19a9fad3":"9267",afee21f6:"9268","3ed9d3dd":"9424","7c046a56":"9428","01709c1f":"9495",ed53dec9:"9540","5e95c892":"9661",dce36073:"9728","78a5e76b":"9798","9362b507":"9896",c65b14c4:"9930"}[e]||e,r.p+r.u(e)},(()=>{var e={1303:0,532:0};r.f.j=(a,d)=>{var f=r.o(e,a)?e[a]:void 0;if(0!==f)if(f)d.push(f[2]);else if(/^(1303|532)$/.test(a))e[a]=0;else{var c=new Promise(((d,c)=>f=e[a]=[d,c]));d.push(f[2]=c);var b=r.p+r.u(a),t=new Error;r.l(b,(d=>{if(r.o(e,a)&&(0!==(f=e[a])&&(e[a]=void 0),f)){var c=d&&("load"===d.type?"missing":d.type),b=d&&d.target&&d.target.src;t.message="Loading chunk "+a+" failed.\n("+c+": "+b+")",t.name="ChunkLoadError",t.type=c,t.request=b,f[1](t)}}),"chunk-"+a,a)}},r.O.j=a=>0===e[a];var a=(a,d)=>{var f,c,b=d[0],t=d[1],o=d[2],n=0;if(b.some((a=>0!==e[a]))){for(f in t)r.o(t,f)&&(r.m[f]=t[f]);if(o)var i=o(r)}for(a&&a(d);n