@geoprotocol/geo-sdk 0.18.3 → 0.20.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1047 -371
- package/dist/contracts.d.ts +0 -11
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +0 -11
- package/dist/contracts.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/lite.d.ts +2 -0
- package/dist/lite.d.ts.map +1 -1
- package/dist/lite.js +2 -0
- package/dist/lite.js.map +1 -1
- package/dist/src/abis/dao-space-factory.d.ts +43 -6
- package/dist/src/abis/dao-space-factory.d.ts.map +1 -1
- package/dist/src/abis/dao-space-factory.js +38 -27
- package/dist/src/abis/dao-space-factory.js.map +1 -1
- package/dist/src/abis/dao-space-v2.test.d.ts +2 -0
- package/dist/src/abis/dao-space-v2.test.d.ts.map +1 -0
- package/dist/src/abis/dao-space-v2.test.js +67 -0
- package/dist/src/abis/dao-space-v2.test.js.map +1 -0
- package/dist/src/abis/dao-space.d.ts +98 -7
- package/dist/src/abis/dao-space.d.ts.map +1 -1
- package/dist/src/abis/dao-space.js +61 -99
- package/dist/src/abis/dao-space.js.map +1 -1
- package/dist/src/abis/index.d.ts +2 -2
- package/dist/src/abis/index.d.ts.map +1 -1
- package/dist/src/abis/index.js +2 -2
- package/dist/src/abis/index.js.map +1 -1
- package/dist/src/api-surface.e2e.test.d.ts +2 -0
- package/dist/src/api-surface.e2e.test.d.ts.map +1 -0
- package/dist/src/api-surface.e2e.test.js +1007 -0
- package/dist/src/api-surface.e2e.test.js.map +1 -0
- package/dist/src/client/api.d.ts +86 -0
- package/dist/src/client/api.d.ts.map +1 -0
- package/dist/src/client/api.js +169 -0
- package/dist/src/client/api.js.map +1 -0
- package/dist/src/client/comments.d.ts +59 -0
- package/dist/src/client/comments.d.ts.map +1 -0
- package/dist/src/client/comments.js +96 -0
- package/dist/src/client/comments.js.map +1 -0
- package/dist/src/client/context.d.ts +20 -0
- package/dist/src/client/context.d.ts.map +1 -0
- package/dist/src/client/context.js +20 -0
- package/dist/src/client/context.js.map +1 -0
- package/dist/src/client/dao-spaces.d.ts +380 -0
- package/dist/src/client/dao-spaces.d.ts.map +1 -0
- package/dist/src/client/dao-spaces.js +585 -0
- package/dist/src/client/dao-spaces.js.map +1 -0
- package/dist/src/client/dao-spaces.test.d.ts +2 -0
- package/dist/src/client/dao-spaces.test.d.ts.map +1 -0
- package/dist/src/client/dao-spaces.test.js +461 -0
- package/dist/src/client/dao-spaces.test.js.map +1 -0
- package/dist/src/client/edits.d.ts +100 -0
- package/dist/src/client/edits.d.ts.map +1 -0
- package/dist/src/client/edits.js +131 -0
- package/dist/src/client/edits.js.map +1 -0
- package/dist/src/client/edits.test.d.ts +2 -0
- package/dist/src/client/edits.test.d.ts.map +1 -0
- package/dist/src/client/edits.test.js +98 -0
- package/dist/src/client/edits.test.js.map +1 -0
- package/dist/src/client/entities.d.ts +23 -0
- package/dist/src/client/entities.d.ts.map +1 -0
- package/dist/src/client/entities.js +88 -0
- package/dist/src/client/entities.js.map +1 -0
- package/dist/src/client/entity-votes.d.ts +141 -0
- package/dist/src/client/entity-votes.d.ts.map +1 -0
- package/dist/src/client/entity-votes.js +168 -0
- package/dist/src/client/entity-votes.js.map +1 -0
- package/dist/src/client/entity-votes.test.d.ts +2 -0
- package/dist/src/client/entity-votes.test.d.ts.map +1 -0
- package/dist/src/client/entity-votes.test.js +93 -0
- package/dist/src/client/entity-votes.test.js.map +1 -0
- package/dist/src/client/graph-workflows.test.d.ts +2 -0
- package/dist/src/client/graph-workflows.test.d.ts.map +1 -0
- package/dist/src/client/graph-workflows.test.js +83 -0
- package/dist/src/client/graph-workflows.test.js.map +1 -0
- package/dist/src/client/images-storage.test.d.ts +2 -0
- package/dist/src/client/images-storage.test.d.ts.map +1 -0
- package/dist/src/client/images-storage.test.js +52 -0
- package/dist/src/client/images-storage.test.js.map +1 -0
- package/dist/src/client/images.d.ts +35 -0
- package/dist/src/client/images.d.ts.map +1 -0
- package/dist/src/client/images.js +90 -0
- package/dist/src/client/images.js.map +1 -0
- package/dist/src/client/personal-spaces.d.ts +155 -0
- package/dist/src/client/personal-spaces.d.ts.map +1 -0
- package/dist/src/client/personal-spaces.js +198 -0
- package/dist/src/client/personal-spaces.js.map +1 -0
- package/dist/src/client/spaces.test.d.ts +2 -0
- package/dist/src/client/spaces.test.d.ts.map +1 -0
- package/dist/src/client/spaces.test.js +157 -0
- package/dist/src/client/spaces.test.js.map +1 -0
- package/dist/src/client/storage.d.ts +52 -0
- package/dist/src/client/storage.d.ts.map +1 -0
- package/dist/src/client/storage.js +53 -0
- package/dist/src/client/storage.js.map +1 -0
- package/dist/src/client.d.ts +328 -0
- package/dist/src/client.d.ts.map +1 -0
- package/dist/src/client.js +441 -0
- package/dist/src/client.js.map +1 -0
- package/dist/src/client.test.d.ts +2 -0
- package/dist/src/client.test.d.ts.map +1 -0
- package/dist/src/client.test.js +125 -0
- package/dist/src/client.test.js.map +1 -0
- package/dist/src/contracts-v2/local-geobrowser.e2e.test.d.ts +2 -0
- package/dist/src/contracts-v2/local-geobrowser.e2e.test.d.ts.map +1 -0
- package/dist/src/contracts-v2/local-geobrowser.e2e.test.js +239 -0
- package/dist/src/contracts-v2/local-geobrowser.e2e.test.js.map +1 -0
- package/dist/src/dao-space/constants.d.ts +16 -3
- package/dist/src/dao-space/constants.d.ts.map +1 -1
- package/dist/src/dao-space/constants.js +16 -5
- package/dist/src/dao-space/constants.js.map +1 -1
- package/dist/src/dao-space/create-space.d.ts +1 -31
- package/dist/src/dao-space/create-space.d.ts.map +1 -1
- package/dist/src/dao-space/create-space.js +5 -70
- package/dist/src/dao-space/create-space.js.map +1 -1
- package/dist/src/dao-space/execute-proposal.d.ts +1 -22
- package/dist/src/dao-space/execute-proposal.d.ts.map +1 -1
- package/dist/src/dao-space/execute-proposal.js +12 -59
- package/dist/src/dao-space/execute-proposal.js.map +1 -1
- package/dist/src/dao-space/index.d.ts +2 -1
- package/dist/src/dao-space/index.d.ts.map +1 -1
- package/dist/src/dao-space/index.js +1 -0
- package/dist/src/dao-space/index.js.map +1 -1
- package/dist/src/dao-space/propose-add-editor.d.ts +1 -20
- package/dist/src/dao-space/propose-add-editor.d.ts.map +1 -1
- package/dist/src/dao-space/propose-add-editor.js +12 -87
- package/dist/src/dao-space/propose-add-editor.js.map +1 -1
- package/dist/src/dao-space/propose-add-editor.test.js +16 -4
- package/dist/src/dao-space/propose-add-editor.test.js.map +1 -1
- package/dist/src/dao-space/propose-add-member.d.ts +1 -20
- package/dist/src/dao-space/propose-add-member.d.ts.map +1 -1
- package/dist/src/dao-space/propose-add-member.js +12 -87
- package/dist/src/dao-space/propose-add-member.js.map +1 -1
- package/dist/src/dao-space/propose-add-member.test.js +13 -0
- package/dist/src/dao-space/propose-add-member.test.js.map +1 -1
- package/dist/src/dao-space/propose-edit.d.ts +1 -30
- package/dist/src/dao-space/propose-edit.d.ts.map +1 -1
- package/dist/src/dao-space/propose-edit.js +12 -108
- package/dist/src/dao-space/propose-edit.js.map +1 -1
- package/dist/src/dao-space/propose-edit.test.js +53 -1
- package/dist/src/dao-space/propose-edit.test.js.map +1 -1
- package/dist/src/dao-space/propose-remove-editor.d.ts +1 -22
- package/dist/src/dao-space/propose-remove-editor.d.ts.map +1 -1
- package/dist/src/dao-space/propose-remove-editor.js +12 -94
- package/dist/src/dao-space/propose-remove-editor.js.map +1 -1
- package/dist/src/dao-space/propose-remove-editor.test.js +24 -11
- package/dist/src/dao-space/propose-remove-editor.test.js.map +1 -1
- package/dist/src/dao-space/propose-remove-member.d.ts +1 -22
- package/dist/src/dao-space/propose-remove-member.d.ts.map +1 -1
- package/dist/src/dao-space/propose-remove-member.js +12 -94
- package/dist/src/dao-space/propose-remove-member.js.map +1 -1
- package/dist/src/dao-space/propose-remove-member.test.js +19 -0
- package/dist/src/dao-space/propose-remove-member.test.js.map +1 -1
- package/dist/src/dao-space/propose-request-membership.d.ts.map +1 -1
- package/dist/src/dao-space/propose-request-membership.js +4 -4
- package/dist/src/dao-space/propose-request-membership.js.map +1 -1
- package/dist/src/dao-space/propose-update-voting-settings.d.ts +8 -0
- package/dist/src/dao-space/propose-update-voting-settings.d.ts.map +1 -0
- package/dist/src/dao-space/propose-update-voting-settings.js +19 -0
- package/dist/src/dao-space/propose-update-voting-settings.js.map +1 -0
- package/dist/src/dao-space/propose-update-voting-settings.test.d.ts +2 -0
- package/dist/src/dao-space/propose-update-voting-settings.test.d.ts.map +1 -0
- package/dist/src/dao-space/propose-update-voting-settings.test.js +118 -0
- package/dist/src/dao-space/propose-update-voting-settings.test.js.map +1 -0
- package/dist/src/dao-space/types.d.ts +72 -11
- package/dist/src/dao-space/types.d.ts.map +1 -1
- package/dist/src/dao-space/vote-proposal.d.ts +1 -24
- package/dist/src/dao-space/vote-proposal.d.ts.map +1 -1
- package/dist/src/dao-space/vote-proposal.js +12 -64
- package/dist/src/dao-space/vote-proposal.js.map +1 -1
- package/dist/src/dao-space/vote-proposal.test.js +54 -0
- package/dist/src/dao-space/vote-proposal.test.js.map +1 -1
- package/dist/src/e2e-test-environment.d.ts +26 -0
- package/dist/src/e2e-test-environment.d.ts.map +1 -0
- package/dist/src/e2e-test-environment.js +150 -0
- package/dist/src/e2e-test-environment.js.map +1 -0
- package/dist/src/encoding.d.ts +3 -0
- package/dist/src/encoding.d.ts.map +1 -1
- package/dist/src/encoding.js +3 -0
- package/dist/src/encoding.js.map +1 -1
- package/dist/src/encodings/get-create-dao-space-calldata.d.ts +34 -97
- package/dist/src/encodings/get-create-dao-space-calldata.d.ts.map +1 -1
- package/dist/src/encodings/get-create-dao-space-calldata.js +66 -109
- package/dist/src/encodings/get-create-dao-space-calldata.js.map +1 -1
- package/dist/src/encodings/get-create-dao-space-calldata.test.js +90 -23
- package/dist/src/encodings/get-create-dao-space-calldata.test.js.map +1 -1
- package/dist/src/encodings/get-create-personal-space-calldata.d.ts +2 -0
- package/dist/src/encodings/get-create-personal-space-calldata.d.ts.map +1 -1
- package/dist/src/encodings/get-create-personal-space-calldata.js +2 -0
- package/dist/src/encodings/get-create-personal-space-calldata.js.map +1 -1
- package/dist/src/full-flow-test.test.js +5 -2
- package/dist/src/full-flow-test.test.js.map +1 -1
- package/dist/src/graph/comment-utils.d.ts +4 -0
- package/dist/src/graph/comment-utils.d.ts.map +1 -1
- package/dist/src/graph/comment-utils.js +4 -0
- package/dist/src/graph/comment-utils.js.map +1 -1
- package/dist/src/graph/constants.d.ts +12 -3
- package/dist/src/graph/constants.d.ts.map +1 -1
- package/dist/src/graph/constants.js +11 -5
- package/dist/src/graph/constants.js.map +1 -1
- package/dist/src/graph/create-comment.d.ts +3 -22
- package/dist/src/graph/create-comment.d.ts.map +1 -1
- package/dist/src/graph/create-comment.js +6 -136
- package/dist/src/graph/create-comment.js.map +1 -1
- package/dist/src/graph/create-comment.test.js +19 -8
- package/dist/src/graph/create-comment.test.js.map +1 -1
- package/dist/src/graph/create-entity.d.ts +2 -0
- package/dist/src/graph/create-entity.d.ts.map +1 -1
- package/dist/src/graph/create-entity.js +2 -0
- package/dist/src/graph/create-entity.js.map +1 -1
- package/dist/src/graph/create-image.d.ts +2 -21
- package/dist/src/graph/create-image.d.ts.map +1 -1
- package/dist/src/graph/create-image.js +7 -69
- package/dist/src/graph/create-image.js.map +1 -1
- package/dist/src/graph/create-property.d.ts +2 -0
- package/dist/src/graph/create-property.d.ts.map +1 -1
- package/dist/src/graph/create-property.js +2 -0
- package/dist/src/graph/create-property.js.map +1 -1
- package/dist/src/graph/create-proposal-review.d.ts +1 -27
- package/dist/src/graph/create-proposal-review.d.ts.map +1 -1
- package/dist/src/graph/create-proposal-review.js +4 -61
- package/dist/src/graph/create-proposal-review.js.map +1 -1
- package/dist/src/graph/create-relation.d.ts +2 -0
- package/dist/src/graph/create-relation.d.ts.map +1 -1
- package/dist/src/graph/create-relation.js +2 -0
- package/dist/src/graph/create-relation.js.map +1 -1
- package/dist/src/graph/create-type.d.ts +2 -0
- package/dist/src/graph/create-type.d.ts.map +1 -1
- package/dist/src/graph/create-type.js +2 -0
- package/dist/src/graph/create-type.js.map +1 -1
- package/dist/src/graph/delete-entity.d.ts +2 -14
- package/dist/src/graph/delete-entity.d.ts.map +1 -1
- package/dist/src/graph/delete-entity.js +5 -78
- package/dist/src/graph/delete-entity.js.map +1 -1
- package/dist/src/graph/delete-entity.test.js +7 -0
- package/dist/src/graph/delete-entity.test.js.map +1 -1
- package/dist/src/graph/delete-relation.d.ts +2 -0
- package/dist/src/graph/delete-relation.d.ts.map +1 -1
- package/dist/src/graph/delete-relation.js +2 -0
- package/dist/src/graph/delete-relation.js.map +1 -1
- package/dist/src/graph/entity-vote.d.ts +3 -3
- package/dist/src/graph/entity-vote.d.ts.map +1 -1
- package/dist/src/graph/entity-vote.js +21 -46
- package/dist/src/graph/entity-vote.js.map +1 -1
- package/dist/src/graph/update-comment.d.ts +3 -0
- package/dist/src/graph/update-comment.d.ts.map +1 -1
- package/dist/src/graph/update-comment.js +3 -0
- package/dist/src/graph/update-comment.js.map +1 -1
- package/dist/src/graph/update-entity.d.ts +2 -0
- package/dist/src/graph/update-entity.d.ts.map +1 -1
- package/dist/src/graph/update-entity.js +2 -0
- package/dist/src/graph/update-entity.js.map +1 -1
- package/dist/src/graph/update-proposal-review.d.ts +2 -27
- package/dist/src/graph/update-proposal-review.d.ts.map +1 -1
- package/dist/src/graph/update-proposal-review.js +4 -50
- package/dist/src/graph/update-proposal-review.js.map +1 -1
- package/dist/src/graph/update-relation.d.ts +2 -0
- package/dist/src/graph/update-relation.d.ts.map +1 -1
- package/dist/src/graph/update-relation.js +2 -0
- package/dist/src/graph/update-relation.js.map +1 -1
- package/dist/src/ipfs-core.d.ts +42 -0
- package/dist/src/ipfs-core.d.ts.map +1 -0
- package/dist/src/ipfs-core.js +165 -0
- package/dist/src/ipfs-core.js.map +1 -0
- package/dist/src/ipfs-core.test.d.ts +2 -0
- package/dist/src/ipfs-core.test.d.ts.map +1 -0
- package/dist/src/ipfs-core.test.js +56 -0
- package/dist/src/ipfs-core.test.js.map +1 -0
- package/dist/src/ipfs.d.ts +7 -52
- package/dist/src/ipfs.d.ts.map +1 -1
- package/dist/src/ipfs.js +27 -170
- package/dist/src/ipfs.js.map +1 -1
- package/dist/src/legacy-api-surface.e2e.test.d.ts +2 -0
- package/dist/src/legacy-api-surface.e2e.test.d.ts.map +1 -0
- package/dist/src/legacy-api-surface.e2e.test.js +860 -0
- package/dist/src/legacy-api-surface.e2e.test.js.map +1 -0
- package/dist/src/networks.d.ts +46 -0
- package/dist/src/networks.d.ts.map +1 -0
- package/dist/src/networks.js +90 -0
- package/dist/src/networks.js.map +1 -0
- package/dist/src/ops/comments.d.ts +80 -0
- package/dist/src/ops/comments.d.ts.map +1 -0
- package/dist/src/ops/comments.js +142 -0
- package/dist/src/ops/comments.js.map +1 -0
- package/dist/src/ops/entities.d.ts +50 -0
- package/dist/src/ops/entities.d.ts.map +1 -0
- package/dist/src/ops/entities.js +51 -0
- package/dist/src/ops/entities.js.map +1 -0
- package/dist/src/ops/index.d.ts +7 -0
- package/dist/src/ops/index.d.ts.map +1 -0
- package/dist/src/ops/index.js +7 -0
- package/dist/src/ops/index.js.map +1 -0
- package/dist/src/ops/index.test.d.ts +2 -0
- package/dist/src/ops/index.test.d.ts.map +1 -0
- package/dist/src/ops/index.test.js +115 -0
- package/dist/src/ops/index.test.js.map +1 -0
- package/dist/src/ops/properties.d.ts +20 -0
- package/dist/src/ops/properties.d.ts.map +1 -0
- package/dist/src/ops/properties.js +20 -0
- package/dist/src/ops/properties.js.map +1 -0
- package/dist/src/ops/proposal-reviews.d.ts +43 -0
- package/dist/src/ops/proposal-reviews.d.ts.map +1 -0
- package/dist/src/ops/proposal-reviews.js +103 -0
- package/dist/src/ops/proposal-reviews.js.map +1 -0
- package/dist/src/ops/relations.d.ts +57 -0
- package/dist/src/ops/relations.d.ts.map +1 -0
- package/dist/src/ops/relations.js +59 -0
- package/dist/src/ops/relations.js.map +1 -0
- package/dist/src/ops/types.d.ts +20 -0
- package/dist/src/ops/types.d.ts.map +1 -0
- package/dist/src/ops/types.js +20 -0
- package/dist/src/ops/types.js.map +1 -0
- package/dist/src/personal-space/constants.d.ts +1 -0
- package/dist/src/personal-space/constants.d.ts.map +1 -1
- package/dist/src/personal-space/constants.js +1 -0
- package/dist/src/personal-space/constants.js.map +1 -1
- package/dist/src/personal-space/create-space.d.ts +3 -20
- package/dist/src/personal-space/create-space.d.ts.map +1 -1
- package/dist/src/personal-space/create-space.js +5 -21
- package/dist/src/personal-space/create-space.js.map +1 -1
- package/dist/src/personal-space/has-space.d.ts +9 -2
- package/dist/src/personal-space/has-space.d.ts.map +1 -1
- package/dist/src/personal-space/has-space.js +9 -13
- package/dist/src/personal-space/has-space.js.map +1 -1
- package/dist/src/personal-space/has-space.test.d.ts +2 -0
- package/dist/src/personal-space/has-space.test.d.ts.map +1 -0
- package/dist/src/personal-space/has-space.test.js +30 -0
- package/dist/src/personal-space/has-space.test.js.map +1 -0
- package/dist/src/personal-space/publish-edit.d.ts +1 -22
- package/dist/src/personal-space/publish-edit.d.ts.map +1 -1
- package/dist/src/personal-space/publish-edit.js +10 -64
- package/dist/src/personal-space/publish-edit.js.map +1 -1
- package/dist/src/personal-space/types.d.ts +4 -1
- package/dist/src/personal-space/types.d.ts.map +1 -1
- package/dist/src/smart-wallet.d.ts +2 -4
- package/dist/src/smart-wallet.d.ts.map +1 -1
- package/dist/src/smart-wallet.js +6 -9
- package/dist/src/smart-wallet.js.map +1 -1
- package/dist/src/types.d.ts +25 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/types.js.map +1 -1
- package/package.json +16 -2
- package/dist/proto.d.ts +0 -5
- package/dist/proto.d.ts.map +0 -1
- package/dist/proto.js +0 -5
- package/dist/proto.js.map +0 -1
- package/dist/src/graph/create-space.d.ts +0 -37
- package/dist/src/graph/create-space.d.ts.map +0 -1
- package/dist/src/graph/create-space.js +0 -67
- package/dist/src/graph/create-space.js.map +0 -1
- package/dist/src/proto/index.d.ts +0 -7
- package/dist/src/proto/index.d.ts.map +0 -1
- package/dist/src/proto/index.js +0 -7
- package/dist/src/proto/index.js.map +0 -1
package/README.md
CHANGED
|
@@ -14,623 +14,1299 @@ If you're using an AI coding assistant (e.g. Claude Code, Codex, Cursor) to work
|
|
|
14
14
|
|
|
15
15
|
## Overview
|
|
16
16
|
|
|
17
|
-
### Data
|
|
17
|
+
### Data Flow
|
|
18
18
|
|
|
19
19
|
Data in The Graph lives both offchain and onchain. This data is written to IPFS, and the resulting content identifier is then posted onchain before being read by the indexing stack. After the indexer finishes processing the data it's exposed by the API.
|
|
20
|
+
|
|
20
21
|

|
|
21
22
|
|
|
22
23
|
### Spaces
|
|
23
24
|
|
|
24
|
-
On The Graph, knowledge is organized into spaces. Anyone can create a space for a community, project or individual. Spaces are organized onchain into a set of
|
|
25
|
-
|
|
26
|
-
### Relations
|
|
27
|
-
|
|
28
|
-
Relations describe the edges within the graph. Relations are themselves entities that include details about the relationship. For example a Company can have Team Members. Each Team Member relation can have an attribute describing when the person joined the team. This is a model that is commonly called a property graph.
|
|
25
|
+
On The Graph, knowledge is organized into spaces. Anyone can create a space for a community, project or individual. Spaces are organized onchain into a set of smart contracts. These contracts represent the space itself, its data and its governance process.
|
|
29
26
|
|
|
30
27
|
### Entities
|
|
31
28
|
|
|
32
|
-
An entity is a unique identifier representing a person, a place, an idea, a concept, or anything else. Entities are
|
|
29
|
+
An entity is a unique identifier representing a person, a place, an idea, a concept, or anything else. Entities are composed from triples and relations that describe what the entity is. An entity's data can be composed from multiple spaces at once. This property is what enables pluralism within The Graph.
|
|
33
30
|
|
|
34
31
|
[More about entities and knowledge graphs](https://www.geobrowser.io/space/720eb279c64d56735dccd17a2a416ba2/a72654b014fa405bbf1250ba901bc082)
|
|
35
32
|
|
|
36
|
-
###
|
|
33
|
+
### Relations
|
|
34
|
+
|
|
35
|
+
Relations describe the edges within the graph. Relations are themselves entities that include details about the relationship. For example, a Company can have Team Members. Each Team Member relation can have an attribute describing when the person joined the team. This is a property graph model.
|
|
36
|
+
|
|
37
|
+
### Ops And Edits
|
|
37
38
|
|
|
38
39
|
Data in The Graph is stored as an Op (operation). Ops represent a set of changes applied to entities. A change could be setting or deleting a triple or a relation. Both triples and relations are represented as Ops.
|
|
39
40
|
|
|
40
|
-
When writing data, these ops are grouped into a logical set called an
|
|
41
|
+
When writing data, these ops are grouped into a logical set called an edit. An edit has a name, authors, and metadata to represent the set of changes. This edit is encoded into a binary representation before being uploaded to IPFS.
|
|
41
42
|
|
|
42
43
|
[Ops and edits in GRC-20](https://github.com/yanivtal/graph-improvement-proposals/blob/new-ops/grcs/0020-knowledge-graph.md#101-operations-op)
|
|
43
44
|
|
|
44
45
|
## Using
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
The preferred API has two parts:
|
|
48
|
+
|
|
49
|
+
- `Ops` builds GRC-20 operations.
|
|
50
|
+
- `createGeoClient(...)` handles configured workflows such as API calls, uploads, RPC reads, and transaction calldata.
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { GeoTestnetConfig, Ops, createGeoClient } from "@geoprotocol/geo-sdk";
|
|
54
|
+
|
|
55
|
+
const geo = createGeoClient({ network: GeoTestnetConfig });
|
|
56
|
+
|
|
57
|
+
const { id: entityId, ops } = Ops.entities.create({
|
|
58
|
+
name: "Test Entity",
|
|
59
|
+
description: "Created with the new API",
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const tx = await geo.personalSpaces.publishEdit({
|
|
63
|
+
name: "Create Test Entity",
|
|
64
|
+
spaceId,
|
|
65
|
+
author: spaceId,
|
|
66
|
+
ops,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
await walletClient.sendTransaction({ to: tx.to, data: tx.calldata });
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Imports
|
|
47
73
|
|
|
48
|
-
|
|
74
|
+
Use the root package when convenience matters:
|
|
49
75
|
|
|
50
76
|
```ts
|
|
51
|
-
import {
|
|
77
|
+
import { GeoTestnetConfig, Ops, createGeoClient } from "@geoprotocol/geo-sdk";
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Subpath exports are available for bundle-sensitive code
|
|
52
81
|
|
|
53
|
-
|
|
82
|
+
```ts
|
|
83
|
+
import { entities, relations } from "@geoprotocol/geo-sdk/ops";
|
|
84
|
+
import { createGeoClient } from "@geoprotocol/geo-sdk/client";
|
|
85
|
+
import {
|
|
86
|
+
GeoTestnetConfig,
|
|
87
|
+
defineGeoNetworkConfig,
|
|
88
|
+
} from "@geoprotocol/geo-sdk/networks";
|
|
54
89
|
```
|
|
55
90
|
|
|
56
|
-
|
|
91
|
+
Use `Ops` from `@geoprotocol/geo-sdk` for op builders. Configured workflows live behind `createGeoClient`.
|
|
57
92
|
|
|
58
|
-
|
|
93
|
+
### Network Configuration
|
|
94
|
+
|
|
95
|
+
Use the built-in testnet config:
|
|
59
96
|
|
|
60
97
|
```ts
|
|
61
|
-
import {
|
|
98
|
+
import { GeoTestnetConfig, createGeoClient } from "@geoprotocol/geo-sdk";
|
|
99
|
+
|
|
100
|
+
const geo = createGeoClient({ network: GeoTestnetConfig });
|
|
101
|
+
|
|
102
|
+
console.log(geo.network.id); // "TESTNET"
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
`network` is required, and the client expects the full config object. Pass `GeoTestnetConfig`, not the string `"TESTNET"`.
|
|
106
|
+
|
|
107
|
+
Define a custom deployment:
|
|
62
108
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
109
|
+
```ts
|
|
110
|
+
import { createGeoClient, defineGeoNetworkConfig } from "@geoprotocol/geo-sdk";
|
|
111
|
+
|
|
112
|
+
const local = defineGeoNetworkConfig({
|
|
113
|
+
id: "LOCAL",
|
|
114
|
+
name: "Local Geo",
|
|
115
|
+
apiOrigin: "http://localhost:3000",
|
|
116
|
+
chain: {
|
|
117
|
+
id: 31337,
|
|
118
|
+
name: "Anvil",
|
|
119
|
+
rpcUrl: "http://localhost:8545",
|
|
120
|
+
},
|
|
121
|
+
contracts: {
|
|
122
|
+
SPACE_REGISTRY_ADDRESS: "0x0000000000000000000000000000000000000001",
|
|
123
|
+
DAO_SPACE_FACTORY_ADDRESS: "0x0000000000000000000000000000000000000002",
|
|
124
|
+
},
|
|
67
125
|
});
|
|
68
126
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
127
|
+
const geo = createGeoClient({ network: local });
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Pass a fetch implementation when your runtime does not provide `globalThis.fetch`, or when you want test isolation:
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
const geo = createGeoClient({
|
|
134
|
+
network: GeoTestnetConfig,
|
|
135
|
+
fetch: customFetch,
|
|
73
136
|
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Local Contracts V2 Validation
|
|
140
|
+
|
|
141
|
+
When working against the local-geobrowser contracts checkout, deploy that stack
|
|
142
|
+
first so it writes `.deployments.json`, then point the SDK opt-in test at it:
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
cd /path/to/local-geobrowser
|
|
146
|
+
just init-infra
|
|
147
|
+
just init-contract
|
|
148
|
+
|
|
149
|
+
cd /path/to/geo-sdk
|
|
150
|
+
GEO_LOCAL_GEOBROWSER_DEPLOYMENTS=/path/to/local-geobrowser/.deployments.json \
|
|
151
|
+
pnpm exec vitest run src/contracts-v2/local-geobrowser.e2e.test.ts
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The test builds a custom `defineGeoNetworkConfig(...)` from the deployment file
|
|
155
|
+
and decodes DAO creation, update-voting-settings proposal, and versioned vote
|
|
156
|
+
calldata against the contracts v2 ABIs.
|
|
157
|
+
|
|
158
|
+
## Ops API
|
|
74
159
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
160
|
+
Ops functions build operation arrays that can be combined before publishing.
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
import type { Op } from "@geoprotocol/geo-sdk";
|
|
164
|
+
|
|
165
|
+
const ops: Op[] = [];
|
|
166
|
+
ops.push(...entityOps);
|
|
167
|
+
ops.push(...relationOps);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Properties, Types, And Entities
|
|
171
|
+
|
|
172
|
+
Create a property, a type, and an entity:
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { Ops } from "@geoprotocol/geo-sdk";
|
|
176
|
+
|
|
177
|
+
const { id: websitePropertyId, ops: propertyOps } = Ops.properties.create({
|
|
178
|
+
name: "Website",
|
|
179
|
+
dataType: "TEXT",
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const { id: restaurantTypeId, ops: typeOps } = Ops.types.create({
|
|
183
|
+
name: "Restaurant",
|
|
184
|
+
properties: [websitePropertyId],
|
|
79
185
|
});
|
|
80
186
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
types: […listOfTypeIds],
|
|
86
|
-
cover: imageId,
|
|
187
|
+
const { id: restaurantId, ops: entityOps } = Ops.entities.create({
|
|
188
|
+
name: "Yum Yum",
|
|
189
|
+
description: "A restaurant serving fusion cuisine",
|
|
190
|
+
types: [restaurantTypeId],
|
|
87
191
|
values: [
|
|
88
192
|
{
|
|
89
|
-
property:
|
|
90
|
-
type:
|
|
91
|
-
value:
|
|
92
|
-
}
|
|
93
|
-
],
|
|
94
|
-
relations: {
|
|
95
|
-
// relation property
|
|
96
|
-
[relationPropertyId]: {
|
|
97
|
-
toEntity: 'id of the entity',
|
|
98
|
-
id: 'id of the relation', // optional
|
|
99
|
-
position: positionString, // optional
|
|
193
|
+
property: websitePropertyId,
|
|
194
|
+
type: "text",
|
|
195
|
+
value: "https://example.com",
|
|
100
196
|
},
|
|
101
|
-
|
|
197
|
+
],
|
|
102
198
|
});
|
|
103
|
-
```
|
|
104
199
|
|
|
105
|
-
|
|
200
|
+
const ops = [...propertyOps, ...typeOps, ...entityOps];
|
|
201
|
+
```
|
|
106
202
|
|
|
107
|
-
|
|
203
|
+
Update an entity:
|
|
108
204
|
|
|
109
205
|
```ts
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
206
|
+
const { ops } = Ops.entities.update({
|
|
207
|
+
id: restaurantId,
|
|
208
|
+
name: "Yum Yum Kitchen",
|
|
113
209
|
values: [
|
|
114
|
-
// Text value (with optional language)
|
|
115
210
|
{
|
|
116
|
-
property:
|
|
211
|
+
property: websitePropertyId,
|
|
117
212
|
type: "text",
|
|
118
|
-
value: "
|
|
119
|
-
language: Id("dad6e52a5e944e559411cfe3a3c3ea64"), // optional
|
|
120
|
-
},
|
|
121
|
-
// Number value — integer (with optional unit)
|
|
122
|
-
{
|
|
123
|
-
property: someIntPropertyId,
|
|
124
|
-
type: "integer",
|
|
125
|
-
value: 42,
|
|
126
|
-
unit: Id("016c9b1cd8a84e4d9e844e40878bb235"), // optional
|
|
213
|
+
value: "https://yum.example",
|
|
127
214
|
},
|
|
128
|
-
|
|
215
|
+
],
|
|
216
|
+
});
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
Unset property values:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const { ops } = Ops.entities.update({
|
|
223
|
+
id: restaurantId,
|
|
224
|
+
unset: [
|
|
225
|
+
{ property: websitePropertyId },
|
|
226
|
+
{ property: descriptionPropertyId, language: "all" },
|
|
227
|
+
],
|
|
228
|
+
});
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Create relation properties:
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
const { id: likesPropertyId, ops } = Ops.properties.create({
|
|
235
|
+
name: "Likes",
|
|
236
|
+
dataType: "RELATION",
|
|
237
|
+
relationValueTypes: [restaurantTypeId],
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Typed Values
|
|
242
|
+
|
|
243
|
+
Entity values are typed objects. The `type` field determines the value shape:
|
|
244
|
+
|
|
245
|
+
```ts
|
|
246
|
+
import { Ops } from "@geoprotocol/geo-sdk";
|
|
247
|
+
|
|
248
|
+
const { ops } = Ops.entities.create({
|
|
249
|
+
name: "Cafe visit",
|
|
250
|
+
values: [
|
|
251
|
+
{ property: namePropertyId, type: "text", value: "Morning Coffee" },
|
|
252
|
+
{ property: openPropertyId, type: "boolean", value: true },
|
|
253
|
+
{ property: visitsPropertyId, type: "integer", value: 42 },
|
|
254
|
+
{ property: ratingPropertyId, type: "float", value: 4.8 },
|
|
255
|
+
{ property: openedDatePropertyId, type: "date", value: "2024-01-15" },
|
|
256
|
+
{ property: opensAtPropertyId, type: "time", value: "08:30:00Z" },
|
|
129
257
|
{
|
|
130
|
-
property:
|
|
131
|
-
type: "
|
|
132
|
-
value:
|
|
133
|
-
unit: Id("016c9b1cd8a84e4d9e844e40878bb235"), // optional
|
|
258
|
+
property: reviewedAtPropertyId,
|
|
259
|
+
type: "datetime",
|
|
260
|
+
value: "2024-01-15T14:30:00Z",
|
|
134
261
|
},
|
|
135
|
-
// Boolean value
|
|
136
262
|
{
|
|
137
|
-
property:
|
|
138
|
-
type: "
|
|
139
|
-
value:
|
|
263
|
+
property: schedulePropertyId,
|
|
264
|
+
type: "schedule",
|
|
265
|
+
value: "FREQ=WEEKLY;BYDAY=MO,WE,FR",
|
|
140
266
|
},
|
|
141
|
-
// Point value (with optional altitude)
|
|
142
267
|
{
|
|
143
|
-
property:
|
|
268
|
+
property: locationPropertyId,
|
|
144
269
|
type: "point",
|
|
145
270
|
lon: -122.4194,
|
|
146
271
|
lat: 37.7749,
|
|
147
|
-
alt: 10.5, // optional
|
|
148
|
-
},
|
|
149
|
-
// Date value (ISO 8601 format: YYYY-MM-DD)
|
|
150
|
-
{
|
|
151
|
-
property: someDatePropertyId,
|
|
152
|
-
type: "date",
|
|
153
|
-
value: "2024-01-15",
|
|
154
|
-
},
|
|
155
|
-
// Time value (ISO 8601 format with timezone)
|
|
156
|
-
{
|
|
157
|
-
property: someTimePropertyId,
|
|
158
|
-
type: "time",
|
|
159
|
-
value: "14:30:00Z",
|
|
160
|
-
},
|
|
161
|
-
// Datetime value (ISO 8601 combined format)
|
|
162
|
-
{
|
|
163
|
-
property: someDatetimePropertyId,
|
|
164
|
-
type: "datetime",
|
|
165
|
-
value: "2024-01-15T14:30:00Z",
|
|
166
272
|
},
|
|
167
|
-
// Schedule value (iCalendar RRULE format)
|
|
168
273
|
{
|
|
169
|
-
property:
|
|
170
|
-
type: "
|
|
171
|
-
value:
|
|
274
|
+
property: bytesPropertyId,
|
|
275
|
+
type: "bytes",
|
|
276
|
+
value: new Uint8Array([1, 2, 3]),
|
|
172
277
|
},
|
|
173
278
|
],
|
|
174
279
|
});
|
|
175
280
|
```
|
|
176
281
|
|
|
177
|
-
|
|
282
|
+
### Relations
|
|
178
283
|
|
|
179
|
-
|
|
180
|
-
import { Graph, type Op } from "@geoprotocol/geo-sdk";
|
|
284
|
+
Create, update, and delete relation entities:
|
|
181
285
|
|
|
182
|
-
|
|
286
|
+
```ts
|
|
287
|
+
import { Ops, Position } from "@geoprotocol/geo-sdk";
|
|
183
288
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
289
|
+
const { id: relationId, ops: createRelationOps } = Ops.relations.create({
|
|
290
|
+
fromEntity: personId,
|
|
291
|
+
toEntity: restaurantId,
|
|
292
|
+
type: likesPropertyId,
|
|
293
|
+
position: Position.generate(),
|
|
188
294
|
});
|
|
189
|
-
ops.push(...createAgePropertyOps);
|
|
190
295
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
name: "Likes",
|
|
196
|
-
});
|
|
197
|
-
ops.push(...createLikesPropertyOps);
|
|
296
|
+
const { ops: updateRelationOps } = Ops.relations.update({
|
|
297
|
+
id: relationId,
|
|
298
|
+
position: Position.generateBetween(previousPosition, nextPosition),
|
|
299
|
+
});
|
|
198
300
|
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
name: "Person",
|
|
202
|
-
cover: personCoverId,
|
|
203
|
-
properties: [agePropertyId, likesPropertyId],
|
|
301
|
+
const { ops: deleteRelationOps } = Ops.relations.delete({
|
|
302
|
+
id: relationId,
|
|
204
303
|
});
|
|
205
|
-
|
|
304
|
+
```
|
|
206
305
|
|
|
207
|
-
|
|
208
|
-
const { id: restaurantCoverId, ops: createRestaurantCoverOps } =
|
|
209
|
-
await Graph.createImage({
|
|
210
|
-
url: "https://example.com/image.png",
|
|
211
|
-
});
|
|
212
|
-
ops.push(...createRestaurantCoverOps);
|
|
306
|
+
Relations can also carry their own entity values:
|
|
213
307
|
|
|
214
|
-
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
values: [
|
|
308
|
+
```ts
|
|
309
|
+
const { ops } = Ops.relations.create({
|
|
310
|
+
fromEntity: personId,
|
|
311
|
+
toEntity: companyId,
|
|
312
|
+
type: teamMemberPropertyId,
|
|
313
|
+
entityName: "Team member",
|
|
314
|
+
entityValues: [
|
|
222
315
|
{
|
|
223
|
-
property:
|
|
224
|
-
type: "
|
|
225
|
-
value: "
|
|
316
|
+
property: joinedDatePropertyId,
|
|
317
|
+
type: "date",
|
|
318
|
+
value: "2024-05-01",
|
|
226
319
|
},
|
|
227
320
|
],
|
|
228
321
|
});
|
|
229
|
-
|
|
322
|
+
```
|
|
230
323
|
|
|
231
|
-
|
|
232
|
-
const { id: personCoverId, ops: createPersonCoverOps } =
|
|
233
|
-
await Graph.createImage({
|
|
234
|
-
url: "https://example.com/avatar.png",
|
|
235
|
-
});
|
|
236
|
-
ops.push(...createPersonCoverOps);
|
|
324
|
+
### Images
|
|
237
325
|
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
326
|
+
Image creation goes through `geo.images.create(...)`. The configured client uploads the image, detects dimensions when possible, and returns the image entity ops.
|
|
327
|
+
|
|
328
|
+
### Comments
|
|
329
|
+
|
|
330
|
+
Create a comment on an entity:
|
|
331
|
+
|
|
332
|
+
```ts
|
|
333
|
+
import { Ops } from "@geoprotocol/geo-sdk";
|
|
334
|
+
|
|
335
|
+
const { id: commentId, ops } = Ops.comments.create({
|
|
336
|
+
content: "Looks good to me.",
|
|
337
|
+
replyTo: {
|
|
338
|
+
entityId,
|
|
339
|
+
spaceId,
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Create a nested comment when you already have reply-chain context:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
const { ops } = Ops.comments.create({
|
|
348
|
+
content: "Replying to the parent comment.",
|
|
349
|
+
replyTo: {
|
|
350
|
+
entityId: parentCommentId,
|
|
351
|
+
spaceId,
|
|
352
|
+
},
|
|
353
|
+
replyToRelations: [
|
|
244
354
|
{
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
355
|
+
entityId: rootEntityId,
|
|
356
|
+
spaceId,
|
|
357
|
+
position: "a0",
|
|
248
358
|
},
|
|
249
359
|
],
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
360
|
+
});
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
Update a comment:
|
|
364
|
+
|
|
365
|
+
```ts
|
|
366
|
+
const { ops } = Ops.comments.update({
|
|
367
|
+
id: commentId,
|
|
368
|
+
content: "Updated comment text.",
|
|
369
|
+
resolved: true,
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
Use `geo.comments.create(...)` when reply-chain context should be fetched from the configured API.
|
|
374
|
+
|
|
375
|
+
### Proposal Reviews
|
|
376
|
+
|
|
377
|
+
Create and update proposal review ops:
|
|
378
|
+
|
|
379
|
+
```ts
|
|
380
|
+
import { Ops } from "@geoprotocol/geo-sdk";
|
|
381
|
+
|
|
382
|
+
const { id: reviewId, ops: createReviewOps } = Ops.proposalReviews.create({
|
|
383
|
+
proposal: {
|
|
384
|
+
id: proposalId,
|
|
385
|
+
name: "Improve restaurant data",
|
|
254
386
|
},
|
|
387
|
+
pass: true,
|
|
388
|
+
content: "The proposal is complete and accurate.",
|
|
389
|
+
completeness: 1,
|
|
390
|
+
accuracy: 0.8,
|
|
391
|
+
skill: 0.8,
|
|
392
|
+
effort: 0.6,
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
const { ops: updateReviewOps } = Ops.proposalReviews.update({
|
|
396
|
+
proposalReviewId: reviewId,
|
|
397
|
+
pass: false,
|
|
398
|
+
content: "Needs more sources.",
|
|
255
399
|
});
|
|
256
|
-
ops.push(...createPersonOps);
|
|
257
400
|
```
|
|
258
401
|
|
|
259
|
-
|
|
402
|
+
## Client API
|
|
260
403
|
|
|
261
|
-
|
|
404
|
+
Create a configured client once and use it for workflows that need API origins, uploads, RPC URLs, or contract addresses.
|
|
262
405
|
|
|
263
406
|
```ts
|
|
264
|
-
import {
|
|
407
|
+
import { GeoTestnetConfig, Ops, createGeoClient } from "@geoprotocol/geo-sdk";
|
|
265
408
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
409
|
+
const geo = createGeoClient({ network: GeoTestnetConfig });
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### `geo.api`
|
|
413
|
+
|
|
414
|
+
Use `geo.api.graphql(...)` for low-level GraphQL requests:
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
const response = await geo.api.graphql<{
|
|
418
|
+
entity: { id: string; name: string | null } | null;
|
|
419
|
+
}>(`
|
|
420
|
+
query {
|
|
421
|
+
entity(id: "3af3e22d21694a078681516710b7ecf1") {
|
|
422
|
+
id
|
|
423
|
+
name
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
`);
|
|
427
|
+
|
|
428
|
+
if (response.errors) {
|
|
429
|
+
console.error(response.errors);
|
|
430
|
+
}
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Use `geo.api.getEditCalldata(...)` when calldata must come from the API:
|
|
434
|
+
|
|
435
|
+
```ts
|
|
436
|
+
const { to, data } = await geo.api.getEditCalldata({
|
|
437
|
+
spaceId,
|
|
438
|
+
cid: "ipfs://bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku",
|
|
278
439
|
});
|
|
279
440
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
441
|
+
await walletClient.sendTransaction({ to, data });
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
For personal-space edits, prefer `geo.personalSpaces.publishEdit(...)`.
|
|
445
|
+
|
|
446
|
+
### `geo.images`
|
|
447
|
+
|
|
448
|
+
Upload an image and build image entity ops in one call:
|
|
449
|
+
|
|
450
|
+
```ts
|
|
451
|
+
const imageFromUrl = await geo.images.create({
|
|
452
|
+
url: "https://example.com/cover.png",
|
|
453
|
+
name: "Cover image",
|
|
454
|
+
description: "Image used as the space cover.",
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
console.log(imageFromUrl.id);
|
|
458
|
+
console.log(imageFromUrl.cid);
|
|
459
|
+
console.log(imageFromUrl.ops);
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
You can also pass a `Blob` directly:
|
|
463
|
+
|
|
464
|
+
```ts
|
|
465
|
+
const file = new Blob([imageBytes], { type: "image/png" });
|
|
466
|
+
|
|
467
|
+
const imageFromBlob = await geo.images.create({
|
|
468
|
+
blob: file,
|
|
469
|
+
name: "Cover image",
|
|
287
470
|
});
|
|
471
|
+
|
|
472
|
+
console.log(imageFromBlob.cid);
|
|
288
473
|
```
|
|
289
474
|
|
|
290
|
-
###
|
|
475
|
+
### `geo.storage`
|
|
291
476
|
|
|
292
|
-
|
|
477
|
+
Use `geo.images.create(...)` when you want to upload an image and create image entity ops in one call. Use `geo.storage.uploadImage(...)` only when you need the raw uploaded CID and detected dimensions without graph ops:
|
|
293
478
|
|
|
294
479
|
```ts
|
|
295
|
-
|
|
480
|
+
const uploaded = await geo.storage.uploadImage({
|
|
481
|
+
url: "https://example.com/photo.png",
|
|
482
|
+
});
|
|
296
483
|
|
|
297
|
-
|
|
484
|
+
console.log(uploaded.cid);
|
|
485
|
+
console.log(uploaded.dimensions);
|
|
486
|
+
```
|
|
487
|
+
|
|
488
|
+
Upload CSV content:
|
|
489
|
+
|
|
490
|
+
```ts
|
|
491
|
+
const cid = await geo.storage.uploadCSV(`name,score
|
|
492
|
+
Alice,10
|
|
493
|
+
Bob,8`);
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
### `geo.entities`
|
|
497
|
+
|
|
498
|
+
Delete an entity from a space:
|
|
499
|
+
|
|
500
|
+
```ts
|
|
501
|
+
const { ops } = await geo.entities.delete({
|
|
298
502
|
id: entityId,
|
|
299
|
-
spaceId
|
|
300
|
-
network: "TESTNET", // optional, defaults to "TESTNET"
|
|
503
|
+
spaceId,
|
|
301
504
|
});
|
|
302
505
|
```
|
|
303
506
|
|
|
304
|
-
|
|
507
|
+
Entity deletion queries the configured API for current values and relations in the target space, then builds ops to unset those values and delete those relations. The entity transitions to an empty state in that space; it is not globally destroyed.
|
|
305
508
|
|
|
306
|
-
###
|
|
509
|
+
### `geo.comments`
|
|
307
510
|
|
|
308
|
-
|
|
511
|
+
Create a comment while preserving reply-to chains:
|
|
309
512
|
|
|
310
513
|
```ts
|
|
311
|
-
|
|
514
|
+
const comment = await geo.comments.create({
|
|
515
|
+
content: "This should be easier to find.",
|
|
516
|
+
replyTo: {
|
|
517
|
+
entityId,
|
|
518
|
+
spaceId,
|
|
519
|
+
},
|
|
520
|
+
});
|
|
521
|
+
```
|
|
312
522
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
523
|
+
Reply to another comment:
|
|
524
|
+
|
|
525
|
+
```ts
|
|
526
|
+
const reply = await geo.comments.create({
|
|
527
|
+
content: "Following up here.",
|
|
528
|
+
replyTo: {
|
|
529
|
+
entityId: comment.id,
|
|
530
|
+
spaceId,
|
|
531
|
+
},
|
|
319
532
|
});
|
|
533
|
+
```
|
|
320
534
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
535
|
+
Update a comment:
|
|
536
|
+
|
|
537
|
+
```ts
|
|
538
|
+
const { ops } = geo.comments.update({
|
|
539
|
+
id: comment.id,
|
|
540
|
+
content: "Updated comment text.",
|
|
541
|
+
resolved: true,
|
|
325
542
|
});
|
|
543
|
+
```
|
|
326
544
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
545
|
+
### `geo.personalSpaces`
|
|
546
|
+
|
|
547
|
+
Check whether an address already has a personal space:
|
|
548
|
+
|
|
549
|
+
```ts
|
|
550
|
+
const hasExistingSpace = await geo.personalSpaces.hasSpace({
|
|
551
|
+
address: account.address,
|
|
330
552
|
});
|
|
331
553
|
```
|
|
332
554
|
|
|
333
|
-
|
|
555
|
+
Create a personal space:
|
|
556
|
+
|
|
557
|
+
```ts
|
|
558
|
+
const createSpace = geo.personalSpaces.create({
|
|
559
|
+
name: "Alice",
|
|
560
|
+
accountAddress: account.address,
|
|
561
|
+
});
|
|
334
562
|
|
|
335
|
-
|
|
563
|
+
await walletClient.sendTransaction({
|
|
564
|
+
to: createSpace.to,
|
|
565
|
+
data: createSpace.calldata,
|
|
566
|
+
});
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
`geo.personalSpaces.create(...)` also returns initial profile ops. After the create-space transaction is mined and you know the new `spaceId`, publish those ops into the space and immediately set the generated space entity as the space topic:
|
|
336
570
|
|
|
337
571
|
```ts
|
|
338
|
-
|
|
572
|
+
const profileTx = await geo.personalSpaces.publishEdit({
|
|
573
|
+
name: "Create personal space profile",
|
|
574
|
+
spaceId,
|
|
575
|
+
author: spaceId,
|
|
576
|
+
ops: createSpace.ops,
|
|
577
|
+
});
|
|
339
578
|
|
|
340
|
-
|
|
341
|
-
|
|
579
|
+
await walletClient.sendTransaction({
|
|
580
|
+
to: profileTx.to,
|
|
581
|
+
data: profileTx.calldata,
|
|
582
|
+
});
|
|
342
583
|
|
|
343
|
-
|
|
344
|
-
|
|
584
|
+
const topicTx = geo.personalSpaces.setTopic({
|
|
585
|
+
spaceId,
|
|
586
|
+
topicId: createSpace.spaceEntityId,
|
|
587
|
+
});
|
|
345
588
|
|
|
346
|
-
|
|
347
|
-
|
|
589
|
+
await walletClient.sendTransaction({
|
|
590
|
+
to: topicTx.to,
|
|
591
|
+
data: topicTx.calldata,
|
|
592
|
+
});
|
|
593
|
+
```
|
|
348
594
|
|
|
349
|
-
|
|
350
|
-
const last = Position.generateBetween(pos1, null);
|
|
595
|
+
Publish any edit to a personal space:
|
|
351
596
|
|
|
352
|
-
|
|
353
|
-
const
|
|
597
|
+
```ts
|
|
598
|
+
const { ops } = Ops.entities.create({
|
|
599
|
+
name: "Test Entity",
|
|
600
|
+
});
|
|
354
601
|
|
|
355
|
-
|
|
356
|
-
|
|
602
|
+
const tx = await geo.personalSpaces.publishEdit({
|
|
603
|
+
name: "Create Test Entity",
|
|
604
|
+
spaceId,
|
|
605
|
+
author: spaceId,
|
|
606
|
+
ops,
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
await walletClient.sendTransaction({
|
|
610
|
+
to: tx.to,
|
|
611
|
+
data: tx.calldata,
|
|
612
|
+
});
|
|
357
613
|
```
|
|
358
614
|
|
|
359
|
-
|
|
615
|
+
The `author` field is the author's personal space ID, not a wallet address.
|
|
360
616
|
|
|
361
|
-
|
|
617
|
+
### `geo.daoSpaces`
|
|
362
618
|
|
|
363
|
-
|
|
619
|
+
DAO helpers target the contracts v2 surface. Voting settings use percentages
|
|
620
|
+
and days on the SDK side; the SDK maps them to ratio-base integers and seconds
|
|
621
|
+
for the contract. Use a network config whose DAO contract addresses point at a
|
|
622
|
+
contracts v2 deployment.
|
|
364
623
|
|
|
365
|
-
|
|
624
|
+
```ts
|
|
625
|
+
const votingSettings = {
|
|
626
|
+
partialPercentageSupportThreshold: 50,
|
|
627
|
+
universalPercentageSupportThreshold: 90,
|
|
628
|
+
flatSupportThreshold: 1,
|
|
629
|
+
quorum: 1,
|
|
630
|
+
durationInDays: 2,
|
|
631
|
+
disableFastPathAccessForNewMembers: true,
|
|
632
|
+
executionGracePeriodInDays: 14,
|
|
633
|
+
};
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
Create a DAO space:
|
|
366
637
|
|
|
367
638
|
```ts
|
|
368
|
-
|
|
639
|
+
const tx = await geo.daoSpaces.create({
|
|
640
|
+
name: "Research DAO",
|
|
641
|
+
author: authorSpaceId,
|
|
642
|
+
initialEditorSpaceIds: [authorSpaceId],
|
|
643
|
+
initialMemberSpaceIds: [authorSpaceId],
|
|
644
|
+
votingSettings,
|
|
645
|
+
});
|
|
369
646
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const smartAccountWalletClient = await getSmartAccountWalletClient({
|
|
374
|
-
privateKey,
|
|
375
|
-
// rpcUrl, // optional
|
|
647
|
+
await walletClient.sendTransaction({
|
|
648
|
+
to: tx.to,
|
|
649
|
+
data: tx.calldata,
|
|
376
650
|
});
|
|
377
651
|
```
|
|
378
652
|
|
|
379
|
-
|
|
653
|
+
Include extra initial ops in the DAO creation edit:
|
|
654
|
+
|
|
655
|
+
```ts
|
|
656
|
+
const { ops } = Ops.entities.create({
|
|
657
|
+
name: "DAO Welcome Page",
|
|
658
|
+
});
|
|
380
659
|
|
|
381
|
-
|
|
660
|
+
const tx = await geo.daoSpaces.create({
|
|
661
|
+
name: "Research DAO",
|
|
662
|
+
author: authorSpaceId,
|
|
663
|
+
initialEditorSpaceIds: [authorSpaceId],
|
|
664
|
+
votingSettings,
|
|
665
|
+
ops,
|
|
666
|
+
});
|
|
667
|
+
```
|
|
382
668
|
|
|
383
|
-
|
|
669
|
+
Propose an edit to a DAO space:
|
|
384
670
|
|
|
385
671
|
```ts
|
|
386
|
-
|
|
672
|
+
const { ops } = Ops.entities.update({
|
|
673
|
+
id: entityId,
|
|
674
|
+
name: "Updated entity name",
|
|
675
|
+
});
|
|
387
676
|
|
|
388
|
-
const
|
|
389
|
-
|
|
677
|
+
const proposal = await geo.daoSpaces.proposeEdit({
|
|
678
|
+
name: "Update entity name",
|
|
679
|
+
ops,
|
|
680
|
+
author: authorSpaceId,
|
|
681
|
+
daoSpaceAddress,
|
|
682
|
+
callerSpaceId: authorSpaceId,
|
|
683
|
+
daoSpaceId,
|
|
684
|
+
votingMode: "FAST",
|
|
390
685
|
});
|
|
391
686
|
|
|
392
|
-
|
|
393
|
-
|
|
687
|
+
await walletClient.sendTransaction({
|
|
688
|
+
to: proposal.to,
|
|
689
|
+
data: proposal.calldata,
|
|
690
|
+
});
|
|
691
|
+
```
|
|
394
692
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
693
|
+
Create a new version of an existing edit proposal:
|
|
694
|
+
|
|
695
|
+
```ts
|
|
696
|
+
const updatedProposal = await geo.daoSpaces.proposeEdit({
|
|
697
|
+
name: "Update entity name, revision 2",
|
|
698
|
+
ops,
|
|
699
|
+
author: authorSpaceId,
|
|
700
|
+
daoSpaceAddress,
|
|
701
|
+
callerSpaceId: authorSpaceId,
|
|
702
|
+
daoSpaceId,
|
|
703
|
+
proposalId,
|
|
704
|
+
updateProposal: true,
|
|
705
|
+
versionId: 2,
|
|
400
706
|
});
|
|
401
707
|
```
|
|
402
708
|
|
|
403
|
-
|
|
709
|
+
If `updateProposal: true` is set and `versionId` is omitted, the SDK reads
|
|
710
|
+
`latestProposalVersion(...)` from the configured network RPC before uploading
|
|
711
|
+
the edit. Pass `versionId` when you already know the next version or when your
|
|
712
|
+
custom network config has no RPC URL.
|
|
713
|
+
|
|
714
|
+
Manage DAO members and editors:
|
|
404
715
|
|
|
405
716
|
```ts
|
|
406
|
-
|
|
717
|
+
const addMember = geo.daoSpaces.proposeAddMember({
|
|
718
|
+
authorSpaceId,
|
|
719
|
+
spaceId: daoSpaceId,
|
|
720
|
+
daoSpaceAddress,
|
|
721
|
+
newMemberSpaceId: memberSpaceId,
|
|
722
|
+
votingMode: "FAST",
|
|
723
|
+
});
|
|
407
724
|
|
|
408
|
-
const
|
|
409
|
-
|
|
410
|
-
spaceId,
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
725
|
+
const removeMember = geo.daoSpaces.proposeRemoveMember({
|
|
726
|
+
authorSpaceId,
|
|
727
|
+
spaceId: daoSpaceId,
|
|
728
|
+
daoSpaceAddress,
|
|
729
|
+
memberToRemoveSpaceId: memberSpaceId,
|
|
730
|
+
});
|
|
731
|
+
|
|
732
|
+
const addEditor = geo.daoSpaces.proposeAddEditor({
|
|
733
|
+
authorSpaceId,
|
|
734
|
+
spaceId: daoSpaceId,
|
|
735
|
+
daoSpaceAddress,
|
|
736
|
+
newEditorSpaceId: editorSpaceId,
|
|
414
737
|
});
|
|
415
738
|
|
|
416
|
-
const
|
|
739
|
+
const removeEditor = geo.daoSpaces.proposeRemoveEditor({
|
|
740
|
+
authorSpaceId,
|
|
741
|
+
spaceId: daoSpaceId,
|
|
742
|
+
daoSpaceAddress,
|
|
743
|
+
editorToRemoveSpaceId: editorSpaceId,
|
|
744
|
+
});
|
|
417
745
|
```
|
|
418
746
|
|
|
419
|
-
|
|
747
|
+
Editor changes only support `SLOW` voting. Member changes can use the default or an explicit `votingMode`.
|
|
748
|
+
|
|
749
|
+
Propose voting-settings changes:
|
|
420
750
|
|
|
421
|
-
|
|
751
|
+
```ts
|
|
752
|
+
const updateVoting = geo.daoSpaces.proposeUpdateVotingSettings({
|
|
753
|
+
authorSpaceId,
|
|
754
|
+
spaceId: daoSpaceId,
|
|
755
|
+
daoSpaceAddress,
|
|
756
|
+
votingSettings: {
|
|
757
|
+
partialPercentageSupportThreshold: 60,
|
|
758
|
+
universalPercentageSupportThreshold: 95,
|
|
759
|
+
flatSupportThreshold: 2,
|
|
760
|
+
quorum: 2,
|
|
761
|
+
durationInDays: 5,
|
|
762
|
+
disableFastPathAccessForNewMembers: true,
|
|
763
|
+
executionGracePeriodInDays: 14,
|
|
764
|
+
},
|
|
765
|
+
});
|
|
766
|
+
```
|
|
422
767
|
|
|
423
|
-
|
|
768
|
+
Updating voting settings only supports `SLOW` voting.
|
|
424
769
|
|
|
425
|
-
|
|
770
|
+
Request membership in a DAO space:
|
|
426
771
|
|
|
427
772
|
```ts
|
|
428
|
-
|
|
773
|
+
const request = geo.daoSpaces.proposeRequestMembership({
|
|
774
|
+
authorSpaceId: requesterSpaceId,
|
|
775
|
+
spaceId: daoSpaceId,
|
|
776
|
+
});
|
|
777
|
+
|
|
778
|
+
await walletClient.sendTransaction({
|
|
779
|
+
to: request.to,
|
|
780
|
+
data: request.calldata,
|
|
781
|
+
});
|
|
782
|
+
```
|
|
429
783
|
|
|
430
|
-
|
|
784
|
+
DAO proposal IDs and DAO space IDs are bytes16 hex strings, usually `0x` plus 32 hex characters.
|
|
431
785
|
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
786
|
+
Vote on a proposal:
|
|
787
|
+
|
|
788
|
+
```ts
|
|
789
|
+
const vote = geo.daoSpaces.voteProposal({
|
|
790
|
+
authorSpaceId,
|
|
791
|
+
spaceId: daoSpaceId,
|
|
792
|
+
proposalId,
|
|
793
|
+
versionId: 1,
|
|
794
|
+
vote: "YES",
|
|
440
795
|
});
|
|
441
796
|
|
|
442
|
-
await walletClient.sendTransaction({
|
|
797
|
+
await walletClient.sendTransaction({
|
|
798
|
+
to: vote.to,
|
|
799
|
+
data: vote.calldata,
|
|
800
|
+
});
|
|
443
801
|
```
|
|
444
802
|
|
|
445
|
-
|
|
803
|
+
`versionId` defaults to `1`. Pass it explicitly when voting on a later proposal
|
|
804
|
+
version.
|
|
446
805
|
|
|
447
|
-
|
|
806
|
+
Execute a passed proposal:
|
|
448
807
|
|
|
449
808
|
```ts
|
|
450
|
-
|
|
809
|
+
const execute = geo.daoSpaces.executeProposal({
|
|
810
|
+
authorSpaceId,
|
|
811
|
+
spaceId: daoSpaceId,
|
|
812
|
+
proposalId,
|
|
813
|
+
});
|
|
814
|
+
|
|
815
|
+
await walletClient.sendTransaction({
|
|
816
|
+
to: execute.to,
|
|
817
|
+
data: execute.calldata,
|
|
818
|
+
});
|
|
819
|
+
```
|
|
451
820
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
821
|
+
### `geo.entityVotes`
|
|
822
|
+
|
|
823
|
+
Upvote, downvote, or withdraw a vote on an entity:
|
|
824
|
+
|
|
825
|
+
```ts
|
|
826
|
+
const upvote = geo.entityVotes.upvote({
|
|
827
|
+
authorSpaceId,
|
|
828
|
+
spaceId,
|
|
829
|
+
entityId,
|
|
456
830
|
});
|
|
457
831
|
|
|
458
|
-
|
|
832
|
+
const downvote = geo.entityVotes.downvote({
|
|
833
|
+
authorSpaceId,
|
|
834
|
+
spaceId,
|
|
835
|
+
entityId,
|
|
836
|
+
});
|
|
837
|
+
|
|
838
|
+
const withdraw = geo.entityVotes.withdraw({
|
|
839
|
+
authorSpaceId,
|
|
840
|
+
spaceId,
|
|
841
|
+
entityId,
|
|
842
|
+
});
|
|
459
843
|
```
|
|
460
844
|
|
|
461
|
-
|
|
845
|
+
Submit any returned transaction with your wallet client:
|
|
462
846
|
|
|
463
|
-
|
|
847
|
+
```ts
|
|
848
|
+
await walletClient.sendTransaction({
|
|
849
|
+
to: upvote.to,
|
|
850
|
+
data: upvote.calldata,
|
|
851
|
+
});
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
## Full Publishing Flow With A Smart Account
|
|
464
855
|
|
|
465
|
-
|
|
856
|
+
This example publishes an edit to an existing personal space using a Geo smart account.
|
|
466
857
|
|
|
467
858
|
```ts
|
|
468
|
-
import { createPublicClient, type Hex
|
|
859
|
+
import { createPublicClient, http, type Hex } from "viem";
|
|
469
860
|
import {
|
|
470
|
-
|
|
471
|
-
|
|
861
|
+
GeoTestnetConfig,
|
|
862
|
+
Ops,
|
|
863
|
+
createGeoClient,
|
|
472
864
|
getSmartAccountWalletClient,
|
|
473
|
-
TESTNET_RPC_URL,
|
|
474
865
|
} from "@geoprotocol/geo-sdk";
|
|
475
866
|
import { SpaceRegistryAbi } from "@geoprotocol/geo-sdk/abis";
|
|
476
|
-
import { TESTNET } from "@geoprotocol/geo-sdk/contracts";
|
|
477
867
|
|
|
478
|
-
// IMPORTANT: Be careful with your private key. Don't commit it to version control.
|
|
479
|
-
// You can get your private key using https://www.geobrowser.io/export-wallet
|
|
480
868
|
const privateKey = `0x${privateKeyFromGeoWallet}` as `0x${string}`;
|
|
481
|
-
|
|
482
|
-
// Get smart account wallet client (Safe + Pimlico paymaster)
|
|
869
|
+
const geo = createGeoClient({ network: GeoTestnetConfig });
|
|
483
870
|
const smartAccount = await getSmartAccountWalletClient({ privateKey });
|
|
484
|
-
const
|
|
871
|
+
const accountAddress = smartAccount.account.address;
|
|
485
872
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
address: smartAccountAddress,
|
|
873
|
+
const hasSpace = await geo.personalSpaces.hasSpace({
|
|
874
|
+
address: accountAddress,
|
|
489
875
|
});
|
|
490
|
-
|
|
491
|
-
|
|
876
|
+
|
|
877
|
+
if (!hasSpace) {
|
|
878
|
+
throw new Error("No personal space found for this account.");
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
const spaceRegistryAddress = GeoTestnetConfig.contracts?.SPACE_REGISTRY_ADDRESS;
|
|
882
|
+
const rpcUrl = GeoTestnetConfig.chain?.rpcUrl;
|
|
883
|
+
if (!spaceRegistryAddress || !rpcUrl) {
|
|
884
|
+
throw new Error("GeoTestnetConfig is missing registry or RPC configuration.");
|
|
492
885
|
}
|
|
493
886
|
|
|
494
887
|
const publicClient = createPublicClient({
|
|
495
|
-
transport: http(
|
|
888
|
+
transport: http(rpcUrl),
|
|
496
889
|
});
|
|
497
890
|
|
|
498
|
-
// Look up the space ID for this smart account address
|
|
499
891
|
const spaceIdHex = (await publicClient.readContract({
|
|
500
|
-
address:
|
|
892
|
+
address: spaceRegistryAddress,
|
|
501
893
|
abi: SpaceRegistryAbi,
|
|
502
894
|
functionName: "addressToSpaceId",
|
|
503
|
-
args: [
|
|
895
|
+
args: [accountAddress],
|
|
504
896
|
})) as Hex;
|
|
505
897
|
|
|
506
|
-
// Convert bytes16 hex to UUID string (without dashes)
|
|
507
898
|
const spaceId = spaceIdHex.slice(2, 34).toLowerCase();
|
|
508
|
-
console.log("spaceId", spaceId);
|
|
509
899
|
|
|
510
|
-
|
|
511
|
-
const { ops, id: entityId } = Graph.createEntity({
|
|
900
|
+
const { id: entityId, ops } = Ops.entities.create({
|
|
512
901
|
name: "Test Entity",
|
|
902
|
+
description: "Created via Geo SDK",
|
|
513
903
|
});
|
|
514
|
-
console.log("entityId", entityId);
|
|
515
904
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
name: "Test Edit",
|
|
905
|
+
const tx = await geo.personalSpaces.publishEdit({
|
|
906
|
+
name: "Create Test Entity",
|
|
519
907
|
spaceId,
|
|
520
|
-
ops,
|
|
521
908
|
author: spaceId,
|
|
522
|
-
|
|
909
|
+
ops,
|
|
523
910
|
});
|
|
524
|
-
console.log("cid", cid);
|
|
525
|
-
console.log("editId", editId);
|
|
526
911
|
|
|
527
|
-
// Send transaction via smart account (account and chain are baked in)
|
|
528
912
|
const txHash = await smartAccount.sendTransaction({
|
|
529
|
-
to,
|
|
530
|
-
data: calldata,
|
|
913
|
+
to: tx.to,
|
|
914
|
+
data: tx.calldata,
|
|
531
915
|
});
|
|
532
|
-
console.log("txHash", txHash);
|
|
533
916
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
});
|
|
537
|
-
console.log("Successfully published edit to space", spaceId);
|
|
917
|
+
await publicClient.waitForTransactionReceipt({ hash: txHash });
|
|
918
|
+
console.log("Published entity", entityId, "to space", spaceId);
|
|
538
919
|
```
|
|
539
920
|
|
|
540
|
-
## Full
|
|
921
|
+
## Full Personal Space Creation Flow
|
|
541
922
|
|
|
542
|
-
This example
|
|
923
|
+
This example creates a personal space with an EOA wallet and then publishes the initial profile ops returned by `geo.personalSpaces.create(...)`.
|
|
543
924
|
|
|
544
925
|
```ts
|
|
545
|
-
import { createPublicClient, type Hex
|
|
926
|
+
import { createPublicClient, http, type Hex } from "viem";
|
|
546
927
|
import { privateKeyToAccount } from "viem/accounts";
|
|
547
928
|
import {
|
|
548
|
-
|
|
549
|
-
|
|
929
|
+
GeoTestnetConfig,
|
|
930
|
+
createGeoClient,
|
|
550
931
|
getWalletClient,
|
|
551
|
-
TESTNET_RPC_URL,
|
|
552
932
|
} from "@geoprotocol/geo-sdk";
|
|
553
933
|
import { SpaceRegistryAbi } from "@geoprotocol/geo-sdk/abis";
|
|
554
|
-
import { TESTNET } from "@geoprotocol/geo-sdk/contracts";
|
|
555
934
|
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
const
|
|
559
|
-
const { address } = privateKeyToAccount(addressPrivateKey);
|
|
935
|
+
const privateKey = "0xTODO" as `0x${string}`;
|
|
936
|
+
const account = privateKeyToAccount(privateKey);
|
|
937
|
+
const geo = createGeoClient({ network: GeoTestnetConfig });
|
|
560
938
|
|
|
561
|
-
// Take the address and enter it in Faucet to get some testnet ETH https://faucet.conduit.xyz/geo-test-zc16z3tcvf
|
|
562
|
-
|
|
563
|
-
// Get wallet client for testnet
|
|
564
939
|
const walletClient = await getWalletClient({
|
|
565
|
-
privateKey
|
|
940
|
+
privateKey,
|
|
566
941
|
});
|
|
567
942
|
|
|
568
|
-
const
|
|
943
|
+
const rpcUrl = GeoTestnetConfig.chain?.rpcUrl;
|
|
944
|
+
const spaceRegistryAddress = GeoTestnetConfig.contracts?.SPACE_REGISTRY_ADDRESS;
|
|
945
|
+
if (!rpcUrl || !spaceRegistryAddress) {
|
|
946
|
+
throw new Error("GeoTestnetConfig is missing registry or RPC configuration.");
|
|
947
|
+
}
|
|
569
948
|
|
|
570
949
|
const publicClient = createPublicClient({
|
|
571
|
-
transport: http(
|
|
950
|
+
transport: http(rpcUrl),
|
|
572
951
|
});
|
|
573
952
|
|
|
574
|
-
|
|
575
|
-
const hasExistingSpace = await personalSpace.hasSpace({
|
|
953
|
+
const hasSpace = await geo.personalSpaces.hasSpace({
|
|
576
954
|
address: account.address,
|
|
577
955
|
});
|
|
578
956
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
957
|
+
let spaceIdHex = (await publicClient.readContract({
|
|
958
|
+
address: spaceRegistryAddress,
|
|
959
|
+
abi: SpaceRegistryAbi,
|
|
960
|
+
functionName: "addressToSpaceId",
|
|
961
|
+
args: [account.address],
|
|
962
|
+
})) as Hex;
|
|
582
963
|
|
|
583
|
-
|
|
964
|
+
if (!hasSpace) {
|
|
965
|
+
const createSpace = geo.personalSpaces.create({
|
|
966
|
+
name: "Alice",
|
|
967
|
+
accountAddress: account.address,
|
|
968
|
+
});
|
|
584
969
|
|
|
585
|
-
const
|
|
970
|
+
const createSpaceHash = await walletClient.sendTransaction({
|
|
586
971
|
account: walletClient.account,
|
|
587
|
-
to,
|
|
588
|
-
data: calldata,
|
|
972
|
+
to: createSpace.to,
|
|
973
|
+
data: createSpace.calldata,
|
|
589
974
|
});
|
|
590
975
|
|
|
591
|
-
await publicClient.waitForTransactionReceipt({ hash:
|
|
592
|
-
|
|
976
|
+
await publicClient.waitForTransactionReceipt({ hash: createSpaceHash });
|
|
977
|
+
|
|
978
|
+
spaceIdHex = (await publicClient.readContract({
|
|
979
|
+
address: spaceRegistryAddress,
|
|
980
|
+
abi: SpaceRegistryAbi,
|
|
981
|
+
functionName: "addressToSpaceId",
|
|
982
|
+
args: [account.address],
|
|
983
|
+
})) as Hex;
|
|
984
|
+
|
|
985
|
+
const spaceId = spaceIdHex.slice(2, 34).toLowerCase();
|
|
986
|
+
const profileTx = await geo.personalSpaces.publishEdit({
|
|
987
|
+
name: "Create personal space profile",
|
|
988
|
+
spaceId,
|
|
989
|
+
author: spaceId,
|
|
990
|
+
ops: createSpace.ops,
|
|
991
|
+
});
|
|
593
992
|
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
})
|
|
993
|
+
const profileHash = await walletClient.sendTransaction({
|
|
994
|
+
account: walletClient.account,
|
|
995
|
+
to: profileTx.to,
|
|
996
|
+
data: profileTx.calldata,
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
await publicClient.waitForTransactionReceipt({ hash: profileHash });
|
|
1000
|
+
|
|
1001
|
+
const topicTx = geo.personalSpaces.setTopic({
|
|
1002
|
+
spaceId,
|
|
1003
|
+
topicId: createSpace.spaceEntityId,
|
|
1004
|
+
});
|
|
1005
|
+
|
|
1006
|
+
const topicHash = await walletClient.sendTransaction({
|
|
1007
|
+
account: walletClient.account,
|
|
1008
|
+
to: topicTx.to,
|
|
1009
|
+
data: topicTx.calldata,
|
|
1010
|
+
});
|
|
1011
|
+
|
|
1012
|
+
await publicClient.waitForTransactionReceipt({ hash: topicHash });
|
|
1013
|
+
}
|
|
601
1014
|
|
|
602
|
-
// Convert bytes16 hex to UUID string (without dashes)
|
|
603
1015
|
const spaceId = spaceIdHex.slice(2, 34).toLowerCase();
|
|
604
|
-
console.log("
|
|
1016
|
+
console.log("Personal space ID", spaceId);
|
|
1017
|
+
```
|
|
605
1018
|
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
1019
|
+
## Utilities
|
|
1020
|
+
|
|
1021
|
+
### IDs
|
|
1022
|
+
|
|
1023
|
+
Entities, properties, relations, spaces, and proposals use globally unique IDs. The canonical SDK ID is a UUID v4 without dashes.
|
|
1024
|
+
|
|
1025
|
+
```ts
|
|
1026
|
+
import { Id, IdUtils } from "@geoprotocol/geo-sdk";
|
|
1027
|
+
|
|
1028
|
+
const generatedId = IdUtils.generate();
|
|
1029
|
+
const checkedId = Id(generatedId);
|
|
1030
|
+
const bytes = IdUtils.toBytes(checkedId);
|
|
1031
|
+
```
|
|
1032
|
+
|
|
1033
|
+
### Positions
|
|
1034
|
+
|
|
1035
|
+
`Position` provides fractional indexing helpers for ordered relations and other ordered items.
|
|
1036
|
+
|
|
1037
|
+
```ts
|
|
1038
|
+
import { Position } from "@geoprotocol/geo-sdk";
|
|
1039
|
+
|
|
1040
|
+
const first = Position.generate();
|
|
1041
|
+
const between = Position.generateBetween(first, null);
|
|
1042
|
+
const sorted = Position.sort([between, null, first]);
|
|
1043
|
+
```
|
|
1044
|
+
|
|
1045
|
+
### Wallet Helpers
|
|
1046
|
+
|
|
1047
|
+
The Geo Genesis browser uses a smart account associated with your account. You can use the same account from code by exporting your private key from https://www.geobrowser.io/export-wallet.
|
|
1048
|
+
|
|
1049
|
+
```ts
|
|
1050
|
+
import {
|
|
1051
|
+
getSmartAccountWalletClient,
|
|
1052
|
+
getWalletClient,
|
|
1053
|
+
} from "@geoprotocol/geo-sdk";
|
|
1054
|
+
|
|
1055
|
+
const smartAccountWalletClient = await getSmartAccountWalletClient({
|
|
1056
|
+
privateKey,
|
|
610
1057
|
});
|
|
611
|
-
console.log("entityId", entityId);
|
|
612
1058
|
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
1059
|
+
const eoaWalletClient = await getWalletClient({
|
|
1060
|
+
privateKey,
|
|
1061
|
+
});
|
|
1062
|
+
```
|
|
1063
|
+
|
|
1064
|
+
Be careful with private keys. Do not commit them to version control.
|
|
1065
|
+
|
|
1066
|
+
## Legacy API
|
|
1067
|
+
|
|
1068
|
+
The legacy namespaces remain exported for compatibility, but new code should prefer `Ops` and `createGeoClient`.
|
|
1069
|
+
|
|
1070
|
+
| Legacy API | Preferred API |
|
|
1071
|
+
| -------------------------- | ------------------------------------------------------------------------------------ |
|
|
1072
|
+
| `Graph.createEntity(...)` | `Ops.entities.create(...)` |
|
|
1073
|
+
| `Graph.updateEntity(...)` | `Ops.entities.update(...)` |
|
|
1074
|
+
| `Graph.deleteEntity(...)` | `geo.entities.delete(...)` |
|
|
1075
|
+
| `Graph.createImage(...)` | `geo.images.create(...)` |
|
|
1076
|
+
| `Graph.createComment(...)` | `geo.comments.create(...)` or `Ops.comments.create(...)` with supplied reply context |
|
|
1077
|
+
| `Ipfs.publishEdit(...)` | `geo.personalSpaces.publishEdit(...)` or `geo.daoSpaces.proposeEdit(...)` |
|
|
1078
|
+
| `Ipfs.uploadImage(...)` | `geo.storage.uploadImage(...)` |
|
|
1079
|
+
| `Ipfs.uploadCSV(...)` | `geo.storage.uploadCSV(...)` |
|
|
1080
|
+
| `personalSpace.*` | `geo.personalSpaces.*` |
|
|
1081
|
+
| `daoSpace.*` | `geo.daoSpaces.*` |
|
|
1082
|
+
| root encoding helpers | configured client transaction helpers where available |
|
|
1083
|
+
|
|
1084
|
+
### Legacy `Graph`
|
|
1085
|
+
|
|
1086
|
+
```ts
|
|
1087
|
+
import { Graph } from "@geoprotocol/geo-sdk";
|
|
1088
|
+
|
|
1089
|
+
const { id: propertyId, ops: propertyOps } = Graph.createProperty({
|
|
1090
|
+
name: "Website",
|
|
1091
|
+
dataType: "TEXT",
|
|
1092
|
+
});
|
|
1093
|
+
|
|
1094
|
+
const { id: typeId, ops: typeOps } = Graph.createType({
|
|
1095
|
+
name: "Restaurant",
|
|
1096
|
+
properties: [propertyId],
|
|
1097
|
+
});
|
|
1098
|
+
|
|
1099
|
+
const { id: entityId, ops: entityOps } = Graph.createEntity({
|
|
1100
|
+
name: "Yum Yum",
|
|
1101
|
+
types: [typeId],
|
|
1102
|
+
values: [
|
|
1103
|
+
{
|
|
1104
|
+
property: propertyId,
|
|
1105
|
+
type: "text",
|
|
1106
|
+
value: "https://example.com",
|
|
1107
|
+
},
|
|
1108
|
+
],
|
|
1109
|
+
});
|
|
1110
|
+
|
|
1111
|
+
const { ops: updateOps } = Graph.updateEntity({
|
|
1112
|
+
id: entityId,
|
|
1113
|
+
name: "Updated name",
|
|
1114
|
+
});
|
|
1115
|
+
|
|
1116
|
+
const { ops: deleteOps } = await Graph.deleteEntity({
|
|
1117
|
+
id: entityId,
|
|
616
1118
|
spaceId,
|
|
1119
|
+
network: "TESTNET",
|
|
1120
|
+
});
|
|
1121
|
+
```
|
|
1122
|
+
|
|
1123
|
+
Legacy relation helpers:
|
|
1124
|
+
|
|
1125
|
+
```ts
|
|
1126
|
+
const { id: relationId, ops: createRelationOps } = Graph.createRelation({
|
|
1127
|
+
fromEntity: personId,
|
|
1128
|
+
toEntity: restaurantId,
|
|
1129
|
+
type: likesPropertyId,
|
|
1130
|
+
});
|
|
1131
|
+
|
|
1132
|
+
const { ops: updateRelationOps } = Graph.updateRelation({
|
|
1133
|
+
id: relationId,
|
|
1134
|
+
position,
|
|
1135
|
+
});
|
|
1136
|
+
|
|
1137
|
+
const { ops: deleteRelationOps } = Graph.deleteRelation({
|
|
1138
|
+
id: relationId,
|
|
1139
|
+
});
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
Legacy image and comment helpers:
|
|
1143
|
+
|
|
1144
|
+
```ts
|
|
1145
|
+
const image = await Graph.createImage({
|
|
1146
|
+
url: "https://example.com/image.png",
|
|
1147
|
+
network: "TESTNET",
|
|
1148
|
+
});
|
|
1149
|
+
|
|
1150
|
+
const comment = await Graph.createComment({
|
|
1151
|
+
content: "Looks good.",
|
|
1152
|
+
replyTo: { entityId, spaceId },
|
|
1153
|
+
network: "TESTNET",
|
|
1154
|
+
});
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
### Legacy `Ipfs`
|
|
1158
|
+
|
|
1159
|
+
```ts
|
|
1160
|
+
import { Ipfs } from "@geoprotocol/geo-sdk";
|
|
1161
|
+
|
|
1162
|
+
const edit = await Ipfs.publishEdit({
|
|
1163
|
+
name: "Create entity",
|
|
1164
|
+
author: spaceId,
|
|
617
1165
|
ops,
|
|
1166
|
+
network: "TESTNET",
|
|
1167
|
+
});
|
|
1168
|
+
|
|
1169
|
+
const image = await Ipfs.uploadImage(
|
|
1170
|
+
{ url: "https://example.com/image.png" },
|
|
1171
|
+
"TESTNET",
|
|
1172
|
+
);
|
|
1173
|
+
|
|
1174
|
+
const csvCid = await Ipfs.uploadCSV("name,score\nAlice,10", "TESTNET");
|
|
1175
|
+
```
|
|
1176
|
+
|
|
1177
|
+
### Legacy `personalSpace`
|
|
1178
|
+
|
|
1179
|
+
```ts
|
|
1180
|
+
import { personalSpace } from "@geoprotocol/geo-sdk";
|
|
1181
|
+
|
|
1182
|
+
const hasSpace = await personalSpace.hasSpace({
|
|
1183
|
+
address: account.address,
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
const createSpace = personalSpace.createSpace();
|
|
1187
|
+
|
|
1188
|
+
const publish = await personalSpace.publishEdit({
|
|
1189
|
+
name: "My Edit",
|
|
1190
|
+
spaceId,
|
|
618
1191
|
author: spaceId,
|
|
1192
|
+
ops,
|
|
1193
|
+
network: "TESTNET",
|
|
1194
|
+
});
|
|
1195
|
+
```
|
|
1196
|
+
|
|
1197
|
+
### Legacy `daoSpace`
|
|
1198
|
+
|
|
1199
|
+
```ts
|
|
1200
|
+
import { daoSpace } from "@geoprotocol/geo-sdk";
|
|
1201
|
+
|
|
1202
|
+
const createDao = await daoSpace.createSpace({
|
|
1203
|
+
name: "Research DAO",
|
|
1204
|
+
author: authorSpaceId,
|
|
1205
|
+
initialEditorSpaceIds: [authorSpaceId],
|
|
1206
|
+
votingSettings,
|
|
1207
|
+
network: "TESTNET",
|
|
1208
|
+
});
|
|
1209
|
+
|
|
1210
|
+
const proposal = await daoSpace.proposeEdit({
|
|
1211
|
+
name: "Update entity",
|
|
1212
|
+
ops,
|
|
1213
|
+
author: authorSpaceId,
|
|
1214
|
+
daoSpaceAddress,
|
|
1215
|
+
callerSpaceId: authorSpaceId,
|
|
1216
|
+
daoSpaceId,
|
|
1217
|
+
network: "TESTNET",
|
|
1218
|
+
});
|
|
1219
|
+
|
|
1220
|
+
const vote = daoSpace.voteProposal({
|
|
1221
|
+
authorSpaceId,
|
|
1222
|
+
spaceId: daoSpaceId,
|
|
1223
|
+
proposalId,
|
|
1224
|
+
versionId: 1,
|
|
1225
|
+
vote: "YES",
|
|
619
1226
|
network: "TESTNET",
|
|
620
1227
|
});
|
|
621
|
-
console.log("cid", cid);
|
|
622
|
-
console.log("editId", editId);
|
|
623
1228
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
1229
|
+
const execute = daoSpace.executeProposal({
|
|
1230
|
+
authorSpaceId,
|
|
1231
|
+
spaceId: daoSpaceId,
|
|
1232
|
+
proposalId,
|
|
1233
|
+
network: "TESTNET",
|
|
1234
|
+
});
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
Legacy DAO membership helpers:
|
|
1238
|
+
|
|
1239
|
+
```ts
|
|
1240
|
+
daoSpace.proposeAddMember({
|
|
1241
|
+
authorSpaceId,
|
|
1242
|
+
spaceId: daoSpaceId,
|
|
1243
|
+
daoSpaceAddress,
|
|
1244
|
+
newMemberSpaceId,
|
|
1245
|
+
network: "TESTNET",
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
daoSpace.proposeRemoveMember({
|
|
1249
|
+
authorSpaceId,
|
|
1250
|
+
spaceId: daoSpaceId,
|
|
1251
|
+
daoSpaceAddress,
|
|
1252
|
+
memberToRemoveSpaceId,
|
|
1253
|
+
network: "TESTNET",
|
|
1254
|
+
});
|
|
1255
|
+
|
|
1256
|
+
daoSpace.proposeAddEditor({
|
|
1257
|
+
authorSpaceId,
|
|
1258
|
+
spaceId: daoSpaceId,
|
|
1259
|
+
daoSpaceAddress,
|
|
1260
|
+
newEditorSpaceId,
|
|
1261
|
+
network: "TESTNET",
|
|
629
1262
|
});
|
|
630
|
-
console.log("publishTxHash", publishTxHash);
|
|
631
1263
|
|
|
632
|
-
|
|
633
|
-
|
|
1264
|
+
daoSpace.proposeRemoveEditor({
|
|
1265
|
+
authorSpaceId,
|
|
1266
|
+
spaceId: daoSpaceId,
|
|
1267
|
+
daoSpaceAddress,
|
|
1268
|
+
editorToRemoveSpaceId,
|
|
1269
|
+
network: "TESTNET",
|
|
634
1270
|
});
|
|
635
|
-
|
|
1271
|
+
|
|
1272
|
+
daoSpace.proposeUpdateVotingSettings({
|
|
1273
|
+
authorSpaceId,
|
|
1274
|
+
spaceId: daoSpaceId,
|
|
1275
|
+
daoSpaceAddress,
|
|
1276
|
+
votingSettings,
|
|
1277
|
+
network: "TESTNET",
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
daoSpace.proposeRequestMembership({
|
|
1281
|
+
authorSpaceId: requesterSpaceId,
|
|
1282
|
+
spaceId: daoSpaceId,
|
|
1283
|
+
network: "TESTNET",
|
|
1284
|
+
});
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
### Legacy Encoding Helpers
|
|
1288
|
+
|
|
1289
|
+
Low-level encoding helpers are still available for compatibility when you need exact calldata primitives:
|
|
1290
|
+
|
|
1291
|
+
```ts
|
|
1292
|
+
import {
|
|
1293
|
+
getCreateDaoSpaceCalldata,
|
|
1294
|
+
getCreatePersonalSpaceCalldata,
|
|
1295
|
+
getProcessGeoProposalArguments,
|
|
1296
|
+
} from "@geoprotocol/geo-sdk";
|
|
1297
|
+
|
|
1298
|
+
const personalSpaceCalldata = getCreatePersonalSpaceCalldata();
|
|
1299
|
+
|
|
1300
|
+
const daoSpaceCalldata = getCreateDaoSpaceCalldata({
|
|
1301
|
+
votingSettings,
|
|
1302
|
+
initialEditorSpaceIds: [authorSpaceId],
|
|
1303
|
+
initialMemberSpaceIds: [],
|
|
1304
|
+
initialEditsContentUri:
|
|
1305
|
+
"ipfs://bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku",
|
|
1306
|
+
});
|
|
1307
|
+
|
|
1308
|
+
const proposalArgs = getProcessGeoProposalArguments(
|
|
1309
|
+
spacePluginAddress,
|
|
1310
|
+
"ipfs://bafkreihdwdcefgh4dqkjv67uzcmw7ojee6xedzdetojuzjevtenxquvyku",
|
|
1311
|
+
);
|
|
636
1312
|
```
|