Search
Search

Transaction: CC9GcHy...2NT3

Receiver
Status
Succeeded
Transaction Fee
0.01069 
Deposit Value
2.2701 
Gas Used
107 Tgas
Attached Gas
300 Tgas
Created
May 31, 2024 at 11:45:44pm
Hash
CC9GcHy83rphSqwYdFGRGRyFvEi4uTU9wceCkLZk2NT3

Actions

Called method: 'set' in contract: social.near
Arguments:
{ "data": { "hyperbuild.near": { "widget": { "explore.thing": { "": "if (typeof props.path !== \"string\") return \"send {path} as string in props\";\nState.init({\n selectedTab: \"explore\",\n selectedBlockHeight: \"final\",\n});\nconst historyBlocksRequest = Social.keys(`${props.path}`, \"final\", {\n return_type: \"History\",\n});\nif (historyBlocksRequest === null) return \"loading...\";\nconst [widgetAccountId, _, widgetName] = props.path.split(\"/\");\nlet blocksChanges =\n historyBlocksRequest[widgetAccountId]?.[\"widget\"]?.[widgetName];\nif (props.count) props.count(blocksChanges.length);\nif (blocksChanges) blocksChanges = blocksChanges?.sort((a, b) => b - a);\nif (!state.selectedBlockHeight) state.selectedBlockHeight = blocksChanges[0];\nfunction getDatastringFromBlockHeight(blockHeight) {\n const block = Near.block(blockHeight);\n const date = new Date(block.header.timestamp_nanosec / 1e6);\n return date.toDateString() + \" \" + date.toLocaleTimeString();\n}\nconst renderBlockChangesLink = (blockHeight) => {\n return (\n <div>\n <button\n className={`list-group-item list-group-item-action ${\n state.selectedBlockHeight != blockHeight ? \"\" : \"list-group-item-info\"\n }`}\n onClick={() => {\n State.update({ selectedBlockHeight: blockHeight });\n }}\n >\n #{blockHeight} * {getDatastringFromBlockHeight(blockHeight)}\n </button>\n </div>\n );\n};\nfunction blockHeightToWidgetCode(blockHeight) {\n const index = blocksChanges.findIndex((el) => el == blockHeight);\n return (\n <div class=\"mb-3\">\n <Widget\n key={blockHeight}\n src={`bozon.near/widget/WidgetHistory.CodeHistoryCard`}\n props={{\n pathToWidget: props.path,\n currentBlockHeight: blockHeight,\n prevBlockHeight: blocksChanges[index + 1],\n }}\n />\n </div>\n );\n}\nfunction blockHeightToWidgetRender(blockHeight) {\n const index = blocksChanges.findIndex((el) => el == blockHeight);\n return (\n <Widget\n style={{ minHeight: \"200px\" }}\n key={blockHeight}\n src={`bozon.near/widget/WidgetHistory.RenderCode`}\n props={{\n pathToWidget: props.path,\n currentBlockHeight: blockHeight,\n prevBlockHeight: blocksChanges[index + 1],\n }}\n />\n );\n}\nconst Tabs = styled.div`\n display: flex;\n padding: 0 12px;\n height: 48px;\n border-bottom: 1px solid #eceef0;\n`;\nconst TabsButton = styled.button`\n font-weight: 400;\n font-size: 14px;\n line-height: 17px;\n padding: 0 12px;\n position: relative;\n color: ${(p) => (p.selected ? \"#11181C\" : \"#687076\")};\n background: none;\n border: none;\n outline: none;\n &:hover {\n color: #11181c;\n }\n &::after {\n content: \"\";\n display: ${(p) => (p.selected ? \"block\" : \"none\")};\n position: absolute;\n bottom: 0;\n left: 12px;\n right: 12px;\n height: 3px;\n background: #0091ff;\n }\n`;\nreturn (\n <div>\n {!blocksChanges ? (\n <div>invalid path</div>\n ) : (\n <div>\n <Tabs>\n <TabsButton\n type=\"button\"\n onClick={() =>\n State.update({\n selectedTab: \"connect\",\n })\n }\n selected={state.selectedTab == \"connect\"}\n >\n Connect\n </TabsButton>\n <TabsButton\n type=\"button\"\n onClick={() =>\n State.update({\n selectedTab: \"explore\",\n })\n }\n selected={state.selectedTab == \"explore\"}\n >\n Explore\n </TabsButton>\n </Tabs>\n {!state.selectedTab && (\n <div className=\"m-2\">\n <p>Hello</p>\n </div>\n )}\n {state.selectedTab == \"connect\" && (\n <div className=\"m-2\">\n <Widget src=\"hack.near/widget/explore.connect\" />\n </div>\n )}\n {state.selectedTab == \"explore\" && (\n <div>{blockHeightToWidgetRender(state.selectedBlockHeight)}</div>\n )}\n </div>\n )}\n </div>\n);\n" }, "tools.ipfs.pdfUpload": { "": "const fileAccept = props.fileAccept || \"application/pdf\";\nconst fileIcon = props.fileIcon || \"bi-file-earmark-pdf\";\nconst buttonText = props.buttonText || \"Upload pdf files\";\n// if (!props.update) return \"Update function is required\";\ninitState({\n uploading: false,\n files: [],\n});\nconst ipfsUrl = (cid) => `https://ipfs.near.social/ipfs/${cid}`;\nconst filesOnChange = (files) => {\n State.update({\n uploading: true,\n files: [],\n });\n if (files?.length > 0) {\n files.map((file, index) => {\n const body = file;\n asyncFetch(\"https://ipfs.near.social/add\", {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n },\n body,\n }).then((res) => {\n const cid = res.body.cid;\n State.update({\n files: [...state.files, { index, name: file.name, cid }],\n });\n });\n });\n State.update({ uploading: false });\n props.update(state.files);\n } else {\n State.update({\n uploading: false,\n files: null,\n });\n }\n};\nconst onClickDelete = (index) => {\n const filesUpdated = state.files.filter((file) => file.index !== index);\n State.update({ files: filesUpdated });\n};\nconst filesUploaded = () => {\n if (state.files.length > 0) {\n return state.files.map((file) => (\n <div class=\"d-flex flex-row gap-2 align-items-center\">\n <button\n class=\"btn btn-danger rounded-0\"\n type=\"button\"\n data-toggle=\"tooltip\"\n data-placement=\"top\"\n title=\"Delete\"\n onClick={() => onClickDelete(file.index)}\n >\n <i class=\"bi bi-trash\" />\n </button>\n <i class={`bi fs-3 ${fileIcon}`} />\n <p>{file.name}</p>\n </div>\n ));\n }\n return <></>;\n};\nreturn (\n <div className=\"d-inline-block\">\n {filesUploaded()}\n <Files\n multiple={true}\n accepts={[fileAccept]}\n minFileSize={1}\n clickable\n className=\"btn btn-outline-primary\"\n onChange={filesOnChange}\n >\n {state.uploading\n ? \"Uploading\"\n : state.files.length > 0\n ? \"Replace All\"\n : buttonText}\n </Files>\n <div>\n Raw State:\n <pre>{JSON.stringify(state)}</pre>\n </div>\n </div>\n);\n" }, "profile.cleanup": { "": "const accountId = context.accountId;\nif (!accountId) {\n return \"Please sign in with NEAR wallet\";\n}\nState.init({\n selectedKeys: {},\n nonce: 0,\n});\nconst value = Social.getr(accountId, undefined, {\n nonce: state.nonce,\n});\nconst extractKeys = (data, prefix) =>\n Object.entries(data)\n .map((kv) =>\n typeof kv[1] === \"string\"\n ? { key: `${prefix}${kv[0]}`, value: kv[1] }\n : extractKeys(kv[1], `${prefix}${kv[0]}/`)\n )\n .flat();\nconst kvs = extractKeys(value || {}, \"\");\nkvs.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key));\nconst hasKey = (key) => {\n let t = state.selectedKeys;\n key.split(\"/\").forEach((k) => {\n t = t[k];\n });\n return t === null;\n};\nconst onSelect = (key) => {\n const val = hasKey(key) ? undefined : null;\n let t = state.selectedKeys;\n const path = key.split(\"/\");\n path.slice(0, -1).forEach((k) => {\n t[k] = t[k] || {};\n t = t[k];\n });\n t[path[path.length - 1]] = val;\n State.update();\n};\nreturn (\n <div>\n <h4>Select keys to delete</h4>\n <table className=\"table table-striped\">\n <thead>\n <tr>\n <th>X</th>\n <th>Key</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n {kvs.map((kv) => {\n return (\n <tr>\n <td>\n <input\n className=\"form-check-input\"\n type=\"checkbox\"\n checked={hasKey(kv.key)}\n onChange={() => onSelect(kv.key)}\n />\n </td>\n <td className=\"text-truncate font-monospace\">{kv.key}</td>\n <td className=\"text-truncate font-monospace\">{kv.value}</td>\n </tr>\n );\n })}\n </tbody>\n </table>\n <div>\n <CommitButton\n data={state.selectedKeys}\n disabled={Object.keys(state.selectedKeys).length === 0}\n onCommit={() =>\n State.update({ selectedKeys: {}, nonce: state.nonce + 1 })\n }\n >\n Delete selected keys\n </CommitButton>\n </div>\n </div>\n);\n" }, "adapter.github": { "": "// Function to construct a GitHub API URL given a file path in a repository\nconst githubUrl = (filePath) =>\n `https://api.github.com/repos/your-username/your-repository/contents/${filePath}`;\n\n// Function to retrieve data from GitHub given a file path\nfunction get(filePath) {\n return fetch(githubUrl(filePath), {\n headers: {\n Accept: \"application/vnd.github.v3.raw\", // Set Accept header to get raw content of the file\n Authorization: \"token YOUR_GITHUB_TOKEN\", // Authorization header with your GitHub token\n },\n }).then((response) => {\n if (!response.ok) {\n throw new Error(\"Failed to fetch data\");\n }\n return response.text(); // Use .text() for raw content, not .json()\n });\n}\n\n// Function to create and upload data to GitHub, returning a promise with the URL of the uploaded content\nfunction create(filePath, data) {\n // Added filePath to the parameters\n return new Promise((resolve, reject) => {\n if (data.length) {\n const content = btoa(data); // Convert data to Base64 for GitHub API\n fetch(githubUrl(filePath), {\n method: \"PUT\",\n headers: {\n Accept: \"application/vnd.github.v3+json\", // Set Accept header to expect JSON responses\n Authorization: \"token YOUR_GITHUB_TOKEN\", // Authorization header with your GitHub token\n \"Content-Type\": \"application/json\", // Set the Content-Type header\n },\n body: JSON.stringify({\n message: `Upload ${filePath}`, // Commit message\n content: content, // Base64 encoded content\n }),\n })\n .then((response) => response.json()) // Parse the JSON response\n .then((data) => {\n if (data.content && data.content.html_url) {\n resolve({ url: data.content.html_url }); // Resolve the promise with the HTML URL of the new content\n } else {\n throw new Error(\"Invalid response from GitHub\");\n }\n })\n .catch((error) => {\n console.error(\"Error in create function:\", error);\n reject(error); // Reject the promise in case of an error\n });\n } else {\n reject(\"No data provided\"); // Reject the promise if no data is provided\n }\n });\n}\n\n// Return the get and create functions for use elsewhere\nreturn { get, create };\n" }, "explore.view.node": { "": "const key = props.key;\nconst label = props.label;\nconst node = props.node;\nconst type = props.type;\nconst path = props.path;\nconst setPath = props.setPath;\nconst history = props.history;\nconst setHistory = props.setHistory;\nconst setType = props.setType;\nconst isRoot = props.isRoot;\nconst styles = {\n subject: {\n fontFamily: \"Arial, sans-serif\",\n fontWeight: \"bold\", // Bold text\n cursor: \"pointer\",\n },\n};\n\nState.init({\n expanded: false,\n});\nfunction handleExpand() {\n State.update({ expanded: !state.expanded });\n}\nfunction handleInto() {\n // Check if node is an object and not null\n if (node && typeof node === \"object\") {\n setPath(path);\n setHistory([...history, path]);\n setType(type);\n } else {\n console.error(\"Invalid node structure\");\n }\n}\nfunction handleBack() {\n const newPath = history[history.length - 2] || \"\";\n setPath(newPath);\n setHistory(history.slice(0, -1));\n}\n// Basic Button Style\nconst Button = styled.button`\n text-transform: lowercase !important;\n display: inline-block;\n text-align: center;\n text-decoration: none;\n border: 2px outset #333;\n background-color: #f5f5f5;\n cursor: pointer;\n color: #333;\n`;\nconst ChildNode = styled.div`\n margin-left: ${String(path).split(\"/\").length * 4}px;\n`;\nfunction renderView() {\n // Root vs Leaf?\n return <Widget src=\"efiz.near/widget/View\" props={{ path, type }} />;\n}\nfunction getType() {\n const parts = String(path).split(\"/\");\n if (parts.length === 1) {\n return \"account\";\n } else if (parts.length === 2) {\n return parts[1];\n } else {\n const standard = parts[1];\n if (standard === \"thing\") {\n // We're gonna grab the type from the thing itself\n }\n return standard;\n }\n}\n\nreturn (\n <div>\n <div>\n {/** CONTROLLER */}\n {history.length > 1 && isRoot && (\n <Button onClick={handleBack}>back</Button>\n )}\n {isRoot ? (\n <div style={styles?.subject}>{label} (root)</div>\n ) : (\n <div style={styles?.subject}>{path}</div>\n )}\n <Button onClick={handleExpand}>{state.expanded ? \"-\" : \"+\"}</Button>\n </div>\n {state.expanded && (\n <div>\n {/** EDGES */}\n {node && typeof node === \"object\" ? (\n Object.entries(node).map(([key, val]) => (\n <ChildNode>\n <Widget\n src=\"hyperbuild.near/widget/explore.view.node\"\n props={{\n key,\n label: key,\n node: val,\n type: getType(),\n path: `${path}/${key}`,\n setPath: setPath,\n history,\n setHistory: setHistory,\n isRoot: false,\n }}\n />\n </ChildNode>\n ))\n ) : (\n <>\n {/** VIEW */}\n <div>{renderView()}</div>\n </>\n )}\n </div>\n )}\n </div>\n);\n" }, "explore.search": { "": "const queries = props.predefinedQueries || [\n //{ name: \"Widget Builders\", query: \"*/widget/*\" },\n //{ name: \"Feature Builders\", query: \"*/widget/*/metadata/tags/app\" },\n { name: \"Hyperfiles\", query: \"*/hyperfile/*\" },\n { name: \"Attestations\", query: \"*/attestation/*\" },\n { name: \"Schemas\", query: \"*/schema/*\" },\n { name: \"Types\", query: \"*/type/*\" },\n { name: \"Jobs\", query: \"*/job/*\" },\n //{ name: \"Feature Builders\", query: \"*/widget/*/metadata/tags/app\" },\n];\n\nconst [inputPath, setInputPath] = useState(\"\");\nconst defaultPath = props.defaultPath;\nconst onUpdateSearchResult = props.onUpdateSearchResult || \"/hyperfile\";\nconst debug = props.debug || false;\nif (!onUpdateSearchResult)\n return \"Must provide a callback function over props.onUpdateSearchResult\";\n\nState.init({\n path: defaultPath,\n accounts: [],\n});\n\nconst onChangePath = (path) => {\n const value = Social.get(path, \"final\");\n const accounts = Object.keys(value);\n onUpdateSearchResult(accounts);\n State.update({ path: path, accounts: accounts });\n setInputPath(path);\n console.log(\"Failed to fetch data:\", error);\n};\n\nconst handleSubmit = () => {\n onPathChange(inputPath); // This callback updates the parent component's state\n};\n\n// Integrate mob.near/widget/ComponentSearch to show results for queried objects\n// Format results with starred components = mob.near/widget/Applications\n// const allComponents = [];\n\nconst allPeople = [];\n\nfor (let i = 0; i < state.accounts.length; ++i) {\n const accountId = state.accounts[i];\n\n allPeople.push(\n <a\n href={`#/mob.near/widget/ProfilePage?accountId=${accountId}`}\n className=\"text-decoration-none\"\n key={`people_${i}`}\n >\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId,\n tooltip: true,\n className: \"d-inline-block overflow-hidden\",\n }}\n />\n </a>\n );\n}\n\nreturn (\n <div>\n <div class=\"mb-2\">\n <input\n type=\"text\"\n value={state.path}\n onChange={(e) => onChangePath(e.target.value)}\n placeholder={\"*/widget/*/metadata/tags/app\"}\n />\n <button onClick={handleSubmit}>Update Path</button>\n </div>\n <div class=\"d-flex flex-wrap flex-row mb-2\">\n <div class=\"btn-toolbar\" role=\"toolbar\" aria-label=\"Generated queries\">\n {queries &&\n queries.length &&\n queries.map((q, i) => {\n return (\n <button\n type=\"button\"\n key={`query_${i}`}\n class=\"btn btn-primary btn-sm mr-2\"\n onClick={() => {\n onChangePath(q.query);\n }}\n >\n {q.name}\n </button>\n );\n })}\n </div>\n <div>{debug && allPeople}</div>\n </div>\n </div>\n);\n" }, "explore.every.schema": { "": "const accountId = props.accountId ?? \"*\" ?? context.accountId;\nconst schemaName = props.schemaName || \"schema\";\nconst tag = props.tag;\nconst metadataTemplate =\n props.metadataTemplate || \"efiz.near/widget/every.type.metadata\";\nlet keys = `${accountId ?? \"*\"}/${schemaName}/*`;\nif (tag) {\n const taggedWidgets = Social.keys(\n `${accountId ?? \"*\"}/${schemaName}/*/metadata/tags/${tag}`,\n \"final\"\n );\n if (taggedWidgets === null) {\n return render(\"Loading tags\");\n }\n keys = Object.entries(taggedWidgets)\n .map((kv) =>\n Object.keys(kv[1][schemaName]).map((w) => `${kv[0]}/${schemaName}/${w}`)\n )\n .flat();\n if (!keys.length) {\n return render(`No schemas found by tag #${tag}`);\n }\n}\nconst data = Social.keys(keys, \"final\", {\n return_schema: \"BlockHeight\",\n limit: 1,\n});\nif (data === null) {\n return <p>\"Loading\"</p>;\n}\nconst processData = (data) => {\n const accounts = Object.entries(data);\n const allItems = accounts\n .map((account) => {\n const accountId = account[0];\n return Object.entries(account[1][schemaName]).map((kv) => ({\n accountId,\n schemaName: kv[0],\n blockHeight: kv[1],\n }));\n })\n .flat();\n allItems.sort((a, b) => b.blockHeight - a.blockHeight);\n return allItems;\n};\nconst renderItem = (a) => {\n return (\n <div className=\"mb-3\" key={JSON.stringify(a)} style={{ minHeight: \"10em\" }}>\n <Widget\n src=\"efiz.near/widget/every.type.metadata\"\n props={{\n accountId: a.accountId,\n widgetName: a.schemaName,\n blockHeight: a.blockHeight,\n }}\n />\n </div>\n );\n};\nif (JSON.stringify(data) !== JSON.stringify(state.data || {})) {\n State.update({\n data,\n allItems: processData(data),\n });\n}\nreturn (\n <div className=\"px-2 mx-auto\">\n {(accountId || tag) && (\n <div className=\"mb-2\">\n Filter:\n {accountId && (\n <a className=\"btn btn-outline-primary\">\n <Widget\n src=\"mob.near/widget/ProfileLine\"\n props={{ accountId, link: false }}\n />\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n {tag && (\n <a className=\"btn btn-outline-primary\">\n <span className=\"badge text-bg-secondary\">#{tag}</span>\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n </div>\n )}\n <Widget\n src=\"efiz.near/widget/ItemFeed\"\n props={{ items: state.allItems || [], renderItem }}\n />\n </div>\n);\n" }, "explore.view.path": { "": "State.init({\n path: props.path,\n});\n\nconst value = Social.get(state.path, \"final\");\n\nconst text = `\n \\`\\`\\`json\n ${JSON.stringify(value, undefined, 2)}\n \\`\\`\\`\n `;\n\nreturn (\n <div>\n <div>\n <input\n type=\"text\"\n value={state.path}\n placeholder=\"self.social.near/profile/**\"\n />\n </div>\n <Markdown text={text} />\n </div>\n);\n" }, "tools.nearfs.utils": { "": "// fork_Of: \"sdks.near/widget/Utils.NearFS\"\nconst NEAR_SOCIAL_IPFS_URL = \"https://ipfs.near.social\";\nconst NEAR_SOCIAL_ADD_ENDPOINT = `${NEAR_SOCIAL_IPFS_URL}/add`;\nconst NearFS = {\n get: (cid) =>\n asyncFetch(NearFS.getIpfsUrl(cid)).then((data) => data.body || null),\n upload: (metadata) => {\n return asyncFetch(NEAR_SOCIAL_ADD_ENDPOINT, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n },\n body: JSON.stringify(metadata),\n }).then((data) => {\n return {\n cid: data.body.cid || null,\n url: data.body.cid ? NearFS.getIpfsUrl(data.body.cid) : null,\n };\n });\n },\n getIpfsUrl: (cid) => {\n return `${NEAR_SOCIAL_IPFS_URL}/ipfs/${cid}`;\n },\n};\nreturn NearFS;\n" }, "explore.every.type": { "": "const accountId = props.accountId ?? \"*\" ?? context.accountId;\nconst typeName = props.typeName || \"type\";\nconst tag = props.tag;\nconst metadataTemplate =\n props.metadataTemplate || \"efiz.near/widget/every.type.metadata\";\nlet keys = `${accountId ?? \"*\"}/${typeName}/*`;\nif (tag) {\n const taggedWidgets = Social.keys(\n `${accountId ?? \"*\"}/${typeName}/*/metadata/tags/${tag}`,\n \"final\"\n );\n if (taggedWidgets === null) {\n return render(\"Loading tags\");\n }\n keys = Object.entries(taggedWidgets)\n .map((kv) =>\n Object.keys(kv[1][typeName]).map((w) => `${kv[0]}/${typeName}/${w}`)\n )\n .flat();\n if (!keys.length) {\n return render(`No types found by tag #${tag}`);\n }\n}\nconst data = Social.keys(keys, \"final\", {\n return_type: \"BlockHeight\",\n limit: 1,\n});\nif (data === null) {\n return <p>\"Loading\"</p>;\n}\nconst processData = (data) => {\n const accounts = Object.entries(data);\n const allItems = accounts\n .map((account) => {\n const accountId = account[0];\n return Object.entries(account[1][typeName]).map((kv) => ({\n accountId,\n typeName: kv[0],\n blockHeight: kv[1],\n }));\n })\n .flat();\n allItems.sort((a, b) => b.blockHeight - a.blockHeight);\n return allItems;\n};\nconst renderItem = (a) => {\n return (\n <div className=\"mb-3\" key={JSON.stringify(a)} style={{ minHeight: \"10em\" }}>\n <Widget\n src=\"efiz.near/widget/every.type.metadata\"\n props={{\n accountId: a.accountId,\n widgetName: a.typeName,\n blockHeight: a.blockHeight,\n }}\n />\n </div>\n );\n};\nif (JSON.stringify(data) !== JSON.stringify(state.data || {})) {\n State.update({\n data,\n allItems: processData(data),\n });\n}\nreturn (\n <div className=\"px-2 mx-auto\">\n {(accountId || tag) && (\n <div className=\"mb-2\">\n Filter:\n {accountId && (\n <a className=\"btn btn-outline-primary\">\n <Widget\n src=\"mob.near/widget/ProfileLine\"\n props={{ accountId, link: false }}\n />\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n {tag && (\n <a className=\"btn btn-outline-primary\">\n <span className=\"badge text-bg-secondary\">#{tag}</span>\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n </div>\n )}\n <Widget\n src=\"efiz.near/widget/ItemFeed\"\n props={{ items: state.allItems || [], renderItem }}\n />\n </div>\n);\n" }, "create.edit.source": { "": "const sourcePattern = props.sourcePattern ?? \"*/profile/source/*\";\nconst placeholder = props.placeholder ?? \"Source\";\nconst initialSourceObject = props.initialSourceObject || {};\nconst sourceObject = Social.keys(sourcePattern, \"final\");\nif (sourceObject === null) {\n return \"Loading\";\n}\nconst normalizeProf = (prof) =>\n prof\n .replaceAll(/[- \\.]/g, \"_\")\n .replaceAll(/[^\\w]+/g, \"\")\n .replaceAll(/_+/g, \"-\")\n .replace(/^-+/, \"\")\n .replace(/-+$/, \"\")\n .toLowerCase()\n .trim(\"-\");\nconst sourceCount = {};\nconst processSourceObject = (obj) => {\n Object.entries(obj).forEach((kv) => {\n if (typeof kv[1] === \"object\") {\n processSourceObject(kv[1]);\n } else {\n const prof = normalizeProf(kv[0]);\n sourceCount[prof] = (sourceCount[prof] || 0) + 1;\n }\n });\n};\nconst getSource = () => {\n processSourceObject(sourceObject);\n const source = Object.entries(sourceCount);\n source.sort((a, b) => b[1] - a[1]);\n return source.map((t) => ({\n name: t[0],\n count: t[1],\n }));\n};\nif (!state.allSource) {\n initState({\n allSource: getSource(),\n source: Object.keys(initialSourceObject).map((prof) => ({\n name: normalizeProf(prof),\n })),\n originalSource: Object.fromEntries(\n Object.keys(initialSourceObject).map((prof) => [prof, null])\n ),\n id: `source-selector-${Date.now()}`,\n });\n}\nconst setSource = (source) => {\n source = source.map((o) => {\n o.name = normalizeProf(o.name);\n return o;\n });\n State.update({ source });\n if (props.setSourceObject) {\n props.setSourceObject(\n Object.assign(\n {},\n state.originalSource,\n Object.fromEntries(source.map((prof) => [prof.name, \"\"]))\n )\n );\n }\n};\nreturn (\n <>\n <Typeahead\n id={state.id}\n labelKey=\"name\"\n onChange={setSource}\n options={state.allSource}\n placeholder={placeholder}\n selected={state.source}\n positionFixed\n allowNew\n />\n {props.debug && (\n <div>\n Debugging source:\n <pre>{JSON.stringify(state.source)}</pre>\n </div>\n )}\n </>\n);\n" }, "explore.view.history": { "": "/*\n---props---\nprops.post: {};\nprops.id: number;\nprops.newTab: boolean;\nprops.timestamp: number;\nprops.referral: any;\n*/\nconst postId = props.post.id ?? (props.id ? parseInt(props.id) : 0);\nconst post =\n props.post ??\n Near.view(\"devgovgigs.near\", \"get_post\", {\n post_id: postId,\n });\nif (!post || post.snapshot_history.length === 0) {\n return <div class=\"bi bi-clock-history px-2\"></div>;\n}\nconst referral = props.referral;\nfunction readableDate(timestamp) {\n var a = new Date(timestamp);\n return (\n a.toDateString() +\n \" \" +\n a.toLocaleTimeString([], { hour: \"2-digit\", minute: \"2-digit\" })\n ).substring(4);\n}\nfunction historyHref(widgetName, linkProps) {\n linkProps = { ...linkProps };\n const linkPropsQuery = Object.entries(linkProps)\n .map(([key, value]) => `${key}=${value}`)\n .join(\"&\");\n return `#/markeljan.near/widget/${widgetName}${\n linkPropsQuery ? \"?\" : \"\"\n }${linkPropsQuery}`;\n}\nconst currentTimestamp = props.timestamp ?? post.snapshot.timestamp;\nconst snapshot = post.snapshot;\nconst snapshotHistory = post.snapshot_history;\nsnapshotHistory.push(snapshot);\nsnapshotHistory.reverse();\nconst history = (\n <div class=\"btn-group\" role=\"group\">\n <a\n class=\"card-link\"\n role=\"button\"\n title=\"Object History\"\n data-bs-toggle=\"dropdown\"\n aria-expanded=\"false\"\n type=\"button\"\n >\n <div class=\"bi bi-clock-history px-2\"></div>\n </a>\n <ul class=\"dropdown-menu\">\n <a\n class=\"d-flex text-muted\"\n style={{ fontSize: \"12px\", textDecoration: \"none\", cursor: \"default\" }}\n >\n <a\n style={{\n textAlign: \"center\",\n minWidth: \"290px\",\n maxWidth: \"290px\",\n }}\n >\n Edit History\n </a>\n <a style={{ marginRight: \"8px\" }}>Compare</a>\n </a>\n {snapshotHistory.map((item) => {\n if (item === undefined) return;\n return (\n <li style={{ display: \"flex\" }}>\n <div\n style={{\n minWidth: \"290px\",\n maxWidth: \"290px\",\n }}\n >\n <a\n class=\"dropdown-item\"\n href={historyHref(\"PostWithHistory\", {\n id: postId,\n timestamp: item.timestamp,\n compareTimestamp: null,\n referral,\n })}\n target={props.newTab ? \"_blank\" : undefined}\n >\n {readableDate(item.timestamp / 1000000)}\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: item.editor_id,\n style: {\n width: \"1.25em\",\n height: \"1.25em\",\n },\n imageStyle: {\n transform: \"translateY(-12.5%)\",\n },\n }}\n />\n {post.author_id.substring(0, 8)}\n </a>\n </div>\n <a\n class=\"dropdown-item\"\n href={historyHref(\"PostWithHistory\", {\n id: postId,\n timestamp: currentTimestamp,\n compareTimestamp: item.timestamp,\n referral,\n })}\n >\n <i class=\"bi bi-file-earmark-diff\" />\n </a>\n </li>\n );\n })}\n </ul>\n <Widget\n src=\"efiz.near/widget/Every.Thing.History\"\n props={{\n path: \"hyperfiles.near/widget/index-dev\",\n count: (count) => console.log(\"Number of changes:\", count),\n }}\n />\n </div>\n);\nreturn history;\n" }, "adapter.ipfs": { "": "const ipfsUrl = (cid) => `https://ipfs.near.social/ipfs/${cid}`;\nfunction get(ref) {\n const data = fetch(`https://ipfs.near.social/ipfs/${ref.cid}`);\n return data.body;\n}\nfunction create(data) {\n return new Promise((resolve, reject) => {\n if (data.length) {\n const body = new Blob([data], { type: \"application/json\" });\n console.log(body);\n asyncFetch(\"https://ipfs.near.social/add\", {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n },\n body,\n })\n .then((res) => {\n resolve({ cid: res.body.cid }); // Resolve the promise with the necessary data\n })\n .catch((error) => {\n console.error(\"Error in create function:\", error);\n reject(error); // Reject the promise in case of an error\n });\n } else {\n reject(\"No data provided\"); // Reject the promise if no data is provided\n }\n });\n}\nreturn { get, create };\n" }, "explore.view.graph": { "": "const accountId = props.accountId ?? context.accountId;\nif (!accountId) {\n return \"Please connect your NEAR wallet :)\";\n}\nState.init({\n accounts: [\"every.near\", context.accountId],\n newAccount: \"\",\n thing: thingId,\n});\nfunction addAccount(newAccount) {\n state.accounts.push(newAccount);\n State.update({\n accounts: state.accounts,\n });\n}\nfunction removeAccount(accountKey) {\n const updatedAccounts = state.accounts.filter(\n (account) => account !== accountKey\n );\n State.update({\n accounts: updatedAccounts,\n });\n}\nreturn (\n <div>\n <div className=\"mb-2\">\n <h5>Graph ID</h5>\n <p>\n <i>\n Default graph is \"follow\". Use \"*/graph/*\" in the Explore Data section\n below to find more. Other options include: follow, like, star, etc.\n </i>\n </p>\n <input type=\"text\" value={state.thing} placeholder={defaultThing} />\n </div>\n <div>\n <h5>Account IDs</h5>\n <input\n placeholder=\"<example>.near\"\n onChange={(e) => State.update({ newAccount: e.target.value })}\n />\n <div className=\"d-flex align-items-center mt-2\">\n <button\n className=\"btn btn-primary m-2\"\n onClick={() => addAccount(state.newAccount)}\n >\n add\n </button>\n </div>\n </div>\n <div>\n {state.accounts.map((a) => {\n return (\n <div className=\"d-flex m-2 p-2 justify-content-between align-items-center\">\n <div className=\"d-flex align-items-center\">\n <Widget src=\"mob.near/widget/Profile\" props={{ accountId: a }} />\n </div>\n <button\n className=\"btn btn-danger m-1\"\n onClick={() => removeAccount(a)}\n >\n remove\n </button>\n </div>\n );\n })}\n </div>\n <hr />\n {state.accounts.length > 1 ? (\n <div className=\"mb-2\">\n <Widget\n src=\"hyperbuild.near/widget/explore.socialgraph\"\n props={{\n accountIds: state.accounts,\n thingId: state.thing,\n }}\n />\n </div>\n ) : (\n <div className=\"mb-2\">\n <h5>input 2+ accounts</h5>\n </div>\n )}\n </div>\n);\n" }, "profile.social": { "": "const darkColors = {\n page_bg: \"rgb(25,33,50)\",\n horizen_bg: \"#fff\",\n header_bg: \"rgb(49,62,89)\",\n sideBar: {\n sideBar_bg: \"rgb(49,62,89)\",\n sideBar_color: \"#fff\",\n },\n footer: {\n titlenelowBackground: \"#806ce1\",\n titleBackground: \"#fff\",\n fromBackground: \"rgb(55,72,107)\",\n toBackground: \"rgb(55,72,107)\",\n belowBackground: \"rgb(210, 202, 250)\",\n },\n dynamic_header: {\n afterbrandcolor: \"\",\n color1brand: \"#fff\",\n color2brand: \"rgb(210, 202, 250)\",\n colordescription: \"rgb(210, 202, 250)\",\n background:\n \"radial-gradient(circle, rgb(49,62,89) 0%, rgba(230,230,231,0.01) 0%, rgb(49,62,89) 100%, rgb(49,62,89) 100%, rgb(49,62,89) 100%, rgba(46,52,90,1) 100%);\",\n },\n search_sbt: {\n section_bg: \"transparent\",\n card_bg: \"transparent)\",\n search_btn_bg: \"rgb(49,62,89)\",\n search_btn_bg_hover: \"rgba(49,62,89,0.8)\",\n search_btn_text: \"rgb(255,255,255)\",\n input_bg: \"rgb(49,62,89)\",\n input_bg_hover: \"rgba(49,62,89,0.8)\",\n input_text_color: \"rgb(255,255,255)\",\n input_border: \"rgba(49,62,89,0.8)\",\n table_bg: \"transparent\",\n table_color: \"rgb(255,255,255)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(255,255,255)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(255,255,255)\",\n table_hover_bg: \"\",\n },\n profileInlineBlock: {\n name: \"#fff\",\n accountId: \"#fff\",\n tag: \"#fff\",\n description: \"#fff\",\n },\n table_pagination: {\n table_bg: \"rgb(49,62,89)\",\n table_color: \"rgb(255,255,255)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(255,255,255)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(255,255,255)\",\n table_hover_bg: \"\",\n btn_border: \"rgb(25,33,50)\",\n btn_bg: \"rgb(49,62,89)\",\n btn_bg_active: \"rgb(25,33,50)\",\n btn_color: \"#fff\",\n input_bg: \"#2f3b54\",\n },\n card: {\n card_bg: \"rgb(49,62,89)\",\n tabSelect_bg: \"#192132\",\n tabSelect_text_color: \"#fff\",\n tabSelect_input_bg: \"rgb(49,62,89)\",\n tabSelect_btn_active_bg: \"rgb(49,62,89)\",\n text_color: \"rgba(255,255,255,1)\",\n },\n chart: {\n title: \"rgb(255,255,255)\",\n subtitle: \"rgba(255,255,255,0.7)\",\n xAxis: \"rgb(255,255,255)\",\n yAxis: \"rgb(255,255,255)\",\n legend: \"rgba(255,255,255,0.7)\",\n legendHover: \"rgb(255,255,255)\",\n rangeSelector: {\n labels: \"rgba(255,255,255,0.7)\",\n inputColor: \"rgb(255,255,255)\",\n btn_bg: \"rgba(25,33,50,0.3)\",\n btn_color: \"rgba(255,255,255,0.7)\",\n btn_hover_bg: \"rgba(25,33,50,0.5)\",\n btn_hover_color: \"rgba(255,255,255,0.8)\",\n btn_active_bg: \"rgba(25,33,50,0.8)\",\n btn_active_color: \"rgb(255,255,255)\",\n },\n },\n tree: {\n subject: {\n color: \"#fff\",\n fontweight: 400,\n fontSize: \"2em\",\n },\n nodes: {\n color: \"#fff\",\n // borderColor: \"#fff\",\n backgroundColor: \"rgb(49,62,89)\",\n },\n overrideNodeStyles: {\n // backgroundColor: \"red\",\n },\n },\n spinnerColors: [\"#6F61C0\", \"#241468\"],\n chartColor: [\n \"#F79BD3\",\n \"#A084E8\",\n \"#EA1179\",\n \"#F79BD3\",\n \"#A084E8\",\n \"#6F61C0\",\n \"#241468\",\n \"#9F0D7F\",\n ],\n};\nconst lightColors = {\n page_bg: \"#fff\",\n horizen_bg: \"#391b86\",\n header_bg: \"rgb(210, 202, 250)\",\n sideBar: {\n sideBar_bg: \"rgb(210, 202, 250)\",\n sideBar_color: \"#fff\",\n },\n footer: {\n titlenelowBackground: \"#806ce1\",\n titleBackground: \"#fff\",\n fromBackground: \"rgb(210, 202, 250)\",\n toBackground: \"rgb(210, 202, 250)\",\n belowBackground: \"#806ce1\",\n },\n dynamic_header: {\n afterbrandcolor: \"#789efb\",\n color1brand: \"#000\",\n color2brand: \"#806ce1\",\n colordescription: \"#806ce1\",\n background:\n \"radial-gradient(circle, rgba(210,202,250,1) 0%, rgba(210,202,250,0.01) 0%, rgba(235,231,253,1) 100%, rgba(255,241,241,1) 100%, rgba(46,52,90,1) 100%);\",\n },\n search_sbt: {\n section_bg: \"rgb(235, 231, 253)\",\n card_bg: \"\",\n search_btn_bg: \"rgb(210, 202, 250)\",\n search_btn_bg_hover: \"rgba(210, 202, 250,0.8)\",\n search_btn_text: \"rgb(0,0,0)\",\n input_bg: \"rgba(210, 202, 250,0.2)\",\n input_bg_hover: \"rgba(210, 202, 250,0.4)\",\n input_text_color: \"rgb(0,0,0)\",\n input_border: \"rgba(210, 202, 250,0.4)\",\n table_bg: \"transparent\",\n table_color: \"rgb(0,0,0)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(0,0,0)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(0,0,0)\",\n table_hover_bg: \"\",\n },\n profileInlineBlock: {\n name: \"#000\",\n accountId: \"#000\",\n tag: \"#000\",\n description: \"#000\",\n },\n table_pagination: {\n table_bg: \"rgb(255,255,255)\",\n table_color: \"rgb(0,0,0)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(0,0,0)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(0,0,0)\",\n table_hover_bg: \"\",\n btn_border: \"#000\",\n btn_border: \"#806ce1\",\n btn_bg: \"#fff\",\n btn_bg_active: \"rgb(235, 231, 253)\",\n btn_color: \"#000\",\n },\n card: {\n card_bg: \"rgb(255, 255, 255)\",\n tabSelect_bg: \"#e6e6e7\",\n tabSelect_text_color: \"#000\",\n tabSelect_input_bg: \"rgb(210, 202, 250)\",\n tabSelect_btn_active_bg: \"rgb(210, 202, 250)\",\n text_color: \"rgba(0,0,0,1)\",\n },\n chart: {\n title: \"rgba(0,0,0,1)\",\n subtitle: \"rgba(0,0,0,0.7)\",\n xAxis: \"rgba(0,0,0,1)\",\n yAxis: \"rgba(0,0,0,1)\",\n legend: \"rgba(0,0,0,0.7)\",\n legendHover: \"rgba(0,0,0,1)\",\n rangeSelector: {\n labels: \"rgba(0,0,0,0.7)\",\n inputColor: \"rgba(0,0,0,0.5)\",\n btn_bg: \"rgba(0,0,0,0.3)\",\n btn_color: \"rgba(0,0,0,0.8)\",\n btn_hover_bg: \"rgba(0,0,0,0.4)\",\n btn_hover_color: \"rgba(0,0,0,1)\",\n btn_active_bg: \"rgb(235, 231, 253)\",\n btn_active_color: \"rgba(0,0,0,1)\",\n },\n },\n tree: {\n subject: {\n color: \"#000\",\n fontweight: 400,\n fontSize: \"2em\",\n },\n nodes: {\n color: \"#000\",\n // borderColor: \"#000\",\n backgroundColor: \"#fff\",\n },\n overrideNodeStyles: {\n // backgroundColor: \"red\",\n },\n },\n spinnerColors: [\"#6F61C0\", \"#241468\"],\n chartColor: [\n \"#F79BD3\",\n \"#A084E8\",\n \"#EA1179\",\n \"#F79BD3\",\n \"#A084E8\",\n \"#6F61C0\",\n \"#241468\",\n \"#9F0D7F\",\n ],\n};\nconst themeColor = props.themeColor || lightColors;\n// const themeColor = props.themeColor || lightColors;\n// #####################################\nState.init({\n singer: context.accountId || \"hyperfiles.near\",\n result: [],\n data: context.accountId || \"hyperfiles.near\",\n isLoading: false,\n error: [],\n});\nconst inputHandler = ({ target }) => {\n const singer = target.value.toLowerCase().trim();\n State.update({ singer: singer });\n};\nconst handleData = () => {\n if (!state.singer.length) {\n State.update({ error: [...state.error, \"please insert an address\"] });\n return;\n }\n if (state.data === state.singer) {\n State.update({ error: [...state.error, \"please insert a new address\"] });\n return;\n }\n State.update({ data: state.singer });\n};\nif (state.error.length > 0) {\n function hide() {\n const errors = state.error;\n errors.shift();\n if (errors.length > 0) setTimeout(hide, 2500);\n State.update({ error: errors });\n }\n setTimeout(hide, 2500);\n}\nconst Input = styled.input`\n color: ${themeColor?.search_sbt?.input_text_color};\n background-color: ${themeColor?.search_sbt?.input_bg};\n border: 1px solid ${themeColor?.search_sbt?.input_border};\n &:focus {\n background-color: ${themeColor?.search_sbt?.input_bg};\n color: ${themeColor?.search_sbt?.input_text_color};\n border: 1px solid ${themeColor?.search_sbt?.input_border};\n }\n &:hover {\n background-color: ${themeColor?.search_sbt?.input_bg_hover};\n }\n`;\nconst Button = styled.button`\n color: ${themeColor?.search_sbt?.search_btn_text};\n font-size: 16px;\n padding: 0.5rem 1rem;\n font-weight: 400;\n background-color: ${themeColor?.search_sbt?.search_btn_bg};\n &:hover {\n background-color: ${themeColor?.search_sbt?.search_btn_bg_hover};\n }\n border: 1px solid ${themeColor?.search_sbt?.search_btn_bg};\n box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02);\n min-height: calc(1.5em + 1rem + 2px);\n border-radius: 40px;\n line-height: 29px;\n letter-spacing: 0.01em;\n`;\n// -------------------------------------------------------------------\nconst singer = state.data;\nconst status = Social.index(\"notify\", singer, { order: \"desc\" }) || [];\nconst receivedPoke = status.filter(\n (notification) => notification?.value?.type === \"poke\"\n);\nconst numReceivedPoke = receivedPoke?.length || 0;\nconst receivedLike = status.filter(\n (notification) => notification?.value?.type === \"like\"\n);\nconst numReceivedLike = receivedLike?.length || 0;\nconst receivedComment = status.filter(\n (notification) => notification?.value?.type === \"comment\"\n);\nconst numReceivedComment = receivedComment?.length || 0;\nconst receivedRepost = status.filter(\n (notification) => notification?.value?.type === \"repost\"\n);\nconst numReceivedRepost = receivedRepost?.length || 0;\nconst nummention =\n status.filter((notification) =>\n notification?.value?.type.includes?.(\"mention\")\n ).length || 0;\n//---------------------------------------------------part1------------------------------------------------------\nconst following = Social.keys(`${singer}/graph/follow/*`, \"final\", {\n return_type: \"BlockHeight\",\n values_only: true,\n});\nconst numFollowing = following\n ? Object.keys(following[singer]?.graph?.follow || {}).length\n : 0;\n//---------------------------\nconst followers = Social.keys(`*/graph/follow/${singer}`, \"final\", {\n return_type: \"BlockHeight\",\n values_only: true,\n});\nconst numFollowers = followers ? Object.keys(followers || {}).length : 0;\n//--------------------------\nconst likes = Social.keys(`${singer}/index/like`, \"final\", {\n return_type: \"History\",\n});\nconst numlikes = likes\n ? Object.keys(likes[singer]?.index?.like || {}).length\n : 0;\n//--------------------------\nconst posts = Social.keys(`${singer}/index/post`, \"final\", {\n return_type: \"History\",\n});\nconst numposts = posts\n ? Object.keys(posts[singer]?.index?.post || {}).length\n : 0;\n//--------------------------\nconst comments = Social.keys(`${singer}/post/comment`, \"final\", {\n return_type: \"History\",\n});\nconst numcomments = comments\n ? Object.keys(comments[singer]?.post?.comment || {}).length\n : 0;\n//--------------------------\nconst tx_widgets = Social.keys(`${singer}/widget`, \"final\", {\n return_type: \"History\",\n});\nconst tx_numwidgets = tx_widgets\n ? Object.keys(tx_widgets[singer]?.widget || {}).length\n : 0;\n//--------------------------\nconst reposts = Social.keys(`${singer}/index/repost`, \"final\", {\n return_type: \"History\",\n});\nconst numreposts = reposts\n ? Object.keys(reposts[singer]?.index?.repost || {}).length\n : 0;\n//--------------------------\n// const pokes = Social.keys(`${singer}/*`, \"final\", {\n// return_type: \"History\",\n// });\n// const numPokes = pokes\n// ? Object.keys(pokes[singer].index.graph || {}).length\n// : 0;\nconst numPokes = \"N/A\";\n//--------------------------\nconst allTx = Social.keys(`${singer}/*`, \"final\", {\n return_type: \"History\",\n}) || { [singer]: [] };\nconst joinDateTimeBlock =\n Object.values(allTx[singer] || {})\n .flat()\n .sort((a, b) => a - b)[0] || \"-\";\nlet joinDate = fetch(\n \"https://api.near.social/time?blockHeight=\" + joinDateTimeBlock\n).body;\njoinDate = Number.isInteger(joinDate)\n ? `${new Date(joinDate).getFullYear()}/${\n new Date(joinDate).getMonth() + 1\n }/${new Date(joinDate).getDate()}`\n : \"-\";\n//--------------------------\nconst hashtag = Social.keys(`${singer}/index/hashtag`, \"final\", {\n return_type: \"History\",\n});\nconst numHashtags = hashtag\n ? Object.keys(hashtag[singer]?.index?.hashtag || {}).length\n : 0;\n//--------------------------\nconst widgets = Social.keys(`${singer ?? \"*\"}/widget/*`, \"final\", {\n return_type: \"History\",\n});\n// console.log(\"widgets\", widgets);\nconst numWidgets = widgets[singer]?.widget\n ? Object.keys(widgets[singer]?.widget || {}).length\n : 0;\n//--------------------------\nconst forkof = Social.keys(`${singer}/widget/*/metadata/fork_of`, \"final\", {\n return_type: \"History\",\n});\nconst numForkof = forkof ? Object.keys(forkof[singer]?.widget || {}).length : 0;\n//--------------------------\nconst un_star = Social.keys(`${singer}/index/star`, \"final\", {\n return_type: \"History\",\n});\nconst numUn_star = un_star\n ? Object.keys(un_star[singer]?.index?.star || {}).length\n : 0;\n//--------------------------\n// const totalTx = Social.keys(`${singer}/*`, \"final\", {\n// return_type: \"History\",\n// });\n// const numTotalTx = totalTx\n// ? new Set(Object.values(totalTx[singer] || {}).flat()).size\n// : 0;\nconst totalTx = fetch(\n `https://api.nearblocks.io/v1/account/${singer}/txns/count?to=social.near`\n).body;\nconst numTotalTx = totalTx ? totalTx.txns[0]?.count ?? \"-\" : \"-\";\n//--------------------------\n//-----------------------------------------------part1----------------------------------------------------\n//-----------------------------------------------part2----------------------------------------------------\nconst generaltheme = {\n height: \"90px\",\n align: \"center\",\n description: \"\",\n brand: \"BOS Activity\",\n fontsize: \"35px\",\n fontweight: \"25px\",\n afterbrand: \"Profile\",\n afterbrandcolor: themeColor?.dynamic_header?.afterbrandcolor || \"#789efb\",\n fontbrand: \" Arial, sans-serif\",\n color1brand: themeColor?.dynamic_header?.color1brand || \"#000\",\n color2brand: themeColor?.dynamic_header?.color2brand || \"#806ce1\",\n colordescription: themeColor?.dynamic_header?.colordescription || \"#806ce1\",\n fontsubtitle: \" Arial, sans-serif\",\n background:\n themeColor?.dynamic_header?.background ||\n \"radial-gradient(circle, rgba(210,202,250,1) 0%, rgba(230,230,231,0.01) 0%, rgba(235,238,255,1) 100%, rgba(235,231,253,1) 100%, rgba(255,241,241,1) 100%, rgba(46,52,90,1) 100%);\",\n};\nconst baseHeaderDynamic = {\n height: \"80px\",\n align: \"center\",\n description: ``,\n brand: ``,\n fontsize: \"15px\",\n fontweight: \"10px\",\n afterbrand: \"\",\n afterbrandcolor: themeColor?.dynamic_header?.afterbrandcolor || \"#789efb\",\n fontbrand: \" Arial, sans-serif\",\n color1brand: themeColor?.dynamic_header?.color1brand || \"#000\",\n color2brand: themeColor?.dynamic_header?.color2brand || \"#806ce1\",\n colordescription: themeColor?.dynamic_header?.colordescription || \"#806ce1\",\n fontsubtitle: \" Arial, sans-serif\",\n background:\n themeColor?.dynamic_header?.background ||\n \"radial-gradient(circle, rgba(210,202,250,1) 0%, rgba(230,230,231,0.01) 0%, rgba(235,238,255,1) 100%, rgba(235,231,253,1) 100%, rgba(255,241,241,1) 100%, rgba(46,52,90,1) 100%);\",\n};\nconst cardObjects = [\n {\n name: \"followers\",\n description: `${numFollowers}`,\n brand: \"Followers\",\n afterbrand: \"\",\n },\n {\n name: \"followings\",\n description: `${numFollowing}`,\n brand: \"Followings\",\n afterbrand: \"\",\n },\n { name: \"posts\", description: `${numposts}`, brand: \"Posts\", afterbrand: \"\" },\n {\n name: \"reposts\",\n description: `${numreposts}`,\n brand: \"Reposts\",\n afterbrand: \"\",\n },\n {\n name: \"comments\",\n description: `${numcomments}`,\n brand: \"Comments\",\n afterbrand: \"\",\n },\n { name: \"likes\", description: `${numlikes}`, brand: \"Likes\", afterbrand: \"\" },\n {\n name: \"pokes\",\n description: `${numPokes}`,\n brand: \"Pokes\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"tx_widgets\",\n description: `${tx_numwidgets}`,\n brand: \"Widgets (trx)\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"received_pokes\",\n description: `${numReceivedPoke}`,\n brand: \"Received\",\n afterbrand: \"Pokes\",\n },\n {\n name: \"received_likes\",\n description: `${numReceivedLike}`,\n brand: \"Received\",\n afterbrand: \"Likes\",\n },\n {\n name: \"received_comments\",\n description: `${numReceivedComment}`,\n brand: \"Received\",\n afterbrand: \"Comments\",\n },\n {\n name: \"received_reposts\",\n description: `${numReceivedRepost}`,\n brand: \"Received\",\n afterbrand: \"Reposts\",\n },\n {\n name: \"mentions\",\n description: `${nummention}`,\n brand: \"Mentions\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"widgets\",\n description: `${numWidgets}`,\n brand: \"Widgets\",\n afterbrand: \"\",\n },\n {\n name: \"joinDate\",\n description: `${joinDate}`,\n brand: \"Join Date\",\n afterbrand: \"\",\n offChart: true,\n offGrid: true,\n },\n {\n name: \"hashtags\",\n description: `${numHashtags}`,\n brand: \"Hashtags\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"forkof\",\n description: `${numForkof}`,\n brand: \"Forks\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"star-unstar\",\n description: `${numUn_star}`,\n brand: \"Un/star\",\n afterbrand: \"\",\n },\n {\n name: \"total-tx\",\n description: `${numTotalTx}`,\n brand: \"Total trx\",\n afterbrand: \"\",\n offChart: true,\n offGrid: true,\n },\n];\n//---------------------------------------------------------------------------------------------------\nconst SearchInput = (\n <div\n style={{ background: themeColor?.sbt_area?.section_bg }}\n className=\"search p-4\"\n >\n <div className=\"row\">\n <div className=\"col-8 \">\n <Input\n onBlur={inputHandler}\n defaultValue={state.singer}\n type=\"input\"\n className=\"form-control form-control-lg rounded-4\"\n id=\"address\"\n placeholder=\"jlw.near\"\n />\n </div>\n <div className=\"col-4 col-lg-auto\">\n <Button\n disabled={state.isLoading}\n onClick={handleData}\n className=\"btn-lg\"\n type=\"button\"\n >\n {state.isLoading ? (\n <div className=\"text-center px-4\">\n <div className=\"spinner-border spinner-border-sm\" role=\"status\">\n <span className=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n ) : (\n \"search\"\n )}\n </Button>\n </div>\n </div>\n </div>\n);\nconst TableSection = (\n <div\n style={{ background: themeColor?.sbt_area?.section_bg }}\n className=\"shadow-sm rounded-2 overflow-auto p-2\"\n >\n <div\n className=\"container\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div className=\"row\">\n <div className=\"col-md-12\">\n <div className=\"row\">\n <div className=\"col-md-6\">\n <Widget\n src=\"lord1.near/widget/nearwidgetProfile\"\n props={{\n accountId: singer,\n themeColor: {\n profile_large: themeColor.profile_large,\n profileInlineBlock: { ...themeColor.profileInlineBlock },\n },\n }}\n />\n </div>\n <div className=\"col-md-4\">\n <Widget\n src=\"lord1.near/widget/header-dynamic\"\n props={{\n ...baseHeaderDynamic,\n ...cardObjects.find((o) => o.name === \"joinDate\"),\n }}\n />\n </div>\n <div className=\"col-md-2\">\n <Widget\n src=\"lord1.near/widget/header-dynamic\"\n props={{\n ...baseHeaderDynamic,\n ...cardObjects.find((o) => o.name === \"total-tx\"),\n }}\n />\n </div>\n </div>\n </div>\n </div>\n <div className=\"row\">\n <div className=\"col-md-12\">\n <div className=\"row\">\n {cardObjects\n .filter((o) => !o.offGrid)\n .map((card) => (\n <div key={card.name} className=\"col-md-2\">\n <Widget\n src=\"lord1.near/widget/header-dynamic\"\n props={{ ...baseHeaderDynamic, ...card }}\n />\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n);\n// --------------------- pie chart ------------------------\nconst getPieProps = (data, [key, value], colors, chartOption) => {\n data = data || [];\n colors = colors || [];\n chartOption = chartOption || {};\n const dataFormat = data.map((s) => [s[key], s[value]]);\n const props = {\n data: dataFormat,\n colors: colors,\n chartOption: {\n title: \"chart title\",\n type: \"pie\",\n legend: false,\n connector: false,\n ...chartOption,\n },\n themeColor: { chart: themeColor.chart },\n spinnerColors: themeColor.spinnerColors,\n };\n return props;\n};\nconst pieChartData = () => {\n return cardObjects\n .filter((o) => !o.offChart)\n .map((o) => {\n return {\n title: `${o.brand} ${o.afterbrand}`,\n value: Number.parseInt(o.description),\n };\n });\n};\nconst PieChart = (\n <div\n className=\"col-lg-8\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4 \"\n >\n <Widget\n src=\"lord1.near/widget/Pie-chart\"\n props={getPieProps(\n pieChartData(),\n [\"title\", \"value\"],\n themeColor.chartColor,\n {\n title: \"Social Actions\",\n subtitle: \"Social Actions\",\n type: \"pie\",\n connector: true,\n legend: true,\n }\n )}\n />\n </div>\n </div>\n);\n// -------------------- mix chart -------------------\nlet blockHeightData = fetch(\n `https://api.flipsidecrypto.com/api/v2/queries/6b01d203-0d80-4e70-84ee-c6aa37578ce8/data/latest`\n);\nblockHeightData = blockHeightData.body || [];\nconst getMixData = (accountId) => {\n const myData = {};\n const initDataValue = {\n follower: 0,\n follow: 0,\n like: 0,\n post: 0,\n comment: 0,\n repost: 0,\n un_star: 0,\n receivedComment: 0,\n receivedLike: 0,\n receivedPoke: 0,\n receivedRepost: 0,\n widgets: 0,\n };\n followers &&\n Object.values(followers).forEach((i) => {\n const count = myData[i.graph.follow[accountId]];\n myData[i.graph.follow[accountId]] = {\n ...initDataValue,\n ...count,\n follower: (count.follower ?? 0) + 1,\n };\n });\n following &&\n Object.values(following[accountId]?.graph?.follow || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n follow: (count.follow ?? 0) + 1,\n };\n });\n likes &&\n Object.values(likes[accountId]?.index?.like || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n like: (count.like ?? 0) + 1,\n };\n });\n posts &&\n Object.values(posts[accountId]?.index?.post || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n post: (count.post ?? 0) + 1,\n };\n });\n comments &&\n Object.values(comments[accountId]?.post?.comment || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n comment: (count.comment ?? 0) + 1,\n };\n });\n reposts &&\n Object.values(reposts[accountId]?.index?.repost || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n repost: (count.repost ?? 0) + 1,\n };\n });\n un_star &&\n Object.values(un_star[accountId]?.index?.star || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n un_star: (count.un_star ?? 0) + 1,\n };\n });\n receivedComment.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedComment: (count.receivedComment ?? 0) + 1,\n };\n });\n receivedLike.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedLike: (count.receivedLike ?? 0) + 1,\n };\n });\n receivedPoke.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedPoke: (count.receivedPoke ?? 0) + 1,\n };\n });\n receivedRepost.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedRepost: (count.receivedRepost ?? 0) + 1,\n };\n });\n widgets &&\n Object.values(widgets[accountId]?.widget || {}).forEach(([i]) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n widgets: (count.widgets ?? 0) + 1,\n };\n });\n return myData;\n};\nconst splitTime = () => {\n let timeIndex = 0;\n const splitedData = {};\n Object.entries(getMixData(singer)).forEach(([blockTime, counts]) => {\n for (; timeIndex <= blockHeightData.length; ++timeIndex) {\n if (\n timeIndex === 0 &&\n Number(blockTime) < blockHeightData[timeIndex].min_block\n ) {\n break;\n }\n if (\n (Number(blockTime) >= blockHeightData[timeIndex].min_block &&\n Number(blockTime) <= blockHeightData[timeIndex].max_block) ||\n (timeIndex === blockHeightData.length - 1 &&\n Number(blockTime) > blockHeightData[timeIndex].max_block)\n ) {\n const prevCount = splitedData[blockHeightData[timeIndex].date] ?? {\n follower: 0,\n follow: 0,\n like: 0,\n post: 0,\n comment: 0,\n repost: 0,\n un_star: 0,\n receivedComment: 0,\n receivedLike: 0,\n receivedPoke: 0,\n receivedRepost: 0,\n widgets: 0,\n };\n const newCount = {\n follower: prevCount.follower + counts.follower,\n follow: prevCount.follow + counts.follow,\n like: prevCount.like + counts.like,\n post: prevCount.post + counts.post,\n comment: prevCount.comment + counts.comment,\n repost: prevCount.repost + counts.repost,\n un_star: prevCount.un_star + counts.un_star,\n receivedComment: prevCount.receivedComment + counts.receivedComment,\n receivedLike: prevCount.receivedLike + counts.receivedLike,\n receivedPoke: prevCount.receivedPoke + counts.receivedPoke,\n receivedRepost: prevCount.receivedRepost + counts.receivedRepost,\n widgets: prevCount.widgets + counts.widgets,\n };\n splitedData[blockHeightData[timeIndex].date] = newCount;\n break;\n } else {\n continue;\n }\n }\n });\n return Object.entries(splitedData).map(([date, values]) => {\n return { date: new Date(date).getTime(), ...values };\n });\n};\nconst getMixProps = (data, dateKey, serieses, colors, chartOption) => {\n data = data || [];\n serieses = serieses || [{ key: \"\", seriesName: \"\", type: \"\", id: 1 }];\n colors = colors || [];\n chartOption = chartOption || {};\n const dataFormat = serieses.map((series) => {\n const dataFormated = data.map((d) => [d[dateKey], d[series.key] || null]);\n return {\n data: dataFormated,\n name: series.seriesName,\n type: series.type,\n axisId: series.id,\n };\n });\n const props = {\n series: dataFormat,\n colors: colors,\n chartOption: {\n title: \"chart title\",\n subtitle: \"chart subtitle\",\n legend: true,\n stacking: \"false\",\n ...chartOption,\n },\n overrideOptions: {\n plotOptions: {\n column: {\n stacking: \"false\",\n },\n series: {\n dataGrouping: { enabled: false },\n },\n },\n },\n themeColor: { chart: themeColor.chart },\n spinnerColors: themeColor.spinnerColors,\n };\n return props;\n};\nconst MixChart = (\n <div className=\"col-lg-12\">\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n src=\"lord1.near/widget/mix-chart\"\n props={getMixProps(\n splitTime(),\n \"date\",\n [\n {\n key: \"follow\",\n seriesName: \"Follow\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"follower\",\n seriesName: \"Follower\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"like\",\n seriesName: \"Like\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"post\",\n seriesName: \"Post\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"comment\",\n seriesName: \"Comment\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"repost\",\n seriesName: \"Repost\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"un_star\",\n seriesName: \"Un/Star\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedRepost\",\n seriesName: \"Received Repost\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedLike\",\n seriesName: \"Received Like\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedComment\",\n seriesName: \"Received Comment\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedPoke\",\n seriesName: \"Received Poke\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"widgets\",\n seriesName: \"widgets\",\n type: \"column\",\n id: 1,\n },\n ],\n themeColor.chartColor,\n {\n title: \"\",\n subtitle: \"Daily social actions\",\n }\n )}\n />\n </div>\n </div>\n);\n// --------------- social graph -------------------\nconst SocialGraph = (\n <div\n className=\"col-lg-4\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n key={state.data}\n src=\"lord1.near/widget/SocialGraph\"\n props={{\n accountIds: [state.data, \"\"],\n spinnerColors: themeColor.spinnerColors,\n }}\n />\n </div>\n </div>\n);\n// --------------- nodes -------------------\nconst Nodes = (\n <div\n className=\"col-lg-12 pb-4\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n key={state.data}\n src=\"hyperbuild.near/widget/explore.view.tree\"\n props={{\n rootPath: state.data,\n themeColor: themeColor.tree,\n }}\n />\n </div>\n </div>\n);\n// -------------------------------------------\nreturn (\n <div style={{ backgroundColor: themeColor.page_bg }}>\n <Widget src=\"lord1.near/widget/header-dynamic\" props={generaltheme} />\n {SearchInput}\n {TableSection}\n <div style={{ width: \"100%\", height: \"30px\" }}></div>\n <div\n className=\"row rounded-3\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n {PieChart}\n {SocialGraph}\n </div>\n <div style={{ width: \"100%\", height: \"20px\" }}></div>\n <div\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n backgroundColor: themeColor.card?.card_bg,\n }}\n className=\"p-2 rounded-3\"\n >\n <div className=\"row\">{MixChart}</div>\n </div>\n <div className=\"toast-container position-fixed bottom-0 end-0 p-3\">\n {state.error.length > 0 &&\n state.error.map((er) => (\n <div\n className=\"toast show align-items-center text-bg-danger border-0\"\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n >\n <div className=\"d-flex\">\n <div className=\"toast-body\">{er}</div>\n </div>\n </div>\n ))}\n </div>\n </div>\n);\n" }, "create.edit.schema": { "": "// TO DO:\n// schema typechecking with PropTypes\n//\nconst { generateUID } = VM.require(\"flowscience.near/widget/generateUID\");\nconst path = props.path;\nconst typeSrc = props.typeSrc || \"every.near\";\nconst schemaSrc = context.accountId ?? props.schemaSrc ?? \"attestations.near\";\nconst blockHeight = props.blockHeight || \"final\";\nconst selectedSchema = props.selectedSchema;\nlet type = {\n name: \"\",\n properties: [],\n widgets: {},\n};\nconst [jsonSchema, setJsonSchema] = useState({\n schema: path,\n id: generateUID(),\n title: \"\",\n description: \"\",\n schemaType: \"object\", // Default to 'object'\n properties: [],\n required: [],\n});\nState.init({\n newType: typeSrc,\n typeName: type.name || \"\",\n properties: type.properties || [],\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newTypeSrc: \"\",\n typeSrc: typeSrc,\n schemaSrc: schemaSrc,\n expanded: false,\n selectedSchema: selectedSchema,\n schemaPath: path,\n});\nlet importedTypes = [];\nif (state.typeSrc !== \"\") {\n const defaultTypes = Social.get(`every.near/type/**`, \"final\");\n const hyperfilesTypes = Social.get(`hyperfiles.near/type/**`, \"final\");\n const types = Social.get(`${state.typeSrc}/type/**`, \"final\");\n if (!types) {\n return <></>;\n }\n importedTypes =\n Object.keys(types)?.map((it) => `${state.typeSrc}/type/${it}`) || [];\n}\nconst availableTypes = JSON.parse(props.availableTypes) || [\n \"string\",\n \"boolean\",\n \"number\",\n \"date\",\n \"time\",\n \"tags\",\n ...importedTypes,\n];\nconst create = () => {\n const output = {\n schema: {\n [jsonSchema.title]: JSON.stringify({\n ...jsonSchema,\n properties: state.properties,\n required:\n state.properties &&\n state.properties\n .filter((it) => it.isRequired)\n .map((it) => (it = it.name)),\n }),\n },\n };\n Social.set(output, { force });\n};\nconst Container = styled.div`\n margin: 20px 0;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Row = styled.div`\n display: flex;\n gap: 10px;\n`;\nconst Input = styled.input`\n flex: 1;\n max-width: 200px;\n margin-bottom: 10px;\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n height: 30px;\n`;\nconst Text = styled.p`\n display: inline-block;\n margin-right: 10px;\n`;\nconst Label = styled.label`\n display: block;\n margin-bottom: 5px;\n`;\nconst loadType = () => {\n const parts = state.newType.split(\"/\");\n type = JSON.parse(Social.get(state.newType, blockHeight) || null);\n if (type) {\n type.name = parts[2];\n State.update({\n typeName: type.name,\n properties: type.properties,\n widgets: type.widgets,\n });\n }\n};\nif (prop.typeSrc !== \"\" && state.typeName === \"\") {\n loadType();\n}\n// fix loadSchema\nconst loadSchema = () => {\n State.update({ selectedSchema: newSchema });\n const parts = state.newSchema.split(\"/\");\n schema = JSON.parse(Social.get(state.newSchema, blockHeight) || null);\n if (schema) {\n schema.name = parts[2];\n State.update({\n schemaName: schema.name,\n properties: schema.properties,\n widgets: type.widgets,\n });\n }\n};\nif (prop.schemaSrc !== \"\" && state.schemaName === \"\") {\n loadSchema();\n}\n// fix handleJsonSchemaChange\nconst handleJsonSchemaChange = (e) => {\n const { name, value } = e.target; // Destructure name and value from the event target\n setJsonSchema((prevJsonSchema) => ({\n ...prevJsonSchema,\n [name]: value, // Dynamically update the property based on input name\n }));\n};\nconst handleSchemaTitleChange = (e) => {\n const value = e.target.value;\n setJsonSchema((prev) => ({ ...prev, title: value }));\n};\nconst handleSchemaDescriptionChange = (e) => {\n const value = e.target.value;\n setJsonSchema((prev) => ({ ...prev, description: value }));\n};\nconst handleSchemaTypeChange = (e) => {\n const value = e.target.value;\n setJsonSchema((prev) => ({ ...prev, schemaType: value }));\n};\nconst handleAddProperty = () => {\n if (state.newPropertyName.trim() === \"\") return;\n const newProperty = {\n name: state.newPropertyName,\n type: state.newPropertyType,\n isRequired: state.newPropertyIsRequired,\n isMulti: state.newPropertyIsMulti,\n };\n State.update({\n properties: [...state.properties, newProperty],\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newPropertyisRequired: false,\n newPropertyIsMulti: false,\n });\n};\nconst handleRemoveProperty = (index) => {\n const updatedProperties = [...state.properties];\n updatedProperties.splice(index, 1);\n State.update({ properties: updatedProperties });\n};\nconst handlePropertyNameChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].name = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleTypeChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].type = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleMultiChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].isMulti = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleRequiredChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].isRequired = e.target.value;\n State.update({ properties: updatedProperties });\n setJsonSchema((prev) => ({\n ...prev,\n required: updatedProperties,\n }));\n};\nfunction TypeSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n {availableTypes.map((it) => (\n <option value={it} key={it}>\n {it}\n </option>\n ))}\n </Select>\n );\n}\n// convert Multi and Required selects to checkboxes\nfunction MultiSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n <option value={false}>single</option>\n <option value={true}>multi</option>\n </Select>\n );\n}\nfunction RequiredSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n <option value={false}>no</option>\n <option value={true}>yes</option>\n </Select>\n );\n}\nreturn (\n <Container>\n <Row>\n <Text>\n <b>Import Schema:</b>\n </Text>\n <Input\n type=\"text\"\n value={state.newSchema}\n onChange={(e) => State.update({ newSchema: e.target.value })}\n placeholder={\"account/schema/title\"}\n />\n <Button onClick={loadSchema}>load</Button>\n </Row>\n <Row>\n <Text>\n <b>Import Types:</b>\n </Text>\n <Input\n type=\"text\"\n value={state.newTypeSrc}\n onChange={(e) => State.update({ newTypeSrc: e.target.value })}\n placeholder={\"hyperfiles.near\"}\n />\n <Button onClick={() => State.update({ typeSrc: state.newTypeSrc })}>\n apply\n </Button>\n </Row>\n <FormContainer>\n <Row>\n <Text>\n <b>Title:</b>\n </Text>\n <Input\n type=\"text\"\n name=\"title\"\n value={jsonSchema.title}\n onChange={handleSchemaTitleChange}\n placeholder=\"Schema_Title\"\n />\n <i>*overwrites existing path when saved</i>\n </Row>\n <Row>\n <Text>\n <b>Description:</b>\n </Text>\n <Input\n type=\"text\"\n placeholder=\"Concisely explain.\"\n value={jsonSchema.description}\n onChange={handleSchemaDescriptionChange}\n />\n </Row>\n <Row>\n <Text>\n <b>Schema Type:</b>\n </Text>\n <Select value={value} onChange={handleSchemaTypeChange}>\n <option value={\"object\"}>object</option>\n <option value={\"boolean\"}>boolean</option>\n </Select>\n </Row>\n <hr></hr>\n <Text>\n <h4>Schema Properties</h4>\n <i>*Add properties below that are relevant to your use case.</i>\n <br />\n <br />\n <b>1.</b> [Name]: describe the property\n <br />\n <b>2.</b> [Type]: how is the property structured?\n <a href=\"https://everything.dev/every.near/widget/every.type.create\">\n <i>[Define new types]</i>\n </a>\n <br />\n <b>3.</b> [Single/Multi]: can the property be an array?\n <br />\n <b>4.</b> [Required]: is the property required?\n </Text>\n {state.properties?.map((property, index) => (\n <Row key={index}>\n <div>\n <Label>Name:</Label>\n <Input\n type=\"text\"\n value={property.name}\n onChange={(e) => handlePropertyNameChange(e, index)}\n />\n </div>\n <div>\n <Label>Property Type:</Label>\n <TypeSelect\n value={property.type}\n onChange={(e) => handleTypeChange(e, index)}\n />\n </div>\n <div>\n <Label>isMulti:</Label>\n <MultiSelect\n value={property.isMulti}\n onChange={(e) => handleMultiChange(e, index)}\n />\n </div>\n <div>\n <Label>Required:</Label>\n <RequiredSelect\n value={property.isRequired}\n onChange={(e) => handleRequiredChange(e, index)}\n />\n </div>\n <div>\n <Label>Remove:</Label>\n <Button onClick={() => handleRemoveProperty(index)}>Remove</Button>\n </div>\n </Row>\n ))}\n <Row>\n <div>\n <Label>New Property Name:</Label>\n <Input\n type=\"text\"\n placeholder=\"Property Name\"\n value={state.newPropertyName}\n onChange={(e) => State.update({ newPropertyName: e.target.value })}\n />\n </div>\n <div>\n <Label>New Type:</Label>\n <TypeSelect\n value={state.newPropertyType}\n onChange={(e) => State.update({ newPropertyType: e.target.value })}\n />\n </div>\n <div>\n <Label>isMulti:</Label>\n <MultiSelect\n value={state.newPropertyIsMulti}\n onChange={(e) =>\n State.update({ newPropertyIsMulti: e.target.value })\n }\n />\n </div>\n <div>\n <Label>Required:</Label>\n <RequiredSelect\n value={state.newPropertyIsRequired}\n onChange={(e) =>\n State.update({ newPropertyIsRequired: e.target.value })\n }\n />\n </div>\n <div>\n <Label>Add:</Label>\n <Button\n onClick={handleAddProperty}\n disabled={state.newPropertyName.trim() === \"\"}\n >\n +\n </Button>\n </div>\n </Row>\n <hr></hr>\n <Row>\n <Button\n onClick={create}\n disabled={state.properties.length === 0}\n className=\"styless\"\n >\n Publish/Update Schema\n </Button>\n </Row>\n </FormContainer>\n </Container>\n);\n``;\n" }, "explore.view.data": { "": "const DataViewer = ({ path, adapter }) => {\n const [data, setData] = useState(null);\n\n useEffect(() => {\n const fetchData = async () => {\n const adapterScript = VM.require(adapter);\n const content = await adapterScript.get(path);\n setData(content);\n };\n fetchData();\n }, [path, adapter]);\n\n return data ? (\n <div className=\"container\">\n {/* Render content based on data type here */}\n </div>\n ) : (\n <p>Loading...</p>\n );\n};\n" }, "explore.select.source.array": { "": "const sourceArray = [{ name: \"Text\" }, { name: \"Canvas\" }, { name: \"Other\" }];\nconst label = props.label ?? \"Label\";\nconst placeholder = props.placeholder ?? \"Placeholder\";\nconst value = props.value ?? \"\";\nconst options = props.options ?? sourceArray;\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst labelKey = props.labelKey ?? \"name\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n .typeahead {\n width: 100%;\n & > div {\n padding: 0.5em 0.75em;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n color: #101828;\n }\n .rbt-token {\n background: #f2f4f7;\n border: 1px solid #d0d5dd;\n border-radius: 3px;\n font-style: normal;\n font-weight: 500;\n font-size: 0.95em;\n line-height: 1.25em;\n text-align: center;\n color: #344054;\n & > button {\n font-size: 1.25em;\n color: #98a2b3;\n }\n }\n }\n`;\nconst Label = styled.label`\n font-style: normal;\n font-weight: 600;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #344054;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nreturn (\n <Container>\n {props.noLabel ? <></> : <Label>{label}</Label>}\n <Typeahead\n id\n placeholder={placeholder}\n labelKey={labelKey}\n onChange={onChange}\n options={options}\n selected={value}\n className=\"typeahead\"\n positionFixed\n allowNew\n />\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "explore.view.hyperfile": { "": "const { path } = props;\nif (!path) {\n return <p>No path provided.</p>;\n}\nconst thing = Social.get(`${path}/**`, \"final\");\nif (!thing) {\n return <p>Loading...</p>;\n}\nconst hyperfile = JSON.parse(thing[\"\"]);\nconst { get } = VM.require(hyperfile.adapter || (() => {}));\nif (get) {\n const content = get(hyperfile.reference);\n if (content === null) return <p>no content</p>;\n return (\n <div className=\"container\">\n {thing.metadata.type === \"md\" ? (\n <Widget\n src=\"openwebbuild.near/widget/Post.Markdown\"\n props={{\n text: content,\n }}\n />\n ) : (\n <p>viewer does not currently support type: {thing.type}</p>\n )}\n </div>\n );\n} else {\n return <p>Invalid adapter: {hyperfile.adapter}</p>;\n}\n" }, "create.edit.type": { "": "const typeSrc = props.typeSrc || \"\";\nconst blockHeight = props.blockHeight || \"final\";\nlet type = {\n name: \"\",\n properties: [],\n widgets: {},\n};\nState.init({\n newType: typeSrc,\n typeName: type.name || \"\",\n properties: type.properties || [],\n widgets: type.widgets || {},\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newWidgetKey: \"\",\n newWidgetSrc: \"\",\n newTypeSrc: \"every.near\",\n typeSrc: \"every.near\",\n expanded: false,\n});\nlet importedTypes = [];\nif (state.typeSrc !== \"\") {\n const types = Social.get(`${state.typeSrc}/type/**`, \"final\");\n if (!types) {\n return <></>;\n }\n importedTypes =\n Object.keys(types)?.map((it) => `${state.typeSrc}/type/${it}`) || [];\n}\nconst availableTypes = JSON.parse(props.availableTypes) || [\n \"string\",\n \"boolean\",\n \"number\",\n \"date\",\n \"time\",\n \"tags\",\n ...importedTypes,\n];\nconst Container = styled.div`\n margin: 20px;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Row = styled.div`\n display: flex;\n gap: 10px;\n`;\nconst Input = styled.input`\n flex: 1;\n max-width: 200px;\n margin-bottom: 10px;\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n height: 30px;\n`;\nconst Text = styled.p`\n display: inline-block;\n margin-right: 10px;\n`;\nconst loadType = () => {\n const parts = state.newType.split(\"/\");\n type = JSON.parse(Social.get(state.newType, blockHeight) || null);\n if (type) {\n type.name = parts[2];\n State.update({\n typeName: type.name,\n properties: type.properties,\n widgets: type.widgets,\n });\n }\n};\nconst handleAddProperty = () => {\n if (state.newPropertyName.trim() === \"\") return;\n const newProperty = {\n name: state.newPropertyName,\n type: state.newPropertyType,\n required: state.newPropertyRequired,\n isMulti: state.newPropertyIsMulti,\n };\n State.update({\n properties: [...state.properties, newProperty],\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newPropertyIsMulti: false,\n });\n};\nconst handleRemoveProperty = (index) => {\n const updatedProperties = [...state.properties];\n updatedProperties.splice(index, 1);\n State.update({ properties: updatedProperties });\n};\nconst handlePropertyChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].name = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleTypeChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].type = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleMultiChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].isMulti = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleTypeNameChange = (e) => {\n State.update({ typeName: e.target.value.toLowerCase() });\n};\nconst handleWidgetKeyChange = (e) => {\n State.update({ newWidgetKey: e.target.value.toLowerCase() });\n};\nconst handleWidgetSrcChange = (e) => {\n State.update({ newWidgetSrc: e.target.value });\n};\nconst handleAddWidget = () => {\n if (state.newWidgetKey.trim() === \"\" || state.newWidgetSrc.trim() === \"\")\n return;\n const newWidget = {\n [state.newWidgetKey]: state.newWidgetSrc,\n };\n State.update({\n widgets: { ...state.widgets, ...newWidget },\n newWidgetKey: \"\",\n newWidgetSrc: \"\",\n });\n};\nconst handleRemoveWidget = (key) => {\n const updatedWidgets = { ...state.widgets };\n delete updatedWidgets[key];\n State.update({ widgets: updatedWidgets });\n};\nconst composeData = () => {\n const data = {\n type: {\n [state.typeName]: JSON.stringify({\n properties: state.properties,\n widgets: state.widgets,\n }),\n },\n };\n return data;\n};\nfunction TypeSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n {availableTypes.map((it) => (\n <option value={it} key={it}>\n {it}\n </option>\n ))}\n </Select>\n );\n}\nfunction MultiSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n <option value={false}>single</option>\n <option value={true}>multi</option>\n </Select>\n );\n}\nreturn (\n <Container>\n <Widget src=\"hyperbuild.near/widget/explore.select.type\" />\n <FormContainer>\n <Row>\n <Text>Type Name:</Text>\n <Input\n type=\"text\"\n placeholder=\"Type Name\"\n value={state.typeName}\n onChange={handleTypeNameChange}\n />\n </Row>\n <Text>Properties:</Text>\n {state.properties?.map((property, index) => (\n <Row key={index}>\n <Input\n type=\"text\"\n value={property.name}\n onChange={(e) => handlePropertyChange(e, index)}\n />\n <TypeSelect\n value={property.type}\n onChange={(e) => handleTypeChange(e, index)}\n />\n <MultiSelect\n value={property.isMulti}\n onChange={(e) => handleMultiChange(e, index)}\n />\n <Button onClick={() => handleRemoveProperty(index)}>Remove</Button>\n </Row>\n ))}\n <Row>\n <Input\n type=\"text\"\n placeholder=\"Property Name\"\n value={state.newPropertyName}\n onChange={(e) => State.update({ newPropertyName: e.target.value })}\n />\n <TypeSelect\n value={state.newPropertyType}\n onChange={(e) => State.update({ newPropertyType: e.target.value })}\n />\n <MultiSelect\n value={state.newPropertyIsMulti}\n onChange={(e) => State.update({ newPropertyIsMulti: e.target.value })}\n />\n <Button\n onClick={handleAddProperty}\n disabled={state.newPropertyName.trim() === \"\"}\n >\n Add Property\n </Button>\n </Row>\n <Text>Widgets:</Text>\n {Object.entries(state.widgets)?.map(([key, src]) => (\n <Row key={key}>\n <Text>{key}:</Text>\n <Input type=\"text\" value={src} onChange={() => {}} />\n <Button onClick={() => handleRemoveWidget(key)}>Remove</Button>\n </Row>\n ))}\n <Row>\n <Input\n type=\"text\"\n placeholder=\"Widget Key\"\n value={state.newWidgetKey}\n onChange={handleWidgetKeyChange}\n />\n {\":\"}\n <Input\n type=\"text\"\n placeholder=\"Widget Src\"\n value={state.newWidgetSrc}\n onChange={handleWidgetSrcChange}\n />\n <Button\n onClick={handleAddWidget}\n disabled={\n state.newWidgetKey.trim() === \"\" || state.newWidgetSrc.trim() === \"\"\n }\n >\n Add Widget\n </Button>\n </Row>\n <Row>\n <CommitButton\n force\n data={composeData()}\n disabled={state.properties.length === 0}\n className=\"styless\"\n >\n create\n </CommitButton>\n </Row>\n </FormContainer>\n </Container>\n);\n" }, "tools.files.provider": { "": "const path = props.path || context.accountId;\nif (!path) return <p>Please login.</p>;\nconst getSecretKey = () => {\n const accountId = context.accountId;\n if (!accountId) {\n return null;\n }\n const registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n );\n const savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\n\n if (savedSecretKeyBase64 === null || registeredPublicKey === null) {\n return null;\n }\n\n return savedSecretKeyBase64;\n};\n\nconst savedSecretKeyBase64 = getSecretKey();\nif (!savedSecretKeyBase64) {\n return \"Enter a Secret Key or Password to unlock your files.\";\n}\nState.init({\n layout: \"LIST\",\n path,\n history: [path],\n currentHistoryIndex: 0,\n showPreview: false,\n selectedPath: \"\",\n filesSource: \"BOS_IPFS\",\n decryptSk: new Uint8Array(Buffer.from(savedSecretKeyBase64, \"base64\")), // Convert base64 to Uint8Array\n});\nfunction isNearAccount(str) {\n return typeof str === \"string\" && str.endsWith(\".near\");\n}\nfunction setPath(v) {\n const updatedHistory = state.history\n .slice(0, state.currentHistoryIndex + 1)\n .concat(v);\n const parts = v.split(\"/\");\n const lastPart = parts[parts.length - 1];\n if (isNearAccount(lastPart)) {\n v = lastPart;\n }\n State.update({\n path: v,\n history: updatedHistory,\n currentHistoryIndex: updatedHistory.length - 1,\n });\n}\nfunction setFilesSource(source) {\n State.update({\n filesSource: source,\n });\n console.log(\"File source set to:\", state.filesSource);\n}\nfunction goBack() {\n // Check if we can go back\n if (state.currentHistoryIndex > 0) {\n const newIndex = state.currentHistoryIndex - 1;\n State.update({\n currentHistoryIndex: newIndex,\n path: state.history[newIndex],\n });\n }\n}\nfunction goForward() {\n // Check if we can go forward\n if (state.currentHistoryIndex < state.history.length - 1) {\n const newIndex = state.currentHistoryIndex + 1;\n State.update({\n currentHistoryIndex: newIndex,\n path: state.history[newIndex],\n });\n }\n}\nfunction setSelectedPath(v) {\n State.update({ selectedPath: v });\n}\nfunction setHistory(v) {\n State.update({ history: v });\n}\nfunction setLayout(v) {\n State.update({ layout: v });\n}\nfunction togglePreview() {\n State.update({ showPreview: !state.showPreview });\n}\nconst Children = props.Children;\nreturn (\n <Children\n setPath={setPath}\n setFilesSource={setFilesSource}\n setHistory={setHistory}\n setLayout={setLayout}\n showPreview={state.showPreview}\n togglePreview={togglePreview}\n selectedPath={state.selectedPath}\n setSelectedPath={setSelectedPath}\n path={state.path}\n layout={state.layout}\n goBack={goBack}\n goForward={goForward}\n decryptSk={state.decryptSk} // Ensure decryptSk is passed here\n />\n);\n" }, "create.newthings": { "": "// Style components\nconst Input = styled.input`\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n text-transform: lowercase !important;\n padding: 8px;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Label = styled.label``;\n// Define dynamic input based on type\nconst DynamicInput = ({ type, onChange, value, placeholder }) => {\n if (type === \"boolean\") {\n return (\n <Select onChange={(e) => onChange(e.target.value)} value={value}>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </Select>\n );\n } else {\n return (\n <Input\n type={type}\n onChange={(e) => onChange(e.target.value)}\n value={value}\n placeholder={placeholder}\n />\n );\n }\n};\n// Main component\nconst NewThings = ({ item, onChange }) => {\n const [state, setState] = useState(item.value);\n const handleInputChange = (name, value) => {\n const newState = { ...state, [name]: value };\n setState(newState);\n onChange(newState);\n };\n // Import type data and widgets if needed using VM.require()\n const typeData = JSON.parse(Social.get(item.type, \"final\") || \"{}\");\n const { properties, widgets } = typeData;\n return (\n <Container>\n {properties.map((property) => (\n <Row key={property.name}>\n <Label>{property.name}</Label>\n <DynamicInput\n type={property.type}\n value={state[property.name]}\n onChange={(value) => handleInputChange(property.name, value)}\n placeholder={property.name}\n />\n </Row>\n ))}\n {widgets?.create && (\n <Widget src={widgets.create} props={{ onChange: handleInputChange }} />\n )}\n </Container>\n );\n};\nexport { NewThings };\n" }, "page.tools": { "": "const [decryptSk, setDecryptSk] = useState(null);\n// Callback function to handle the private key from PrivateMailBox\nconst handlePrivateKey = (key) => {\n setDecryptSk(key);\n console.log(\"DecryptSk:\", decryptSk); // Add this line to debug\n};\nreturn (\n <div className=\"p-3 border bg-light\">\n {/*<Widget src=\"hyperbuild.near/widget/tools.ipfsPDF\" />*/}\n <Widget\n src=\"hyperbuild.near/widget/tools.local.index\"\n props={{\n onPrivateKeyRetrieved: handlePrivateKey, // Pass the callback to retrieve the private key\n }}\n />\n <hr />\n <h1>Data Explorer</h1>\n <Widget\n src=\"hyperbuild.near/widget/tools.files.index\"\n props={{\n decryptSk,\n }}\n />\n </div>\n);\n" }, "tools.local.getSecret": { "": "function GetSecretKey() {\n const accountId = context.accountId;\n if (!accountId) {\n return null;\n }\n const registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n );\n const savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\n\n if (savedSecretKeyBase64 === null || registeredPublicKey === null) {\n return null;\n }\n\n return savedSecretKeyBase64;\n}\nreturn { GetSecretKey };\n" }, "explore.select.schema": { "": "const Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Button = styled.button``;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Select = styled.select``;\nconst Label = styled.label``;\nconst Input = styled.input``;\nconst initialSchemaSrc = props.schemaSrc || \"hyperfiles.near\";\nconst [newSchemaSrc, setNewSchemaSrc] = useState(initialSchemaSrc);\nconst [schemaSrc, setSchemaSrc] = useState(initialSchemaSrc);\nconst [selectedSchema, setSelectedSchema] = useState(\n props.selectedSchema || \"\"\n);\nconst [availableSchemas, setAvailableSchemas] = useState([]);\nconst [isLoading, setIsLoading] = useState(true);\nconst [fetchedData, setFetchedData] = useState({}); // State for debugging\nuseEffect(() => {\n setIsLoading(true);\n const fetchSchemasList = () => {\n const query = schemaSrc === \"*\" ? \"*/schema/**\" : `${schemaSrc}/schema/**`;\n const schemas = Social.get(query, \"final\");\n setFetchedData(schemas); // Store raw data for debugging\n if (schemas) {\n let schemasSet = new Set();\n if (schemaSrc === \"*\") {\n // Collect schemas from all fetched data\n Object.values(schemas).forEach((accountSchemas) => {\n Object.values(accountSchemas).forEach((schemaObj) => {\n Object.keys(schemaObj).forEach((schemaName) => {\n schemasSet.add(schemaName);\n });\n });\n });\n } else {\n // Schemas from a specific account\n Object.keys(schemas).forEach((key) => schemasSet.add(key));\n }\n setAvailableSchemas(Array.from(schemasSet));\n } else {\n setAvailableSchemas([]);\n }\n setIsLoading(false);\n };\n fetchSchemasList();\n}, [schemaSrc]);\nuseEffect(() => {\n setSelectedSchema(props.selectedSchema);\n}, [props.selectedSchema]);\nconst handleSchemaChange = (event) => {\n setSelectedSchema(event.target.value);\n if (props.onSelectedSchemaChange) {\n props.onSelectedSchemaChange(event.target.value);\n }\n};\nconst handleSchemaSrcChange = (event) => {\n setNewSchemaSrc(event.target.value);\n};\nconst applySchemaSrc = () => {\n setSchemaSrc(newSchemaSrc);\n};\nconst showAllSchemas = () => {\n setSchemaSrc(\"*\");\n};\nreturn (\n <FormContainer>\n <Label>Schema Owner:</Label>\n <Row>\n <Input\n schema=\"text\"\n onChange={handleSchemaSrcChange}\n value={newSchemaSrc}\n placeholder=\"accountId\"\n />\n <Button onClick={applySchemaSrc}>Apply</Button>\n </Row>\n <Label>Schema:</Label>\n <Row>\n {isLoading ? (\n <div>Loading...</div>\n ) : (\n <Select value={selectedSchema} onChange={handleSchemaChange}>\n <option value=\"\">Choose a schema</option>\n {availableSchemas.map((schema) => (\n <option key={schema} value={schema}>\n {schema}\n </option>\n ))}\n </Select>\n )}\n <Button onClick={showAllSchemas}>Show All</Button>\n </Row>\n </FormContainer>\n);\n// <pre>{JSON.stringify(fetchedData, null, 2)}</pre> {/* Debug output */}\n" }, "create.merge": { "": "const Wrapper = styled.div`\n max-width: 400px;\n margin: 0 auto;\n`;\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst adapters = [\n // these can come from the user (or app) settings\n // {\n // title: \"Local Storage\",\n // value: \"everycanvas.near/widget/adapter.local_storage\",\n // saveRef: false\n // },\n // {\n // title: \"SocialDB\",\n // value: \"everycanvas.near/widget/adapter.social\",\n // },\n {\n title: \"IPFS\",\n value: \"everycanvas.near/widget/adapter.ipfs\",\n },\n // {\n // title: \"GitHub\",\n // value: \"hack.near/widget/adapter.github\",\n // },\n // {\n // title: \"Obsidian\",\n // value: \"hack.near/widget/adapter.obsidian\",\n // },\n // {\n // title: \"Tldraw\",\n // value: \"hack.near/widget/adapter.tldraw\",\n // },\n];\nconst defaultAdapter = adapters[0];\nconst { creatorId } = props;\nconst [json, setJson] = useState(props.data ?? \"\");\nconst [source, setSource] = useState(props.source ?? \"\");\nconst [adapter, setAdapter] = useState(defaultAdapter.value ?? \"\");\nconst [reference, setReference] = useState(undefined);\nconst [filename, setFilename] = useState(props.filename ?? \"\");\nconst [activeTab, setActiveTab] = useState(\"data\");\nconst [name, setName] = useState(props.name ?? \"\");\nconst [description, setDescription] = useState(props.description ?? \"\");\nfunction generateUID() {\n return (\n Math.random().toString(16).slice(2) +\n Date.now().toString(36) +\n Math.random().toString(16).slice(2)\n );\n}\nconst handleCreate = () => {\n const isCreator = context.accountId === creatorId;\n // load in the state.adapter (modules for IPFS, Arweave, Ceramic, Verida, On Machina... )\n const { create } = VM.require(adapter) || (() => {});\n if (create) {\n // store the data somewhere, based on the adapter\n create(json).then((reference) => {\n // now we have a reference to the data\n // we need to name it... are we the original creator or are we forking? We don't want to overwrite any of the users custom (or maybe we do!)\n const thingId = filename ?? generateUID();\n const hyperfile = {\n [props.type]: {\n // which we store in the social contract\n [thingId]: {\n \"\": JSON.stringify({\n fileformat: `${props.type}.${source}`,\n source: source,\n adapter: adapter,\n reference: reference,\n }),\n metadata: {\n name: name,\n description: description,\n type: props.type,\n },\n },\n },\n };\n if (creatorId !== context.accountId) {\n // handle request merge\n hyperfile.index = {\n notify: JSON.stringify({\n key: creatorId,\n value: {\n type: \"request\",\n data: {\n type: \"merge\",\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n origin: `${context.accountId}/${props.type}/${thingId}`,\n },\n },\n }),\n };\n hyperfile[props.type][thingId].metadata = {\n ...hyperfile[props.type][thingId].metadata,\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n };\n // I want to make a request to merge\n // set upstream and downstream\n }\n // sometimes we're not logged in, so it doesn't do anything!\n Social.set(hyperfile, { force: true });\n });\n }\n};\nreturn (\n <Wrapper>\n <h3>{context.accountId === creatorId ? \"create\" : \"request merge\"}</h3>\n <ul className=\"nav nav-tabs\">\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"data\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"data\")}\n >\n Data\n </a>\n </li>\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"metadata\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"metadata\")}\n >\n Metadata\n </a>\n </li>\n </ul>\n <TabContent>\n {activeTab === \"data\" && (\n <Form>\n <FormGroup>\n <Label>source</Label>\n <Input\n type=\"text\"\n value={source}\n onChange={(e) => onChangeSource(e.target.value)}\n disabled={props.source} // disable if source is passed in\n />\n </FormGroup>\n {/* <Widget\n src=\"bozon.near/widget/CodeDiff\"\n props={{ currentCode: update, prevCode: src, ...props }}\n /> */}\n <textarea\n className=\"form-control mb-3\"\n rows={5}\n value={json}\n onChange={(e) => setJson(e.target.value)}\n />\n <FormGroup>\n <Label>adapter</Label>\n <Select\n value={adapter}\n onChange={(e) => setAdapter(e.target.value)}\n >\n {adapters.map((o) => (\n <option value={o.value}>{o.title}</option>\n ))}\n </Select>\n </FormGroup>\n </Form>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <Form>\n <FormGroup>\n <Label>name</Label>\n <Input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </FormGroup>\n <FormGroup>\n <Label>description</Label>\n <textarea\n className=\"form-control mb-3\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n />\n </FormGroup>\n </Form>\n )}\n </TabContent>\n <FormGroup>\n <button className=\"btn btn-success mb-1\" onClick={handleCreate}>\n Create\n </button>\n </FormGroup>\n </Wrapper>\n);\n" }, "navigation.Navbar": { "": "const StyledButton = styled.button`\n all: unset;\n display: ${(props) => (props.type === \"icon\" ? \"flex\" : \"inline-flex\")};\n width: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n height: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n padding: ${(props) => (props.type === \"icon\" ? \"0\" : \"10px 20px\")};\n justify-content: center;\n align-items: center;\n gap: 5px;\n border-radius: ${(props) => (props.type === \"icon\" ? \"50%\" : \"8px\")};\n font-size: 15px;\n letter-spacing: 2px;\n font-weight: 555;\n font-family: \"Courier\", sans-serif;\n background: ${(props) =>\n props.isActive ? \"#39f095\" : `var(--button-${props.variant}-bg, #23242B)`};\n color: ${(props) =>\n props.isActive ? \"#000\" : `var(--button-${props.variant}-color, #39f095)`};\n border: ${(props) =>\n props.variant === \"outline\"\n ? \"1px solid rgba(255, 255, 255, 0.20)\"\n : \"none\"};\n transition: background 300ms, color 300ms;\n &:hover:not(:disabled),\n &:focus {\n background: #39f095;\n color: #000;\n }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\nconst StyledNavbar = styled.div`\n width: 100%;\n justify-content: space-between;\n align-items: center;\n padding: 15px 23px;\n height: 80px;\n background-color: #0b0c14;\n border-bottom: 1px solid var(--stroke-color, rgba(255, 255, 255, 0.2));\n border-radius: 8px;\n @media screen and (max-width: 768px) {\n padding: 15px;\n }\n`;\nconst ButtonGroup = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 0.888rem;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n width: 100%;\n a {\n display: flex;\n }\n }\n`;\nconst DesktopNavigation = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst MobileNavigation = styled.div`\n display: none;\n @media screen and (max-width: 768px) {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n }\n`;\nconst { href } = VM.require(\"buildhub.near/widget/lib.url\") || {\n href: () => {},\n};\nconst NavLink = ({ to, children }) => (\n <Link\n key={to}\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: to,\n },\n })}\n >\n {children}\n </Link>\n);\nconst [showMenu, setShowMenu] = useState(false);\nconst toggleDropdown = () => setShowMenu(!showMenu);\nconst SignInOrConnect = () => (\n <>\n {context.accountId ? (\n <p\n className=\"m-2\"\n style={{\n color: \"#39f095\",\n fontSize: \"16px\",\n letterSpacing: \"2px\",\n fontFamily: \"Courier, sans-serif\",\n }}\n >\n Connected\n </p>\n ) : (\n <p\n className=\"m-2\"\n style={{\n color: \"#39f095\",\n fontSize: \"16px\",\n letterSpacing: \"2px\",\n fontFamily: \"Courier, sans-serif\",\n }}\n >\n Connect\n </p>\n )}\n </>\n);\nconst Navbar = ({ page, routes, ...props }) => (\n <StyledNavbar>\n <div className=\"d-flex align-items-center justify-content-between w-100\">\n <DesktopNavigation className=\"container-xl\">\n <Link\n style={{ flex: 1 }}\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: \"home\",\n },\n })}\n >\n <img\n style={{ width: 42, objectFit: \"cover\" }}\n src=\"https://builders.mypinata.cloud/ipfs/QmQuePz1JfSQ2jh9pDCh95rHeUvPSyDrddetaWJKDXaimZ\"\n alt=\"Hyperfiles\"\n />\n </Link>\n <ButtonGroup style={{ flex: 1 }}>\n {routes &&\n (Object.keys(routes) || []).map((k) => {\n const route = routes[k];\n if (route.hide) {\n return null;\n }\n return (\n <NavLink to={k}>\n <StyledButton key={k} isActive={page === k}>\n {route.init.icon && <i className={route.init.icon}></i>}\n {route.init.name}\n </StyledButton>\n </NavLink>\n );\n })}\n </ButtonGroup>\n <div\n style={{\n flex: 1,\n display: \"flex\",\n justifyContent: \"flex-end\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <SignInOrConnect />\n </div>\n </DesktopNavigation>\n <MobileNavigation>\n <Link\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: \"home\",\n },\n })}\n >\n <img\n style={{ width: 39, objectFit: \"cover\" }}\n src=\"https://builders.mypinata.cloud/ipfs/QmQuePz1JfSQ2jh9pDCh95rHeUvPSyDrddetaWJKDXaimZ\"\n alt=\"Hyperfiles\"\n />\n </Link>\n <StyledButton\n type=\"icon\"\n variant=\"outline\"\n className=\"rounded-2\"\n onClick={toggleDropdown}\n >\n <i style={{ fontSize: 24 }} className=\"bi bi-list\"></i>\n </StyledButton>\n </MobileNavigation>\n </div>\n <MobileNavigation>\n {showMenu && (\n <div className=\"text-white w-100 d-flex flex-column gap-3 mt-3\">\n <ButtonGroup className=\"align-items-stretch\">\n {routes &&\n (Object.keys(routes) || []).map((k) => {\n const route = routes[k];\n if (route.hide) {\n return null;\n }\n return (\n <NavLink to={k} style={{ textDecoration: \"none\" }}>\n <StyledButton\n key={k}\n variant={page === k && \"primary\"}\n className=\"w-100\"\n onClick={() => setShowMenu(false)}\n >\n {route.init.icon && <i className={route.init.icon}></i>}\n {route.init.name}\n </StyledButton>\n </NavLink>\n );\n })}\n </ButtonGroup>\n <div className=\"d-flex w-100 align-items-center gap-3 justify-content-center\">\n <SignInOrConnect />\n </div>\n </div>\n )}\n </MobileNavigation>\n </StyledNavbar>\n);\nreturn <Navbar page={props.page} routes={props.routes} {...props} />;\n" }, "profile.main": { "": "const AccordionHeader = styled.div`\n cursor: pointer;\n background-color: #f8f9fa;\n padding: 1rem;\n margin: 0;\n border: 1px solid #dee2e6;\n display: flex;\n align-items: center;\n justify-content: space-between;\n`;\nconst Icon = styled.span`\n display: inline-block;\n transition: transform 0.3s ease;\n transform: ${(props) =>\n props.isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\"};\n`;\nconst AccordionContent = styled.div`\n max-height: ${(props) => (props.isExpanded ? \"1000px\" : \"0\")};\n overflow: auto;\n transition: max-height 0.5s ease;\n border: 1px solid #dee2e6; /* Ensure border is continuous */\n padding: ${(props) => (props.isExpanded ? \"1rem\" : \"0\")};\n`;\nconst accountId = props.accountId || context.accountId;\nif (!accountId) return \"Login or send accountId in the props\";\nconst profile = Social.getr(`${accountId}/profile`);\nconst allWidgetsHistoryChangesBlocks = Social.keys(\n `${accountId}/widget/*`,\n \"final\",\n {\n return_type: \"History\",\n }\n);\nif (allWidgetsHistoryChangesBlocks === null) return \"Loading...\";\nconst widget = allWidgetsHistoryChangesBlocks[accountId].widget;\nconst totalCommits = Object.keys(widget)\n .map((key) => widget[key])\n .flat();\nconst widgets = Social.getr(`${accountId}/widget`) ?? {};\nconst [isExpanded, setIsExpanded] = useState(false);\nconst toggleAccordion = () => {\n setIsExpanded(!isExpanded);\n};\n// --------------- nodes -------------------\nconst Nodes = (\n <div\n className=\"col-lg-12 pb-4\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n key={state.data}\n src=\"hyperbuild.near/widget/explore.view.tree\"\n props={{\n rootPath: state.data,\n themeColor: themeColor.tree,\n }}\n />\n </div>\n </div>\n);\nreturn (\n <div>\n <div>\n <h2>Data Tree</h2>\n </div>\n <div className=\"row\">{Nodes}</div>\n <div className=\"rightSection\">\n <div>\n <AccordionHeader onClick={toggleAccordion} aria-expanded={isExpanded}>\n <div>\n <h2>\n <Icon isExpanded={isExpanded} className=\"bi bi-chevron-down\" />\n Widgets\n </h2>\n </div>\n <span>\n {isExpanded ? \"(click to collapse)\" : \"(click to expand)\"}\n </span>\n </AccordionHeader>\n <AccordionContent isExpanded={isExpanded}>\n <div className=\"widgetsContainer\">\n {Object.keys(widgets)?.length > 0 ? (\n Object.keys(widgets)?.map((item, index) => (\n <Widget\n key={index}\n src=\"zahidulislam.near/widget/Profile.WidgetItem\"\n props={{\n name: item,\n accountId,\n commits:\n allWidgetsHistoryChangesBlocks[accountId].widget[item],\n }}\n />\n ))\n ) : (\n <p\n style={{\n padding: 20,\n textAlign: \"center\",\n color: \"rgba(0,0,0,.75)\",\n }}\n >\n {profile?.name} does not have any widget.\n </p>\n )}\n </div>\n </AccordionContent>\n </div>\n <div>\n <h2>{totalCommits.length} contributions</h2>\n <div style={{ marginTop: 20 }} />\n <Widget\n src=\"zahidulislam.near/widget/Profile.Contributions\"\n props={{ theme: props.theme }}\n />\n </div>\n </div>\n </div>\n);\n" }, "create.job": { "": "State.init({\n jsonStr: JSON.stringify(state.jsonStr),\n prettifiedJson: \"\",\n fiexedJsonErrors: \"\",\n});\n\nconsole.log(state.jsonStr);\n\nfunction formatClickHandler() {\n let formattedJsonStr = \"\";\n let fixedErrors = \"\";\n\n try {\n // Validate input as JSON according to RFC 8259\n const jsonObj = JSON.parse(state.jsonStr);\n console.log(jsonObj);\n // Stringify the JSON object with indentation and sorting keys\n formattedJsonStr = JSON.stringify(jsonObj, null, 4);\n } catch (error) {\n // If parsing fails, try to fix common errors in the JSON string\n let fixedJsonStr = jsonStr\n // Fix missing quotes around property names\n .replace(/([{,]\\s*)([a-zA-Z0-9_$]+)\\s*:/g, (match, p1, p2) => {\n fixedErrors += `Missing quotes around \"${p2}\"\\n`;\n return `${p1}\"${p2}\":`;\n })\n // Fix trailing commas in arrays and objects\n .replace(/,(?=\\s*([}\\]]))/g, (match) => {\n fixedErrors += `Trailing comma removed\\n`;\n return \"\";\n })\n // Fix single quotes around property names and string values\n .replace(/'/g, (match) => {\n fixedErrors += `Single quotes replaced with double quotes\\n`;\n return '\"';\n })\n // Fix unquoted property values\n .replace(\n /([{,]\\s*)([a-zA-Z0-9_$]+)\\s*:\\s*([a-zA-Z0-9_$]+)\\s*(?=([,}]))/g,\n (match, p1, p2, p3, p4) => {\n fixedErrors += `Unquoted value \"${p3}\" surrounded with quotes\\n`;\n return `${p1}\"${p2}\":\"${p3}\"${p4}`;\n }\n )\n // Fix invalid escape sequences in string values\n .replace(/\\\\([^\"\\\\/bfnrtu])/g, (match, p1) => {\n fixedErrors += `Invalid escape sequence \"\\\\${p1}\" removed\\n`;\n return \"\";\n });\n try {\n // Try to parse the fixed JSON string\n const jsonObj = JSON.parse(fixedJsonStr);\n // Stringify the JSON object with indentation and sorting keys\n formattedJsonStr = JSON.stringify(jsonObj, null, 4);\n } catch (error) {\n // If parsing still fails, return an error message\n formattedJsonStr = `Error: ${error.message}`;\n }\n }\n State.update({ prettifiedJson: formattedJsonStr });\n State.update({ fiexedJsonErrors: fixedErrors });\n}\n\nasync function dragAndDropHandler(event) {\n event.preventDefault();\n const file = event.dataTransfer.files[0];\n const fileReader = new FileReader();\n fileReader.onload = function () {\n const fileData = fileReader.result;\n State.update({ jsonStr: fileData });\n State.update({ prettifiedJson: \"\" });\n State.update({ fiexedJsonErrors: \"\" });\n };\n fileReader.readAsText(file);\n}\n\nfunction fileUploadHandler({ target }) {\n const file = target.files[0];\n\n if (!file) {\n return;\n }\n\n const fileReader = new FileReader();\n fileReader.onload = () => {\n const fileData = JSON.parse(fileReader.result);\n State.update({ jsonStr: fileData });\n State.update({ prettifiedJson: \"\" });\n State.update({ fiexedJsonErrors: \"\" });\n };\n fileReader.readAsText(file);\n}\n\nasync function urlInputHandler(event) {\n const url = event.target.value;\n try {\n const response = await fetch(url);\n const jsonData = await response.json();\n const newJsonStr = JSON.stringify(jsonData, null, 4);\n State.update({ jsonStr: newJsonStr });\n State.update({ prettifiedJson: \"\" });\n State.update({ fiexedJsonErrors: \"\" });\n } catch (error) {\n console.error(error);\n State.update({ jsonStr: \"\" });\n State.update({\n prettifiedJson: \"Error: Failed to fetch JSON data from URL\",\n });\n State.update({ fiexedJsonErrors: \"\" });\n }\n}\n\nconst clickCopyHandler = () => {\n navigator.clipboard.writeText(state.prettifiedJson);\n};\n\nconst fileDownloadHandler = () => {\n const element = document.createElement(\"a\");\n const file = new Blob([state.prettifiedJson], { type: \"text/plain\" });\n element.href = URL.createObjectURL(file);\n element.download = \"formatted.json\";\n document.body.appendChild(element);\n element.click();\n};\n\nconst changeHandler = ({ target }) => {\n State.update({ jsonStr: target.value });\n console.log(state.jsonStr);\n};\n\nreturn (\n <div>\n <div class=\"container-fluid\">\n <h3 class=\"text-center\">Input JSON data</h3>\n <textarea\n class=\"container-fluid\"\n rows=\"10\"\n value={state.jsonStr}\n defaultValue={\"{name: 'gunna',age: 12}\"}\n onChange={changeHandler}\n onDrop={dragAndDropHandler}\n onDragOver={(e) => e.preventDefault()}\n placeholder=\"Enter or drag and drop JSON data here...\"\n />\n <div className=\"input-actions\">\n <input type=\"file\" accept=\".json\" onChange={fileUploadHandler} />\n <input\n type=\"text\"\n placeholder=\"Enter URL to fetch JSON data\"\n onBlur={urlInputHandler}\n />\n </div>\n </div>\n <button onClick={formatClickHandler}>Format JSON</button>\n {state.prettifiedJson && (\n <>\n <div class=\"output-container\">\n <h3>Formatted JSON data</h3>\n {state.fiexedJsonErrors && (\n <div class=\"border\">\n <h3>Fixed errors</h3>\n <pre>{state.fiexedJsonErrors}</pre>\n </div>\n )}\n <textarea\n class=\"container-fluid\"\n rows=\"10\"\n value={state.prettifiedJson}\n readOnly\n />\n </div>\n <div class=\"output-actions\"></div>\n </>\n )}\n </div>\n);\n" }, "explore.fetch.things": { "": "// fork_Of: \"hack.near/widget/fetch.things\"\nconst { fetchThings } = VM.require(\n \"buildhub.near/widget/lib.everything-sdk\"\n) || {\n fetchThings: () => {},\n};\n\nconst app = props.app ?? \"graph\";\nconst thing = props.thing ?? \"commons\";\nconst things = fetchThings(app, thing);\n\nreturn (\n <>\n <p>{JSON.stringify(things)}</p>\n </>\n);\n" }, "create.reference": { "": "// Example attestation UID: 0xff5dc0cdc3de27dfe6a4352c596c0f97b1f99c51a67bbae142ce315e34969dcd\n// Example schema UID: 0x6ab5d34260fca0cfcf0e76e96d439cace6aa7c3c019d7c4580ed52c6845e9c89\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst [activeTab, setActiveTab] = useState(\"query\");\nconst [defaultView, setDefaultView] = useState(\"QUERY\") || props.defaultView;\n// Need to finish getAttestation refactor to imported component\n//const { GetAttestation } = VM.require(\"flowscience.near/widget/getAttestation\");\n//const { attest } = VM.require(\"flowscience.near/widget/easAttest\");\n//const { getSchema } = VM.require(\"flowscience.near/widget/getSchema\");\n//const { register } = VM.require(\"flowscience.near/widget/easRegister\");\n//const { revoke } = VM.require(\"flowscience.near/widget/easRevoke\");\n//const { timestamp } = VM.require(\"flowscience.near/widget/easTimestamp\");\nconst user = Ethers.send(\"eth_requestAccounts\", [])[0];\n// if (!user) return <Web3Connect connectLabel=\"Connect\" />;\n{\n /*\nconst chain = Ethers.provider()\n .getNetwork()\n .{then}((chainIdData) => {\n console.log(chainIdData.chainId);\n });\n*/\n}\nconst provider = new ethers.providers.JsonRpcProvider(\n \"https://optimism.drpc.org\"\n);\nconst signer = provider.getSigner(user);\n// console.log(\"chain:\", chain);\n// console.log(\"signer:\", signer);\nreturn (\n <div className=\"p-3 border bg-light\">\n <div className=\"m-2\">\n <h1>EAS on BOS</h1>\n <p>\n Querying currently only works on\n <a href=\"https://optimism.easscan.org/\">Optimism</a>.\n </p>\n <hr />\n </div>\n <ul className=\"nav nav-tabs\">\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"query\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"query\")}\n >\n Query\n </a>\n </li>\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"Create\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"Create\")}\n >\n Create\n </a>\n </li>\n </ul>\n <TabContent>\n {activeTab === \"query\" && (\n <div>\n <div className=\"m-2\">\n <Widget src=\"flowscience.near/widget/getAttestation\" />\n <hr />\n </div>\n <div className=\"m-2\">\n <Widget src=\"flowscience.near/widget/getSchema\" />\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"Create\" && (\n <div>\n <div className=\"m-2\">\n <h5>Create Attestations (Hyperfiles reference objects) Near</h5>\n <Widget src=\"flowscience.near/widget/attest\" />\n <hr />\n <h5>Coming soon: create Attestations & Schemas on Optimism!</h5>\n <Widget src=\"flowscience.near/widget/attestEAS\" />\n <hr />\n </div>\n </div>\n )}\n </TabContent>\n </div>\n);\n" }, "explore.things": { "": "const type = props.type ?? \"type\";\nconst [searchTerm, setSearchTerm] = useState(\"\");\nconst [hideDetails, setHideDetails] = useState(true);\nconst [selectedPath, setSelectedPath] = useState(null);\nconst [object, setObject] = useState(Social.get(`*/${type}/*`, \"final\") || {});\nconst [filteredResults, setFilteredResults] = useState([]);\nuseEffect(() => {\n const results = {};\n Object.entries(object).forEach(([creator, detail]) => {\n const entries = detail[type] || {};\n Object.keys(entries).forEach((id) => {\n const path = `${creator}/${type}/${id}`;\n if (path.includes(searchTerm)) {\n if (!results[id]) {\n results[id] = { count: 0, accounts: new Set() };\n }\n results[id].count++;\n results[id].accounts.add(creator);\n }\n });\n });\n setFilteredResults(\n Object.entries(results)\n .sort((a, b) => b[1].count - a[1].count)\n .map(([id, data]) => ({\n id,\n accounts: Array.from(data.accounts),\n count: data.count,\n }))\n );\n}, [searchTerm, object]);\nconst handleInputChange = (event) => {\n setSearchTerm(event.target.value);\n};\nconst toggleModal = (path) => {\n setSelectedPath(path);\n setHideDetails(!hideDetails);\n};\nconst Profiles = styled.a`\n display: inline-block;\n position: relative;\n img {\n object-fit: cover;\n border-radius: 50%;\n width: 100%;\n height: 100%;\n transition: transform 0.3s ease, box-shadow 0.3s ease;\n }\n &:hover img {\n transform: scale(1.1);\n box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);\n }\n`;\nreturn (\n <div className=\"m-3\">\n <input\n type=\"text\"\n value={searchTerm}\n onChange={handleInputChange}\n placeholder={`🔭 Search for a type of things...`}\n />\n {!hideDetails ? (\n <div className=\"m-3 mt-4\">\n <Widget\n src=\"hack.near/widget/explore.creators\"\n props={{ id: selectedPath.split(\"/\").pop() }}\n />\n <button className=\"m-2 btn-sm\" onClick={() => toggleModal(\"\")}>\n Reset\n </button>\n <Widget\n src=\"hack.near/widget/explore.view\"\n props={{ path: selectedPath, showInput: false }}\n />\n </div>\n ) : (\n <div className=\"m-3 mt-4\">\n {filteredResults.map(({ id, accounts, count }) => (\n <div className=\"d-flex flex-row justify-content-between\">\n <h5 className=\"mt-2\">\n <b>{id}</b>\n </h5>\n <div>\n {accounts.map((creator) => (\n <Profiles\n key={creator}\n onClick={() => toggleModal(`${creator}/${type}/${id}`)}\n >\n <span className=\"d-inline-block\">\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: creator,\n imageStyle: {\n height: \"38px\",\n width: \"38px\",\n },\n imageClassName: \"\",\n }}\n />\n </span>\n </Profiles>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n);\n" }, "tools.local.index": { "": "const accountId = context.accountId;\nif (!accountId) {\n return \"Please sign in with NEAR wallet\";\n}\nconst registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n);\nconst savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\nif (savedSecretKeyBase64 === null || registeredPublicKey === null)\n return \"Loading\";\n// Utility function to retrieve secret key\nconst getSecretKey = () => {\n const accountId = context.accountId;\n if (!accountId) {\n return null;\n }\n const registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n );\n const savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\n if (savedSecretKeyBase64 === null || registeredPublicKey === null) {\n return null;\n }\n return savedSecretKeyBase64;\n};\nconst handleSignIn = () => {\n try {\n const keyPairFromSaved = nacl.box.keyPair.fromSecretKey(\n Buffer.from(state.inputSecretKey, \"base64\")\n );\n if (\n Buffer.from(keyPairFromSaved.publicKey).toString(\"base64\") !==\n registeredPublicKey\n ) {\n State.update({ errorInputSecretKey: \"⚠️ key does not fit\" });\n } else {\n const secretKey = Buffer.from(keyPairFromSaved.secretKey).toString(\n \"base64\"\n );\n Storage.privateSet(\"secretKey\", secretKey);\n State.update({\n savedSecretKeyBase64: secretKey,\n });\n // Directly save the secret key in local storage\n Storage.privateSet(\"secretKey\", secretKey);\n }\n } catch {\n State.update({ errorInputSecretKey: \"⚠️ invalid secret key\" });\n }\n};\nState.init({\n selectedUser,\n registerPage: false,\n loginPage: !savedSecretKeyBase64 ? true : false,\n userListPage: savedSecretKeyBase64 ? true : false,\n});\nfunction renderLoginPage() {\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\"></div>\n <h1 class=\"col\">Encryption Tools</h1>\n <div class=\"col\"></div>\n </div>\n {registeredPublicKey && (\n <div>\n <label class=\"mb-3\">You registered using this public key:</label>\n <input\n class=\"form-control mb-3\"\n value={registeredPublicKey}\n disabled\n />\n </div>\n )}\n <input\n class=\"form-control mb-3\"\n placeholder=\"Input secret key\"\n key=\"inputSecret\"\n onChange={(e) => State.update({ inputSecretKey: e.target.value })}\n />\n <label class=\"mb-3\">{state.errorInputSecretKey}</label>\n <div>\n <button\n onClick={() => {\n try {\n const keyPairFromSaved = nacl.box.keyPair.fromSecretKey(\n Buffer.from(state.inputSecretKey, \"base64\")\n );\n if (\n Buffer.from(keyPairFromSaved.publicKey).toString(\"base64\") !=\n registeredPublicKey\n ) {\n State.update({ errorInputSecretKey: \"⚠️ key does not fit\" });\n } else {\n const secretKey = Buffer.from(\n keyPairFromSaved.secretKey\n ).toString(\"base64\");\n Storage.privateSet(\"secretKey\", secretKey);\n State.update({\n savedSecretKeyBase64: secretKey,\n });\n // Call the callback with the private key as decryptSk\n if (props.onPrivateKeyRetrieved) {\n props.onPrivateKeyRetrieved(secretKey);\n }\n }\n } catch {\n State.update({ errorInputSecretKey: \"⚠️ invalid secret key\" });\n }\n }}\n >\n Login\n </button>\n <button\n className=\"btn btn-outline-primary\"\n onClick={() => State.update({ registerPage: true })}\n >\n Register\n </button>\n </div>\n </div>\n );\n}\nif (state.registerPage) {\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\">\n <button\n class=\"btn btn-secondary\n float-right\"\n onClick={() => {\n State.update({ registerPage: false });\n }}\n >\n {\"<\"}\n </button>\n </div>\n <h1 class=\"col\">Register Public Key</h1>\n <div class=\"col\"></div>\n </div>\n <Widget\n src=\"hyperbuild.near/widget/tools.local.register\"\n props={{\n onRegisterComplete: () => {\n State.update({ registerPage: false });\n },\n }}\n />\n </div>\n );\n}\nif (state.selectedUser) {\n console.log({\n receiverAccountId: state.selectedUser.accountId,\n secretKeyBase64: savedSecretKeyBase64,\n receiverPublicKeyBase64: state.selectedUser.publicKeyBase64,\n });\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\">\n <button\n class=\"btn btn-secondary\n float-right\"\n onClick={() => {\n State.update({ selectedUser: null });\n }}\n >\n {\"<\"}\n </button>\n </div>\n <div class=\"col\">\n <Widget\n src=\"mob.near/widget/Profile.ShortInlineBlock\"\n props={{\n accountId: state.selectedUser.accountId,\n }}\n />\n </div>\n <div class=\"col\"></div>\n </div>\n <Widget\n src=\"bozon.near/widget/PrivateMailBox.UserMessages\"\n props={{\n receiverAccountId: state.selectedUser.accountId,\n secretKeyBase64: savedSecretKeyBase64,\n receiverPublicKeyBase64: state.selectedUser.publicKeyBase64,\n }}\n />\n </div>\n );\n}\nif (!savedSecretKeyBase64) return renderLoginPage();\nelse if (savedSecretKeyBase64)\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\"></div>\n <h1 class=\"col\">Private MailBox</h1>\n <div class=\"col d-flex justify-content-end\">\n <button\n class=\"btn btn-danger \n float-right\"\n onClick={() => {\n Storage.privateSet(\"secretKey\", undefined);\n }}\n >\n Logout\n </button>\n </div>\n </div>\n <Widget\n src=\"bozon.near/widget/PrivateMailBox.UserList\"\n props={{\n secretKeyBase64: savedSecretKeyBase64,\n onSelectedUser: (accountId, publicKeyBase64) => {\n State.update({ selectedUser: { accountId, publicKeyBase64 } });\n },\n }}\n />\n </div>\n );\n" }, "create.things": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Checkbox = styled.input`\n type: checkbox;\n`;\n// Utility to parse JSON properties safely\nconst safelyParseJSON = (json) => {\n try {\n return JSON.parse(json);\n } catch (e) {\n return []; // return an empty array if JSON is invalid\n }\n};\nconst CreateThings = ({ item, onChange }) => {\n // Destructure and parse properties, handling both direct object access and stringified JSON\n const properties =\n typeof item.type === \"string\"\n ? safelyParseJSON(Social.get(item.type, \"final\") || \"{}\").properties\n : item.type.properties;\n // Handle input changes and propagate them upwards\n const handleInputChange = (propertyName, newValue) => {\n onChange({\n ...item.value,\n [propertyName]: newValue,\n });\n };\n const renderInput = (property) => {\n const value = item.value[property.name] || \"\";\n switch (property.type) {\n case \"boolean\":\n return (\n <Checkbox\n checked={value}\n onChange={(e) => handleInputChange(property.name, e.target.checked)}\n />\n );\n case \"string\":\n case \"number\":\n case \"date\":\n return (\n <Input\n type={property.type === \"date\" ? \"date\" : \"text\"}\n value={value}\n onChange={(e) => handleInputChange(property.name, e.target.value)}\n />\n );\n default:\n return (\n <Input\n value={value}\n onChange={(e) => handleInputChange(property.name, e.target.value)}\n />\n );\n }\n };\n return (\n <Container>\n {properties.map((property) => (\n <FormGroup key={property.name}>\n <Label>{`${property.name}${property.isRequired ? \" *\" : \"\"}`}</Label>\n {renderInput(property)}\n </FormGroup>\n ))}\n </Container>\n );\n};\nexport { CreateThings };\n" }, "explore.socialgraph": { "": "const accountId = props.accountId ?? context.accountId ?? \"buildcommons.near\";\nconst GraphContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: ${(props) => props.height || \"325px\"};\n`;\nconst ProfileContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: row;\n gap: 23px;\n width: 100%;\n`;\nconst [accountIds, setAccountIds] = useState(props.accountIds || [accountId]);\nconst graphId = props.graphId ?? \"commons\";\nconst generatePaths = () => {\n return (\n props.paths ??\n accountIds.map((accountId) => {\n return `${accountId}/graph/${graphId}`;\n })\n );\n};\nconst paths = generatePaths();\nconst data = Social.getr(paths, \"final\");\nconst [nodesState, setNodesState] = useState(null);\nconst [focus, setFocus] = useState(null);\nconst debug = false;\nuseEffect(() => {\n setNodesState(data);\n}, [data]);\nif (!nodesState) {\n return <GraphContainer></GraphContainer>;\n}\nconst [selectedAccountId, setSelectedAccountId] = useState(null);\nconst [message, setMessage] = useState(null);\nuseEffect(() => {\n if (!nodesState) {\n return;\n }\n const nodes = {};\n const edges = [];\n const createNodesAndEdges = (accountId, graphData) => {\n if (!(accountId in nodes)) {\n nodes[accountId] = {\n id: accountId,\n size: 139,\n };\n }\n Object.values(graphData).forEach((links) => {\n console.log(graphData);\n Object.keys(links).forEach((memberId) => {\n if (!(memberId in nodes)) {\n nodes[memberId] = {\n id: memberId,\n size: 139,\n };\n }\n edges.push({\n source: accountId,\n target: memberId,\n value: 1,\n });\n });\n });\n };\n if (accountIds.length === 1) {\n const accountId = accountIds[0];\n createNodesAndEdges(accountId, { [graphId]: nodesState });\n } else if (accountIds.length > 1) {\n Object.entries(nodesState).forEach(([accountId, graphData]) => {\n createNodesAndEdges(accountId, graphData.graph);\n });\n }\n console.log(\"nodes\", nodes);\n console.log(\"edges\", edges);\n setMessage({\n nodes: Object.values(nodes),\n edges,\n });\n}, [nodesState, accountIds]);\nuseEffect(() => {\n if (selectedAccountId) {\n if (accountIds.includes(selectedAccountId)) {\n setAccountIds(accountIds.filter((it) => it !== selectedAccountId));\n } else {\n setAccountIds([...accountIds, selectedAccountId]);\n }\n }\n}, [selectedAccountId]);\nconst graphEdge = Social.keys(\n `${context.accountId}/graph/${graphId}/${accountId}`,\n undefined,\n {\n values_only: true,\n }\n);\nconst inverseEdge = Social.keys(\n `${accountId}/graph/${graphId}/${context.accountId}`,\n undefined,\n {\n values_only: true,\n }\n);\nconst loading = graphEdge === null || inverseEdge === null;\nconst attested = graphEdge && Object.keys(graphEdge).length;\nconst inverse = inverseEdge && Object.keys(inverseEdge).length;\nconst type = attested ? \"undo\" : graphId;\nconst attestation = props.attestation ?? {\n graph: { [graphId]: { [accountId]: attested ? null : \"\" } },\n};\nconst attest = () => {\n Social.set(data);\n};\nlet height = props.height || 325;\nconst code = `\n<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<!-- Load d3.js -->\n<script src=\"https://d3js.org/d3.v6.js\"></script>\n<div class=\"container\">\n <svg id=\"graph\" width=\"100%\" height=\"auto\" viewBox=\"0 0 650 325\" preserveAspectRatio=\"xMidYMid meet\" style=\"display: block; margin: auto;\">\n</div>\n<style>\n .container {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n width: 100%;\n }\n</style>\n<script>\nconst run = (data) => {\n const width = 650;\n const height = \\`${height}\\`;\n let dragIsOn = false;\n // The force simulation mutates links and nodes, so create a copy\n // so that re-evaluating this cell produces the same result.\n const links = data.edges.map(d => ({...d}));\n const nodes = data.nodes.map(d => ({...d}));\n // Create a simulation with several forces.\n const simulation = d3.forceSimulation(nodes)\n .force(\"link\", d3.forceLink(links).id(d => d.id))\n .force(\"charge\", d3.forceManyBody().strength(-500))\n .force(\"collide\", d3.forceCollide().radius(d => Math.sqrt(d.size) ))\n .force(\"center\", d3.forceCenter(width / 2, height / 2))\n .on(\"tick\", ticked);\n simulation.force(\"collide\")\n .strength(.7)\n .radius(d => Math.sqrt(d.size))\n .iterations(1);\n // Create the SVG container.\n const svg = d3.select(\"#graph\")\n .attr(\"width\", width)\n .attr(\"height\", height)\n .attr(\"viewBox\", [0, 0, width, height])\n .attr(\"style\", \"max-width: 100%; height: auto;\");\n // Add a line for each link, and a circle for each node.\n const link = svg.append(\"g\")\n .attr(\"stroke\", \"#999\")\n .attr(\"stroke-opacity\", 0.6)\n .selectAll()\n .data(links)\n .join(\"line\")\n .attr(\"stroke-width\", 1);\nconst node = svg.append(\"g\")\n .selectAll(\"g\")\n .data(nodes)\n .enter()\n .append(\"g\");\n node\n .append(\"image\")\n .attr(\"xlink:href\", (d) => \\`https://i.near.social/magic/thumbnail/https://near.social/magic/img/account/\\${d.id}\\`) // Set the image URL based on your data\n .attr(\"x\", (d) => -Math.sqrt(d.size) - 5)\n .attr(\"y\", (d) => -Math.sqrt(d.size) - 5)\n .attr(\"clip-path\", d => \\`circle(\\${Math.sqrt(d.size) + 5}px at \\${Math.sqrt(d.size) + 5} \\${Math.sqrt(d.size) + 5})\\`)\n .attr(\"width\", (d) => 2 * Math.sqrt(d.size) + 10);\n node\n .append(\"circle\")\n .attr(\"r\", d => Math.sqrt(d.size) + 5)\n .attr(\"fill\", \"none\");\n node.append(\"title\")\n .text(d => d.id);\n // Add a drag behavior.\n node.call(d3.drag()\n .on(\"start\", dragstarted)\n .on(\"drag\", dragged)\n .on(\"end\", dragended));\n node.on(\"mouseover\", handleMouseOver)\n .on(\"mouseout\", handleMouseOut)\n .on(\"click\", handleMouseClick);\n function handleMouseClick(e) {\n const d = e.target.__data__;\n window.top.postMessage({ handler: \"click\", data: d.id }, \"*\");\n }\n function handleMouseOver(d) {\n d = d.target.__data__;\n // Highlight connected edges\n link.attr(\"stroke-opacity\", e => (e.source === d || e.target === d) ? 1 : 0.1);\n // Highlight connected nodes\n node.attr(\"opacity\", function (n) {\n return n === d || isConnected(d, n) ? 1: 0.3;\n });\n window.top.postMessage({ handler: \"mouseover\", data: d.id }, \"*\");\n}\nfunction handleMouseOut() {\n if (dragIsOn) {\n return;\n }\n // Reset edge and node styles\n link\n .attr(\"stroke-opacity\", 0.6);\n node.attr(\"opacity\", 1);\n window.top.postMessage({ handler: \"mouseout\", data: \"out\" }, \"*\");\n}\nfunction isConnected(a, b) {\n // Check if two nodes are connected\n return links.some(function (link) {\n return (link.source === a && link.target === b) || (link.source === b && link.target === a);\n });\n}\n // Set the position attributes of links and nodes each time the simulation ticks.\n function ticked() {\n link\n .attr(\"x1\", d => d.source.x)\n .attr(\"y1\", d => d.source.y)\n .attr(\"x2\", d => d.target.x)\n .attr(\"y2\", d => d.target.y);\n node.attr(\"transform\", d => \\`translate(\\${d.x}, \\${d.y})\\`)\n }\n // Reheat the simulation when drag starts, and fix the subject position.\n function dragstarted(event) {\n dragIsOn = true;\n if (!event.active) simulation.alphaTarget(0.3).restart();\n event.subject.fx = event.subject.x;\n event.subject.fy = event.subject.y;\n }\n // Update the subject (dragged node) position during drag.\n function dragged(event) {\n event.subject.fx = event.x;\n event.subject.fy = event.y;\n }\n // Restore the target alpha so the simulation cools after dragging ends.\n // Unfix the subject position now that it’s no longer being dragged.\n function dragended(event) {\n if (!event.active) simulation.alphaTarget(0);\n event.subject.fx = null;\n event.subject.fy = null;\n dragIsOn = false;\n handleMouseOut();\n }\n // When this cell is re-run, stop the previous simulation. (This doesn’t\n // really matter since the target alpha is zero and the simulation will\n // stop naturally, but it’s a good practice.)\n // invalidation.then(() => simulation.stop());\n return simulation;\n};\nlet simulation = null;\nwindow.addEventListener(\"message\", (event) => {\n if (simulation) {\n simulation.stop();\n d3.select(\"#graph\").selectAll(\"*\").remove();\n }\n if (event.data) {\n simulation = run(event.data);\n }\n});\n</script>\n`;\nconst [onMessage] = useState(() => {\n return (data) => {\n if (data) {\n switch (data.handler) {\n case \"click\":\n setSelectedAccountId(data.data);\n break;\n }\n }\n };\n});\nreturn (\n <>\n <GraphContainer height={height}>\n <iframe\n className=\"w-100 h-100\"\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n minHeight: \"325px\",\n maxWidth: \"888px\",\n width: \"100%\",\n }}\n srcDoc={code}\n message={message}\n onMessage={onMessage}\n />\n </GraphContainer>\n </>\n);\n" }, "explore.view.thing": { "": "const path = props.path; // every piece of data on social contract has a path\nconst blockHeight = props.blockHeight || \"final\"; // and a blockHeight (~version)\nconst templateOverride = props.templateOverride;\n// split the path\nconst parts = path.split(\"/\");\nconst creatorId = parts[0];\nlet type;\nif (parts.length === 1) {\n if (parts[0].charAt(0) === \"#\") {\n // hashtag\n type = \"hashtag\";\n } else {\n // every root of a path is an account\n type = \"account\";\n }\n} else {\n // otherwise the \"standard\" is the type (widget, post, type, thing...)\n // for thing, we'll extract the actual \"Type\" later\n type = parts[1];\n}\nState.init({\n view: \"THING\",\n});\nconst Container = styled.div`\n //border: 1px solid #ccc;\n height: fit-content;\n`;\nconst Header = styled.div`\n display: flex;\n align-items: center;\n justify-content: flex-end;\n //border-bottom: 1px solid #ccc;\n`;\nconst Content = styled.div`\n padding: 1px;\n min-height: 300px;\n`;\nfunction Thing() {\n // Renders the path according to type\n switch (type) {\n case \"thing\":\n {\n // get the thing data\n const thing = JSON.parse(Social.get(path, blockHeight) || \"null\");\n type = thing.type || null;\n // get the type data\n const typeObj = JSON.parse(Social.get(type, blockHeight) || \"null\");\n if (typeObj === null) {\n console.log(\n `edge case: thing ${path} had an invalid type: ${thingType}`\n );\n }\n // determine the widget to render this thing (is there a default view?)\n console.log(\"TemplateOverride\", templateOverride);\n const widgetSrc =\n templateOverride || thing.template?.src || typeObj?.widgets?.view;\n //Template\n //hard code until finding template override prop\n //const widgetSrc = \"harmonic1.near/widget/artist2\";\n return (\n <Widget\n src={widgetSrc}\n props={{ data: thing.data, path, blockHeight }}\n />\n );\n }\n // DEFAULT:\n return <p>The type: {type} is not yet supported.</p>;\n }\n}\n// <ButtonRow>\n// <Modifier />\n// </ButtonRow>\nreturn (\n <Container id={path}>\n <Content>\n <Thing />\n </Content>\n </Container>\n);\n" }, "page.profile": { "": "const profile = props.profile;\nconst cssFont = fetch(\n \"https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap\"\n).body;\nconst css = fetch(\n \"https://raw.githubusercontent.com/cryptosynk/near-social-profile/main/css/mainLight.css\"\n).body;\nconst theme = \"light\";\nconst Theme = styled.div`\n font-family: \"Open Sans\", sans-serif;\n ${cssFont}\n ${css}\n`;\nconst Container = styled.div`\n max-width: 100%;\n overflow: auto;\n border: 1px solid #dee2e6;\n padding: 1rem;\n margin-bottom: 1rem;\n`;\nreturn (\n <div className=\"container mt-3 p-3 border bg-light\">\n <div className=\"row\">\n <h1>Manage {context.accountId}'s Profile</h1>\n <p>\n <ul>\n <li>Edit basic profile info in the left sidebar.</li>\n <li>\n View widgets you've created and a heatmap of your on-chain activity.\n </li>\n <li>\n Explore social profiles, data trees, and delete \"keys\" for entries\n in your data tree.\n </li>\n </ul>\n </p>\n <hr />\n </div>\n <Theme>\n <div className=\"container\">\n <div className=\"content\">\n <Widget\n src=\"hyperbuild.near/widget/profile.sidebar\"\n props={{ accountId, profile, theme }}\n />\n <Widget\n src=\"hyperbuild.near/widget/profile.main\"\n props={{ accountId, profile, theme }}\n />\n </div>\n </div>\n <hr />\n </Theme>\n <div>\n <Widget src=\"hyperbuild.near/widget/profile.social\" props={{}} />\n <hr />\n <Container>\n <h2>Profile Cleanup</h2>\n <hr />\n <Widget src=\"hyperbuild.near/widget/profile.cleanup\" props={{}} />\n </Container>\n </div>\n </div>\n);\n" }, "profile.sidebar": { "": "const accountId = props.accountId || context.accountId;\nif (!accountId) return \"Login or send accountId in the props\";\nconst profile = Social.getr(`${accountId}/profile`);\nconst name = profile?.name;\nconst image = profile?.image;\nconst url = image.ipfs_cid\n ? `https://ipfs.near.social/ipfs/${image?.ipfs_cid}`\n : \"https://thewiki.io/static/media/sasha_anon.6ba19561.png\";\nconst cssFont = fetch(\n \"https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap\"\n).body;\nconst css = fetch(\n \"https://raw.githubusercontent.com/cryptosynk/near-social-profile/main/css/mainLight.css\"\n).body;\nconst Theme = styled.div`\n font-family: \"Open Sans\", sans-serif;\n ${cssFont}\n ${css}\n`;\nif (!cssFont || !css) return \"Loading fonts & css\";\nState.init({\n showEditProfile: false,\n});\nreturn (\n <Theme>\n <div className=\"leftSection\">\n <div>\n <div>\n <img className=\"profileImage\" src={url} alt=\"profile\" />\n <div style={{ paddingBlock: 10 }}>\n <h2>{name}</h2>\n <p>@{accountId}</p>\n </div>\n </div>\n <p className=\"description\">{profile?.description}</p>\n </div>\n {state.showEditProfile ? (\n <>\n <Widget\n src=\"zahidulislam.near/widget/Profile.Editor\"\n props={{ showEditProfile }}\n />\n <button\n style={{ marginBottom: 20 }}\n onClick={() => {\n State.update({\n showEditProfile: false,\n });\n }}\n >\n Cancel\n </button>\n </>\n ) : (\n <>\n <Widget\n src=\"zahidulislam.near/widget/Profile.SocialLinks\"\n props={{ profile }}\n />\n <button\n onClick={() => {\n State.update({\n showEditProfile: true,\n });\n }}\n >\n Edit Profile\n </button>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10 }}>\n <Widget src=\"mob.near/widget/FollowStats\" props={{ accountId }} />\n <Widget\n src=\"zahidulislam.near/widget/Profile.IconButton\"\n props={{\n icon: \"https://cdn-icons-png.flaticon.com/512/3179/3179068.png\",\n label: profile?.location ?? \"Add Location\",\n }}\n />\n </div>\n </>\n )}\n </div>\n </Theme>\n);\n" }, "page.explore": { "": "const [path, setPath] = useState(\"\");\nconst [accounts, setAccounts] = useState([]);\n// Function to handle updates based on predefined queries\nconst handleQueryChange = (query) => {\n const value = Social.get(query, \"final\");\n const accountsFromQuery = Object.keys(value);\n setAccounts(accountsFromQuery);\n setPath(query);\n};\nconst handlePathUpdate = (newPath) => {\n setPath(newPath);\n};\nreturn (\n <div className=\"container mt-3 p-3 border bg-light\">\n <div className=\"row\">\n <h1>Hyperfiles Explorer</h1>\n <p>\n <i>\n *View the\n <a href=\"https://opencann.notion.site/Hyperfiles-52cdfb892aff4d0ebe2178436c5edf6d\">\n docs\n </a>\n to learn more about how Hyperfiles data structures work.\n </i>\n </p>\n <p>\n <ul>\n <li>\n Search for fields, schemas, types, profiles, and other content\n metadata.\n </li>\n <li>\n Explore the network of related entities (data + creators) and\n actions (references + jobs).\n </li>\n </ul>\n </p>\n <hr />\n </div>\n <h2>Explore Social Graphs</h2>\n <div style={{ flex: 1 }}>\n <Widget src=\"hyperbuild.near/widget/explore.view.graph\" props={{}} />\n </div>\n <h2>Explore Data</h2>\n <div>\n <div>\n <Widget\n src=\"hyperbuild.near/widget/explore.view.path\"\n props={{\n path: \"hyperfiles.near/type/**\",\n }}\n />\n </div>\n </div>\n <h2>Explore Types</h2>\n <div style={{ display: \"flex\", flexDirection: \"row\" }}>\n <div style={{ flex: 1 }}>\n <Widget src=\"hyperbuild.near/widget/explore.types\" />\n </div>\n </div>\n </div>\n);\n" }, "create.thing": { "": "const item = props.item;\nconst onChange = props.onChange;\nconst Input = styled.input`\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n text-transform: lowercase !important;\n padding: 8px;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Label = styled.label``;\nState.init({\n ...item.value,\n});\nconst DynamicInput = ({ type, onChange, value, placeholder }) => {\n if (type === \"boolean\") {\n return (\n <Select onChange={onChange} value={value}>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </Select>\n );\n } else {\n return (\n <Input\n type={type}\n onChange={onChange}\n value={value}\n placeholder={placeholder}\n />\n );\n }\n};\n// Primitive checks\nif ([\"string\", \"number\", \"date\", \"time\", \"boolean\"].includes(item.type)) {\n return (\n <DynamicInput\n type={item.type === \"string\" ? \"text\" : item.type}\n onChange={onChange}\n value={item.value}\n />\n );\n}\n// On-chain Type\nconst type = JSON.parse(Social.get(item.type, \"final\") || \"null\");\nconst properties = type.properties || [];\nconst createWidgetSrc = type.widgets?.create;\nconst handleInputChange = (name, value) => {\n State.update({ [name]: value });\n if (props.onChange) {\n props.onChange({ [name]: value });\n }\n};\nfunction Property({ property, value }) {\n // If property is multiple values\n if (property.isMulti === \"true\") {\n // Build an array (recursively calls this Widget)\n return (\n <Widget\n src=\"efiz.near/widget/every.array.build\"\n props={{\n item: { ...property, value },\n onChange: (val) => handleInputChange(property.name, val),\n }}\n />\n );\n }\n // Else check for primitives\n if ([\"string\", \"number\", \"date\", \"time\", \"boolean\"].includes(property.type)) {\n return (\n <DynamicInput\n type={property.type === \"string\" ? \"text\" : property.type}\n onChange={(e) => handleInputChange(property.name, e.target.value)}\n value={state[property.name] || \"\"}\n placeholder={property.name}\n />\n );\n } else {\n // This requires a specific type of creator\n // (like image upload)\n // TODO: I don't think this does what I want it to yet...\n const propertyType = JSON.parse(\n Social.get(property.type, \"final\") || \"null\"\n );\n const widgetSrc = propertyType?.widgets?.create;\n // it would be great to modify the onChange function\n return (\n <Widget\n src={widgetSrc}\n props={{ onChange: (e) => handleInputChange(property.name, e) }}\n />\n );\n }\n}\nreturn (\n <Container>\n {createWidgetSrc ? (\n <>\n <Widget src={createWidgetSrc} props={{ onChange }} />\n </>\n ) : (\n <>\n {properties?.map((property) => (\n <div key={property.name}>\n <Label>{property.name}</Label>\n <Row>\n <Property property={property} value={item.value[property.name]} />\n </Row>\n </div>\n ))}\n </>\n )}\n </Container>\n);\n" }, "explore.view.tree": { "": "const labelStyles = {\n fontFamily: \"Arial, sans-serif\",\n fontSize: \"1.2em\", // Slightly larger font size\n fontWeight: \"bold\", // Bold text\n marginRight: \"10px\",\n};\n/**\n * Takes in a rootPath and rootType\n */\nconst rootPath = props.rootPath || context.accountId || \"hyperfiles.near\";\nconst rootType = props.rootType || \"account\";\nconst rootNode = props.rootNode || {};\nconst [inputValue, setInputValue] = useState(\"\");\nState.init({\n path: rootPath,\n type: rootType,\n history: [rootPath],\n});\nfunction setPath(path) {\n State.update({ path });\n}\nfunction setHistory(history) {\n State.update({ history });\n}\nfunction setType(type) {\n State.update({ type });\n}\nfunction setRoot(newPath, newType) {\n State.update({\n path: newPath,\n type: newType,\n });\n}\nconst handleInputChange = (event) => {\n setInputValue(event.target.value);\n};\nconst handleExploreClick = () => {\n setPath(inputValue); // Assuming setPath updates the state as needed\n};\n// WHEN A NEW ROOT IS SET //\n// GET DATA AT THIS PATH //\nfunction getNode(path, type) {\n const parts = path.split(\"/\");\n let value = {};\n // ACCOUNT //\n if (type === \"account\") {\n if (parts.length > 1) {\n // GRAPH // FOLLOW // BACK TO ACCOUNT : WORKING\n setRoot(parts[3], \"account\");\n } else {\n if (parts[0] !== \"*\") {\n parts.push(\"**\");\n }\n value = Social.get(parts.join(\"/\"), \"final\");\n return value;\n }\n // THING //\n } else if (type === \"thing\") {\n // path: \"everything\"\n // type: \"thing\"\n return rootNode; // Or should \"everything\" be \"*\"?\n // PROFILE //\n } else if (type === \"profile\") {\n value = Social.get(parts.join(\"/\"), \"final\");\n // POST : WIP //\n } else if (type === \"post\") {\n value = path;\n // NAMETAG : WIP //\n } else if (type === \"nametag\") {\n if (parts.length > 2) {\n if (parts.length === 3) {\n // BACK TO ACCOUNT\n setRoot(parts[3], \"account\");\n } else if (parts.length === 4) {\n // ALL TAGS BY ACCOUNT\n value = Social.keys(`${parts[0]}/profile/tags/*`, \"final\");\n } else {\n // THIS TAG\n value = parts[5];\n }\n }\n } else {\n parts.push(\"**\");\n value = Social.get(parts.join(\"/\"), \"final\");\n return value;\n }\n}\nconst node = getNode(state.path, state.type);\nreturn (\n <div className=\"p-3 border bg-light\">\n <label htmlFor=\"pathInput\" style={labelStyles}>\n Enter Profile Account ID:\n </label>\n <div style={{ display: \"flex\", alignItems: \"center\" }}>\n <input\n id=\"pathInput\"\n type=\"text\"\n value={inputValue}\n onChange={handleInputChange}\n placeholder=\"e.g. hyperfiles.near\"\n />\n <button onClick={handleExploreClick}>Load Data Tree</button>\n </div>\n <hr />\n <Widget\n src=\"hyperbuild.near/widget/explore.view.node\"\n props={{\n label: state.path,\n node,\n type: state.type,\n path: state.path,\n setPath: setPath,\n history: state.history,\n setHistory: setHistory,\n setType: setType,\n isRoot: true,\n styles: {\n subject: {\n fontFamily: \"Arial, sans-serif\",\n fontSize: \"2em\",\n lineHeight: \"1.25\",\n fontWeight: 300,\n cursor: \"pointer\",\n },\n },\n }}\n />\n </div>\n);\n" }, "profile.links": { "": "const accountId = props.accountId ?? context.accountId;\nconst profile = props.profile ?? Social.getr(`${accountId}/profile`);\nconst linktree = profile.linktree;\nreturn (\n <div className=\"socialLinks\">\n {linktree &&\n Object.entries(linktree)?.map(([name, value], index) => (\n <>\n {(name === \"twitter\" && (\n <a\n className=\"socialIcon\"\n href={`https://twitter.com/${value}`}\n target=\"_blank\"\n >\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/733/733635.png\"\n alt=\"twitter\"\n />\n </a>\n )) ||\n (name === \"github\" && (\n <a\n className=\"socialIcon\"\n href={`https://github.com/${value}`}\n target=\"_blank\"\n >\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/2111/2111425.png\"\n alt=\"github\"\n />\n </a>\n )) ||\n (name === \"telegram\" && (\n <a\n className=\"socialIcon\"\n href={`https://t.me/${value}`}\n target=\"_blank\"\n >\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/2111/2111708.png\"\n alt=\"telegram\"\n />\n </a>\n )) ||\n (name === \"website\" && (\n <a className=\"socialIcon\" href={value} target=\"_blank\">\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/1006/1006771.png\"\n alt=\"website\"\n />\n </a>\n ))}\n </>\n ))}\n </div>\n);\n" }, "tools.local.register": { "": "//props:\n//onRegisterComplete(secretKeyBase64)\nconst accountId = context.accountId;\nif (!accountId) {\n return \"Please sign in with NEAR wallet\";\n}\nif (!props.onRegisterComplete) {\n return \"send onRegisterComplete in props\";\n}\nconst registeredPublicKeyBase64 = Social.get(\n `${accountId}/private_message/public_key`\n);\nif (registeredPublicKeyBase64 === null) return \"Loading\";\nfunction randomKeyPairBase64() {\n const keyPair = nacl.box.keyPair();\n return {\n secretKey: Buffer.from(keyPair.secretKey).toString(\"base64\"),\n publicKey: Buffer.from(keyPair.publicKey).toString(\"base64\"),\n };\n}\nconst keyPair = randomKeyPairBase64();\nState.init({\n registeredPublicKeyBase64,\n secretKeyBase64: keyPair.secretKey,\n publicKeyBase64: keyPair.publicKey,\n});\nreturn (\n <div>\n {registeredPublicKeyBase64 && (\n <div class=\"mb-3\">\n {\n \"You're already registered. If your key is compromised you can re-register, but will lose access to old messages.\"\n }\n </div>\n )}\n <div class=\"mb-3\">\n <label for=\"inputSercetKey\" class=\"form-label\">\n Secret key:\n </label>\n <div class=\"mb-3 input-group\">\n <input\n type=\"text\"\n value={state.secretKeyBase64}\n class=\"form-control\"\n readonly=\"\"\n />\n <button\n class=\"btn btn-outline-primary\"\n disabled={state.registeredProsessing}\n onClick={() => {\n const keyPair = randomKeyPairBase64();\n //re-render\n State.update({\n secretKeyBase64: keyPair.secretKey,\n publicKeyBase64: keyPair.publicKey,\n });\n }}\n >\n Generate Random Key\n </button>\n </div>\n </div>\n <div class=\"mb-3 form-check\">\n <input\n onClick={() => {\n State.update({\n checkboxSaveSecretKey: !state.checkboxSaveSecretKey,\n });\n }}\n defaultChecked={state.checkboxSaveSecretKey}\n class=\"form-check-input\"\n type=\"checkbox\"\n id=\"flexCheckDefault\"\n />\n <label class=\"form-check-label\" for=\"flexCheckDefault\">\n <b>I SAVED MY SECRET KEY</b>\n </label>\n </div>\n <CommitButton\n disabled={!state.checkboxSaveSecretKey}\n onClick={() => {\n State.update({ processedSecretKey: state.secretKeyBase64 });\n }}\n onCommit={() => {\n State.update({\n registeredProsessing: false,\n });\n props.onRegisterComplete(state.processedSecretKey);\n }}\n data={{ private_message: { public_key: state.publicKeyBase64 } }}\n >\n Register\n </CommitButton>\n </div>\n);\n" }, "tools.files.index": { "": "const Container = styled.div`\n display: flex;\n height: 100vh;\n width: 100%;\n`;\nconst MainContent = styled.div`\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n`;\nfunction Header({ path, goBack, goForward, setLayout, togglePreview }) {\n return (\n <Widget\n src=\"fastvault.near/widget/voyager.header.index\"\n props={{\n path,\n goBack,\n goForward,\n setLayout,\n togglePreview,\n }}\n />\n );\n}\nfunction Content({\n layout,\n path,\n setPath,\n setFilesSource,\n showPreview,\n selectedPath,\n setSelectedPath,\n decryptSk, // Ensure decryptSk is passed here\n}) {\n return (\n <Widget\n src=\"hyperbuild.near/widget/tools.files.content\"\n props={{\n layout,\n path,\n setPath,\n setFilesSource,\n showPreview,\n selectedPath,\n setSelectedPath,\n decryptSk, // Ensure decryptSk is passed here\n }}\n />\n );\n}\nfunction Sidebar({ setPath, setFilesSource, setHistory }) {\n return (\n <Widget\n src=\"fastvault.near/widget/voyager.sidebar.index\"\n props={{\n path,\n setPath,\n setFilesSource,\n setHistory,\n }}\n />\n );\n}\nreturn (\n <Widget\n src=\"hyperbuild.near/widget/tools.files.provider\"\n props={{\n path: props.path,\n setFilesSource: props.setFilesSource,\n Children: (p) => (\n <Container>\n <Sidebar {...p} />\n <MainContent>\n <Header {...p} />\n <Content {...p} />\n </MainContent>\n </Container>\n ),\n }}\n />\n);\n" }, "explore.select.type": { "": "const Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Button = styled.button``;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Select = styled.select``;\nconst Label = styled.label``;\nconst Input = styled.input``;\nconst initialTypeSrc = props.typeSrc || \"hyperfiles.near\";\nconst [newTypeSrc, setNewTypeSrc] = useState(initialTypeSrc);\nconst [typeSrc, setTypeSrc] = useState(initialTypeSrc);\nconst [selectedType, setSelectedType] = useState(props.selectedType || \"\");\nconst [availableTypes, setAvailableTypes] = useState([]);\nconst [isLoading, setIsLoading] = useState(true);\nconst [fetchedData, setFetchedData] = useState({}); // State for debugging\nuseEffect(() => {\n setIsLoading(true);\n const fetchTypesList = () => {\n const query = typeSrc === \"*\" ? \"*/type/**\" : `${typeSrc}/type/**`;\n const types = Social.get(query, \"final\");\n setFetchedData(types); // Store raw data for debugging\n if (types) {\n let typesSet = new Set();\n if (typeSrc === \"*\") {\n // Collect types from all fetched data\n Object.values(types).forEach((accountTypes) => {\n Object.values(accountTypes).forEach((typeObj) => {\n Object.keys(typeObj).forEach((typeName) => {\n typesSet.add(typeName);\n });\n });\n });\n } else {\n // Types from a specific account\n Object.keys(types).forEach((key) => typesSet.add(key));\n }\n setAvailableTypes(Array.from(typesSet));\n } else {\n setAvailableTypes([]);\n }\n setIsLoading(false);\n };\n fetchTypesList();\n}, [typeSrc]);\nuseEffect(() => {\n setSelectedType(props.selectedType);\n}, [props.selectedType]);\nconst handleTypeChange = (event) => {\n setSelectedType(event.target.value);\n if (props.onSelectedTypeChange) {\n props.onSelectedTypeChange(event.target.value);\n }\n};\nconst handleTypeSrcChange = (event) => {\n setNewTypeSrc(event.target.value);\n};\nconst applyTypeSrc = () => {\n setTypeSrc(newTypeSrc);\n};\nconst showAllTypes = () => {\n setTypeSrc(\"*\");\n};\nreturn (\n <FormContainer>\n <Label>Import Type for Editing:</Label>\n <Row>\n <Input\n type=\"text\"\n value={state.newType}\n onChange={(e) => State.update({ newType: e.target.value })}\n placeholder={\"accountId/type/Type\"}\n />\n <Button onClick={loadType}>load</Button>\n </Row>\n <Label>Import Property Types:</Label>\n <Row>\n <Input\n type=\"text\"\n onChange={handleTypeSrcChange}\n value={newTypeSrc}\n placeholder=\"accountId\"\n />\n <Button onClick={applyTypeSrc}>Apply</Button>\n </Row>\n <Label>Select Type to Edit:</Label>\n <Row>\n {isLoading ? (\n <div>Loading...</div>\n ) : (\n <Select value={selectedType} onChange={handleTypeChange}>\n <option value=\"\">Choose a type</option>\n {availableTypes.map((type) => (\n <option key={type} value={type}>\n {type}\n </option>\n ))}\n </Select>\n )}\n <p />\n <Button onClick={showAllTypes}>Show All</Button>\n </Row>\n </FormContainer>\n);\n// <pre>{JSON.stringify(fetchedData, null, 2)}</pre> {/* Debug output */}\n" }, "create.metadata": { "": "const Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nfunction CreateMetadata({ name, setName, description, setDescription }) {\n return (\n <Form>\n <h3>Metadata</h3>\n <FormGroup>\n <Label>Name</Label>\n <Input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </FormGroup>\n <FormGroup>\n <Label>Description</Label>\n <textarea\n className=\"form-control mb-3\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n />\n </FormGroup>\n <FormGroup>\n <Label>Tags</Label>\n <Widget src=\"mob.near/widget/TagsEditor\" />\n </FormGroup>\n </Form>\n );\n}\n\nreturn { CreateMetadata };\n" }, "config.app": { "": "return {\n type: \"app\",\n routes: {\n home: {\n path: \"hyperbuild.near/widget/page.home\",\n blockHeight: \"final\",\n init: {\n name: \"Home\",\n },\n },\n create: {\n path: \"hyperbuild.near/widget/page.create\",\n blockHeight: \"final\",\n init: {\n name: \"Create\",\n },\n },\n explore: {\n path: \"hyperbuild.near/widget/page.explore\",\n blockHeight: \"final\",\n init: {\n name: \"Explore\",\n },\n },\n profile: {\n path: \"hyperbuild.near/widget/page.profile\",\n blockHeight: \"final\",\n init: {\n name: \"Profile\",\n },\n },\n tools: {\n path: \"hyperbuild.near/widget/page.tools\",\n blockHeight: \"final\",\n init: {\n name: \"Tools\",\n },\n },\n },\n};\n" }, "page.create": { "": "const { DataCreator } = VM.require(\"hyperbuild.near/widget/create.data\");\nconst { CreateHyperfile } = VM.require(\n \"hyperbuild.near/widget/create.hyperfiles\"\n);\n//const { GitHubAPIExample } = VM.require( \"create.near/widget/GitHub.API.Example\");\nconst { CreateMetadata } = VM.require(\"hyperbuild.near/widget/create.metadata\");\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Button = styled.button``;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst [rawData, setRawData] = useState(\"\");\nconst [source, setSource] = useState(\"\");\nconst [schema, setSchema] = useState(\"\");\nconst [adapter, setAdapter] = useState(\"\");\nconst [reference, setReference] = useState(undefined);\nconst [activeTab, setActiveTab] = useState(\"content\");\nconst [name, setName] = useState(props.name ?? \"\");\nconst [description, setDescription] = useState(props.description ?? \"\");\nconst [hyperfile, setHyperfile] = useState(\"\");\nconst [type, setType] = useState(\"\");\nconst [filePath, setFilePath] = useState(null);\nconst [defaultView, setDefaultView] =\n useState(\"HYPERFILE\") || props.defaultView;\nfunction generateUID() {\n const maxHex = 0xffffffff;\n const randomNumber = Math.floor(Math.random() * maxHex);\n return randomNumber.toString(16).padStart(8, \"0\");\n}\nconst handleCreate = () => {\n if (create) {\n console.log(\"it's something\", rawData);\n // store the data somewhere, based on the adapter\n create(rawData).then((reference) => {\n // now we have a reference to the data\n const thingId = generateUID();\n const hyperfile = {\n thing: {\n // which we store in the social contract\n [thingId]: {\n \"\": JSON.stringify({\n source: source,\n adapter: adapter,\n reference: reference,\n }),\n metadata: {\n name: name,\n description: description,\n schema: schema,\n },\n },\n },\n };\n setHyperfile(JSON.stringify(hyperfile, null, 2));\n });\n } else {\n console.log(\"invalid adapter\");\n }\n};\nconsole.log(\"source: \", source);\nconsole.log(\"schema: \", schema);\nconsole.log(\"data: \", rawData);\nconsole.log(\"adapter: \", adapter);\nreturn (\n <div className=\"container mt-3 p-3 border bg-light\">\n <div className=\"row\">\n <h1>Hyperfiles Creator</h1>\n <p>\n <i>\n *View the\n <a href=\"https://opencann.notion.site/Hyperfiles-52cdfb892aff4d0ebe2178436c5edf6d\">\n docs\n </a>\n to learn more about how Hyperfiles data structures work.\n </i>\n </p>\n <p>\n <ul>\n <li>\n Publish structured data objects, attest (add references) to data and\n reference objects, and run jobs (coming soon).\n </li>\n <li>\n Each schema contains an ordered list of types that describes the\n structure of corresponding data objects.\n </li>\n <li>\n Common types & schemas compose into a graph of related entities\n (data + creators) and actions (references + jobs).\n </li>\n </ul>\n </p>\n <hr />\n </div>\n <Row style={{ gap: \"10px\", marginBottom: \"16px\" }}>\n <h2>Create</h2>{\" \"}\n <Select\n value={state.defaultView}\n onChange={(e) => setDefaultView(e.target.value)}\n >\n <option value=\"HYPERFILE\">Data Object</option>\n <option value=\"ATTESTATION\">Attestation</option>\n <option value=\"SCHEMA\">Schema</option>\n <option value=\"TYPE\">Type</option>\n <option value=\"JOB\">Job</option>\n </Select>\n </Row>\n <ul className=\"nav nav-tabs\">\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"content\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"content\")}\n >\n Content\n </a>\n </li>\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"metadata\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"metadata\")}\n >\n Metadata\n </a>\n </li>\n </ul>\n <div className=\"row\">\n <TabContent>\n {defaultView === \"HYPERFILE\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.hyperfile\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"ATTESTATION\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.reference\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"SCHEMA\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.edit.schema\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"TYPE\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.edit.type\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"JOB\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.job\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n </div>\n </div>\n);\n" }, "tools.files.module.crypto": { "": "// Uint8Array -> Array\nconst array2buf = (array) => Array.from(array);\n// Uint8Array -> str\nconst arr2str = (array) => {\n var result = \"\";\n for (var i = 0; i < array.length; i++) {\n result += String.fromCharCode(array[i]);\n }\n return result;\n};\n// str -> Uint8Array\nconst str2array = (str) => {\n return new Uint8Array(Array.from(str).map((letter) => letter.charCodeAt(0)));\n};\n// accountId: str, password: str\nconst newSecretKey = (accountId, password) => {\n const hashed_id = nacl.hash(str2array(accountId));\n const hashed_pw = nacl.hash(str2array(password));\n const sk = new Uint8Array(nacl.secretbox.keyLength);\n for (var i = 0; i < hashed_id.length; i++) {\n const sk_i = i % sk.length;\n if (i >= sk.length) {\n sk[sk_i] = sk[sk_i] + (hashed_id[i] + hashed_pw[i]);\n } else {\n sk[sk_i] = hashed_id[i] + hashed_pw[i];\n }\n }\n return sk;\n};\nconst newNonce = (message) => {\n const hash = nacl.hash(message);\n const nonce = new Uint8Array(nacl.secretbox.nonceLength);\n for (var i = 0; i < hash.length; i++) {\n const n_i = i % nonce.length;\n if (i >= nonce.length) {\n nonce[n_i] += hash[i];\n } else {\n nonce[n_i] = i & hash[i];\n }\n }\n return nonce;\n};\n// message: Uint8Array\nconst encrypt = (message, storageSk) => {\n const nonce = newNonce(message);\n const ciphertext = nacl.secretbox(message, nonce, storageSk);\n return {\n nonce: Array.from(nonce),\n ciphertext: Array.from(ciphertext),\n };\n};\n// message: str\nconst encryptStr = (text, storageSk) => {\n return encrypt(str2array(text), storageSk);\n};\n// message: JS Object\nconst encryptObject = (obj, storageSk) => {\n return encrypt(str2array(JSON.stringify(obj)), storageSk);\n};\n// nonce: Uint8Array\n// ciphertext: Uint8Array\n// storageSk: Uint8Array\nconst decrypt = (nonce, ciphertext, storageSk) => {\n return nacl.secretbox.open(ciphertext, nonce, storageSk);\n};\n// message: JS Object\nconst decryptObject = (nonce, ciphertext, storageSk) => {\n return JSON.parse(arr2str(decrypt(nonce, ciphertext, storageSk)));\n};\nreturn {\n encrypt,\n encryptStr,\n encryptObject,\n decrypt,\n decryptObject,\n newSecretKey,\n};\n" }, "page.home": { "": "const { currentPath, page, ...passProps } = props;\nconst NavbarHeight = 70; // Assumed height of the Navbar\nconst Card3D = styled.div`\n perspective: 2000px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n`;\nconst ScaleUp = {\n transform: \"scale(1.5)\", // Scale up by 25%\n paddingTop: `${NavbarHeight}px`, // Ensure content starts below the navbar\n marginTop: `-${NavbarHeight * 2}px`, // Offset the padding\n boxSizing: \"border-box\", // Include padding in the element's total width and height\n};\nconst CardContent = styled.div`\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n background-color: #fff;\n color: #000;\n padding: 2rem;\n`;\nconst Container = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n margin-top: 1rem;\n`;\nconst Tagline = styled.p`\n text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5), 2px 2px 2px rgba(0, 0, 0, 0.3);\n text-align: right; /* Right align the tagline */\n width: 100%;\n`;\nconst MainButton = styled.button`\n margin: 0.3em;\n text-decoration: none;\n`;\nconst { href } = VM.require(\"buildhub.near/widget/lib.url\") || {\n href: () => {},\n};\nconst ButtonLink = ({ to, children }) => (\n <Link\n key={to}\n style={{ textDecoration: \"none\" }}\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: to,\n },\n })}\n >\n {children}\n </Link>\n);\nreturn (\n <div className=\"vh-100 w-100\">\n <Card3D>\n <CardContent style={ScaleUp}>\n <h1\n className=\"display-4 font-weight-bold text-black mb-2\"\n style={{\n textShadow:\n \"1px 1px 1px rgba(0, 0, 0, 0.5), 4px 4px 4px rgba(0, 0, 0, 0.3)\",\n }}\n >\n hyperfiles\n </h1>\n <Tagline className=\"h5 text-success mb-4\">organize everything</Tagline>\n <Container>\n <ButtonLink to={\"create\"}>\n <MainButton key={\"create\"} variant={page === \"create\" && \"primary\"}>\n Create\n </MainButton>\n </ButtonLink>\n <ButtonLink to={\"explore\"}>\n <MainButton\n key={\"explore\"}\n variant={page === \"explore\" && \"primary\"}\n >\n Explore\n </MainButton>\n </ButtonLink>\n <ButtonLink to={\"tools\"}>\n <MainButton key={\"tools\"} variant={page === \"tools\" && \"primary\"}>\n Tools\n </MainButton>\n </ButtonLink>\n </Container>\n <Container>\n <div style={{ marginTop: \"1rem\", width: \"100%\" }}>\n <Widget\n src=\"hyperbuild.near/widget/profile.links\"\n props={{ accountId: \"hyperfiles.near\" }}\n />\n </div>\n </Container>\n </CardContent>\n </Card3D>\n </div>\n);\n" }, "explore.select.schema.array": { "": "const defaultOptions = [\n { name: \"Markdown\" },\n { name: \"JSON\" },\n { name: \"Other\" },\n];\n\nconst schemaPattern = props.schemaPattern ?? \"*/schema/*\";\nconst placeholder = props.placeholder ?? \"Schema\";\nconst initialSchemaObject = props.initialSchemaObject || {};\n\nconst schemaObject = Social.keys(schemaPattern, \"final\");\n\nif (schemaObject === null) {\n return \"Loading\";\n}\n\nconst normalizeProf = (prof) =>\n prof\n .replaceAll(/[- \\.]/g, \"_\")\n .replaceAll(/[^\\w]+/g, \"\")\n .replaceAll(/_+/g, \"-\")\n .replace(/^-+/, \"\")\n .replace(/-+$/, \"\")\n .toLowerCase()\n .trim(\"-\");\n\nconst schemaCount = {};\n\nconst processSchemaObject = (obj) => {\n Object.entries(obj).forEach(([key, value]) => {\n if (typeof value === \"object\") {\n processSchemaObject(value);\n } else {\n const prof = normalizeProf(key);\n schemaCount[prof] = (schemaCount[prof] || 0) + 1;\n }\n });\n};\n\nconst getSchema = () => {\n processSchemaObject(schemaObject);\n const schema = Object.entries(schemaCount);\n schema.sort((a, b) => b[1] - a[1]);\n return schema.map((t) => ({ name: t[0], count: t[1] }));\n};\n\nif (!state.allSchema) {\n initState({\n allSchema: getSchema().length > 0 ? getSchema() : schemaArray || [], // Fallback to empty array if schemaArray is undefined\n schema: Object.keys(initialSchemaObject).map((prof) => ({\n name: normalizeProf(prof),\n })),\n originalSchema: Object.fromEntries(\n Object.keys(initialSchemaObject).map((prof) => [prof, null])\n ),\n id: `schema-selector-${Date.now()}`,\n });\n}\n\nconst setSchema = (schema) => {\n schema = schema.map((o) => ({ name: normalizeProf(o.name) }));\n State.update({ schema });\n if (props.setSchemaObject) {\n props.setSchemaObject(\n Object.assign(\n {},\n state.originalSchema,\n Object.fromEntries(schema.map((prof) => [prof.name, \"\"]))\n )\n );\n }\n};\n\nreturn (\n <>\n <Typeahead\n id={state.id}\n labelKey=\"name\"\n onChange={setSchema}\n options={state.allSchema}\n placeholder={placeholder}\n selected={state.schema}\n positionFixed\n allowNew\n />\n {props.debug && (\n <div>\n Debugging schema:\n <pre>{JSON.stringify(state.schema)}</pre>\n </div>\n )}\n </>\n);\n" }, "create.new": { "": "const { NewThings } = VM.require(\"hyperbuild.near/widget/create.newthings\");\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst FormGroup = styled.div`\n margin-bottom: 10px;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Select = styled.select`\n height: 30px;\n margin-bottom: 10px;\n`;\nconst Button = styled.button`\n height: 30px;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n margin-top: 10px;\n`;\nconst Row = styled.div`\n display: flex;\n gap: 10px;\n`;\n// Initializing state and utility functions\nconst CreateNew = ({ initialData = {}, types, schemas }) => {\n const [data, setData] = useState(initialData);\n const [selectedTypeOrSchema, setSelectedTypeOrSchema] = useState(\"\");\n // Load available types or schemas\n const options = { ...types, ...schemas }; // Merging types and schemas into a single object\n const handleTypeOrSchemaChange = (e) => {\n setSelectedTypeOrSchema(e.target.value);\n setData({}); // Reset data when type or schema changes\n };\n const handleChange = (newData) => {\n setData(newData);\n };\n const handleSave = () => {\n console.log(\"Saving data:\", data);\n // Implement save functionality here\n };\n return (\n <Container>\n <FormGroup>\n <Label>Select Type or Schema:</Label>\n <Select\n value={selectedTypeOrSchema}\n onChange={handleTypeOrSchemaChange}\n >\n <option value=\"\">Select an option</option>\n {Object.keys(options).map((key) => (\n <option key={key} value={key}>\n {key}\n </option>\n ))}\n </Select>\n </FormGroup>\n {selectedTypeOrSchema && (\n <FormContainer>\n <NewThings\n item={{ type: options[selectedTypeOrSchema], value: data }}\n onChange={handleChange}\n />\n <Row>\n <Button onClick={handleSave}>Save</Button>\n </Row>\n </FormContainer>\n )}\n </Container>\n );\n};\nexport { CreateNew };\n" }, "create.data": { "": "const DataCreator = ({ initialData, onCreation, adapters, schema }) => {\n const [data, setData] = useState(initialData);\n const [selectedAdapter, setAdapter] = useState(adapters[0].value);\n\n const handleInputChange = (name, value) => {\n setData((prev) => ({ ...prev, [name]: value }));\n };\n\n const createData = async () => {\n const adapterScript = VM.require(selectedAdapter);\n const reference = await adapterScript.create(data);\n onCreation(reference);\n };\n\n return (\n <Form>\n {Object.entries(schema.properties).map(([name, spec]) => (\n <FormGroup key={name}>\n <Label>{spec.label}</Label>\n <Input\n type={spec.type}\n value={data[name]}\n onChange={(e) => handleInputChange(name, e.target.value)}\n />\n </FormGroup>\n ))}\n <Button onClick={createData}>Create</Button>\n </Form>\n );\n};\n" }, "create.hyperfiles": { "": "const Wrapper = styled.div`\n max-width: 400px;\n margin: 0 auto;\n`;\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Button = styled.button``;\nfunction CreateHyperfile(props) {\n // Initialize state\n let newSchemaSrc = props.schemaSrc || \"hyperfiles.near\";\n let schemaSrc = newSchemaSrc;\n let availableSchemas = [];\n let isLoading = true;\n let selectedSchema = props.selectedSchema || \"hyperfiles.near/schema/test\";\n let source = props.source || \"\";\n let adapter = props.adapters ? props.adapters[0].value : \"\";\n let reference = undefined;\n let filename = props.filename || \"\";\n let activeTab = \"data\";\n let name = props.name || \"\";\n let description = props.description || \"\";\n let json = props.data || \"\";\n let data = props.data || {};\n let hyperfile = \"\";\n // Functions to handle state changes\n function setState(newState) {\n Object.assign(state, newState);\n render();\n }\n function handleOnChange(value) {\n setState({ data: { ...state.data, ...value } });\n }\n function handleSchemaSrcChange(newSchemaSrc) {\n setState({ schemaSrc: newSchemaSrc, selectedSchema: \"\" });\n }\n function handleSelectedSchemaChange(newValue) {\n setState({ selectedSchema: newValue });\n }\n function handleThingUpdate(newData) {\n console.log(\"Thing Data Updated:\", newData);\n }\n function generateUID() {\n return (\n Math.random().toString(16).slice(2) +\n Date.now().toString(36) +\n Math.random().toString(16).slice(2)\n );\n }\n function handleCreate() {\n const isCreator = context.accountId === props.creatorId;\n const { create } = VM.require(adapter) || (() => {});\n if (create) {\n create(json).then((reference) => {\n const thingId = filename || generateUID();\n const hyperfileData = {\n [props.type]: {\n [thingId]: {\n \"\": JSON.stringify({\n schema: schema,\n source: source,\n adapter: adapter,\n reference: reference,\n metadata: {\n name: name,\n description: description,\n type: props.type,\n },\n }),\n },\n },\n };\n if (creatorId !== context.accountId) {\n hyperfileData.index = {\n notify: JSON.stringify({\n key: creatorId,\n value: {\n type: \"request\",\n data: {\n type: \"merge\",\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n origin: `${context.accountId}/${props.type}/${thingId}`,\n },\n },\n }),\n };\n hyperfileData[props.type][thingId].metadata = {\n ...hyperfileData[props.type][thingId].metadata,\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n };\n }\n hyperfile = JSON.stringify(hyperfileData);\n Social.set(hyperfileData, { force: true });\n });\n }\n }\n // Rendering function\n function render() {\n return (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Data</h3>\n <FormGroup>\n <Label>Source</Label>\n <Widget\n src={`hyperbuild.near/widget/profile.metadataEditor`}\n props={{\n initialMetadata: profile,\n onChange: (newValue) => {\n setSource(newValue);\n State.update({\n profile: { ...profile, source: newValue },\n });\n },\n value: source,\n options: {\n source: {\n sourcePattern: \"*/profile/source/*\",\n placeholder: \"Select a source\",\n },\n },\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Schema</Label>\n <p>{JSON.stringify(selectedSchema)}</p>\n <Widget\n src={`hyperbuild.near/widget/explore.select.schema`}\n props={{\n onSchemaSrcChange: handleSchemaSrcChange,\n onSelectedSchemaChange: handleSelectedSchemaChange,\n selectedSchema: selectedSchema,\n schemaSrc: schemaSrc,\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Input Your Data</Label>\n <FormContainer>\n <Widget\n src={`hyperbuild.near/widget/create.thing`}\n props={{\n item: {\n type: selectedSchema,\n value: data,\n },\n onChange: handleOnChange,\n }}\n />\n </FormContainer>\n </FormGroup>\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Storage</h3>\n <FormGroup>\n <Label>Adapter</Label>\n <Select\n value={adapter}\n onChange={(e) => setAdapter(e.target.value)}\n >\n {props.adapters &&\n props.adapters.map((o) => (\n <option key={o.value} value={o.value}>\n {o.title}\n </option>\n ))}\n </Select>\n </FormGroup>\n {rawAdapter && <>{parseAdapter(rawAdapter)}</>}\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <Button\n onClick={handleCreate}\n disabled={!adapter || !schema || !source || !json}\n >\n create reference\n </Button>\n {hyperfile !== \"\" && (\n <>\n <FormGroup>\n <textarea\n className=\"form-control\"\n value={hyperfile}\n disabled\n style={{ width: \"100%\", height: \"400px\" }}\n />\n </FormGroup>\n <Button\n onClick={() =>\n Social.set(JSON.parse(hyperfile), {\n force: true,\n })\n }\n >\n save\n </Button>\n </>\n )}\n </Form>\n </div>\n </div>\n </div>\n );\n }\n // Initial render call\n return render();\n}\nreturn { CreateHyperfile };\n" }, "profile.metadataEditor": { "": "const initialMetadata = props.initialMetadata ?? {};\nconst onChange = props.onChange;\nconst options = props.options;\nState.init({\n initialMetadata,\n metadata: initialMetadata,\n reportedMetadata: initialMetadata,\n linktree: initialMetadata.linktree ?? {},\n image: initialMetadata.image,\n backgroundImage: initialMetadata.backgroundImage,\n source: initialMetadata.source ?? {},\n schema: initialMetadata.schema ?? {},\n});\nconst metadata = {\n name: options.name ? state.metadata.name : undefined,\n description: options.name ? state.metadata.description : undefined,\n linktree:\n options.linktree && Object.keys(state.linktree).length > 0\n ? state.linktree\n : undefined,\n image:\n options.image && state.image && Object.keys(state.image).length > 0\n ? state.image\n : undefined,\n backgroundImage:\n options.backgroundImage &&\n state.backgroundImage &&\n Object.keys(state.backgroundImage).length > 0\n ? state.backgroundImage\n : undefined,\n tags: options.tags ? state.metadata.tags : undefined,\n source: options.source ? state.metadata.source : undefined,\n schema: options.schema ? state.metadata.schema : undefined,\n};\nif (\n onChange &&\n JSON.stringify(state.reportedMetadata) !== JSON.stringify(metadata)\n) {\n State.update({\n reportedMetadata: metadata,\n });\n onChange(metadata);\n}\nconst debounce = (func, wait) => {\n const pause = wait || 350;\n let timeout;\n return (args) => {\n const later = () => {\n clearTimeout(timeout);\n func(args);\n };\n clearTimeout(timeout);\n timeout = setTimeout(later, pause);\n };\n};\nconst onNameChange = debounce((e) => {\n State.update({\n metadata: {\n ...state.metadata,\n name: e.target.value,\n },\n });\n});\nconst onDescriptionChange = debounce((e) => {\n State.update({\n metadata: {\n ...state.metadata,\n description: e.target.value,\n },\n });\n});\nconst onLinkTreeChange = debounce((e) => {\n State.update({\n linktree: {\n ...state.linktree,\n [e.target.id]: e.target.value,\n },\n });\n});\nconst onSkillsChange = debounce((e) => {\n State.update({\n skills: {\n ...state.skills,\n [e.target.id]: e.target.value,\n },\n });\n});\nconst onSourceChange = debounce((e) => {\n State.update({\n source: {\n ...state.source,\n [e.target.id]: e.target.value,\n },\n });\n});\nconst onSchemaChange = debounce((e) => {\n State.update({\n schema: {\n ...state.schema,\n [e.target.id]: e.target.value,\n },\n });\n});\nreturn (\n <>\n {options.name && (\n <div className=\"mb-2\">\n {options.name.label ?? \"Name\"}\n <input\n type=\"text\"\n defaultValue={state.metadata.name}\n onChange={onNameChange}\n />\n </div>\n )}\n {options.image && (\n <div className=\"mb-2\">\n {options.image.label ?? \"Image\"}\n <Widget\n src=\"near/widget/ImageEditorTabs\"\n props={{\n image: state.image,\n onChange: (image) => State.update({ image }),\n }}\n />\n </div>\n )}\n {options.backgroundImage && (\n <div className=\"mb-2\">\n {options.backgroundImage.label ?? \"Background image\"}\n <Widget\n src=\"near/widget/ImageEditorTabs\"\n props={{\n image: state.backgroundImage,\n onChange: (backgroundImage) => State.update({ backgroundImage }),\n debounce,\n }}\n />\n </div>\n )}\n {options.description && (\n <div className=\"mb-2\">\n {options.description.label ?? \"Description\"}\n <span className=\"text-secondary\"> (supports markdown)</span>\n <textarea\n className=\"form-control\"\n rows={5}\n defaultValue={state.metadata.description}\n onChange={onDescriptionChange}\n />\n </div>\n )}\n {options.tags && (\n <div className=\"mb-2\">\n {options.tags.label ?? \"Tags\"}\n <Widget\n src=\"mob.near/widget/TagsEditor\"\n props={{\n initialTagsObject: metadata.tags,\n tagsPattern: options.tags.pattern,\n placeholder:\n options.tags.placeholder ??\n \"rust, engineer, artist, humanguild, nft, learner, founder\",\n setTagsObject: (tags) => {\n state.metadata.tags = tags;\n State.update();\n },\n }}\n />\n </div>\n )}\n {options.source && (\n <div className=\"mb-2\">\n <Widget\n src=\"hyperfiles.near/widget/source.edit\"\n props={{\n initialSourceObject: state.metadata.source,\n sourcePattern: options.source.pattern,\n placeholder: options.source.placeholder ?? \"\",\n setSourceObject: (source) => {\n state.metadata.source = source;\n State.update();\n onChange({ ...state.metadata, source }); // Trigger parent onChange with new metadata\n },\n }}\n />\n </div>\n )}\n {options.schema && (\n <div className=\"mb-2\">\n <Widget\n src=\"hyperfiles.near/widget/schema.array\"\n props={{\n initialSchemaObject: state.metadata.schema,\n schemaPattern: options.schema.pattern,\n placeholder: options.schema.placeholder ?? \"\",\n setSchemaObject: (schema) => {\n state.metadata.schema = schema;\n State.update();\n onChange({ ...state.metadata, schema }); // Trigger parent onChange with new metadata\n },\n }}\n />\n </div>\n )}\n {options.linktree &&\n (options.linktree.links ?? []).map((link) => (\n <div className=\"mb-2\">\n {link.label}\n <div className=\"input-group\">\n <span className=\"input-group-text\">{link.prefix}</span>\n <input\n type=\"text\"\n id={link.name}\n defaultValue={state.linktree[link.name]}\n onChange={onLinkTreeChange}\n />\n </div>\n </div>\n ))}\n </>\n);\n" }, "template.AppLayout": { "": "const StyledButton = styled.button`\n all: unset;\n display: ${(props) => (props.type === \"icon\" ? \"flex\" : \"inline-flex\")};\n width: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n height: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n padding: ${(props) => (props.type === \"icon\" ? \"0\" : \"10px 20px\")};\n justify-content: center;\n align-items: center;\n gap: 4px;\n border-radius: ${(props) => (props.type === \"icon\" ? \"50%\" : \"8px\")};\n font-size: ${(props) => (props.type === \"icon\" ? \"16px\" : \"14px\")};\n font-weight: 600;\n font-family: \"Poppins\", sans-serif;\n background: var(--button-${props.variant}-bg, #23242b);\n color: var(--button-${props.variant}-color, #cdd0d5);\n border: ${(props) =>\n props.variant === \"outline\"\n ? \"1px solid rgba(255, 255, 255, 0.20)\"\n : \"none\"};\n transition: background 300ms, color 300ms;\n\n &:hover:not(:disabled) {\n background: var(--button-${props.variant}-hover-bg, #17181c);\n }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n`;\nconst ContentContainer = styled.div`\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n height: 100%;\n`;\nconst Header = ({ page, routes, ...props }) => (\n <Widget\n src=\"hyperbuild.near/widget/navigation.Navbar\"\n props={{ page, routes, ...props }}\n />\n);\nconst Footer = (props) => {\n return <></>;\n};\nfunction AppLayout({ routes, page, children, ...props }) {\n return (\n <Container>\n <Header page={page} routes={routes} {...props} />\n <ContentContainer key={page}>{children}</ContentContainer>\n <Footer page={page} />\n </Container>\n );\n}\nreturn { AppLayout };\n" }, "tools.files.content": { "": "const Content = styled.div`\n flex: 1;\n padding: 20px;\n background-color: #f9f9f9;\n width: 100%;\n overflow: auto;\n`;\nconst Overlay = styled.div`\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: 50%;\n background-color: #fff;\n`;\nconst Grid = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n @media (min-width: 600px) {\n gap: 20px;\n }\n`;\nconst GridItem = styled.div`\n flex: 1 0 calc(33.333% - 10px);\n @media (min-width: 600px) {\n flex: 1 0 calc(25% - 20px);\n }\n`;\nconst Columns = styled.div`\n display: flex;\n`;\nconst Column = styled.div`\n min-width: 200px;\n border-right: 1px solid #e0e0e0;\n`;\nconst layout = props.layout || \"LIST\";\nconst setPath = props.setPath || (() => {});\nconst path = props.path || context.accountId;\nconst showPreview = props.showPreview || false;\nconst setSelectedPath = props.setSelectedPath || (() => {});\nconst selectedPath = props.selectedPath || \"\";\nconst decryptSk = props.decryptSk || \"\"; // Use decryptSk instead of password\nconst { newSecretKey, decryptObject } = VM.require(\n \"fastvault.near/widget/module.crypto\"\n);\nconst [storageSk, _] = useState(() => {\n if (decryptSk) {\n // decryptSk is available. use it instead of recovering\n console.log(\"Utilizing decryptSk over password\");\n return decryptSk;\n }\n const localSk = Storage.privateGet(\"storage_secret\");\n if (localSk && !password) {\n return localSk;\n }\n const sk = newSecretKey(context.accountId, password);\n console.log(\"recovered decryption key from local storage\");\n Storage.privateSet(\"storage_secret\", sk);\n return sk;\n});\n// --- FV START ---\nconst files = Social.index(\"fastvault_experimental\", \"add\", {\n accountId: context.accountId,\n});\nconsole.log(\"indexed\", files);\nlet data = {};\nif (files) {\n data = files.reduce((acc, file) => {\n const encryptedMetadata = file.value;\n if (!encryptedMetadata.nonce || !encryptedMetadata.ciphertext) {\n console.log(\"invalid file metadata to be decrypted\", file);\n return acc;\n }\n const metadata = decryptObject(\n new Uint8Array(encryptedMetadata.nonce),\n new Uint8Array(encryptedMetadata.ciphertext),\n storageSk\n );\n acc[metadata.filename] = {\n value: metadata.cid + \"|\" + (metadata.filetype ?? \"???\"),\n cid: metadata.cid,\n filetype: metadata.filetype,\n byteSize: metadata.byteSize,\n };\n return acc;\n }, {});\n}\n// --- FV END ---\nif (!data) {\n return <p>Loading...</p>;\n}\nState.init({\n activePath: [],\n selectedPath: \"\",\n showTextDialog: false,\n dataToDisplay: null,\n});\nfunction setActivePath(v) {\n State.update({ activePath: v });\n}\nconst ArrowIcon = styled.span`\n display: inline-block;\n width: 10px;\n height: 10px;\n border-top: 2px solid black;\n border-right: 2px solid black;\n transform: ${(props) =>\n props.isExpanded ? \"rotate(135deg)\" : \"rotate(45deg)\"};\n margin-right: 5px;\n`;\nconst ItemContainer = styled.span`\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n font-size: 18px;\n`;\nconst ItemInfo = styled.span`\n display: flex;\n gap: 10px;\n width: 200px;\n justify-content: space-between;\n`;\nconst ItemDetails = styled.span`\n display: flex;\n gap: 4px;\n align-items: center;\n`;\nconst IconDiv = styled.div`\n background-color: white;\n border-radius: 8px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 5em;\n height: 5em;\n cursor: pointer;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n &:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);\n }\n &:active {\n transform: scale(0.95);\n background-color: #f0f0f0;\n }\n`;\nconst { ContextMenu } = VM.require(\"efiz.near/widget/Module.ContextMenu\");\nContextMenu = ContextMenu || (() => <></>);\nfunction deleteFile(path) {\n function buildObjectWithLastNull(path) {\n const parts = path.split(\"/\").slice(1); // Remove the first part of the path\n let currentObj = {};\n let pointer = currentObj;\n parts.forEach((component, i) => {\n if (i === parts.length - 1) {\n pointer[component] = null;\n } else {\n pointer[component] = {};\n pointer = pointer[component];\n }\n });\n return currentObj;\n }\n const result = buildObjectWithLastNull(path);\n Social.set(result);\n}\nfunction deleteFolder(path, data) {\n function setLeavesToNull(obj) {\n Object.keys(obj).forEach((key) => {\n if (typeof obj[key] === \"object\" && obj[key] !== null) {\n obj[key] = setLeavesToNull(obj[key]);\n } else {\n obj[key] = null;\n }\n });\n return obj;\n }\n function buildObjectWithPath(path, data) {\n const parts = path.split(\"/\").slice(1);\n const value = parts.reduce(\n (current, part) => (current && current[part] ? current[part] : undefined),\n data\n );\n let currentObj = {};\n let pointer = currentObj;\n parts.forEach((component, i) => {\n if (i === parts.length - 1) {\n pointer[component] = setLeavesToNull(value);\n } else {\n pointer[component] = {};\n pointer = pointer[component];\n }\n });\n return currentObj;\n }\n const newData = buildObjectWithPath(path, data);\n Social.set(newData);\n}\nfunction calculateSize(data) {\n const str = typeof data === \"object\" ? JSON.stringify(data) : data;\n let sizeInBytes = 0;\n for (let i = 0; i < str.length; i++) {\n const charCode = str.charCodeAt(i);\n if (charCode <= 0x7f) {\n sizeInBytes += 1;\n } else if (charCode <= 0x7ff) {\n sizeInBytes += 2;\n } else if (charCode <= 0xffff) {\n sizeInBytes += 3;\n } else {\n sizeInBytes += 4;\n }\n }\n if (sizeInBytes < 1024) {\n return sizeInBytes + \" Bytes\";\n } else if (sizeInBytes < 1024 * 1024) {\n return (sizeInBytes / 1024).toFixed(2) + \" KB\";\n } else {\n return (sizeInBytes / (1024 * 1024)).toFixed(2) + \" MB\";\n }\n}\nfunction determineType(path, data) {\n const parts = path.split(\"/\");\n if (parts.length === 1) {\n return \"account\";\n } else {\n const v = parts[1];\n return v;\n }\n}\nconst iconMap = {\n nametag: \"bi bi-person-badge\",\n profile: \"bi bi-person-circle\",\n index: \"bi bi-list-ol\",\n graph: \"bi bi-graph-up\",\n widget: \"bi bi-layout-text-sidebar-reverse\",\n post: \"bi bi-file-post\",\n thing: \"bi bi-box\",\n type: \"bi bi-type\",\n settings: \"bi bi-gear\",\n};\nconst handleColumnClick = (key) => {\n setActivePath([...state.activePath, key]);\n};\nfunction RenderData({ data, layout }) {\n switch (layout) {\n case \"LIST\":\n const dataList =\n state.activePath.length === 0 ? data : getNestedData(data, activePath);\n return (\n <>\n {Object.keys(dataList).map((key) => (\n <div key={key}>\n <Widget\n src=\"fastvault.near/widget/voyager.item\"\n loading={<></>}\n props={{\n path: key,\n data: dataList[key],\n level: 0,\n eFile: ({ key, data, level }) => {\n const updatedPath = [path, key].join(\"/\");\n return (\n <ContextMenu\n Item={() => (\n <ItemContainer\n onDoubleClick={() => setPath(updatedPath)} // open file\n onClick={() => {\n if (data.filetype.includes(\"text\")) {\n console.log(\"clicked file ln 325\", data);\n data.key = key;\n State.update({ dataToDisplay: data });\n }\n }}\n style={{\n marginLeft: level * 20,\n backgroundColor:\n selectedPath === updatedPath\n ? \"#f0f0f0\"\n : \"transparent\",\n }}\n >\n <ItemDetails>\n <i className=\"bi bi-file\"></i>\n <span>{key.split(\"/\").pop()}</span>\n </ItemDetails>\n <ItemInfo>\n <span>{formatBytes(data.byteSize)}</span>\n <span>{data.filetype}</span>\n <span />\n </ItemInfo>\n </ItemContainer>\n )}\n passProps={{\n delete: { path: updatedPath, data },\n }}\n handlers={{\n delete: ({ path }) => {\n deleteFile(path);\n },\n }}\n items={{\n delete: () => (\n <>\n <i className=\"menu__item__icon bi bi-x-lg\" />\n Delete\n </>\n ),\n }}\n />\n );\n },\n eFolder: ({ toggleExpand, isExpanded, key, level }) => {\n const updatedPath = [path, key].join(\"/\");\n return (\n <ContextMenu\n Item={() => (\n <ItemContainer\n onDoubleClick={() => setPath(updatedPath)} // open folder\n onClick={() => {\n toggleExpand();\n }}\n style={{\n marginLeft: level * 20,\n }}\n >\n <ItemDetails>\n <ArrowIcon isExpanded={isExpanded} />\n <i className=\"bi bi-folder\"></i>\n <span>{key.split(\"/\").pop()}</span>{\" \"}\n </ItemDetails>\n <ItemInfo>\n <span>--</span>\n <span>Folder</span>\n <span />\n </ItemInfo>\n </ItemContainer>\n )}\n passProps={{\n delete: { path: updatedPath, data },\n }}\n handlers={{\n delete: ({ path, data }) => {\n deleteFolder(path, data);\n },\n }}\n items={{\n delete: () => (\n <>\n <i className=\"menu__item__icon bi bi-x-lg\" />\n Delete\n </>\n ),\n }}\n />\n );\n },\n }}\n />\n </div>\n ))}\n </>\n );\n case \"GRID\":\n return decryptSk ? (\n <Grid>\n {Object.keys(data).map((key) => {\n const updatedPath = [path, key].join(\"/\");\n return (\n <GridItem key={key}>\n <Widget\n src=\"fastvault.near/widget/EncryptedImage\"\n props={{\n decryptSk: decryptSk,\n image: { ipfs_cid: data[key].cid },\n style: { height: \"200px\", width: \"200px\" },\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreihdxorcz6wflgfhrwtguibaf6pbizp7mpavkwuhqxniaqloq3f2ae\",\n }}\n />\n <p>{key}</p>\n </GridItem>\n );\n })}\n </Grid>\n ) : (\n <p>Password was not provided</p>\n );\n default:\n return null;\n }\n}\nfunction getNestedData(data, pathArray) {\n return pathArray.reduce((currentData, key) => currentData[key] || {}, data);\n}\n// --- FV START ---\n// https://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-in-javascript\nfunction formatBytes(bytes) {\n const decimals = 2;\n if (!bytes) return \"0 Bytes\";\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = [\n \"Bytes\",\n \"KiB\",\n \"MiB\",\n \"GiB\",\n \"TiB\",\n \"PiB\",\n \"EiB\",\n \"ZiB\",\n \"YiB\",\n ];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;\n}\n// --- FV END ---\nreturn (\n <Content>\n <FileUpload\n onUploadIPFS={handleUploadIPFS}\n onUploadNEARFS={handleUploadNEARFS}\n />\n <RenderData layout={layout} data={data} />\n {showPreview && (\n <Overlay>\n <div key={selectedPath}>\n <p>lol it's way to slow to allow preview rn</p>\n </div>\n </Overlay>\n )}\n <Widget\n src=\"near/widget/DIG.Dialog\"\n props={{\n type: \"dialog\",\n open: !!state.dataToDisplay,\n confirmButtonText: \"Close\",\n actionButtons: <></>,\n content: (\n <Widget\n src=\"fastvault.near/widget/EncryptedText\"\n props={{\n decryptSk: decryptSk,\n cid: state.dataToDisplay?.cid,\n fileType: state.dataToDisplay?.filetype,\n key: state.dataToDisplay?.key,\n }}\n />\n ),\n onOpenChange: (value) => State.update({ dataToDisplay: null }),\n }}\n />\n </Content>\n);\n" }, "create.hyperfile": { "": "// const { NewThings } = VM.require('hyperbuild.near/widget/create.newthing');\n// <NewThings item={{ type: 'specificType', value: {} }} onChange={handleThingUpdate} />\nconst Wrapper = styled.div`\n max-width: 400px;\n margin: 0 auto;\n`;\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Button = styled.button``;\n// Define adapter array before initializing constants below\nconst adapters = [\n // these can come from the user (or app) settings\n // {\n // title: \"Local Storage\",\n // value: \"everycanvas.near/widget/adapter.local_storage\",\n // saveRef: false\n // },\n // {\n // title: \"SocialDB\",\n // value: \"everycanvas.near/widget/adapter.social\",\n // },\n {\n title: \"\",\n value: \"\",\n },\n {\n title: \"IPFS\",\n value: \"everycanvas.near/widget/adapter.ipfs\",\n refType: { cid: \"string\" },\n },\n // {\n // title: \"Custom\",\n // value: \"custom\",\n // },\n {\n title: \"GitHub\",\n value: \"hyperfiles.near/widget/adapter.github\",\n },\n // {\n // title: \"Obsidian\",\n // value: \"hack.near/widget/adapter.obsidian\",\n // },\n // {\n // title: \"Tldraw\",\n // value: \"hack.near/widget/adapter.tldraw\",\n // },\n];\n// Schema constants\nconst initialSchemaSrc = props.schemaSrc || \"hyperfiles.near\";\nconst [newSchemaSrc, setNewSchemaSrc] = useState(initialSchemaSrc);\nconst [schemaSrc, setSchemaSrc] = useState(initialSchemaSrc);\nconst [availableSchemas, setAvailableSchemas] = useState([]);\nconst [isLoading, setIsLoading] = useState(true);\nconst [selectedSchema, setSelectedSchema] = useState(\n props.selectedSchema || \"\"\n);\n// Creator constants\nconst defaultAdapter = adapters[0];\nconst { creatorId } = props;\nconst [source, setSource] = useState(props.source ?? \"\");\nconst [adapter, setAdapter] = useState(defaultAdapter.value ?? \"\");\nconst [reference, setReference] = useState(undefined);\nconst [filename, setFilename] = useState(props.filename ?? \"\");\nconst [activeTab, setActiveTab] = useState(\"data\");\nconst [name, setName] = useState(props.name ?? \"\");\nconst [description, setDescription] = useState(props.description ?? \"\");\nconst [json, setJson] = useState(props.data ?? \"\");\nconst [state, setState] = useState({\n data,\n});\nconst handleOnChange = (value) => {\n setState((prevState) => {\n const newData = { value };\n console.log(\"Current Data:\", newData);\n return {\n data: newData,\n };\n });\n};\nconst handleSchemaSrcChange = (newSchemaSrc) => {\n setSchemaSrc(newSchemaSrc);\n setSelectedSchema(\"\"); // Reset the selected schema when the source changes\n};\nconst handleSelectedSchemaChange = (newValue) => {\n const fullSchemaPath = `${schemaSrc}/schema/${newValue}`;\n setSelectedSchema(fullSchemaPath);\n console.log(\"Selected Schema Changed:\", fullSchemaPath);\n};\nconst handleThingUpdate = (newData) => {\n console.log(\"Thing Data Updated:\", newData);\n // Handle the new data, such as saving to a state or sending to a server\n};\nconst handleSelectRepository = (selectedFilePath) => {\n console.log(\"Selected repository:\", selectedFilePath);\n // Assuming you need the repository's file path or some specific identifier\n setFilePath(selectedFilePath); // or any specific attribute you need\n};\nconst rawAdapter =\n (adapter !== \"\" || adapter !== \"custom\") && Social.get(adapter, \"final\");\nconst { create } =\n ((adapter !== \"\" || adapter !== \"custom\") && VM.require(adapter)) ||\n (() => {});\nconst functionRegex = /function\\s+(\\w+)\\s*\\(([^)]*)\\)\\s*{([\\s\\S]*?)\\n}/g;\nfunction parseAdapter(code) {\n let match;\n const functions = [];\n while ((match = functionRegex.exec(code)) !== null) {\n const [_, functionName, params, content] = match;\n functions.push({ functionName, params, content });\n }\n return functions.map((func, index) => (\n <FormGroup key={index}>\n <Label>{func.functionName}</Label>\n <textarea\n className=\"form-control\"\n style={{ width: \"100%\", height: \"100%\" }}\n value={func.content.trim()}\n disabled\n />\n </FormGroup>\n ));\n}\n// TODO: Import keccak from ethers to hash Hyperfile contents\nfunction generateUID() {\n return (\n Math.random().toString(16).slice(2) +\n Date.now().toString(36) +\n Math.random().toString(16).slice(2)\n );\n}\nconst handleCreate = () => {\n const isCreator = context.accountId === creatorId;\n // load in the state.adapter (modules for IPFS, Arweave, Ceramic, Verida, On Machina... )\n const { create } = VM.require(adapter) || (() => {});\n if (create) {\n // store the data somewhere, based on the adapter\n create(json).then((reference) => {\n // now we have a reference to the data\n // we need to name it... are we the original creator or are we forking? We don't want to overwrite any of the users custom (or maybe we do!)\n const thingId = filename ?? generateUID();\n const hyperfile = {\n [props.type]: {\n // which we store in the social contract\n [thingId]: {\n \"\": JSON.stringify({\n schema: schema,\n source: source,\n adapter: adapter,\n reference: reference,\n metadata: {\n name: name,\n description: description,\n type: props.type,\n },\n }),\n },\n },\n };\n if (creatorId !== context.accountId) {\n // handle request merge\n hyperfile.index = {\n notify: JSON.stringify({\n key: creatorId,\n value: {\n type: \"request\",\n data: {\n type: \"merge\",\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n origin: `${context.accountId}/${props.type}/${thingId}`,\n },\n },\n }),\n };\n hyperfile[props.type][thingId].metadata = {\n ...hyperfile[props.type][thingId].metadata,\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n };\n // I want to make a request to merge\n // set upstream and downstream\n }\n // sometimes we're not logged in, so it doesn't do anything!\n Social.set(hyperfile, { force: true });\n });\n }\n};\nreturn (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n {/* Save data source names to user profile */}\n <Form>\n <h3>Enter Content</h3>\n <FormGroup>\n <Label>Source</Label>\n <Widget\n src=\"hyperbuild.near/widget/profile.metadataEditor\"\n props={{\n initialMetadata: profile,\n onChange: (newValue) => {\n console.log(\"New Source:\", newValue);\n setSource(newValue); // Update local state\n State.update({\n profile: { ...profile, source: newValue }, // Update external state\n });\n },\n value: source,\n options: {\n source: {\n sourcePattern: \"*/profile/source/*\",\n placeholder: \"Select a source\",\n },\n },\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Schema</Label>\n <p>{selectedSchema}</p>\n <Widget\n src=\"hyperbuild.near/widget/explore.select.schema\"\n props={{\n onSchemaSrcChange: handleSchemaSrcChange,\n onSelectedSchemaChange: handleSelectedSchemaChange,\n selectedSchema: selectedSchema,\n schemaSrc: schemaSrc,\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Input Data</Label>\n <FormContainer>\n {/*<near-social-viewer></near-social-viewer>*/}\n <Widget\n src=\"hyperbuild.near/widget/create.thing\"\n props={{\n item: {\n type: selectedSchema,\n value: state.data,\n },\n onChange: handleOnChange,\n }}\n />\n </FormContainer>\n </FormGroup>\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Select Storage</h3>\n <FormGroup>\n <Label>Adapter</Label>\n <Select\n value={adapter}\n onChange={(e) => setAdapter(e.target.value)}\n >\n {adapters.map((o) => (\n <option value={o.value}>{o.title}</option>\n ))}\n </Select>\n </FormGroup>\n {rawAdapter && <>{parseAdapter(rawAdapter)}</>}\n {adapter === \"hyperfiles.near/widget/adapter.github\" && (\n <Widget\n src=\"flowscience.near/widget/GitHubSearchSelect\"\n onSelectRepository={handleSelectRepository}\n ></Widget>\n )}\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Deploy It</h3>\n <Button\n onClick={handleCreate}\n disabled={!adapter || !selectedSchema || !source || !state.data}\n >\n Publish Data to `{adapter}`\n </Button>\n {hyperfile !== \"\" && (\n <>\n <FormGroup>\n <textarea\n className=\"form-control\"\n value={hyperfile}\n disabled\n style={{ width: \"100%\", height: \"400px\" }}\n />\n </FormGroup>\n <Button\n onClick={() =>\n Social.set(JSON.parse(hyperfile), { force: true })\n }\n >\n Save Reference\n </Button>\n </>\n )}\n </Form>\n </div>\n </div>\n </div>\n);\n" }, "tools.nearfs.imageUpload": { "": "// fork_Of: \"vlad.near/widget/NEARFSImageUpload\"\ninitState({\n img: null,\n});\n\nconst networkId = \"mainnet\";\nconst domain = {\n testnet: \"testnet.page\",\n mainnet: \"near.page\",\n}[networkId];\n\n// Code mostly taken from https://github.com/NearSocial/viewer/pull/97\n\nconst ipfsUrl = (cid) => `https://ipfs.web4.${domain}/ipfs/${cid}`;\n\nconst filesOnChange = (files) => {\n if (files?.length > 0) {\n State.update({\n img: {\n uploading: true,\n cid: null,\n },\n });\n const body = files[0];\n\n Near.call(\n \"social.near\",\n \"fs_store\",\n Uint8Array.from(body.arrayBuffer())\n ).then((res) => {\n // TODO: hash\n // const cid = res.body.cid;\n // State.update({\n // img: {\n // cid,\n // },\n // });\n });\n } else {\n State.update({\n img: null,\n });\n }\n};\n\nreturn (\n <div className=\"d-inline-block\">\n {state.img?.cid && (\n <div\n className=\"d-inline-block me-2 overflow-hidden align-middle\"\n style={{ width: \"2.5em\", height: \"2.5em\" }}\n >\n <img\n className=\"rounded w-100 h-100\"\n style={{ objectFit: \"cover\" }}\n src={ipfsUrl(state.img?.cid)}\n alt=\"upload preview\"\n />\n </div>\n )}\n <Files\n multiple={false}\n accepts={[\"image/*\"]}\n minFileSize={1}\n clickable\n className=\"btn btn-outline-primary\"\n onChange={filesOnChange}\n >\n {state.img?.uploading ? (\n <>{Loading} Uploading</>\n ) : state.img?.cid ? (\n \"Replace\"\n ) : (\n \"Upload an Image\"\n )}\n </Files>\n </div>\n);\n" }, "explore.types": { "": "const path = props.path || \"hack.near/widget/explore.things\";\nreturn (\n <>\n <Widget\n src={`hack.near/widget/explore.thing`}\n props={{\n path,\n }}\n />\n </>\n);\n" }, "docs": { "": "return (\n <iframe\n className=\"w-100 vh-100\"\n title=\"Hyperfiles | Documentation\"\n src=\"https://opencann-network.super.site/hyperfiles\"\n sandbox=\"allow-same-origin\"\n ></iframe>\n);\n" } } } } }

Transaction Execution Plan

Convert Transaction To Receipt
Gas Burned:
844 Ggas
Tokens Burned:
0.00008 
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
106 Tgas
Tokens Burned:
0.01061 
Called method: 'set' in contract: social.near
Arguments:
{ "data": { "hyperbuild.near": { "widget": { "explore.thing": { "": "if (typeof props.path !== \"string\") return \"send {path} as string in props\";\nState.init({\n selectedTab: \"explore\",\n selectedBlockHeight: \"final\",\n});\nconst historyBlocksRequest = Social.keys(`${props.path}`, \"final\", {\n return_type: \"History\",\n});\nif (historyBlocksRequest === null) return \"loading...\";\nconst [widgetAccountId, _, widgetName] = props.path.split(\"/\");\nlet blocksChanges =\n historyBlocksRequest[widgetAccountId]?.[\"widget\"]?.[widgetName];\nif (props.count) props.count(blocksChanges.length);\nif (blocksChanges) blocksChanges = blocksChanges?.sort((a, b) => b - a);\nif (!state.selectedBlockHeight) state.selectedBlockHeight = blocksChanges[0];\nfunction getDatastringFromBlockHeight(blockHeight) {\n const block = Near.block(blockHeight);\n const date = new Date(block.header.timestamp_nanosec / 1e6);\n return date.toDateString() + \" \" + date.toLocaleTimeString();\n}\nconst renderBlockChangesLink = (blockHeight) => {\n return (\n <div>\n <button\n className={`list-group-item list-group-item-action ${\n state.selectedBlockHeight != blockHeight ? \"\" : \"list-group-item-info\"\n }`}\n onClick={() => {\n State.update({ selectedBlockHeight: blockHeight });\n }}\n >\n #{blockHeight} * {getDatastringFromBlockHeight(blockHeight)}\n </button>\n </div>\n );\n};\nfunction blockHeightToWidgetCode(blockHeight) {\n const index = blocksChanges.findIndex((el) => el == blockHeight);\n return (\n <div class=\"mb-3\">\n <Widget\n key={blockHeight}\n src={`bozon.near/widget/WidgetHistory.CodeHistoryCard`}\n props={{\n pathToWidget: props.path,\n currentBlockHeight: blockHeight,\n prevBlockHeight: blocksChanges[index + 1],\n }}\n />\n </div>\n );\n}\nfunction blockHeightToWidgetRender(blockHeight) {\n const index = blocksChanges.findIndex((el) => el == blockHeight);\n return (\n <Widget\n style={{ minHeight: \"200px\" }}\n key={blockHeight}\n src={`bozon.near/widget/WidgetHistory.RenderCode`}\n props={{\n pathToWidget: props.path,\n currentBlockHeight: blockHeight,\n prevBlockHeight: blocksChanges[index + 1],\n }}\n />\n );\n}\nconst Tabs = styled.div`\n display: flex;\n padding: 0 12px;\n height: 48px;\n border-bottom: 1px solid #eceef0;\n`;\nconst TabsButton = styled.button`\n font-weight: 400;\n font-size: 14px;\n line-height: 17px;\n padding: 0 12px;\n position: relative;\n color: ${(p) => (p.selected ? \"#11181C\" : \"#687076\")};\n background: none;\n border: none;\n outline: none;\n &:hover {\n color: #11181c;\n }\n &::after {\n content: \"\";\n display: ${(p) => (p.selected ? \"block\" : \"none\")};\n position: absolute;\n bottom: 0;\n left: 12px;\n right: 12px;\n height: 3px;\n background: #0091ff;\n }\n`;\nreturn (\n <div>\n {!blocksChanges ? (\n <div>invalid path</div>\n ) : (\n <div>\n <Tabs>\n <TabsButton\n type=\"button\"\n onClick={() =>\n State.update({\n selectedTab: \"connect\",\n })\n }\n selected={state.selectedTab == \"connect\"}\n >\n Connect\n </TabsButton>\n <TabsButton\n type=\"button\"\n onClick={() =>\n State.update({\n selectedTab: \"explore\",\n })\n }\n selected={state.selectedTab == \"explore\"}\n >\n Explore\n </TabsButton>\n </Tabs>\n {!state.selectedTab && (\n <div className=\"m-2\">\n <p>Hello</p>\n </div>\n )}\n {state.selectedTab == \"connect\" && (\n <div className=\"m-2\">\n <Widget src=\"hack.near/widget/explore.connect\" />\n </div>\n )}\n {state.selectedTab == \"explore\" && (\n <div>{blockHeightToWidgetRender(state.selectedBlockHeight)}</div>\n )}\n </div>\n )}\n </div>\n);\n" }, "tools.ipfs.pdfUpload": { "": "const fileAccept = props.fileAccept || \"application/pdf\";\nconst fileIcon = props.fileIcon || \"bi-file-earmark-pdf\";\nconst buttonText = props.buttonText || \"Upload pdf files\";\n// if (!props.update) return \"Update function is required\";\ninitState({\n uploading: false,\n files: [],\n});\nconst ipfsUrl = (cid) => `https://ipfs.near.social/ipfs/${cid}`;\nconst filesOnChange = (files) => {\n State.update({\n uploading: true,\n files: [],\n });\n if (files?.length > 0) {\n files.map((file, index) => {\n const body = file;\n asyncFetch(\"https://ipfs.near.social/add\", {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n },\n body,\n }).then((res) => {\n const cid = res.body.cid;\n State.update({\n files: [...state.files, { index, name: file.name, cid }],\n });\n });\n });\n State.update({ uploading: false });\n props.update(state.files);\n } else {\n State.update({\n uploading: false,\n files: null,\n });\n }\n};\nconst onClickDelete = (index) => {\n const filesUpdated = state.files.filter((file) => file.index !== index);\n State.update({ files: filesUpdated });\n};\nconst filesUploaded = () => {\n if (state.files.length > 0) {\n return state.files.map((file) => (\n <div class=\"d-flex flex-row gap-2 align-items-center\">\n <button\n class=\"btn btn-danger rounded-0\"\n type=\"button\"\n data-toggle=\"tooltip\"\n data-placement=\"top\"\n title=\"Delete\"\n onClick={() => onClickDelete(file.index)}\n >\n <i class=\"bi bi-trash\" />\n </button>\n <i class={`bi fs-3 ${fileIcon}`} />\n <p>{file.name}</p>\n </div>\n ));\n }\n return <></>;\n};\nreturn (\n <div className=\"d-inline-block\">\n {filesUploaded()}\n <Files\n multiple={true}\n accepts={[fileAccept]}\n minFileSize={1}\n clickable\n className=\"btn btn-outline-primary\"\n onChange={filesOnChange}\n >\n {state.uploading\n ? \"Uploading\"\n : state.files.length > 0\n ? \"Replace All\"\n : buttonText}\n </Files>\n <div>\n Raw State:\n <pre>{JSON.stringify(state)}</pre>\n </div>\n </div>\n);\n" }, "profile.cleanup": { "": "const accountId = context.accountId;\nif (!accountId) {\n return \"Please sign in with NEAR wallet\";\n}\nState.init({\n selectedKeys: {},\n nonce: 0,\n});\nconst value = Social.getr(accountId, undefined, {\n nonce: state.nonce,\n});\nconst extractKeys = (data, prefix) =>\n Object.entries(data)\n .map((kv) =>\n typeof kv[1] === \"string\"\n ? { key: `${prefix}${kv[0]}`, value: kv[1] }\n : extractKeys(kv[1], `${prefix}${kv[0]}/`)\n )\n .flat();\nconst kvs = extractKeys(value || {}, \"\");\nkvs.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key));\nconst hasKey = (key) => {\n let t = state.selectedKeys;\n key.split(\"/\").forEach((k) => {\n t = t[k];\n });\n return t === null;\n};\nconst onSelect = (key) => {\n const val = hasKey(key) ? undefined : null;\n let t = state.selectedKeys;\n const path = key.split(\"/\");\n path.slice(0, -1).forEach((k) => {\n t[k] = t[k] || {};\n t = t[k];\n });\n t[path[path.length - 1]] = val;\n State.update();\n};\nreturn (\n <div>\n <h4>Select keys to delete</h4>\n <table className=\"table table-striped\">\n <thead>\n <tr>\n <th>X</th>\n <th>Key</th>\n <th>Value</th>\n </tr>\n </thead>\n <tbody>\n {kvs.map((kv) => {\n return (\n <tr>\n <td>\n <input\n className=\"form-check-input\"\n type=\"checkbox\"\n checked={hasKey(kv.key)}\n onChange={() => onSelect(kv.key)}\n />\n </td>\n <td className=\"text-truncate font-monospace\">{kv.key}</td>\n <td className=\"text-truncate font-monospace\">{kv.value}</td>\n </tr>\n );\n })}\n </tbody>\n </table>\n <div>\n <CommitButton\n data={state.selectedKeys}\n disabled={Object.keys(state.selectedKeys).length === 0}\n onCommit={() =>\n State.update({ selectedKeys: {}, nonce: state.nonce + 1 })\n }\n >\n Delete selected keys\n </CommitButton>\n </div>\n </div>\n);\n" }, "adapter.github": { "": "// Function to construct a GitHub API URL given a file path in a repository\nconst githubUrl = (filePath) =>\n `https://api.github.com/repos/your-username/your-repository/contents/${filePath}`;\n\n// Function to retrieve data from GitHub given a file path\nfunction get(filePath) {\n return fetch(githubUrl(filePath), {\n headers: {\n Accept: \"application/vnd.github.v3.raw\", // Set Accept header to get raw content of the file\n Authorization: \"token YOUR_GITHUB_TOKEN\", // Authorization header with your GitHub token\n },\n }).then((response) => {\n if (!response.ok) {\n throw new Error(\"Failed to fetch data\");\n }\n return response.text(); // Use .text() for raw content, not .json()\n });\n}\n\n// Function to create and upload data to GitHub, returning a promise with the URL of the uploaded content\nfunction create(filePath, data) {\n // Added filePath to the parameters\n return new Promise((resolve, reject) => {\n if (data.length) {\n const content = btoa(data); // Convert data to Base64 for GitHub API\n fetch(githubUrl(filePath), {\n method: \"PUT\",\n headers: {\n Accept: \"application/vnd.github.v3+json\", // Set Accept header to expect JSON responses\n Authorization: \"token YOUR_GITHUB_TOKEN\", // Authorization header with your GitHub token\n \"Content-Type\": \"application/json\", // Set the Content-Type header\n },\n body: JSON.stringify({\n message: `Upload ${filePath}`, // Commit message\n content: content, // Base64 encoded content\n }),\n })\n .then((response) => response.json()) // Parse the JSON response\n .then((data) => {\n if (data.content && data.content.html_url) {\n resolve({ url: data.content.html_url }); // Resolve the promise with the HTML URL of the new content\n } else {\n throw new Error(\"Invalid response from GitHub\");\n }\n })\n .catch((error) => {\n console.error(\"Error in create function:\", error);\n reject(error); // Reject the promise in case of an error\n });\n } else {\n reject(\"No data provided\"); // Reject the promise if no data is provided\n }\n });\n}\n\n// Return the get and create functions for use elsewhere\nreturn { get, create };\n" }, "explore.view.node": { "": "const key = props.key;\nconst label = props.label;\nconst node = props.node;\nconst type = props.type;\nconst path = props.path;\nconst setPath = props.setPath;\nconst history = props.history;\nconst setHistory = props.setHistory;\nconst setType = props.setType;\nconst isRoot = props.isRoot;\nconst styles = {\n subject: {\n fontFamily: \"Arial, sans-serif\",\n fontWeight: \"bold\", // Bold text\n cursor: \"pointer\",\n },\n};\n\nState.init({\n expanded: false,\n});\nfunction handleExpand() {\n State.update({ expanded: !state.expanded });\n}\nfunction handleInto() {\n // Check if node is an object and not null\n if (node && typeof node === \"object\") {\n setPath(path);\n setHistory([...history, path]);\n setType(type);\n } else {\n console.error(\"Invalid node structure\");\n }\n}\nfunction handleBack() {\n const newPath = history[history.length - 2] || \"\";\n setPath(newPath);\n setHistory(history.slice(0, -1));\n}\n// Basic Button Style\nconst Button = styled.button`\n text-transform: lowercase !important;\n display: inline-block;\n text-align: center;\n text-decoration: none;\n border: 2px outset #333;\n background-color: #f5f5f5;\n cursor: pointer;\n color: #333;\n`;\nconst ChildNode = styled.div`\n margin-left: ${String(path).split(\"/\").length * 4}px;\n`;\nfunction renderView() {\n // Root vs Leaf?\n return <Widget src=\"efiz.near/widget/View\" props={{ path, type }} />;\n}\nfunction getType() {\n const parts = String(path).split(\"/\");\n if (parts.length === 1) {\n return \"account\";\n } else if (parts.length === 2) {\n return parts[1];\n } else {\n const standard = parts[1];\n if (standard === \"thing\") {\n // We're gonna grab the type from the thing itself\n }\n return standard;\n }\n}\n\nreturn (\n <div>\n <div>\n {/** CONTROLLER */}\n {history.length > 1 && isRoot && (\n <Button onClick={handleBack}>back</Button>\n )}\n {isRoot ? (\n <div style={styles?.subject}>{label} (root)</div>\n ) : (\n <div style={styles?.subject}>{path}</div>\n )}\n <Button onClick={handleExpand}>{state.expanded ? \"-\" : \"+\"}</Button>\n </div>\n {state.expanded && (\n <div>\n {/** EDGES */}\n {node && typeof node === \"object\" ? (\n Object.entries(node).map(([key, val]) => (\n <ChildNode>\n <Widget\n src=\"hyperbuild.near/widget/explore.view.node\"\n props={{\n key,\n label: key,\n node: val,\n type: getType(),\n path: `${path}/${key}`,\n setPath: setPath,\n history,\n setHistory: setHistory,\n isRoot: false,\n }}\n />\n </ChildNode>\n ))\n ) : (\n <>\n {/** VIEW */}\n <div>{renderView()}</div>\n </>\n )}\n </div>\n )}\n </div>\n);\n" }, "explore.search": { "": "const queries = props.predefinedQueries || [\n //{ name: \"Widget Builders\", query: \"*/widget/*\" },\n //{ name: \"Feature Builders\", query: \"*/widget/*/metadata/tags/app\" },\n { name: \"Hyperfiles\", query: \"*/hyperfile/*\" },\n { name: \"Attestations\", query: \"*/attestation/*\" },\n { name: \"Schemas\", query: \"*/schema/*\" },\n { name: \"Types\", query: \"*/type/*\" },\n { name: \"Jobs\", query: \"*/job/*\" },\n //{ name: \"Feature Builders\", query: \"*/widget/*/metadata/tags/app\" },\n];\n\nconst [inputPath, setInputPath] = useState(\"\");\nconst defaultPath = props.defaultPath;\nconst onUpdateSearchResult = props.onUpdateSearchResult || \"/hyperfile\";\nconst debug = props.debug || false;\nif (!onUpdateSearchResult)\n return \"Must provide a callback function over props.onUpdateSearchResult\";\n\nState.init({\n path: defaultPath,\n accounts: [],\n});\n\nconst onChangePath = (path) => {\n const value = Social.get(path, \"final\");\n const accounts = Object.keys(value);\n onUpdateSearchResult(accounts);\n State.update({ path: path, accounts: accounts });\n setInputPath(path);\n console.log(\"Failed to fetch data:\", error);\n};\n\nconst handleSubmit = () => {\n onPathChange(inputPath); // This callback updates the parent component's state\n};\n\n// Integrate mob.near/widget/ComponentSearch to show results for queried objects\n// Format results with starred components = mob.near/widget/Applications\n// const allComponents = [];\n\nconst allPeople = [];\n\nfor (let i = 0; i < state.accounts.length; ++i) {\n const accountId = state.accounts[i];\n\n allPeople.push(\n <a\n href={`#/mob.near/widget/ProfilePage?accountId=${accountId}`}\n className=\"text-decoration-none\"\n key={`people_${i}`}\n >\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId,\n tooltip: true,\n className: \"d-inline-block overflow-hidden\",\n }}\n />\n </a>\n );\n}\n\nreturn (\n <div>\n <div class=\"mb-2\">\n <input\n type=\"text\"\n value={state.path}\n onChange={(e) => onChangePath(e.target.value)}\n placeholder={\"*/widget/*/metadata/tags/app\"}\n />\n <button onClick={handleSubmit}>Update Path</button>\n </div>\n <div class=\"d-flex flex-wrap flex-row mb-2\">\n <div class=\"btn-toolbar\" role=\"toolbar\" aria-label=\"Generated queries\">\n {queries &&\n queries.length &&\n queries.map((q, i) => {\n return (\n <button\n type=\"button\"\n key={`query_${i}`}\n class=\"btn btn-primary btn-sm mr-2\"\n onClick={() => {\n onChangePath(q.query);\n }}\n >\n {q.name}\n </button>\n );\n })}\n </div>\n <div>{debug && allPeople}</div>\n </div>\n </div>\n);\n" }, "explore.every.schema": { "": "const accountId = props.accountId ?? \"*\" ?? context.accountId;\nconst schemaName = props.schemaName || \"schema\";\nconst tag = props.tag;\nconst metadataTemplate =\n props.metadataTemplate || \"efiz.near/widget/every.type.metadata\";\nlet keys = `${accountId ?? \"*\"}/${schemaName}/*`;\nif (tag) {\n const taggedWidgets = Social.keys(\n `${accountId ?? \"*\"}/${schemaName}/*/metadata/tags/${tag}`,\n \"final\"\n );\n if (taggedWidgets === null) {\n return render(\"Loading tags\");\n }\n keys = Object.entries(taggedWidgets)\n .map((kv) =>\n Object.keys(kv[1][schemaName]).map((w) => `${kv[0]}/${schemaName}/${w}`)\n )\n .flat();\n if (!keys.length) {\n return render(`No schemas found by tag #${tag}`);\n }\n}\nconst data = Social.keys(keys, \"final\", {\n return_schema: \"BlockHeight\",\n limit: 1,\n});\nif (data === null) {\n return <p>\"Loading\"</p>;\n}\nconst processData = (data) => {\n const accounts = Object.entries(data);\n const allItems = accounts\n .map((account) => {\n const accountId = account[0];\n return Object.entries(account[1][schemaName]).map((kv) => ({\n accountId,\n schemaName: kv[0],\n blockHeight: kv[1],\n }));\n })\n .flat();\n allItems.sort((a, b) => b.blockHeight - a.blockHeight);\n return allItems;\n};\nconst renderItem = (a) => {\n return (\n <div className=\"mb-3\" key={JSON.stringify(a)} style={{ minHeight: \"10em\" }}>\n <Widget\n src=\"efiz.near/widget/every.type.metadata\"\n props={{\n accountId: a.accountId,\n widgetName: a.schemaName,\n blockHeight: a.blockHeight,\n }}\n />\n </div>\n );\n};\nif (JSON.stringify(data) !== JSON.stringify(state.data || {})) {\n State.update({\n data,\n allItems: processData(data),\n });\n}\nreturn (\n <div className=\"px-2 mx-auto\">\n {(accountId || tag) && (\n <div className=\"mb-2\">\n Filter:\n {accountId && (\n <a className=\"btn btn-outline-primary\">\n <Widget\n src=\"mob.near/widget/ProfileLine\"\n props={{ accountId, link: false }}\n />\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n {tag && (\n <a className=\"btn btn-outline-primary\">\n <span className=\"badge text-bg-secondary\">#{tag}</span>\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n </div>\n )}\n <Widget\n src=\"efiz.near/widget/ItemFeed\"\n props={{ items: state.allItems || [], renderItem }}\n />\n </div>\n);\n" }, "explore.view.path": { "": "State.init({\n path: props.path,\n});\n\nconst value = Social.get(state.path, \"final\");\n\nconst text = `\n \\`\\`\\`json\n ${JSON.stringify(value, undefined, 2)}\n \\`\\`\\`\n `;\n\nreturn (\n <div>\n <div>\n <input\n type=\"text\"\n value={state.path}\n placeholder=\"self.social.near/profile/**\"\n />\n </div>\n <Markdown text={text} />\n </div>\n);\n" }, "tools.nearfs.utils": { "": "// fork_Of: \"sdks.near/widget/Utils.NearFS\"\nconst NEAR_SOCIAL_IPFS_URL = \"https://ipfs.near.social\";\nconst NEAR_SOCIAL_ADD_ENDPOINT = `${NEAR_SOCIAL_IPFS_URL}/add`;\nconst NearFS = {\n get: (cid) =>\n asyncFetch(NearFS.getIpfsUrl(cid)).then((data) => data.body || null),\n upload: (metadata) => {\n return asyncFetch(NEAR_SOCIAL_ADD_ENDPOINT, {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n },\n body: JSON.stringify(metadata),\n }).then((data) => {\n return {\n cid: data.body.cid || null,\n url: data.body.cid ? NearFS.getIpfsUrl(data.body.cid) : null,\n };\n });\n },\n getIpfsUrl: (cid) => {\n return `${NEAR_SOCIAL_IPFS_URL}/ipfs/${cid}`;\n },\n};\nreturn NearFS;\n" }, "explore.every.type": { "": "const accountId = props.accountId ?? \"*\" ?? context.accountId;\nconst typeName = props.typeName || \"type\";\nconst tag = props.tag;\nconst metadataTemplate =\n props.metadataTemplate || \"efiz.near/widget/every.type.metadata\";\nlet keys = `${accountId ?? \"*\"}/${typeName}/*`;\nif (tag) {\n const taggedWidgets = Social.keys(\n `${accountId ?? \"*\"}/${typeName}/*/metadata/tags/${tag}`,\n \"final\"\n );\n if (taggedWidgets === null) {\n return render(\"Loading tags\");\n }\n keys = Object.entries(taggedWidgets)\n .map((kv) =>\n Object.keys(kv[1][typeName]).map((w) => `${kv[0]}/${typeName}/${w}`)\n )\n .flat();\n if (!keys.length) {\n return render(`No types found by tag #${tag}`);\n }\n}\nconst data = Social.keys(keys, \"final\", {\n return_type: \"BlockHeight\",\n limit: 1,\n});\nif (data === null) {\n return <p>\"Loading\"</p>;\n}\nconst processData = (data) => {\n const accounts = Object.entries(data);\n const allItems = accounts\n .map((account) => {\n const accountId = account[0];\n return Object.entries(account[1][typeName]).map((kv) => ({\n accountId,\n typeName: kv[0],\n blockHeight: kv[1],\n }));\n })\n .flat();\n allItems.sort((a, b) => b.blockHeight - a.blockHeight);\n return allItems;\n};\nconst renderItem = (a) => {\n return (\n <div className=\"mb-3\" key={JSON.stringify(a)} style={{ minHeight: \"10em\" }}>\n <Widget\n src=\"efiz.near/widget/every.type.metadata\"\n props={{\n accountId: a.accountId,\n widgetName: a.typeName,\n blockHeight: a.blockHeight,\n }}\n />\n </div>\n );\n};\nif (JSON.stringify(data) !== JSON.stringify(state.data || {})) {\n State.update({\n data,\n allItems: processData(data),\n });\n}\nreturn (\n <div className=\"px-2 mx-auto\">\n {(accountId || tag) && (\n <div className=\"mb-2\">\n Filter:\n {accountId && (\n <a className=\"btn btn-outline-primary\">\n <Widget\n src=\"mob.near/widget/ProfileLine\"\n props={{ accountId, link: false }}\n />\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n {tag && (\n <a className=\"btn btn-outline-primary\">\n <span className=\"badge text-bg-secondary\">#{tag}</span>\n <i className=\"bi bi-x-square\"></i>\n </a>\n )}\n </div>\n )}\n <Widget\n src=\"efiz.near/widget/ItemFeed\"\n props={{ items: state.allItems || [], renderItem }}\n />\n </div>\n);\n" }, "create.edit.source": { "": "const sourcePattern = props.sourcePattern ?? \"*/profile/source/*\";\nconst placeholder = props.placeholder ?? \"Source\";\nconst initialSourceObject = props.initialSourceObject || {};\nconst sourceObject = Social.keys(sourcePattern, \"final\");\nif (sourceObject === null) {\n return \"Loading\";\n}\nconst normalizeProf = (prof) =>\n prof\n .replaceAll(/[- \\.]/g, \"_\")\n .replaceAll(/[^\\w]+/g, \"\")\n .replaceAll(/_+/g, \"-\")\n .replace(/^-+/, \"\")\n .replace(/-+$/, \"\")\n .toLowerCase()\n .trim(\"-\");\nconst sourceCount = {};\nconst processSourceObject = (obj) => {\n Object.entries(obj).forEach((kv) => {\n if (typeof kv[1] === \"object\") {\n processSourceObject(kv[1]);\n } else {\n const prof = normalizeProf(kv[0]);\n sourceCount[prof] = (sourceCount[prof] || 0) + 1;\n }\n });\n};\nconst getSource = () => {\n processSourceObject(sourceObject);\n const source = Object.entries(sourceCount);\n source.sort((a, b) => b[1] - a[1]);\n return source.map((t) => ({\n name: t[0],\n count: t[1],\n }));\n};\nif (!state.allSource) {\n initState({\n allSource: getSource(),\n source: Object.keys(initialSourceObject).map((prof) => ({\n name: normalizeProf(prof),\n })),\n originalSource: Object.fromEntries(\n Object.keys(initialSourceObject).map((prof) => [prof, null])\n ),\n id: `source-selector-${Date.now()}`,\n });\n}\nconst setSource = (source) => {\n source = source.map((o) => {\n o.name = normalizeProf(o.name);\n return o;\n });\n State.update({ source });\n if (props.setSourceObject) {\n props.setSourceObject(\n Object.assign(\n {},\n state.originalSource,\n Object.fromEntries(source.map((prof) => [prof.name, \"\"]))\n )\n );\n }\n};\nreturn (\n <>\n <Typeahead\n id={state.id}\n labelKey=\"name\"\n onChange={setSource}\n options={state.allSource}\n placeholder={placeholder}\n selected={state.source}\n positionFixed\n allowNew\n />\n {props.debug && (\n <div>\n Debugging source:\n <pre>{JSON.stringify(state.source)}</pre>\n </div>\n )}\n </>\n);\n" }, "explore.view.history": { "": "/*\n---props---\nprops.post: {};\nprops.id: number;\nprops.newTab: boolean;\nprops.timestamp: number;\nprops.referral: any;\n*/\nconst postId = props.post.id ?? (props.id ? parseInt(props.id) : 0);\nconst post =\n props.post ??\n Near.view(\"devgovgigs.near\", \"get_post\", {\n post_id: postId,\n });\nif (!post || post.snapshot_history.length === 0) {\n return <div class=\"bi bi-clock-history px-2\"></div>;\n}\nconst referral = props.referral;\nfunction readableDate(timestamp) {\n var a = new Date(timestamp);\n return (\n a.toDateString() +\n \" \" +\n a.toLocaleTimeString([], { hour: \"2-digit\", minute: \"2-digit\" })\n ).substring(4);\n}\nfunction historyHref(widgetName, linkProps) {\n linkProps = { ...linkProps };\n const linkPropsQuery = Object.entries(linkProps)\n .map(([key, value]) => `${key}=${value}`)\n .join(\"&\");\n return `#/markeljan.near/widget/${widgetName}${\n linkPropsQuery ? \"?\" : \"\"\n }${linkPropsQuery}`;\n}\nconst currentTimestamp = props.timestamp ?? post.snapshot.timestamp;\nconst snapshot = post.snapshot;\nconst snapshotHistory = post.snapshot_history;\nsnapshotHistory.push(snapshot);\nsnapshotHistory.reverse();\nconst history = (\n <div class=\"btn-group\" role=\"group\">\n <a\n class=\"card-link\"\n role=\"button\"\n title=\"Object History\"\n data-bs-toggle=\"dropdown\"\n aria-expanded=\"false\"\n type=\"button\"\n >\n <div class=\"bi bi-clock-history px-2\"></div>\n </a>\n <ul class=\"dropdown-menu\">\n <a\n class=\"d-flex text-muted\"\n style={{ fontSize: \"12px\", textDecoration: \"none\", cursor: \"default\" }}\n >\n <a\n style={{\n textAlign: \"center\",\n minWidth: \"290px\",\n maxWidth: \"290px\",\n }}\n >\n Edit History\n </a>\n <a style={{ marginRight: \"8px\" }}>Compare</a>\n </a>\n {snapshotHistory.map((item) => {\n if (item === undefined) return;\n return (\n <li style={{ display: \"flex\" }}>\n <div\n style={{\n minWidth: \"290px\",\n maxWidth: \"290px\",\n }}\n >\n <a\n class=\"dropdown-item\"\n href={historyHref(\"PostWithHistory\", {\n id: postId,\n timestamp: item.timestamp,\n compareTimestamp: null,\n referral,\n })}\n target={props.newTab ? \"_blank\" : undefined}\n >\n {readableDate(item.timestamp / 1000000)}\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: item.editor_id,\n style: {\n width: \"1.25em\",\n height: \"1.25em\",\n },\n imageStyle: {\n transform: \"translateY(-12.5%)\",\n },\n }}\n />\n {post.author_id.substring(0, 8)}\n </a>\n </div>\n <a\n class=\"dropdown-item\"\n href={historyHref(\"PostWithHistory\", {\n id: postId,\n timestamp: currentTimestamp,\n compareTimestamp: item.timestamp,\n referral,\n })}\n >\n <i class=\"bi bi-file-earmark-diff\" />\n </a>\n </li>\n );\n })}\n </ul>\n <Widget\n src=\"efiz.near/widget/Every.Thing.History\"\n props={{\n path: \"hyperfiles.near/widget/index-dev\",\n count: (count) => console.log(\"Number of changes:\", count),\n }}\n />\n </div>\n);\nreturn history;\n" }, "adapter.ipfs": { "": "const ipfsUrl = (cid) => `https://ipfs.near.social/ipfs/${cid}`;\nfunction get(ref) {\n const data = fetch(`https://ipfs.near.social/ipfs/${ref.cid}`);\n return data.body;\n}\nfunction create(data) {\n return new Promise((resolve, reject) => {\n if (data.length) {\n const body = new Blob([data], { type: \"application/json\" });\n console.log(body);\n asyncFetch(\"https://ipfs.near.social/add\", {\n method: \"POST\",\n headers: {\n Accept: \"application/json\",\n },\n body,\n })\n .then((res) => {\n resolve({ cid: res.body.cid }); // Resolve the promise with the necessary data\n })\n .catch((error) => {\n console.error(\"Error in create function:\", error);\n reject(error); // Reject the promise in case of an error\n });\n } else {\n reject(\"No data provided\"); // Reject the promise if no data is provided\n }\n });\n}\nreturn { get, create };\n" }, "explore.view.graph": { "": "const accountId = props.accountId ?? context.accountId;\nif (!accountId) {\n return \"Please connect your NEAR wallet :)\";\n}\nState.init({\n accounts: [\"every.near\", context.accountId],\n newAccount: \"\",\n thing: thingId,\n});\nfunction addAccount(newAccount) {\n state.accounts.push(newAccount);\n State.update({\n accounts: state.accounts,\n });\n}\nfunction removeAccount(accountKey) {\n const updatedAccounts = state.accounts.filter(\n (account) => account !== accountKey\n );\n State.update({\n accounts: updatedAccounts,\n });\n}\nreturn (\n <div>\n <div className=\"mb-2\">\n <h5>Graph ID</h5>\n <p>\n <i>\n Default graph is \"follow\". Use \"*/graph/*\" in the Explore Data section\n below to find more. Other options include: follow, like, star, etc.\n </i>\n </p>\n <input type=\"text\" value={state.thing} placeholder={defaultThing} />\n </div>\n <div>\n <h5>Account IDs</h5>\n <input\n placeholder=\"<example>.near\"\n onChange={(e) => State.update({ newAccount: e.target.value })}\n />\n <div className=\"d-flex align-items-center mt-2\">\n <button\n className=\"btn btn-primary m-2\"\n onClick={() => addAccount(state.newAccount)}\n >\n add\n </button>\n </div>\n </div>\n <div>\n {state.accounts.map((a) => {\n return (\n <div className=\"d-flex m-2 p-2 justify-content-between align-items-center\">\n <div className=\"d-flex align-items-center\">\n <Widget src=\"mob.near/widget/Profile\" props={{ accountId: a }} />\n </div>\n <button\n className=\"btn btn-danger m-1\"\n onClick={() => removeAccount(a)}\n >\n remove\n </button>\n </div>\n );\n })}\n </div>\n <hr />\n {state.accounts.length > 1 ? (\n <div className=\"mb-2\">\n <Widget\n src=\"hyperbuild.near/widget/explore.socialgraph\"\n props={{\n accountIds: state.accounts,\n thingId: state.thing,\n }}\n />\n </div>\n ) : (\n <div className=\"mb-2\">\n <h5>input 2+ accounts</h5>\n </div>\n )}\n </div>\n);\n" }, "profile.social": { "": "const darkColors = {\n page_bg: \"rgb(25,33,50)\",\n horizen_bg: \"#fff\",\n header_bg: \"rgb(49,62,89)\",\n sideBar: {\n sideBar_bg: \"rgb(49,62,89)\",\n sideBar_color: \"#fff\",\n },\n footer: {\n titlenelowBackground: \"#806ce1\",\n titleBackground: \"#fff\",\n fromBackground: \"rgb(55,72,107)\",\n toBackground: \"rgb(55,72,107)\",\n belowBackground: \"rgb(210, 202, 250)\",\n },\n dynamic_header: {\n afterbrandcolor: \"\",\n color1brand: \"#fff\",\n color2brand: \"rgb(210, 202, 250)\",\n colordescription: \"rgb(210, 202, 250)\",\n background:\n \"radial-gradient(circle, rgb(49,62,89) 0%, rgba(230,230,231,0.01) 0%, rgb(49,62,89) 100%, rgb(49,62,89) 100%, rgb(49,62,89) 100%, rgba(46,52,90,1) 100%);\",\n },\n search_sbt: {\n section_bg: \"transparent\",\n card_bg: \"transparent)\",\n search_btn_bg: \"rgb(49,62,89)\",\n search_btn_bg_hover: \"rgba(49,62,89,0.8)\",\n search_btn_text: \"rgb(255,255,255)\",\n input_bg: \"rgb(49,62,89)\",\n input_bg_hover: \"rgba(49,62,89,0.8)\",\n input_text_color: \"rgb(255,255,255)\",\n input_border: \"rgba(49,62,89,0.8)\",\n table_bg: \"transparent\",\n table_color: \"rgb(255,255,255)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(255,255,255)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(255,255,255)\",\n table_hover_bg: \"\",\n },\n profileInlineBlock: {\n name: \"#fff\",\n accountId: \"#fff\",\n tag: \"#fff\",\n description: \"#fff\",\n },\n table_pagination: {\n table_bg: \"rgb(49,62,89)\",\n table_color: \"rgb(255,255,255)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(255,255,255)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(255,255,255)\",\n table_hover_bg: \"\",\n btn_border: \"rgb(25,33,50)\",\n btn_bg: \"rgb(49,62,89)\",\n btn_bg_active: \"rgb(25,33,50)\",\n btn_color: \"#fff\",\n input_bg: \"#2f3b54\",\n },\n card: {\n card_bg: \"rgb(49,62,89)\",\n tabSelect_bg: \"#192132\",\n tabSelect_text_color: \"#fff\",\n tabSelect_input_bg: \"rgb(49,62,89)\",\n tabSelect_btn_active_bg: \"rgb(49,62,89)\",\n text_color: \"rgba(255,255,255,1)\",\n },\n chart: {\n title: \"rgb(255,255,255)\",\n subtitle: \"rgba(255,255,255,0.7)\",\n xAxis: \"rgb(255,255,255)\",\n yAxis: \"rgb(255,255,255)\",\n legend: \"rgba(255,255,255,0.7)\",\n legendHover: \"rgb(255,255,255)\",\n rangeSelector: {\n labels: \"rgba(255,255,255,0.7)\",\n inputColor: \"rgb(255,255,255)\",\n btn_bg: \"rgba(25,33,50,0.3)\",\n btn_color: \"rgba(255,255,255,0.7)\",\n btn_hover_bg: \"rgba(25,33,50,0.5)\",\n btn_hover_color: \"rgba(255,255,255,0.8)\",\n btn_active_bg: \"rgba(25,33,50,0.8)\",\n btn_active_color: \"rgb(255,255,255)\",\n },\n },\n tree: {\n subject: {\n color: \"#fff\",\n fontweight: 400,\n fontSize: \"2em\",\n },\n nodes: {\n color: \"#fff\",\n // borderColor: \"#fff\",\n backgroundColor: \"rgb(49,62,89)\",\n },\n overrideNodeStyles: {\n // backgroundColor: \"red\",\n },\n },\n spinnerColors: [\"#6F61C0\", \"#241468\"],\n chartColor: [\n \"#F79BD3\",\n \"#A084E8\",\n \"#EA1179\",\n \"#F79BD3\",\n \"#A084E8\",\n \"#6F61C0\",\n \"#241468\",\n \"#9F0D7F\",\n ],\n};\nconst lightColors = {\n page_bg: \"#fff\",\n horizen_bg: \"#391b86\",\n header_bg: \"rgb(210, 202, 250)\",\n sideBar: {\n sideBar_bg: \"rgb(210, 202, 250)\",\n sideBar_color: \"#fff\",\n },\n footer: {\n titlenelowBackground: \"#806ce1\",\n titleBackground: \"#fff\",\n fromBackground: \"rgb(210, 202, 250)\",\n toBackground: \"rgb(210, 202, 250)\",\n belowBackground: \"#806ce1\",\n },\n dynamic_header: {\n afterbrandcolor: \"#789efb\",\n color1brand: \"#000\",\n color2brand: \"#806ce1\",\n colordescription: \"#806ce1\",\n background:\n \"radial-gradient(circle, rgba(210,202,250,1) 0%, rgba(210,202,250,0.01) 0%, rgba(235,231,253,1) 100%, rgba(255,241,241,1) 100%, rgba(46,52,90,1) 100%);\",\n },\n search_sbt: {\n section_bg: \"rgb(235, 231, 253)\",\n card_bg: \"\",\n search_btn_bg: \"rgb(210, 202, 250)\",\n search_btn_bg_hover: \"rgba(210, 202, 250,0.8)\",\n search_btn_text: \"rgb(0,0,0)\",\n input_bg: \"rgba(210, 202, 250,0.2)\",\n input_bg_hover: \"rgba(210, 202, 250,0.4)\",\n input_text_color: \"rgb(0,0,0)\",\n input_border: \"rgba(210, 202, 250,0.4)\",\n table_bg: \"transparent\",\n table_color: \"rgb(0,0,0)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(0,0,0)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(0,0,0)\",\n table_hover_bg: \"\",\n },\n profileInlineBlock: {\n name: \"#000\",\n accountId: \"#000\",\n tag: \"#000\",\n description: \"#000\",\n },\n table_pagination: {\n table_bg: \"rgb(255,255,255)\",\n table_color: \"rgb(0,0,0)\",\n table_border_color: \"\",\n table_accent_bg: \"\",\n table_striped_color: \"rgb(0,0,0)\",\n table_striped_bg: \"\",\n table_hover_color: \"rgb(0,0,0)\",\n table_hover_bg: \"\",\n btn_border: \"#000\",\n btn_border: \"#806ce1\",\n btn_bg: \"#fff\",\n btn_bg_active: \"rgb(235, 231, 253)\",\n btn_color: \"#000\",\n },\n card: {\n card_bg: \"rgb(255, 255, 255)\",\n tabSelect_bg: \"#e6e6e7\",\n tabSelect_text_color: \"#000\",\n tabSelect_input_bg: \"rgb(210, 202, 250)\",\n tabSelect_btn_active_bg: \"rgb(210, 202, 250)\",\n text_color: \"rgba(0,0,0,1)\",\n },\n chart: {\n title: \"rgba(0,0,0,1)\",\n subtitle: \"rgba(0,0,0,0.7)\",\n xAxis: \"rgba(0,0,0,1)\",\n yAxis: \"rgba(0,0,0,1)\",\n legend: \"rgba(0,0,0,0.7)\",\n legendHover: \"rgba(0,0,0,1)\",\n rangeSelector: {\n labels: \"rgba(0,0,0,0.7)\",\n inputColor: \"rgba(0,0,0,0.5)\",\n btn_bg: \"rgba(0,0,0,0.3)\",\n btn_color: \"rgba(0,0,0,0.8)\",\n btn_hover_bg: \"rgba(0,0,0,0.4)\",\n btn_hover_color: \"rgba(0,0,0,1)\",\n btn_active_bg: \"rgb(235, 231, 253)\",\n btn_active_color: \"rgba(0,0,0,1)\",\n },\n },\n tree: {\n subject: {\n color: \"#000\",\n fontweight: 400,\n fontSize: \"2em\",\n },\n nodes: {\n color: \"#000\",\n // borderColor: \"#000\",\n backgroundColor: \"#fff\",\n },\n overrideNodeStyles: {\n // backgroundColor: \"red\",\n },\n },\n spinnerColors: [\"#6F61C0\", \"#241468\"],\n chartColor: [\n \"#F79BD3\",\n \"#A084E8\",\n \"#EA1179\",\n \"#F79BD3\",\n \"#A084E8\",\n \"#6F61C0\",\n \"#241468\",\n \"#9F0D7F\",\n ],\n};\nconst themeColor = props.themeColor || lightColors;\n// const themeColor = props.themeColor || lightColors;\n// #####################################\nState.init({\n singer: context.accountId || \"hyperfiles.near\",\n result: [],\n data: context.accountId || \"hyperfiles.near\",\n isLoading: false,\n error: [],\n});\nconst inputHandler = ({ target }) => {\n const singer = target.value.toLowerCase().trim();\n State.update({ singer: singer });\n};\nconst handleData = () => {\n if (!state.singer.length) {\n State.update({ error: [...state.error, \"please insert an address\"] });\n return;\n }\n if (state.data === state.singer) {\n State.update({ error: [...state.error, \"please insert a new address\"] });\n return;\n }\n State.update({ data: state.singer });\n};\nif (state.error.length > 0) {\n function hide() {\n const errors = state.error;\n errors.shift();\n if (errors.length > 0) setTimeout(hide, 2500);\n State.update({ error: errors });\n }\n setTimeout(hide, 2500);\n}\nconst Input = styled.input`\n color: ${themeColor?.search_sbt?.input_text_color};\n background-color: ${themeColor?.search_sbt?.input_bg};\n border: 1px solid ${themeColor?.search_sbt?.input_border};\n &:focus {\n background-color: ${themeColor?.search_sbt?.input_bg};\n color: ${themeColor?.search_sbt?.input_text_color};\n border: 1px solid ${themeColor?.search_sbt?.input_border};\n }\n &:hover {\n background-color: ${themeColor?.search_sbt?.input_bg_hover};\n }\n`;\nconst Button = styled.button`\n color: ${themeColor?.search_sbt?.search_btn_text};\n font-size: 16px;\n padding: 0.5rem 1rem;\n font-weight: 400;\n background-color: ${themeColor?.search_sbt?.search_btn_bg};\n &:hover {\n background-color: ${themeColor?.search_sbt?.search_btn_bg_hover};\n }\n border: 1px solid ${themeColor?.search_sbt?.search_btn_bg};\n box-shadow: 0 2px 0 rgba(0, 0, 0, 0.02);\n min-height: calc(1.5em + 1rem + 2px);\n border-radius: 40px;\n line-height: 29px;\n letter-spacing: 0.01em;\n`;\n// -------------------------------------------------------------------\nconst singer = state.data;\nconst status = Social.index(\"notify\", singer, { order: \"desc\" }) || [];\nconst receivedPoke = status.filter(\n (notification) => notification?.value?.type === \"poke\"\n);\nconst numReceivedPoke = receivedPoke?.length || 0;\nconst receivedLike = status.filter(\n (notification) => notification?.value?.type === \"like\"\n);\nconst numReceivedLike = receivedLike?.length || 0;\nconst receivedComment = status.filter(\n (notification) => notification?.value?.type === \"comment\"\n);\nconst numReceivedComment = receivedComment?.length || 0;\nconst receivedRepost = status.filter(\n (notification) => notification?.value?.type === \"repost\"\n);\nconst numReceivedRepost = receivedRepost?.length || 0;\nconst nummention =\n status.filter((notification) =>\n notification?.value?.type.includes?.(\"mention\")\n ).length || 0;\n//---------------------------------------------------part1------------------------------------------------------\nconst following = Social.keys(`${singer}/graph/follow/*`, \"final\", {\n return_type: \"BlockHeight\",\n values_only: true,\n});\nconst numFollowing = following\n ? Object.keys(following[singer]?.graph?.follow || {}).length\n : 0;\n//---------------------------\nconst followers = Social.keys(`*/graph/follow/${singer}`, \"final\", {\n return_type: \"BlockHeight\",\n values_only: true,\n});\nconst numFollowers = followers ? Object.keys(followers || {}).length : 0;\n//--------------------------\nconst likes = Social.keys(`${singer}/index/like`, \"final\", {\n return_type: \"History\",\n});\nconst numlikes = likes\n ? Object.keys(likes[singer]?.index?.like || {}).length\n : 0;\n//--------------------------\nconst posts = Social.keys(`${singer}/index/post`, \"final\", {\n return_type: \"History\",\n});\nconst numposts = posts\n ? Object.keys(posts[singer]?.index?.post || {}).length\n : 0;\n//--------------------------\nconst comments = Social.keys(`${singer}/post/comment`, \"final\", {\n return_type: \"History\",\n});\nconst numcomments = comments\n ? Object.keys(comments[singer]?.post?.comment || {}).length\n : 0;\n//--------------------------\nconst tx_widgets = Social.keys(`${singer}/widget`, \"final\", {\n return_type: \"History\",\n});\nconst tx_numwidgets = tx_widgets\n ? Object.keys(tx_widgets[singer]?.widget || {}).length\n : 0;\n//--------------------------\nconst reposts = Social.keys(`${singer}/index/repost`, \"final\", {\n return_type: \"History\",\n});\nconst numreposts = reposts\n ? Object.keys(reposts[singer]?.index?.repost || {}).length\n : 0;\n//--------------------------\n// const pokes = Social.keys(`${singer}/*`, \"final\", {\n// return_type: \"History\",\n// });\n// const numPokes = pokes\n// ? Object.keys(pokes[singer].index.graph || {}).length\n// : 0;\nconst numPokes = \"N/A\";\n//--------------------------\nconst allTx = Social.keys(`${singer}/*`, \"final\", {\n return_type: \"History\",\n}) || { [singer]: [] };\nconst joinDateTimeBlock =\n Object.values(allTx[singer] || {})\n .flat()\n .sort((a, b) => a - b)[0] || \"-\";\nlet joinDate = fetch(\n \"https://api.near.social/time?blockHeight=\" + joinDateTimeBlock\n).body;\njoinDate = Number.isInteger(joinDate)\n ? `${new Date(joinDate).getFullYear()}/${\n new Date(joinDate).getMonth() + 1\n }/${new Date(joinDate).getDate()}`\n : \"-\";\n//--------------------------\nconst hashtag = Social.keys(`${singer}/index/hashtag`, \"final\", {\n return_type: \"History\",\n});\nconst numHashtags = hashtag\n ? Object.keys(hashtag[singer]?.index?.hashtag || {}).length\n : 0;\n//--------------------------\nconst widgets = Social.keys(`${singer ?? \"*\"}/widget/*`, \"final\", {\n return_type: \"History\",\n});\n// console.log(\"widgets\", widgets);\nconst numWidgets = widgets[singer]?.widget\n ? Object.keys(widgets[singer]?.widget || {}).length\n : 0;\n//--------------------------\nconst forkof = Social.keys(`${singer}/widget/*/metadata/fork_of`, \"final\", {\n return_type: \"History\",\n});\nconst numForkof = forkof ? Object.keys(forkof[singer]?.widget || {}).length : 0;\n//--------------------------\nconst un_star = Social.keys(`${singer}/index/star`, \"final\", {\n return_type: \"History\",\n});\nconst numUn_star = un_star\n ? Object.keys(un_star[singer]?.index?.star || {}).length\n : 0;\n//--------------------------\n// const totalTx = Social.keys(`${singer}/*`, \"final\", {\n// return_type: \"History\",\n// });\n// const numTotalTx = totalTx\n// ? new Set(Object.values(totalTx[singer] || {}).flat()).size\n// : 0;\nconst totalTx = fetch(\n `https://api.nearblocks.io/v1/account/${singer}/txns/count?to=social.near`\n).body;\nconst numTotalTx = totalTx ? totalTx.txns[0]?.count ?? \"-\" : \"-\";\n//--------------------------\n//-----------------------------------------------part1----------------------------------------------------\n//-----------------------------------------------part2----------------------------------------------------\nconst generaltheme = {\n height: \"90px\",\n align: \"center\",\n description: \"\",\n brand: \"BOS Activity\",\n fontsize: \"35px\",\n fontweight: \"25px\",\n afterbrand: \"Profile\",\n afterbrandcolor: themeColor?.dynamic_header?.afterbrandcolor || \"#789efb\",\n fontbrand: \" Arial, sans-serif\",\n color1brand: themeColor?.dynamic_header?.color1brand || \"#000\",\n color2brand: themeColor?.dynamic_header?.color2brand || \"#806ce1\",\n colordescription: themeColor?.dynamic_header?.colordescription || \"#806ce1\",\n fontsubtitle: \" Arial, sans-serif\",\n background:\n themeColor?.dynamic_header?.background ||\n \"radial-gradient(circle, rgba(210,202,250,1) 0%, rgba(230,230,231,0.01) 0%, rgba(235,238,255,1) 100%, rgba(235,231,253,1) 100%, rgba(255,241,241,1) 100%, rgba(46,52,90,1) 100%);\",\n};\nconst baseHeaderDynamic = {\n height: \"80px\",\n align: \"center\",\n description: ``,\n brand: ``,\n fontsize: \"15px\",\n fontweight: \"10px\",\n afterbrand: \"\",\n afterbrandcolor: themeColor?.dynamic_header?.afterbrandcolor || \"#789efb\",\n fontbrand: \" Arial, sans-serif\",\n color1brand: themeColor?.dynamic_header?.color1brand || \"#000\",\n color2brand: themeColor?.dynamic_header?.color2brand || \"#806ce1\",\n colordescription: themeColor?.dynamic_header?.colordescription || \"#806ce1\",\n fontsubtitle: \" Arial, sans-serif\",\n background:\n themeColor?.dynamic_header?.background ||\n \"radial-gradient(circle, rgba(210,202,250,1) 0%, rgba(230,230,231,0.01) 0%, rgba(235,238,255,1) 100%, rgba(235,231,253,1) 100%, rgba(255,241,241,1) 100%, rgba(46,52,90,1) 100%);\",\n};\nconst cardObjects = [\n {\n name: \"followers\",\n description: `${numFollowers}`,\n brand: \"Followers\",\n afterbrand: \"\",\n },\n {\n name: \"followings\",\n description: `${numFollowing}`,\n brand: \"Followings\",\n afterbrand: \"\",\n },\n { name: \"posts\", description: `${numposts}`, brand: \"Posts\", afterbrand: \"\" },\n {\n name: \"reposts\",\n description: `${numreposts}`,\n brand: \"Reposts\",\n afterbrand: \"\",\n },\n {\n name: \"comments\",\n description: `${numcomments}`,\n brand: \"Comments\",\n afterbrand: \"\",\n },\n { name: \"likes\", description: `${numlikes}`, brand: \"Likes\", afterbrand: \"\" },\n {\n name: \"pokes\",\n description: `${numPokes}`,\n brand: \"Pokes\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"tx_widgets\",\n description: `${tx_numwidgets}`,\n brand: \"Widgets (trx)\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"received_pokes\",\n description: `${numReceivedPoke}`,\n brand: \"Received\",\n afterbrand: \"Pokes\",\n },\n {\n name: \"received_likes\",\n description: `${numReceivedLike}`,\n brand: \"Received\",\n afterbrand: \"Likes\",\n },\n {\n name: \"received_comments\",\n description: `${numReceivedComment}`,\n brand: \"Received\",\n afterbrand: \"Comments\",\n },\n {\n name: \"received_reposts\",\n description: `${numReceivedRepost}`,\n brand: \"Received\",\n afterbrand: \"Reposts\",\n },\n {\n name: \"mentions\",\n description: `${nummention}`,\n brand: \"Mentions\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"widgets\",\n description: `${numWidgets}`,\n brand: \"Widgets\",\n afterbrand: \"\",\n },\n {\n name: \"joinDate\",\n description: `${joinDate}`,\n brand: \"Join Date\",\n afterbrand: \"\",\n offChart: true,\n offGrid: true,\n },\n {\n name: \"hashtags\",\n description: `${numHashtags}`,\n brand: \"Hashtags\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"forkof\",\n description: `${numForkof}`,\n brand: \"Forks\",\n afterbrand: \"\",\n offChart: true,\n },\n {\n name: \"star-unstar\",\n description: `${numUn_star}`,\n brand: \"Un/star\",\n afterbrand: \"\",\n },\n {\n name: \"total-tx\",\n description: `${numTotalTx}`,\n brand: \"Total trx\",\n afterbrand: \"\",\n offChart: true,\n offGrid: true,\n },\n];\n//---------------------------------------------------------------------------------------------------\nconst SearchInput = (\n <div\n style={{ background: themeColor?.sbt_area?.section_bg }}\n className=\"search p-4\"\n >\n <div className=\"row\">\n <div className=\"col-8 \">\n <Input\n onBlur={inputHandler}\n defaultValue={state.singer}\n type=\"input\"\n className=\"form-control form-control-lg rounded-4\"\n id=\"address\"\n placeholder=\"jlw.near\"\n />\n </div>\n <div className=\"col-4 col-lg-auto\">\n <Button\n disabled={state.isLoading}\n onClick={handleData}\n className=\"btn-lg\"\n type=\"button\"\n >\n {state.isLoading ? (\n <div className=\"text-center px-4\">\n <div className=\"spinner-border spinner-border-sm\" role=\"status\">\n <span className=\"visually-hidden\">Loading...</span>\n </div>\n </div>\n ) : (\n \"search\"\n )}\n </Button>\n </div>\n </div>\n </div>\n);\nconst TableSection = (\n <div\n style={{ background: themeColor?.sbt_area?.section_bg }}\n className=\"shadow-sm rounded-2 overflow-auto p-2\"\n >\n <div\n className=\"container\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div className=\"row\">\n <div className=\"col-md-12\">\n <div className=\"row\">\n <div className=\"col-md-6\">\n <Widget\n src=\"lord1.near/widget/nearwidgetProfile\"\n props={{\n accountId: singer,\n themeColor: {\n profile_large: themeColor.profile_large,\n profileInlineBlock: { ...themeColor.profileInlineBlock },\n },\n }}\n />\n </div>\n <div className=\"col-md-4\">\n <Widget\n src=\"lord1.near/widget/header-dynamic\"\n props={{\n ...baseHeaderDynamic,\n ...cardObjects.find((o) => o.name === \"joinDate\"),\n }}\n />\n </div>\n <div className=\"col-md-2\">\n <Widget\n src=\"lord1.near/widget/header-dynamic\"\n props={{\n ...baseHeaderDynamic,\n ...cardObjects.find((o) => o.name === \"total-tx\"),\n }}\n />\n </div>\n </div>\n </div>\n </div>\n <div className=\"row\">\n <div className=\"col-md-12\">\n <div className=\"row\">\n {cardObjects\n .filter((o) => !o.offGrid)\n .map((card) => (\n <div key={card.name} className=\"col-md-2\">\n <Widget\n src=\"lord1.near/widget/header-dynamic\"\n props={{ ...baseHeaderDynamic, ...card }}\n />\n </div>\n ))}\n </div>\n </div>\n </div>\n </div>\n </div>\n);\n// --------------------- pie chart ------------------------\nconst getPieProps = (data, [key, value], colors, chartOption) => {\n data = data || [];\n colors = colors || [];\n chartOption = chartOption || {};\n const dataFormat = data.map((s) => [s[key], s[value]]);\n const props = {\n data: dataFormat,\n colors: colors,\n chartOption: {\n title: \"chart title\",\n type: \"pie\",\n legend: false,\n connector: false,\n ...chartOption,\n },\n themeColor: { chart: themeColor.chart },\n spinnerColors: themeColor.spinnerColors,\n };\n return props;\n};\nconst pieChartData = () => {\n return cardObjects\n .filter((o) => !o.offChart)\n .map((o) => {\n return {\n title: `${o.brand} ${o.afterbrand}`,\n value: Number.parseInt(o.description),\n };\n });\n};\nconst PieChart = (\n <div\n className=\"col-lg-8\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4 \"\n >\n <Widget\n src=\"lord1.near/widget/Pie-chart\"\n props={getPieProps(\n pieChartData(),\n [\"title\", \"value\"],\n themeColor.chartColor,\n {\n title: \"Social Actions\",\n subtitle: \"Social Actions\",\n type: \"pie\",\n connector: true,\n legend: true,\n }\n )}\n />\n </div>\n </div>\n);\n// -------------------- mix chart -------------------\nlet blockHeightData = fetch(\n `https://api.flipsidecrypto.com/api/v2/queries/6b01d203-0d80-4e70-84ee-c6aa37578ce8/data/latest`\n);\nblockHeightData = blockHeightData.body || [];\nconst getMixData = (accountId) => {\n const myData = {};\n const initDataValue = {\n follower: 0,\n follow: 0,\n like: 0,\n post: 0,\n comment: 0,\n repost: 0,\n un_star: 0,\n receivedComment: 0,\n receivedLike: 0,\n receivedPoke: 0,\n receivedRepost: 0,\n widgets: 0,\n };\n followers &&\n Object.values(followers).forEach((i) => {\n const count = myData[i.graph.follow[accountId]];\n myData[i.graph.follow[accountId]] = {\n ...initDataValue,\n ...count,\n follower: (count.follower ?? 0) + 1,\n };\n });\n following &&\n Object.values(following[accountId]?.graph?.follow || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n follow: (count.follow ?? 0) + 1,\n };\n });\n likes &&\n Object.values(likes[accountId]?.index?.like || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n like: (count.like ?? 0) + 1,\n };\n });\n posts &&\n Object.values(posts[accountId]?.index?.post || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n post: (count.post ?? 0) + 1,\n };\n });\n comments &&\n Object.values(comments[accountId]?.post?.comment || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n comment: (count.comment ?? 0) + 1,\n };\n });\n reposts &&\n Object.values(reposts[accountId]?.index?.repost || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n repost: (count.repost ?? 0) + 1,\n };\n });\n un_star &&\n Object.values(un_star[accountId]?.index?.star || {}).forEach((i) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n un_star: (count.un_star ?? 0) + 1,\n };\n });\n receivedComment.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedComment: (count.receivedComment ?? 0) + 1,\n };\n });\n receivedLike.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedLike: (count.receivedLike ?? 0) + 1,\n };\n });\n receivedPoke.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedPoke: (count.receivedPoke ?? 0) + 1,\n };\n });\n receivedRepost.forEach(({ blockHeight }) => {\n const count = myData[blockHeight];\n myData[blockHeight] = {\n ...initDataValue,\n ...count,\n receivedRepost: (count.receivedRepost ?? 0) + 1,\n };\n });\n widgets &&\n Object.values(widgets[accountId]?.widget || {}).forEach(([i]) => {\n const count = myData[i];\n myData[i] = {\n ...initDataValue,\n ...count,\n widgets: (count.widgets ?? 0) + 1,\n };\n });\n return myData;\n};\nconst splitTime = () => {\n let timeIndex = 0;\n const splitedData = {};\n Object.entries(getMixData(singer)).forEach(([blockTime, counts]) => {\n for (; timeIndex <= blockHeightData.length; ++timeIndex) {\n if (\n timeIndex === 0 &&\n Number(blockTime) < blockHeightData[timeIndex].min_block\n ) {\n break;\n }\n if (\n (Number(blockTime) >= blockHeightData[timeIndex].min_block &&\n Number(blockTime) <= blockHeightData[timeIndex].max_block) ||\n (timeIndex === blockHeightData.length - 1 &&\n Number(blockTime) > blockHeightData[timeIndex].max_block)\n ) {\n const prevCount = splitedData[blockHeightData[timeIndex].date] ?? {\n follower: 0,\n follow: 0,\n like: 0,\n post: 0,\n comment: 0,\n repost: 0,\n un_star: 0,\n receivedComment: 0,\n receivedLike: 0,\n receivedPoke: 0,\n receivedRepost: 0,\n widgets: 0,\n };\n const newCount = {\n follower: prevCount.follower + counts.follower,\n follow: prevCount.follow + counts.follow,\n like: prevCount.like + counts.like,\n post: prevCount.post + counts.post,\n comment: prevCount.comment + counts.comment,\n repost: prevCount.repost + counts.repost,\n un_star: prevCount.un_star + counts.un_star,\n receivedComment: prevCount.receivedComment + counts.receivedComment,\n receivedLike: prevCount.receivedLike + counts.receivedLike,\n receivedPoke: prevCount.receivedPoke + counts.receivedPoke,\n receivedRepost: prevCount.receivedRepost + counts.receivedRepost,\n widgets: prevCount.widgets + counts.widgets,\n };\n splitedData[blockHeightData[timeIndex].date] = newCount;\n break;\n } else {\n continue;\n }\n }\n });\n return Object.entries(splitedData).map(([date, values]) => {\n return { date: new Date(date).getTime(), ...values };\n });\n};\nconst getMixProps = (data, dateKey, serieses, colors, chartOption) => {\n data = data || [];\n serieses = serieses || [{ key: \"\", seriesName: \"\", type: \"\", id: 1 }];\n colors = colors || [];\n chartOption = chartOption || {};\n const dataFormat = serieses.map((series) => {\n const dataFormated = data.map((d) => [d[dateKey], d[series.key] || null]);\n return {\n data: dataFormated,\n name: series.seriesName,\n type: series.type,\n axisId: series.id,\n };\n });\n const props = {\n series: dataFormat,\n colors: colors,\n chartOption: {\n title: \"chart title\",\n subtitle: \"chart subtitle\",\n legend: true,\n stacking: \"false\",\n ...chartOption,\n },\n overrideOptions: {\n plotOptions: {\n column: {\n stacking: \"false\",\n },\n series: {\n dataGrouping: { enabled: false },\n },\n },\n },\n themeColor: { chart: themeColor.chart },\n spinnerColors: themeColor.spinnerColors,\n };\n return props;\n};\nconst MixChart = (\n <div className=\"col-lg-12\">\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n src=\"lord1.near/widget/mix-chart\"\n props={getMixProps(\n splitTime(),\n \"date\",\n [\n {\n key: \"follow\",\n seriesName: \"Follow\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"follower\",\n seriesName: \"Follower\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"like\",\n seriesName: \"Like\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"post\",\n seriesName: \"Post\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"comment\",\n seriesName: \"Comment\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"repost\",\n seriesName: \"Repost\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"un_star\",\n seriesName: \"Un/Star\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedRepost\",\n seriesName: \"Received Repost\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedLike\",\n seriesName: \"Received Like\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedComment\",\n seriesName: \"Received Comment\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"receivedPoke\",\n seriesName: \"Received Poke\",\n type: \"column\",\n id: 1,\n },\n {\n key: \"widgets\",\n seriesName: \"widgets\",\n type: \"column\",\n id: 1,\n },\n ],\n themeColor.chartColor,\n {\n title: \"\",\n subtitle: \"Daily social actions\",\n }\n )}\n />\n </div>\n </div>\n);\n// --------------- social graph -------------------\nconst SocialGraph = (\n <div\n className=\"col-lg-4\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n key={state.data}\n src=\"lord1.near/widget/SocialGraph\"\n props={{\n accountIds: [state.data, \"\"],\n spinnerColors: themeColor.spinnerColors,\n }}\n />\n </div>\n </div>\n);\n// --------------- nodes -------------------\nconst Nodes = (\n <div\n className=\"col-lg-12 pb-4\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n key={state.data}\n src=\"hyperbuild.near/widget/explore.view.tree\"\n props={{\n rootPath: state.data,\n themeColor: themeColor.tree,\n }}\n />\n </div>\n </div>\n);\n// -------------------------------------------\nreturn (\n <div style={{ backgroundColor: themeColor.page_bg }}>\n <Widget src=\"lord1.near/widget/header-dynamic\" props={generaltheme} />\n {SearchInput}\n {TableSection}\n <div style={{ width: \"100%\", height: \"30px\" }}></div>\n <div\n className=\"row rounded-3\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n {PieChart}\n {SocialGraph}\n </div>\n <div style={{ width: \"100%\", height: \"20px\" }}></div>\n <div\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n backgroundColor: themeColor.card?.card_bg,\n }}\n className=\"p-2 rounded-3\"\n >\n <div className=\"row\">{MixChart}</div>\n </div>\n <div className=\"toast-container position-fixed bottom-0 end-0 p-3\">\n {state.error.length > 0 &&\n state.error.map((er) => (\n <div\n className=\"toast show align-items-center text-bg-danger border-0\"\n role=\"alert\"\n aria-live=\"assertive\"\n aria-atomic=\"true\"\n >\n <div className=\"d-flex\">\n <div className=\"toast-body\">{er}</div>\n </div>\n </div>\n ))}\n </div>\n </div>\n);\n" }, "create.edit.schema": { "": "// TO DO:\n// schema typechecking with PropTypes\n//\nconst { generateUID } = VM.require(\"flowscience.near/widget/generateUID\");\nconst path = props.path;\nconst typeSrc = props.typeSrc || \"every.near\";\nconst schemaSrc = context.accountId ?? props.schemaSrc ?? \"attestations.near\";\nconst blockHeight = props.blockHeight || \"final\";\nconst selectedSchema = props.selectedSchema;\nlet type = {\n name: \"\",\n properties: [],\n widgets: {},\n};\nconst [jsonSchema, setJsonSchema] = useState({\n schema: path,\n id: generateUID(),\n title: \"\",\n description: \"\",\n schemaType: \"object\", // Default to 'object'\n properties: [],\n required: [],\n});\nState.init({\n newType: typeSrc,\n typeName: type.name || \"\",\n properties: type.properties || [],\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newTypeSrc: \"\",\n typeSrc: typeSrc,\n schemaSrc: schemaSrc,\n expanded: false,\n selectedSchema: selectedSchema,\n schemaPath: path,\n});\nlet importedTypes = [];\nif (state.typeSrc !== \"\") {\n const defaultTypes = Social.get(`every.near/type/**`, \"final\");\n const hyperfilesTypes = Social.get(`hyperfiles.near/type/**`, \"final\");\n const types = Social.get(`${state.typeSrc}/type/**`, \"final\");\n if (!types) {\n return <></>;\n }\n importedTypes =\n Object.keys(types)?.map((it) => `${state.typeSrc}/type/${it}`) || [];\n}\nconst availableTypes = JSON.parse(props.availableTypes) || [\n \"string\",\n \"boolean\",\n \"number\",\n \"date\",\n \"time\",\n \"tags\",\n ...importedTypes,\n];\nconst create = () => {\n const output = {\n schema: {\n [jsonSchema.title]: JSON.stringify({\n ...jsonSchema,\n properties: state.properties,\n required:\n state.properties &&\n state.properties\n .filter((it) => it.isRequired)\n .map((it) => (it = it.name)),\n }),\n },\n };\n Social.set(output, { force });\n};\nconst Container = styled.div`\n margin: 20px 0;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Row = styled.div`\n display: flex;\n gap: 10px;\n`;\nconst Input = styled.input`\n flex: 1;\n max-width: 200px;\n margin-bottom: 10px;\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n height: 30px;\n`;\nconst Text = styled.p`\n display: inline-block;\n margin-right: 10px;\n`;\nconst Label = styled.label`\n display: block;\n margin-bottom: 5px;\n`;\nconst loadType = () => {\n const parts = state.newType.split(\"/\");\n type = JSON.parse(Social.get(state.newType, blockHeight) || null);\n if (type) {\n type.name = parts[2];\n State.update({\n typeName: type.name,\n properties: type.properties,\n widgets: type.widgets,\n });\n }\n};\nif (prop.typeSrc !== \"\" && state.typeName === \"\") {\n loadType();\n}\n// fix loadSchema\nconst loadSchema = () => {\n State.update({ selectedSchema: newSchema });\n const parts = state.newSchema.split(\"/\");\n schema = JSON.parse(Social.get(state.newSchema, blockHeight) || null);\n if (schema) {\n schema.name = parts[2];\n State.update({\n schemaName: schema.name,\n properties: schema.properties,\n widgets: type.widgets,\n });\n }\n};\nif (prop.schemaSrc !== \"\" && state.schemaName === \"\") {\n loadSchema();\n}\n// fix handleJsonSchemaChange\nconst handleJsonSchemaChange = (e) => {\n const { name, value } = e.target; // Destructure name and value from the event target\n setJsonSchema((prevJsonSchema) => ({\n ...prevJsonSchema,\n [name]: value, // Dynamically update the property based on input name\n }));\n};\nconst handleSchemaTitleChange = (e) => {\n const value = e.target.value;\n setJsonSchema((prev) => ({ ...prev, title: value }));\n};\nconst handleSchemaDescriptionChange = (e) => {\n const value = e.target.value;\n setJsonSchema((prev) => ({ ...prev, description: value }));\n};\nconst handleSchemaTypeChange = (e) => {\n const value = e.target.value;\n setJsonSchema((prev) => ({ ...prev, schemaType: value }));\n};\nconst handleAddProperty = () => {\n if (state.newPropertyName.trim() === \"\") return;\n const newProperty = {\n name: state.newPropertyName,\n type: state.newPropertyType,\n isRequired: state.newPropertyIsRequired,\n isMulti: state.newPropertyIsMulti,\n };\n State.update({\n properties: [...state.properties, newProperty],\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newPropertyisRequired: false,\n newPropertyIsMulti: false,\n });\n};\nconst handleRemoveProperty = (index) => {\n const updatedProperties = [...state.properties];\n updatedProperties.splice(index, 1);\n State.update({ properties: updatedProperties });\n};\nconst handlePropertyNameChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].name = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleTypeChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].type = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleMultiChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].isMulti = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleRequiredChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].isRequired = e.target.value;\n State.update({ properties: updatedProperties });\n setJsonSchema((prev) => ({\n ...prev,\n required: updatedProperties,\n }));\n};\nfunction TypeSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n {availableTypes.map((it) => (\n <option value={it} key={it}>\n {it}\n </option>\n ))}\n </Select>\n );\n}\n// convert Multi and Required selects to checkboxes\nfunction MultiSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n <option value={false}>single</option>\n <option value={true}>multi</option>\n </Select>\n );\n}\nfunction RequiredSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n <option value={false}>no</option>\n <option value={true}>yes</option>\n </Select>\n );\n}\nreturn (\n <Container>\n <Row>\n <Text>\n <b>Import Schema:</b>\n </Text>\n <Input\n type=\"text\"\n value={state.newSchema}\n onChange={(e) => State.update({ newSchema: e.target.value })}\n placeholder={\"account/schema/title\"}\n />\n <Button onClick={loadSchema}>load</Button>\n </Row>\n <Row>\n <Text>\n <b>Import Types:</b>\n </Text>\n <Input\n type=\"text\"\n value={state.newTypeSrc}\n onChange={(e) => State.update({ newTypeSrc: e.target.value })}\n placeholder={\"hyperfiles.near\"}\n />\n <Button onClick={() => State.update({ typeSrc: state.newTypeSrc })}>\n apply\n </Button>\n </Row>\n <FormContainer>\n <Row>\n <Text>\n <b>Title:</b>\n </Text>\n <Input\n type=\"text\"\n name=\"title\"\n value={jsonSchema.title}\n onChange={handleSchemaTitleChange}\n placeholder=\"Schema_Title\"\n />\n <i>*overwrites existing path when saved</i>\n </Row>\n <Row>\n <Text>\n <b>Description:</b>\n </Text>\n <Input\n type=\"text\"\n placeholder=\"Concisely explain.\"\n value={jsonSchema.description}\n onChange={handleSchemaDescriptionChange}\n />\n </Row>\n <Row>\n <Text>\n <b>Schema Type:</b>\n </Text>\n <Select value={value} onChange={handleSchemaTypeChange}>\n <option value={\"object\"}>object</option>\n <option value={\"boolean\"}>boolean</option>\n </Select>\n </Row>\n <hr></hr>\n <Text>\n <h4>Schema Properties</h4>\n <i>*Add properties below that are relevant to your use case.</i>\n <br />\n <br />\n <b>1.</b> [Name]: describe the property\n <br />\n <b>2.</b> [Type]: how is the property structured?\n <a href=\"https://everything.dev/every.near/widget/every.type.create\">\n <i>[Define new types]</i>\n </a>\n <br />\n <b>3.</b> [Single/Multi]: can the property be an array?\n <br />\n <b>4.</b> [Required]: is the property required?\n </Text>\n {state.properties?.map((property, index) => (\n <Row key={index}>\n <div>\n <Label>Name:</Label>\n <Input\n type=\"text\"\n value={property.name}\n onChange={(e) => handlePropertyNameChange(e, index)}\n />\n </div>\n <div>\n <Label>Property Type:</Label>\n <TypeSelect\n value={property.type}\n onChange={(e) => handleTypeChange(e, index)}\n />\n </div>\n <div>\n <Label>isMulti:</Label>\n <MultiSelect\n value={property.isMulti}\n onChange={(e) => handleMultiChange(e, index)}\n />\n </div>\n <div>\n <Label>Required:</Label>\n <RequiredSelect\n value={property.isRequired}\n onChange={(e) => handleRequiredChange(e, index)}\n />\n </div>\n <div>\n <Label>Remove:</Label>\n <Button onClick={() => handleRemoveProperty(index)}>Remove</Button>\n </div>\n </Row>\n ))}\n <Row>\n <div>\n <Label>New Property Name:</Label>\n <Input\n type=\"text\"\n placeholder=\"Property Name\"\n value={state.newPropertyName}\n onChange={(e) => State.update({ newPropertyName: e.target.value })}\n />\n </div>\n <div>\n <Label>New Type:</Label>\n <TypeSelect\n value={state.newPropertyType}\n onChange={(e) => State.update({ newPropertyType: e.target.value })}\n />\n </div>\n <div>\n <Label>isMulti:</Label>\n <MultiSelect\n value={state.newPropertyIsMulti}\n onChange={(e) =>\n State.update({ newPropertyIsMulti: e.target.value })\n }\n />\n </div>\n <div>\n <Label>Required:</Label>\n <RequiredSelect\n value={state.newPropertyIsRequired}\n onChange={(e) =>\n State.update({ newPropertyIsRequired: e.target.value })\n }\n />\n </div>\n <div>\n <Label>Add:</Label>\n <Button\n onClick={handleAddProperty}\n disabled={state.newPropertyName.trim() === \"\"}\n >\n +\n </Button>\n </div>\n </Row>\n <hr></hr>\n <Row>\n <Button\n onClick={create}\n disabled={state.properties.length === 0}\n className=\"styless\"\n >\n Publish/Update Schema\n </Button>\n </Row>\n </FormContainer>\n </Container>\n);\n``;\n" }, "explore.view.data": { "": "const DataViewer = ({ path, adapter }) => {\n const [data, setData] = useState(null);\n\n useEffect(() => {\n const fetchData = async () => {\n const adapterScript = VM.require(adapter);\n const content = await adapterScript.get(path);\n setData(content);\n };\n fetchData();\n }, [path, adapter]);\n\n return data ? (\n <div className=\"container\">\n {/* Render content based on data type here */}\n </div>\n ) : (\n <p>Loading...</p>\n );\n};\n" }, "explore.select.source.array": { "": "const sourceArray = [{ name: \"Text\" }, { name: \"Canvas\" }, { name: \"Other\" }];\nconst label = props.label ?? \"Label\";\nconst placeholder = props.placeholder ?? \"Placeholder\";\nconst value = props.value ?? \"\";\nconst options = props.options ?? sourceArray;\nconst onChange = props.onChange ?? (() => {});\nconst validate = props.validate ?? (() => {});\nconst error = props.error ?? \"\";\nconst labelKey = props.labelKey ?? \"name\";\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n justify-content: flex-start;\n padding: 0px;\n gap: 0.45em;\n width: 100%;\n .typeahead {\n width: 100%;\n & > div {\n padding: 0.5em 0.75em;\n background: #ffffff;\n border: 1px solid #d0d5dd;\n box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05);\n border-radius: 4px;\n color: #101828;\n }\n .rbt-token {\n background: #f2f4f7;\n border: 1px solid #d0d5dd;\n border-radius: 3px;\n font-style: normal;\n font-weight: 500;\n font-size: 0.95em;\n line-height: 1.25em;\n text-align: center;\n color: #344054;\n & > button {\n font-size: 1.25em;\n color: #98a2b3;\n }\n }\n }\n`;\nconst Label = styled.label`\n font-style: normal;\n font-weight: 600;\n font-size: 0.95em;\n line-height: 1.25em;\n color: #344054;\n`;\nconst Error = styled.span`\n display: inline-block;\n font-style: normal;\n font-weight: 400;\n font-size: 0.75em;\n line-height: 1.25em;\n color: #ff4d4f;\n height: 0;\n overflow: hidden;\n transition: height 0.3s ease-in-out;\n &.show {\n height: 1.25em;\n }\n`;\nreturn (\n <Container>\n {props.noLabel ? <></> : <Label>{label}</Label>}\n <Typeahead\n id\n placeholder={placeholder}\n labelKey={labelKey}\n onChange={onChange}\n options={options}\n selected={value}\n className=\"typeahead\"\n positionFixed\n allowNew\n />\n <Error className={error ? \"show\" : \"\"}>{error}</Error>\n </Container>\n);\n" }, "explore.view.hyperfile": { "": "const { path } = props;\nif (!path) {\n return <p>No path provided.</p>;\n}\nconst thing = Social.get(`${path}/**`, \"final\");\nif (!thing) {\n return <p>Loading...</p>;\n}\nconst hyperfile = JSON.parse(thing[\"\"]);\nconst { get } = VM.require(hyperfile.adapter || (() => {}));\nif (get) {\n const content = get(hyperfile.reference);\n if (content === null) return <p>no content</p>;\n return (\n <div className=\"container\">\n {thing.metadata.type === \"md\" ? (\n <Widget\n src=\"openwebbuild.near/widget/Post.Markdown\"\n props={{\n text: content,\n }}\n />\n ) : (\n <p>viewer does not currently support type: {thing.type}</p>\n )}\n </div>\n );\n} else {\n return <p>Invalid adapter: {hyperfile.adapter}</p>;\n}\n" }, "create.edit.type": { "": "const typeSrc = props.typeSrc || \"\";\nconst blockHeight = props.blockHeight || \"final\";\nlet type = {\n name: \"\",\n properties: [],\n widgets: {},\n};\nState.init({\n newType: typeSrc,\n typeName: type.name || \"\",\n properties: type.properties || [],\n widgets: type.widgets || {},\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newWidgetKey: \"\",\n newWidgetSrc: \"\",\n newTypeSrc: \"every.near\",\n typeSrc: \"every.near\",\n expanded: false,\n});\nlet importedTypes = [];\nif (state.typeSrc !== \"\") {\n const types = Social.get(`${state.typeSrc}/type/**`, \"final\");\n if (!types) {\n return <></>;\n }\n importedTypes =\n Object.keys(types)?.map((it) => `${state.typeSrc}/type/${it}`) || [];\n}\nconst availableTypes = JSON.parse(props.availableTypes) || [\n \"string\",\n \"boolean\",\n \"number\",\n \"date\",\n \"time\",\n \"tags\",\n ...importedTypes,\n];\nconst Container = styled.div`\n margin: 20px;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Row = styled.div`\n display: flex;\n gap: 10px;\n`;\nconst Input = styled.input`\n flex: 1;\n max-width: 200px;\n margin-bottom: 10px;\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n height: 30px;\n`;\nconst Text = styled.p`\n display: inline-block;\n margin-right: 10px;\n`;\nconst loadType = () => {\n const parts = state.newType.split(\"/\");\n type = JSON.parse(Social.get(state.newType, blockHeight) || null);\n if (type) {\n type.name = parts[2];\n State.update({\n typeName: type.name,\n properties: type.properties,\n widgets: type.widgets,\n });\n }\n};\nconst handleAddProperty = () => {\n if (state.newPropertyName.trim() === \"\") return;\n const newProperty = {\n name: state.newPropertyName,\n type: state.newPropertyType,\n required: state.newPropertyRequired,\n isMulti: state.newPropertyIsMulti,\n };\n State.update({\n properties: [...state.properties, newProperty],\n newPropertyName: \"\",\n newPropertyType: \"string\",\n newPropertyIsMulti: false,\n });\n};\nconst handleRemoveProperty = (index) => {\n const updatedProperties = [...state.properties];\n updatedProperties.splice(index, 1);\n State.update({ properties: updatedProperties });\n};\nconst handlePropertyChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].name = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleTypeChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].type = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleMultiChange = (e, index) => {\n const updatedProperties = [...state.properties];\n updatedProperties[index].isMulti = e.target.value;\n State.update({ properties: updatedProperties });\n};\nconst handleTypeNameChange = (e) => {\n State.update({ typeName: e.target.value.toLowerCase() });\n};\nconst handleWidgetKeyChange = (e) => {\n State.update({ newWidgetKey: e.target.value.toLowerCase() });\n};\nconst handleWidgetSrcChange = (e) => {\n State.update({ newWidgetSrc: e.target.value });\n};\nconst handleAddWidget = () => {\n if (state.newWidgetKey.trim() === \"\" || state.newWidgetSrc.trim() === \"\")\n return;\n const newWidget = {\n [state.newWidgetKey]: state.newWidgetSrc,\n };\n State.update({\n widgets: { ...state.widgets, ...newWidget },\n newWidgetKey: \"\",\n newWidgetSrc: \"\",\n });\n};\nconst handleRemoveWidget = (key) => {\n const updatedWidgets = { ...state.widgets };\n delete updatedWidgets[key];\n State.update({ widgets: updatedWidgets });\n};\nconst composeData = () => {\n const data = {\n type: {\n [state.typeName]: JSON.stringify({\n properties: state.properties,\n widgets: state.widgets,\n }),\n },\n };\n return data;\n};\nfunction TypeSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n {availableTypes.map((it) => (\n <option value={it} key={it}>\n {it}\n </option>\n ))}\n </Select>\n );\n}\nfunction MultiSelect({ value, onChange }) {\n return (\n <Select value={value} onChange={onChange}>\n <option value={false}>single</option>\n <option value={true}>multi</option>\n </Select>\n );\n}\nreturn (\n <Container>\n <Widget src=\"hyperbuild.near/widget/explore.select.type\" />\n <FormContainer>\n <Row>\n <Text>Type Name:</Text>\n <Input\n type=\"text\"\n placeholder=\"Type Name\"\n value={state.typeName}\n onChange={handleTypeNameChange}\n />\n </Row>\n <Text>Properties:</Text>\n {state.properties?.map((property, index) => (\n <Row key={index}>\n <Input\n type=\"text\"\n value={property.name}\n onChange={(e) => handlePropertyChange(e, index)}\n />\n <TypeSelect\n value={property.type}\n onChange={(e) => handleTypeChange(e, index)}\n />\n <MultiSelect\n value={property.isMulti}\n onChange={(e) => handleMultiChange(e, index)}\n />\n <Button onClick={() => handleRemoveProperty(index)}>Remove</Button>\n </Row>\n ))}\n <Row>\n <Input\n type=\"text\"\n placeholder=\"Property Name\"\n value={state.newPropertyName}\n onChange={(e) => State.update({ newPropertyName: e.target.value })}\n />\n <TypeSelect\n value={state.newPropertyType}\n onChange={(e) => State.update({ newPropertyType: e.target.value })}\n />\n <MultiSelect\n value={state.newPropertyIsMulti}\n onChange={(e) => State.update({ newPropertyIsMulti: e.target.value })}\n />\n <Button\n onClick={handleAddProperty}\n disabled={state.newPropertyName.trim() === \"\"}\n >\n Add Property\n </Button>\n </Row>\n <Text>Widgets:</Text>\n {Object.entries(state.widgets)?.map(([key, src]) => (\n <Row key={key}>\n <Text>{key}:</Text>\n <Input type=\"text\" value={src} onChange={() => {}} />\n <Button onClick={() => handleRemoveWidget(key)}>Remove</Button>\n </Row>\n ))}\n <Row>\n <Input\n type=\"text\"\n placeholder=\"Widget Key\"\n value={state.newWidgetKey}\n onChange={handleWidgetKeyChange}\n />\n {\":\"}\n <Input\n type=\"text\"\n placeholder=\"Widget Src\"\n value={state.newWidgetSrc}\n onChange={handleWidgetSrcChange}\n />\n <Button\n onClick={handleAddWidget}\n disabled={\n state.newWidgetKey.trim() === \"\" || state.newWidgetSrc.trim() === \"\"\n }\n >\n Add Widget\n </Button>\n </Row>\n <Row>\n <CommitButton\n force\n data={composeData()}\n disabled={state.properties.length === 0}\n className=\"styless\"\n >\n create\n </CommitButton>\n </Row>\n </FormContainer>\n </Container>\n);\n" }, "tools.files.provider": { "": "const path = props.path || context.accountId;\nif (!path) return <p>Please login.</p>;\nconst getSecretKey = () => {\n const accountId = context.accountId;\n if (!accountId) {\n return null;\n }\n const registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n );\n const savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\n\n if (savedSecretKeyBase64 === null || registeredPublicKey === null) {\n return null;\n }\n\n return savedSecretKeyBase64;\n};\n\nconst savedSecretKeyBase64 = getSecretKey();\nif (!savedSecretKeyBase64) {\n return \"Enter a Secret Key or Password to unlock your files.\";\n}\nState.init({\n layout: \"LIST\",\n path,\n history: [path],\n currentHistoryIndex: 0,\n showPreview: false,\n selectedPath: \"\",\n filesSource: \"BOS_IPFS\",\n decryptSk: new Uint8Array(Buffer.from(savedSecretKeyBase64, \"base64\")), // Convert base64 to Uint8Array\n});\nfunction isNearAccount(str) {\n return typeof str === \"string\" && str.endsWith(\".near\");\n}\nfunction setPath(v) {\n const updatedHistory = state.history\n .slice(0, state.currentHistoryIndex + 1)\n .concat(v);\n const parts = v.split(\"/\");\n const lastPart = parts[parts.length - 1];\n if (isNearAccount(lastPart)) {\n v = lastPart;\n }\n State.update({\n path: v,\n history: updatedHistory,\n currentHistoryIndex: updatedHistory.length - 1,\n });\n}\nfunction setFilesSource(source) {\n State.update({\n filesSource: source,\n });\n console.log(\"File source set to:\", state.filesSource);\n}\nfunction goBack() {\n // Check if we can go back\n if (state.currentHistoryIndex > 0) {\n const newIndex = state.currentHistoryIndex - 1;\n State.update({\n currentHistoryIndex: newIndex,\n path: state.history[newIndex],\n });\n }\n}\nfunction goForward() {\n // Check if we can go forward\n if (state.currentHistoryIndex < state.history.length - 1) {\n const newIndex = state.currentHistoryIndex + 1;\n State.update({\n currentHistoryIndex: newIndex,\n path: state.history[newIndex],\n });\n }\n}\nfunction setSelectedPath(v) {\n State.update({ selectedPath: v });\n}\nfunction setHistory(v) {\n State.update({ history: v });\n}\nfunction setLayout(v) {\n State.update({ layout: v });\n}\nfunction togglePreview() {\n State.update({ showPreview: !state.showPreview });\n}\nconst Children = props.Children;\nreturn (\n <Children\n setPath={setPath}\n setFilesSource={setFilesSource}\n setHistory={setHistory}\n setLayout={setLayout}\n showPreview={state.showPreview}\n togglePreview={togglePreview}\n selectedPath={state.selectedPath}\n setSelectedPath={setSelectedPath}\n path={state.path}\n layout={state.layout}\n goBack={goBack}\n goForward={goForward}\n decryptSk={state.decryptSk} // Ensure decryptSk is passed here\n />\n);\n" }, "create.newthings": { "": "// Style components\nconst Input = styled.input`\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n text-transform: lowercase !important;\n padding: 8px;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Label = styled.label``;\n// Define dynamic input based on type\nconst DynamicInput = ({ type, onChange, value, placeholder }) => {\n if (type === \"boolean\") {\n return (\n <Select onChange={(e) => onChange(e.target.value)} value={value}>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </Select>\n );\n } else {\n return (\n <Input\n type={type}\n onChange={(e) => onChange(e.target.value)}\n value={value}\n placeholder={placeholder}\n />\n );\n }\n};\n// Main component\nconst NewThings = ({ item, onChange }) => {\n const [state, setState] = useState(item.value);\n const handleInputChange = (name, value) => {\n const newState = { ...state, [name]: value };\n setState(newState);\n onChange(newState);\n };\n // Import type data and widgets if needed using VM.require()\n const typeData = JSON.parse(Social.get(item.type, \"final\") || \"{}\");\n const { properties, widgets } = typeData;\n return (\n <Container>\n {properties.map((property) => (\n <Row key={property.name}>\n <Label>{property.name}</Label>\n <DynamicInput\n type={property.type}\n value={state[property.name]}\n onChange={(value) => handleInputChange(property.name, value)}\n placeholder={property.name}\n />\n </Row>\n ))}\n {widgets?.create && (\n <Widget src={widgets.create} props={{ onChange: handleInputChange }} />\n )}\n </Container>\n );\n};\nexport { NewThings };\n" }, "page.tools": { "": "const [decryptSk, setDecryptSk] = useState(null);\n// Callback function to handle the private key from PrivateMailBox\nconst handlePrivateKey = (key) => {\n setDecryptSk(key);\n console.log(\"DecryptSk:\", decryptSk); // Add this line to debug\n};\nreturn (\n <div className=\"p-3 border bg-light\">\n {/*<Widget src=\"hyperbuild.near/widget/tools.ipfsPDF\" />*/}\n <Widget\n src=\"hyperbuild.near/widget/tools.local.index\"\n props={{\n onPrivateKeyRetrieved: handlePrivateKey, // Pass the callback to retrieve the private key\n }}\n />\n <hr />\n <h1>Data Explorer</h1>\n <Widget\n src=\"hyperbuild.near/widget/tools.files.index\"\n props={{\n decryptSk,\n }}\n />\n </div>\n);\n" }, "tools.local.getSecret": { "": "function GetSecretKey() {\n const accountId = context.accountId;\n if (!accountId) {\n return null;\n }\n const registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n );\n const savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\n\n if (savedSecretKeyBase64 === null || registeredPublicKey === null) {\n return null;\n }\n\n return savedSecretKeyBase64;\n}\nreturn { GetSecretKey };\n" }, "explore.select.schema": { "": "const Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Button = styled.button``;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Select = styled.select``;\nconst Label = styled.label``;\nconst Input = styled.input``;\nconst initialSchemaSrc = props.schemaSrc || \"hyperfiles.near\";\nconst [newSchemaSrc, setNewSchemaSrc] = useState(initialSchemaSrc);\nconst [schemaSrc, setSchemaSrc] = useState(initialSchemaSrc);\nconst [selectedSchema, setSelectedSchema] = useState(\n props.selectedSchema || \"\"\n);\nconst [availableSchemas, setAvailableSchemas] = useState([]);\nconst [isLoading, setIsLoading] = useState(true);\nconst [fetchedData, setFetchedData] = useState({}); // State for debugging\nuseEffect(() => {\n setIsLoading(true);\n const fetchSchemasList = () => {\n const query = schemaSrc === \"*\" ? \"*/schema/**\" : `${schemaSrc}/schema/**`;\n const schemas = Social.get(query, \"final\");\n setFetchedData(schemas); // Store raw data for debugging\n if (schemas) {\n let schemasSet = new Set();\n if (schemaSrc === \"*\") {\n // Collect schemas from all fetched data\n Object.values(schemas).forEach((accountSchemas) => {\n Object.values(accountSchemas).forEach((schemaObj) => {\n Object.keys(schemaObj).forEach((schemaName) => {\n schemasSet.add(schemaName);\n });\n });\n });\n } else {\n // Schemas from a specific account\n Object.keys(schemas).forEach((key) => schemasSet.add(key));\n }\n setAvailableSchemas(Array.from(schemasSet));\n } else {\n setAvailableSchemas([]);\n }\n setIsLoading(false);\n };\n fetchSchemasList();\n}, [schemaSrc]);\nuseEffect(() => {\n setSelectedSchema(props.selectedSchema);\n}, [props.selectedSchema]);\nconst handleSchemaChange = (event) => {\n setSelectedSchema(event.target.value);\n if (props.onSelectedSchemaChange) {\n props.onSelectedSchemaChange(event.target.value);\n }\n};\nconst handleSchemaSrcChange = (event) => {\n setNewSchemaSrc(event.target.value);\n};\nconst applySchemaSrc = () => {\n setSchemaSrc(newSchemaSrc);\n};\nconst showAllSchemas = () => {\n setSchemaSrc(\"*\");\n};\nreturn (\n <FormContainer>\n <Label>Schema Owner:</Label>\n <Row>\n <Input\n schema=\"text\"\n onChange={handleSchemaSrcChange}\n value={newSchemaSrc}\n placeholder=\"accountId\"\n />\n <Button onClick={applySchemaSrc}>Apply</Button>\n </Row>\n <Label>Schema:</Label>\n <Row>\n {isLoading ? (\n <div>Loading...</div>\n ) : (\n <Select value={selectedSchema} onChange={handleSchemaChange}>\n <option value=\"\">Choose a schema</option>\n {availableSchemas.map((schema) => (\n <option key={schema} value={schema}>\n {schema}\n </option>\n ))}\n </Select>\n )}\n <Button onClick={showAllSchemas}>Show All</Button>\n </Row>\n </FormContainer>\n);\n// <pre>{JSON.stringify(fetchedData, null, 2)}</pre> {/* Debug output */}\n" }, "create.merge": { "": "const Wrapper = styled.div`\n max-width: 400px;\n margin: 0 auto;\n`;\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst adapters = [\n // these can come from the user (or app) settings\n // {\n // title: \"Local Storage\",\n // value: \"everycanvas.near/widget/adapter.local_storage\",\n // saveRef: false\n // },\n // {\n // title: \"SocialDB\",\n // value: \"everycanvas.near/widget/adapter.social\",\n // },\n {\n title: \"IPFS\",\n value: \"everycanvas.near/widget/adapter.ipfs\",\n },\n // {\n // title: \"GitHub\",\n // value: \"hack.near/widget/adapter.github\",\n // },\n // {\n // title: \"Obsidian\",\n // value: \"hack.near/widget/adapter.obsidian\",\n // },\n // {\n // title: \"Tldraw\",\n // value: \"hack.near/widget/adapter.tldraw\",\n // },\n];\nconst defaultAdapter = adapters[0];\nconst { creatorId } = props;\nconst [json, setJson] = useState(props.data ?? \"\");\nconst [source, setSource] = useState(props.source ?? \"\");\nconst [adapter, setAdapter] = useState(defaultAdapter.value ?? \"\");\nconst [reference, setReference] = useState(undefined);\nconst [filename, setFilename] = useState(props.filename ?? \"\");\nconst [activeTab, setActiveTab] = useState(\"data\");\nconst [name, setName] = useState(props.name ?? \"\");\nconst [description, setDescription] = useState(props.description ?? \"\");\nfunction generateUID() {\n return (\n Math.random().toString(16).slice(2) +\n Date.now().toString(36) +\n Math.random().toString(16).slice(2)\n );\n}\nconst handleCreate = () => {\n const isCreator = context.accountId === creatorId;\n // load in the state.adapter (modules for IPFS, Arweave, Ceramic, Verida, On Machina... )\n const { create } = VM.require(adapter) || (() => {});\n if (create) {\n // store the data somewhere, based on the adapter\n create(json).then((reference) => {\n // now we have a reference to the data\n // we need to name it... are we the original creator or are we forking? We don't want to overwrite any of the users custom (or maybe we do!)\n const thingId = filename ?? generateUID();\n const hyperfile = {\n [props.type]: {\n // which we store in the social contract\n [thingId]: {\n \"\": JSON.stringify({\n fileformat: `${props.type}.${source}`,\n source: source,\n adapter: adapter,\n reference: reference,\n }),\n metadata: {\n name: name,\n description: description,\n type: props.type,\n },\n },\n },\n };\n if (creatorId !== context.accountId) {\n // handle request merge\n hyperfile.index = {\n notify: JSON.stringify({\n key: creatorId,\n value: {\n type: \"request\",\n data: {\n type: \"merge\",\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n origin: `${context.accountId}/${props.type}/${thingId}`,\n },\n },\n }),\n };\n hyperfile[props.type][thingId].metadata = {\n ...hyperfile[props.type][thingId].metadata,\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n };\n // I want to make a request to merge\n // set upstream and downstream\n }\n // sometimes we're not logged in, so it doesn't do anything!\n Social.set(hyperfile, { force: true });\n });\n }\n};\nreturn (\n <Wrapper>\n <h3>{context.accountId === creatorId ? \"create\" : \"request merge\"}</h3>\n <ul className=\"nav nav-tabs\">\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"data\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"data\")}\n >\n Data\n </a>\n </li>\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"metadata\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"metadata\")}\n >\n Metadata\n </a>\n </li>\n </ul>\n <TabContent>\n {activeTab === \"data\" && (\n <Form>\n <FormGroup>\n <Label>source</Label>\n <Input\n type=\"text\"\n value={source}\n onChange={(e) => onChangeSource(e.target.value)}\n disabled={props.source} // disable if source is passed in\n />\n </FormGroup>\n {/* <Widget\n src=\"bozon.near/widget/CodeDiff\"\n props={{ currentCode: update, prevCode: src, ...props }}\n /> */}\n <textarea\n className=\"form-control mb-3\"\n rows={5}\n value={json}\n onChange={(e) => setJson(e.target.value)}\n />\n <FormGroup>\n <Label>adapter</Label>\n <Select\n value={adapter}\n onChange={(e) => setAdapter(e.target.value)}\n >\n {adapters.map((o) => (\n <option value={o.value}>{o.title}</option>\n ))}\n </Select>\n </FormGroup>\n </Form>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <Form>\n <FormGroup>\n <Label>name</Label>\n <Input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </FormGroup>\n <FormGroup>\n <Label>description</Label>\n <textarea\n className=\"form-control mb-3\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n />\n </FormGroup>\n </Form>\n )}\n </TabContent>\n <FormGroup>\n <button className=\"btn btn-success mb-1\" onClick={handleCreate}>\n Create\n </button>\n </FormGroup>\n </Wrapper>\n);\n" }, "navigation.Navbar": { "": "const StyledButton = styled.button`\n all: unset;\n display: ${(props) => (props.type === \"icon\" ? \"flex\" : \"inline-flex\")};\n width: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n height: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n padding: ${(props) => (props.type === \"icon\" ? \"0\" : \"10px 20px\")};\n justify-content: center;\n align-items: center;\n gap: 5px;\n border-radius: ${(props) => (props.type === \"icon\" ? \"50%\" : \"8px\")};\n font-size: 15px;\n letter-spacing: 2px;\n font-weight: 555;\n font-family: \"Courier\", sans-serif;\n background: ${(props) =>\n props.isActive ? \"#39f095\" : `var(--button-${props.variant}-bg, #23242B)`};\n color: ${(props) =>\n props.isActive ? \"#000\" : `var(--button-${props.variant}-color, #39f095)`};\n border: ${(props) =>\n props.variant === \"outline\"\n ? \"1px solid rgba(255, 255, 255, 0.20)\"\n : \"none\"};\n transition: background 300ms, color 300ms;\n &:hover:not(:disabled),\n &:focus {\n background: #39f095;\n color: #000;\n }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\nconst StyledNavbar = styled.div`\n width: 100%;\n justify-content: space-between;\n align-items: center;\n padding: 15px 23px;\n height: 80px;\n background-color: #0b0c14;\n border-bottom: 1px solid var(--stroke-color, rgba(255, 255, 255, 0.2));\n border-radius: 8px;\n @media screen and (max-width: 768px) {\n padding: 15px;\n }\n`;\nconst ButtonGroup = styled.div`\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n gap: 0.888rem;\n @media screen and (max-width: 768px) {\n flex-direction: column;\n width: 100%;\n a {\n display: flex;\n }\n }\n`;\nconst DesktopNavigation = styled.div`\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n @media screen and (max-width: 768px) {\n display: none;\n }\n`;\nconst MobileNavigation = styled.div`\n display: none;\n @media screen and (max-width: 768px) {\n display: flex;\n flex-direction: row;\n align-items: center;\n justify-content: space-between;\n width: 100%;\n }\n`;\nconst { href } = VM.require(\"buildhub.near/widget/lib.url\") || {\n href: () => {},\n};\nconst NavLink = ({ to, children }) => (\n <Link\n key={to}\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: to,\n },\n })}\n >\n {children}\n </Link>\n);\nconst [showMenu, setShowMenu] = useState(false);\nconst toggleDropdown = () => setShowMenu(!showMenu);\nconst SignInOrConnect = () => (\n <>\n {context.accountId ? (\n <p\n className=\"m-2\"\n style={{\n color: \"#39f095\",\n fontSize: \"16px\",\n letterSpacing: \"2px\",\n fontFamily: \"Courier, sans-serif\",\n }}\n >\n Connected\n </p>\n ) : (\n <p\n className=\"m-2\"\n style={{\n color: \"#39f095\",\n fontSize: \"16px\",\n letterSpacing: \"2px\",\n fontFamily: \"Courier, sans-serif\",\n }}\n >\n Connect\n </p>\n )}\n </>\n);\nconst Navbar = ({ page, routes, ...props }) => (\n <StyledNavbar>\n <div className=\"d-flex align-items-center justify-content-between w-100\">\n <DesktopNavigation className=\"container-xl\">\n <Link\n style={{ flex: 1 }}\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: \"home\",\n },\n })}\n >\n <img\n style={{ width: 42, objectFit: \"cover\" }}\n src=\"https://builders.mypinata.cloud/ipfs/QmQuePz1JfSQ2jh9pDCh95rHeUvPSyDrddetaWJKDXaimZ\"\n alt=\"Hyperfiles\"\n />\n </Link>\n <ButtonGroup style={{ flex: 1 }}>\n {routes &&\n (Object.keys(routes) || []).map((k) => {\n const route = routes[k];\n if (route.hide) {\n return null;\n }\n return (\n <NavLink to={k}>\n <StyledButton key={k} isActive={page === k}>\n {route.init.icon && <i className={route.init.icon}></i>}\n {route.init.name}\n </StyledButton>\n </NavLink>\n );\n })}\n </ButtonGroup>\n <div\n style={{\n flex: 1,\n display: \"flex\",\n justifyContent: \"flex-end\",\n alignItems: \"center\",\n gap: \"0.5rem\",\n }}\n >\n <SignInOrConnect />\n </div>\n </DesktopNavigation>\n <MobileNavigation>\n <Link\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: \"home\",\n },\n })}\n >\n <img\n style={{ width: 39, objectFit: \"cover\" }}\n src=\"https://builders.mypinata.cloud/ipfs/QmQuePz1JfSQ2jh9pDCh95rHeUvPSyDrddetaWJKDXaimZ\"\n alt=\"Hyperfiles\"\n />\n </Link>\n <StyledButton\n type=\"icon\"\n variant=\"outline\"\n className=\"rounded-2\"\n onClick={toggleDropdown}\n >\n <i style={{ fontSize: 24 }} className=\"bi bi-list\"></i>\n </StyledButton>\n </MobileNavigation>\n </div>\n <MobileNavigation>\n {showMenu && (\n <div className=\"text-white w-100 d-flex flex-column gap-3 mt-3\">\n <ButtonGroup className=\"align-items-stretch\">\n {routes &&\n (Object.keys(routes) || []).map((k) => {\n const route = routes[k];\n if (route.hide) {\n return null;\n }\n return (\n <NavLink to={k} style={{ textDecoration: \"none\" }}>\n <StyledButton\n key={k}\n variant={page === k && \"primary\"}\n className=\"w-100\"\n onClick={() => setShowMenu(false)}\n >\n {route.init.icon && <i className={route.init.icon}></i>}\n {route.init.name}\n </StyledButton>\n </NavLink>\n );\n })}\n </ButtonGroup>\n <div className=\"d-flex w-100 align-items-center gap-3 justify-content-center\">\n <SignInOrConnect />\n </div>\n </div>\n )}\n </MobileNavigation>\n </StyledNavbar>\n);\nreturn <Navbar page={props.page} routes={props.routes} {...props} />;\n" }, "profile.main": { "": "const AccordionHeader = styled.div`\n cursor: pointer;\n background-color: #f8f9fa;\n padding: 1rem;\n margin: 0;\n border: 1px solid #dee2e6;\n display: flex;\n align-items: center;\n justify-content: space-between;\n`;\nconst Icon = styled.span`\n display: inline-block;\n transition: transform 0.3s ease;\n transform: ${(props) =>\n props.isExpanded ? \"rotate(180deg)\" : \"rotate(0deg)\"};\n`;\nconst AccordionContent = styled.div`\n max-height: ${(props) => (props.isExpanded ? \"1000px\" : \"0\")};\n overflow: auto;\n transition: max-height 0.5s ease;\n border: 1px solid #dee2e6; /* Ensure border is continuous */\n padding: ${(props) => (props.isExpanded ? \"1rem\" : \"0\")};\n`;\nconst accountId = props.accountId || context.accountId;\nif (!accountId) return \"Login or send accountId in the props\";\nconst profile = Social.getr(`${accountId}/profile`);\nconst allWidgetsHistoryChangesBlocks = Social.keys(\n `${accountId}/widget/*`,\n \"final\",\n {\n return_type: \"History\",\n }\n);\nif (allWidgetsHistoryChangesBlocks === null) return \"Loading...\";\nconst widget = allWidgetsHistoryChangesBlocks[accountId].widget;\nconst totalCommits = Object.keys(widget)\n .map((key) => widget[key])\n .flat();\nconst widgets = Social.getr(`${accountId}/widget`) ?? {};\nconst [isExpanded, setIsExpanded] = useState(false);\nconst toggleAccordion = () => {\n setIsExpanded(!isExpanded);\n};\n// --------------- nodes -------------------\nconst Nodes = (\n <div\n className=\"col-lg-12 pb-4\"\n style={{\n boxShadow: \"2px 10px 20px rgba(128, 117, 226, 0.2)\",\n }}\n >\n <div\n style={{ backgroundColor: themeColor?.sbt_info?.card_bg }}\n className=\"shadow-sm rounded-4\"\n >\n <Widget\n key={state.data}\n src=\"hyperbuild.near/widget/explore.view.tree\"\n props={{\n rootPath: state.data,\n themeColor: themeColor.tree,\n }}\n />\n </div>\n </div>\n);\nreturn (\n <div>\n <div>\n <h2>Data Tree</h2>\n </div>\n <div className=\"row\">{Nodes}</div>\n <div className=\"rightSection\">\n <div>\n <AccordionHeader onClick={toggleAccordion} aria-expanded={isExpanded}>\n <div>\n <h2>\n <Icon isExpanded={isExpanded} className=\"bi bi-chevron-down\" />\n Widgets\n </h2>\n </div>\n <span>\n {isExpanded ? \"(click to collapse)\" : \"(click to expand)\"}\n </span>\n </AccordionHeader>\n <AccordionContent isExpanded={isExpanded}>\n <div className=\"widgetsContainer\">\n {Object.keys(widgets)?.length > 0 ? (\n Object.keys(widgets)?.map((item, index) => (\n <Widget\n key={index}\n src=\"zahidulislam.near/widget/Profile.WidgetItem\"\n props={{\n name: item,\n accountId,\n commits:\n allWidgetsHistoryChangesBlocks[accountId].widget[item],\n }}\n />\n ))\n ) : (\n <p\n style={{\n padding: 20,\n textAlign: \"center\",\n color: \"rgba(0,0,0,.75)\",\n }}\n >\n {profile?.name} does not have any widget.\n </p>\n )}\n </div>\n </AccordionContent>\n </div>\n <div>\n <h2>{totalCommits.length} contributions</h2>\n <div style={{ marginTop: 20 }} />\n <Widget\n src=\"zahidulislam.near/widget/Profile.Contributions\"\n props={{ theme: props.theme }}\n />\n </div>\n </div>\n </div>\n);\n" }, "create.job": { "": "State.init({\n jsonStr: JSON.stringify(state.jsonStr),\n prettifiedJson: \"\",\n fiexedJsonErrors: \"\",\n});\n\nconsole.log(state.jsonStr);\n\nfunction formatClickHandler() {\n let formattedJsonStr = \"\";\n let fixedErrors = \"\";\n\n try {\n // Validate input as JSON according to RFC 8259\n const jsonObj = JSON.parse(state.jsonStr);\n console.log(jsonObj);\n // Stringify the JSON object with indentation and sorting keys\n formattedJsonStr = JSON.stringify(jsonObj, null, 4);\n } catch (error) {\n // If parsing fails, try to fix common errors in the JSON string\n let fixedJsonStr = jsonStr\n // Fix missing quotes around property names\n .replace(/([{,]\\s*)([a-zA-Z0-9_$]+)\\s*:/g, (match, p1, p2) => {\n fixedErrors += `Missing quotes around \"${p2}\"\\n`;\n return `${p1}\"${p2}\":`;\n })\n // Fix trailing commas in arrays and objects\n .replace(/,(?=\\s*([}\\]]))/g, (match) => {\n fixedErrors += `Trailing comma removed\\n`;\n return \"\";\n })\n // Fix single quotes around property names and string values\n .replace(/'/g, (match) => {\n fixedErrors += `Single quotes replaced with double quotes\\n`;\n return '\"';\n })\n // Fix unquoted property values\n .replace(\n /([{,]\\s*)([a-zA-Z0-9_$]+)\\s*:\\s*([a-zA-Z0-9_$]+)\\s*(?=([,}]))/g,\n (match, p1, p2, p3, p4) => {\n fixedErrors += `Unquoted value \"${p3}\" surrounded with quotes\\n`;\n return `${p1}\"${p2}\":\"${p3}\"${p4}`;\n }\n )\n // Fix invalid escape sequences in string values\n .replace(/\\\\([^\"\\\\/bfnrtu])/g, (match, p1) => {\n fixedErrors += `Invalid escape sequence \"\\\\${p1}\" removed\\n`;\n return \"\";\n });\n try {\n // Try to parse the fixed JSON string\n const jsonObj = JSON.parse(fixedJsonStr);\n // Stringify the JSON object with indentation and sorting keys\n formattedJsonStr = JSON.stringify(jsonObj, null, 4);\n } catch (error) {\n // If parsing still fails, return an error message\n formattedJsonStr = `Error: ${error.message}`;\n }\n }\n State.update({ prettifiedJson: formattedJsonStr });\n State.update({ fiexedJsonErrors: fixedErrors });\n}\n\nasync function dragAndDropHandler(event) {\n event.preventDefault();\n const file = event.dataTransfer.files[0];\n const fileReader = new FileReader();\n fileReader.onload = function () {\n const fileData = fileReader.result;\n State.update({ jsonStr: fileData });\n State.update({ prettifiedJson: \"\" });\n State.update({ fiexedJsonErrors: \"\" });\n };\n fileReader.readAsText(file);\n}\n\nfunction fileUploadHandler({ target }) {\n const file = target.files[0];\n\n if (!file) {\n return;\n }\n\n const fileReader = new FileReader();\n fileReader.onload = () => {\n const fileData = JSON.parse(fileReader.result);\n State.update({ jsonStr: fileData });\n State.update({ prettifiedJson: \"\" });\n State.update({ fiexedJsonErrors: \"\" });\n };\n fileReader.readAsText(file);\n}\n\nasync function urlInputHandler(event) {\n const url = event.target.value;\n try {\n const response = await fetch(url);\n const jsonData = await response.json();\n const newJsonStr = JSON.stringify(jsonData, null, 4);\n State.update({ jsonStr: newJsonStr });\n State.update({ prettifiedJson: \"\" });\n State.update({ fiexedJsonErrors: \"\" });\n } catch (error) {\n console.error(error);\n State.update({ jsonStr: \"\" });\n State.update({\n prettifiedJson: \"Error: Failed to fetch JSON data from URL\",\n });\n State.update({ fiexedJsonErrors: \"\" });\n }\n}\n\nconst clickCopyHandler = () => {\n navigator.clipboard.writeText(state.prettifiedJson);\n};\n\nconst fileDownloadHandler = () => {\n const element = document.createElement(\"a\");\n const file = new Blob([state.prettifiedJson], { type: \"text/plain\" });\n element.href = URL.createObjectURL(file);\n element.download = \"formatted.json\";\n document.body.appendChild(element);\n element.click();\n};\n\nconst changeHandler = ({ target }) => {\n State.update({ jsonStr: target.value });\n console.log(state.jsonStr);\n};\n\nreturn (\n <div>\n <div class=\"container-fluid\">\n <h3 class=\"text-center\">Input JSON data</h3>\n <textarea\n class=\"container-fluid\"\n rows=\"10\"\n value={state.jsonStr}\n defaultValue={\"{name: 'gunna',age: 12}\"}\n onChange={changeHandler}\n onDrop={dragAndDropHandler}\n onDragOver={(e) => e.preventDefault()}\n placeholder=\"Enter or drag and drop JSON data here...\"\n />\n <div className=\"input-actions\">\n <input type=\"file\" accept=\".json\" onChange={fileUploadHandler} />\n <input\n type=\"text\"\n placeholder=\"Enter URL to fetch JSON data\"\n onBlur={urlInputHandler}\n />\n </div>\n </div>\n <button onClick={formatClickHandler}>Format JSON</button>\n {state.prettifiedJson && (\n <>\n <div class=\"output-container\">\n <h3>Formatted JSON data</h3>\n {state.fiexedJsonErrors && (\n <div class=\"border\">\n <h3>Fixed errors</h3>\n <pre>{state.fiexedJsonErrors}</pre>\n </div>\n )}\n <textarea\n class=\"container-fluid\"\n rows=\"10\"\n value={state.prettifiedJson}\n readOnly\n />\n </div>\n <div class=\"output-actions\"></div>\n </>\n )}\n </div>\n);\n" }, "explore.fetch.things": { "": "// fork_Of: \"hack.near/widget/fetch.things\"\nconst { fetchThings } = VM.require(\n \"buildhub.near/widget/lib.everything-sdk\"\n) || {\n fetchThings: () => {},\n};\n\nconst app = props.app ?? \"graph\";\nconst thing = props.thing ?? \"commons\";\nconst things = fetchThings(app, thing);\n\nreturn (\n <>\n <p>{JSON.stringify(things)}</p>\n </>\n);\n" }, "create.reference": { "": "// Example attestation UID: 0xff5dc0cdc3de27dfe6a4352c596c0f97b1f99c51a67bbae142ce315e34969dcd\n// Example schema UID: 0x6ab5d34260fca0cfcf0e76e96d439cace6aa7c3c019d7c4580ed52c6845e9c89\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst [activeTab, setActiveTab] = useState(\"query\");\nconst [defaultView, setDefaultView] = useState(\"QUERY\") || props.defaultView;\n// Need to finish getAttestation refactor to imported component\n//const { GetAttestation } = VM.require(\"flowscience.near/widget/getAttestation\");\n//const { attest } = VM.require(\"flowscience.near/widget/easAttest\");\n//const { getSchema } = VM.require(\"flowscience.near/widget/getSchema\");\n//const { register } = VM.require(\"flowscience.near/widget/easRegister\");\n//const { revoke } = VM.require(\"flowscience.near/widget/easRevoke\");\n//const { timestamp } = VM.require(\"flowscience.near/widget/easTimestamp\");\nconst user = Ethers.send(\"eth_requestAccounts\", [])[0];\n// if (!user) return <Web3Connect connectLabel=\"Connect\" />;\n{\n /*\nconst chain = Ethers.provider()\n .getNetwork()\n .{then}((chainIdData) => {\n console.log(chainIdData.chainId);\n });\n*/\n}\nconst provider = new ethers.providers.JsonRpcProvider(\n \"https://optimism.drpc.org\"\n);\nconst signer = provider.getSigner(user);\n// console.log(\"chain:\", chain);\n// console.log(\"signer:\", signer);\nreturn (\n <div className=\"p-3 border bg-light\">\n <div className=\"m-2\">\n <h1>EAS on BOS</h1>\n <p>\n Querying currently only works on\n <a href=\"https://optimism.easscan.org/\">Optimism</a>.\n </p>\n <hr />\n </div>\n <ul className=\"nav nav-tabs\">\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"query\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"query\")}\n >\n Query\n </a>\n </li>\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"Create\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"Create\")}\n >\n Create\n </a>\n </li>\n </ul>\n <TabContent>\n {activeTab === \"query\" && (\n <div>\n <div className=\"m-2\">\n <Widget src=\"flowscience.near/widget/getAttestation\" />\n <hr />\n </div>\n <div className=\"m-2\">\n <Widget src=\"flowscience.near/widget/getSchema\" />\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"Create\" && (\n <div>\n <div className=\"m-2\">\n <h5>Create Attestations (Hyperfiles reference objects) Near</h5>\n <Widget src=\"flowscience.near/widget/attest\" />\n <hr />\n <h5>Coming soon: create Attestations & Schemas on Optimism!</h5>\n <Widget src=\"flowscience.near/widget/attestEAS\" />\n <hr />\n </div>\n </div>\n )}\n </TabContent>\n </div>\n);\n" }, "explore.things": { "": "const type = props.type ?? \"type\";\nconst [searchTerm, setSearchTerm] = useState(\"\");\nconst [hideDetails, setHideDetails] = useState(true);\nconst [selectedPath, setSelectedPath] = useState(null);\nconst [object, setObject] = useState(Social.get(`*/${type}/*`, \"final\") || {});\nconst [filteredResults, setFilteredResults] = useState([]);\nuseEffect(() => {\n const results = {};\n Object.entries(object).forEach(([creator, detail]) => {\n const entries = detail[type] || {};\n Object.keys(entries).forEach((id) => {\n const path = `${creator}/${type}/${id}`;\n if (path.includes(searchTerm)) {\n if (!results[id]) {\n results[id] = { count: 0, accounts: new Set() };\n }\n results[id].count++;\n results[id].accounts.add(creator);\n }\n });\n });\n setFilteredResults(\n Object.entries(results)\n .sort((a, b) => b[1].count - a[1].count)\n .map(([id, data]) => ({\n id,\n accounts: Array.from(data.accounts),\n count: data.count,\n }))\n );\n}, [searchTerm, object]);\nconst handleInputChange = (event) => {\n setSearchTerm(event.target.value);\n};\nconst toggleModal = (path) => {\n setSelectedPath(path);\n setHideDetails(!hideDetails);\n};\nconst Profiles = styled.a`\n display: inline-block;\n position: relative;\n img {\n object-fit: cover;\n border-radius: 50%;\n width: 100%;\n height: 100%;\n transition: transform 0.3s ease, box-shadow 0.3s ease;\n }\n &:hover img {\n transform: scale(1.1);\n box-shadow: 0 0 8px rgba(0, 0, 0, 0.2);\n }\n`;\nreturn (\n <div className=\"m-3\">\n <input\n type=\"text\"\n value={searchTerm}\n onChange={handleInputChange}\n placeholder={`🔭 Search for a type of things...`}\n />\n {!hideDetails ? (\n <div className=\"m-3 mt-4\">\n <Widget\n src=\"hack.near/widget/explore.creators\"\n props={{ id: selectedPath.split(\"/\").pop() }}\n />\n <button className=\"m-2 btn-sm\" onClick={() => toggleModal(\"\")}>\n Reset\n </button>\n <Widget\n src=\"hack.near/widget/explore.view\"\n props={{ path: selectedPath, showInput: false }}\n />\n </div>\n ) : (\n <div className=\"m-3 mt-4\">\n {filteredResults.map(({ id, accounts, count }) => (\n <div className=\"d-flex flex-row justify-content-between\">\n <h5 className=\"mt-2\">\n <b>{id}</b>\n </h5>\n <div>\n {accounts.map((creator) => (\n <Profiles\n key={creator}\n onClick={() => toggleModal(`${creator}/${type}/${id}`)}\n >\n <span className=\"d-inline-block\">\n <Widget\n src=\"mob.near/widget/ProfileImage\"\n props={{\n accountId: creator,\n imageStyle: {\n height: \"38px\",\n width: \"38px\",\n },\n imageClassName: \"\",\n }}\n />\n </span>\n </Profiles>\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n);\n" }, "tools.local.index": { "": "const accountId = context.accountId;\nif (!accountId) {\n return \"Please sign in with NEAR wallet\";\n}\nconst registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n);\nconst savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\nif (savedSecretKeyBase64 === null || registeredPublicKey === null)\n return \"Loading\";\n// Utility function to retrieve secret key\nconst getSecretKey = () => {\n const accountId = context.accountId;\n if (!accountId) {\n return null;\n }\n const registeredPublicKey = Social.get(\n `${accountId}/private_message/public_key`\n );\n const savedSecretKeyBase64 = Storage.privateGet(\"secretKey\");\n if (savedSecretKeyBase64 === null || registeredPublicKey === null) {\n return null;\n }\n return savedSecretKeyBase64;\n};\nconst handleSignIn = () => {\n try {\n const keyPairFromSaved = nacl.box.keyPair.fromSecretKey(\n Buffer.from(state.inputSecretKey, \"base64\")\n );\n if (\n Buffer.from(keyPairFromSaved.publicKey).toString(\"base64\") !==\n registeredPublicKey\n ) {\n State.update({ errorInputSecretKey: \"⚠️ key does not fit\" });\n } else {\n const secretKey = Buffer.from(keyPairFromSaved.secretKey).toString(\n \"base64\"\n );\n Storage.privateSet(\"secretKey\", secretKey);\n State.update({\n savedSecretKeyBase64: secretKey,\n });\n // Directly save the secret key in local storage\n Storage.privateSet(\"secretKey\", secretKey);\n }\n } catch {\n State.update({ errorInputSecretKey: \"⚠️ invalid secret key\" });\n }\n};\nState.init({\n selectedUser,\n registerPage: false,\n loginPage: !savedSecretKeyBase64 ? true : false,\n userListPage: savedSecretKeyBase64 ? true : false,\n});\nfunction renderLoginPage() {\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\"></div>\n <h1 class=\"col\">Encryption Tools</h1>\n <div class=\"col\"></div>\n </div>\n {registeredPublicKey && (\n <div>\n <label class=\"mb-3\">You registered using this public key:</label>\n <input\n class=\"form-control mb-3\"\n value={registeredPublicKey}\n disabled\n />\n </div>\n )}\n <input\n class=\"form-control mb-3\"\n placeholder=\"Input secret key\"\n key=\"inputSecret\"\n onChange={(e) => State.update({ inputSecretKey: e.target.value })}\n />\n <label class=\"mb-3\">{state.errorInputSecretKey}</label>\n <div>\n <button\n onClick={() => {\n try {\n const keyPairFromSaved = nacl.box.keyPair.fromSecretKey(\n Buffer.from(state.inputSecretKey, \"base64\")\n );\n if (\n Buffer.from(keyPairFromSaved.publicKey).toString(\"base64\") !=\n registeredPublicKey\n ) {\n State.update({ errorInputSecretKey: \"⚠️ key does not fit\" });\n } else {\n const secretKey = Buffer.from(\n keyPairFromSaved.secretKey\n ).toString(\"base64\");\n Storage.privateSet(\"secretKey\", secretKey);\n State.update({\n savedSecretKeyBase64: secretKey,\n });\n // Call the callback with the private key as decryptSk\n if (props.onPrivateKeyRetrieved) {\n props.onPrivateKeyRetrieved(secretKey);\n }\n }\n } catch {\n State.update({ errorInputSecretKey: \"⚠️ invalid secret key\" });\n }\n }}\n >\n Login\n </button>\n <button\n className=\"btn btn-outline-primary\"\n onClick={() => State.update({ registerPage: true })}\n >\n Register\n </button>\n </div>\n </div>\n );\n}\nif (state.registerPage) {\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\">\n <button\n class=\"btn btn-secondary\n float-right\"\n onClick={() => {\n State.update({ registerPage: false });\n }}\n >\n {\"<\"}\n </button>\n </div>\n <h1 class=\"col\">Register Public Key</h1>\n <div class=\"col\"></div>\n </div>\n <Widget\n src=\"hyperbuild.near/widget/tools.local.register\"\n props={{\n onRegisterComplete: () => {\n State.update({ registerPage: false });\n },\n }}\n />\n </div>\n );\n}\nif (state.selectedUser) {\n console.log({\n receiverAccountId: state.selectedUser.accountId,\n secretKeyBase64: savedSecretKeyBase64,\n receiverPublicKeyBase64: state.selectedUser.publicKeyBase64,\n });\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\">\n <button\n class=\"btn btn-secondary\n float-right\"\n onClick={() => {\n State.update({ selectedUser: null });\n }}\n >\n {\"<\"}\n </button>\n </div>\n <div class=\"col\">\n <Widget\n src=\"mob.near/widget/Profile.ShortInlineBlock\"\n props={{\n accountId: state.selectedUser.accountId,\n }}\n />\n </div>\n <div class=\"col\"></div>\n </div>\n <Widget\n src=\"bozon.near/widget/PrivateMailBox.UserMessages\"\n props={{\n receiverAccountId: state.selectedUser.accountId,\n secretKeyBase64: savedSecretKeyBase64,\n receiverPublicKeyBase64: state.selectedUser.publicKeyBase64,\n }}\n />\n </div>\n );\n}\nif (!savedSecretKeyBase64) return renderLoginPage();\nelse if (savedSecretKeyBase64)\n return (\n <div>\n <div class=\"d-flex flex-row align-items-center mb-3\">\n <div class=\"col\"></div>\n <h1 class=\"col\">Private MailBox</h1>\n <div class=\"col d-flex justify-content-end\">\n <button\n class=\"btn btn-danger \n float-right\"\n onClick={() => {\n Storage.privateSet(\"secretKey\", undefined);\n }}\n >\n Logout\n </button>\n </div>\n </div>\n <Widget\n src=\"bozon.near/widget/PrivateMailBox.UserList\"\n props={{\n secretKeyBase64: savedSecretKeyBase64,\n onSelectedUser: (accountId, publicKeyBase64) => {\n State.update({ selectedUser: { accountId, publicKeyBase64 } });\n },\n }}\n />\n </div>\n );\n" }, "create.things": { "": "const Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Checkbox = styled.input`\n type: checkbox;\n`;\n// Utility to parse JSON properties safely\nconst safelyParseJSON = (json) => {\n try {\n return JSON.parse(json);\n } catch (e) {\n return []; // return an empty array if JSON is invalid\n }\n};\nconst CreateThings = ({ item, onChange }) => {\n // Destructure and parse properties, handling both direct object access and stringified JSON\n const properties =\n typeof item.type === \"string\"\n ? safelyParseJSON(Social.get(item.type, \"final\") || \"{}\").properties\n : item.type.properties;\n // Handle input changes and propagate them upwards\n const handleInputChange = (propertyName, newValue) => {\n onChange({\n ...item.value,\n [propertyName]: newValue,\n });\n };\n const renderInput = (property) => {\n const value = item.value[property.name] || \"\";\n switch (property.type) {\n case \"boolean\":\n return (\n <Checkbox\n checked={value}\n onChange={(e) => handleInputChange(property.name, e.target.checked)}\n />\n );\n case \"string\":\n case \"number\":\n case \"date\":\n return (\n <Input\n type={property.type === \"date\" ? \"date\" : \"text\"}\n value={value}\n onChange={(e) => handleInputChange(property.name, e.target.value)}\n />\n );\n default:\n return (\n <Input\n value={value}\n onChange={(e) => handleInputChange(property.name, e.target.value)}\n />\n );\n }\n };\n return (\n <Container>\n {properties.map((property) => (\n <FormGroup key={property.name}>\n <Label>{`${property.name}${property.isRequired ? \" *\" : \"\"}`}</Label>\n {renderInput(property)}\n </FormGroup>\n ))}\n </Container>\n );\n};\nexport { CreateThings };\n" }, "explore.socialgraph": { "": "const accountId = props.accountId ?? context.accountId ?? \"buildcommons.near\";\nconst GraphContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n width: 100%;\n height: ${(props) => props.height || \"325px\"};\n`;\nconst ProfileContainer = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n flex-direction: row;\n gap: 23px;\n width: 100%;\n`;\nconst [accountIds, setAccountIds] = useState(props.accountIds || [accountId]);\nconst graphId = props.graphId ?? \"commons\";\nconst generatePaths = () => {\n return (\n props.paths ??\n accountIds.map((accountId) => {\n return `${accountId}/graph/${graphId}`;\n })\n );\n};\nconst paths = generatePaths();\nconst data = Social.getr(paths, \"final\");\nconst [nodesState, setNodesState] = useState(null);\nconst [focus, setFocus] = useState(null);\nconst debug = false;\nuseEffect(() => {\n setNodesState(data);\n}, [data]);\nif (!nodesState) {\n return <GraphContainer></GraphContainer>;\n}\nconst [selectedAccountId, setSelectedAccountId] = useState(null);\nconst [message, setMessage] = useState(null);\nuseEffect(() => {\n if (!nodesState) {\n return;\n }\n const nodes = {};\n const edges = [];\n const createNodesAndEdges = (accountId, graphData) => {\n if (!(accountId in nodes)) {\n nodes[accountId] = {\n id: accountId,\n size: 139,\n };\n }\n Object.values(graphData).forEach((links) => {\n console.log(graphData);\n Object.keys(links).forEach((memberId) => {\n if (!(memberId in nodes)) {\n nodes[memberId] = {\n id: memberId,\n size: 139,\n };\n }\n edges.push({\n source: accountId,\n target: memberId,\n value: 1,\n });\n });\n });\n };\n if (accountIds.length === 1) {\n const accountId = accountIds[0];\n createNodesAndEdges(accountId, { [graphId]: nodesState });\n } else if (accountIds.length > 1) {\n Object.entries(nodesState).forEach(([accountId, graphData]) => {\n createNodesAndEdges(accountId, graphData.graph);\n });\n }\n console.log(\"nodes\", nodes);\n console.log(\"edges\", edges);\n setMessage({\n nodes: Object.values(nodes),\n edges,\n });\n}, [nodesState, accountIds]);\nuseEffect(() => {\n if (selectedAccountId) {\n if (accountIds.includes(selectedAccountId)) {\n setAccountIds(accountIds.filter((it) => it !== selectedAccountId));\n } else {\n setAccountIds([...accountIds, selectedAccountId]);\n }\n }\n}, [selectedAccountId]);\nconst graphEdge = Social.keys(\n `${context.accountId}/graph/${graphId}/${accountId}`,\n undefined,\n {\n values_only: true,\n }\n);\nconst inverseEdge = Social.keys(\n `${accountId}/graph/${graphId}/${context.accountId}`,\n undefined,\n {\n values_only: true,\n }\n);\nconst loading = graphEdge === null || inverseEdge === null;\nconst attested = graphEdge && Object.keys(graphEdge).length;\nconst inverse = inverseEdge && Object.keys(inverseEdge).length;\nconst type = attested ? \"undo\" : graphId;\nconst attestation = props.attestation ?? {\n graph: { [graphId]: { [accountId]: attested ? null : \"\" } },\n};\nconst attest = () => {\n Social.set(data);\n};\nlet height = props.height || 325;\nconst code = `\n<!DOCTYPE html>\n<meta charset=\"utf-8\">\n<!-- Load d3.js -->\n<script src=\"https://d3js.org/d3.v6.js\"></script>\n<div class=\"container\">\n <svg id=\"graph\" width=\"100%\" height=\"auto\" viewBox=\"0 0 650 325\" preserveAspectRatio=\"xMidYMid meet\" style=\"display: block; margin: auto;\">\n</div>\n<style>\n .container {\n display: flex;\n justify-content: center;\n align-items: center;\n height: 100vh;\n width: 100%;\n }\n</style>\n<script>\nconst run = (data) => {\n const width = 650;\n const height = \\`${height}\\`;\n let dragIsOn = false;\n // The force simulation mutates links and nodes, so create a copy\n // so that re-evaluating this cell produces the same result.\n const links = data.edges.map(d => ({...d}));\n const nodes = data.nodes.map(d => ({...d}));\n // Create a simulation with several forces.\n const simulation = d3.forceSimulation(nodes)\n .force(\"link\", d3.forceLink(links).id(d => d.id))\n .force(\"charge\", d3.forceManyBody().strength(-500))\n .force(\"collide\", d3.forceCollide().radius(d => Math.sqrt(d.size) ))\n .force(\"center\", d3.forceCenter(width / 2, height / 2))\n .on(\"tick\", ticked);\n simulation.force(\"collide\")\n .strength(.7)\n .radius(d => Math.sqrt(d.size))\n .iterations(1);\n // Create the SVG container.\n const svg = d3.select(\"#graph\")\n .attr(\"width\", width)\n .attr(\"height\", height)\n .attr(\"viewBox\", [0, 0, width, height])\n .attr(\"style\", \"max-width: 100%; height: auto;\");\n // Add a line for each link, and a circle for each node.\n const link = svg.append(\"g\")\n .attr(\"stroke\", \"#999\")\n .attr(\"stroke-opacity\", 0.6)\n .selectAll()\n .data(links)\n .join(\"line\")\n .attr(\"stroke-width\", 1);\nconst node = svg.append(\"g\")\n .selectAll(\"g\")\n .data(nodes)\n .enter()\n .append(\"g\");\n node\n .append(\"image\")\n .attr(\"xlink:href\", (d) => \\`https://i.near.social/magic/thumbnail/https://near.social/magic/img/account/\\${d.id}\\`) // Set the image URL based on your data\n .attr(\"x\", (d) => -Math.sqrt(d.size) - 5)\n .attr(\"y\", (d) => -Math.sqrt(d.size) - 5)\n .attr(\"clip-path\", d => \\`circle(\\${Math.sqrt(d.size) + 5}px at \\${Math.sqrt(d.size) + 5} \\${Math.sqrt(d.size) + 5})\\`)\n .attr(\"width\", (d) => 2 * Math.sqrt(d.size) + 10);\n node\n .append(\"circle\")\n .attr(\"r\", d => Math.sqrt(d.size) + 5)\n .attr(\"fill\", \"none\");\n node.append(\"title\")\n .text(d => d.id);\n // Add a drag behavior.\n node.call(d3.drag()\n .on(\"start\", dragstarted)\n .on(\"drag\", dragged)\n .on(\"end\", dragended));\n node.on(\"mouseover\", handleMouseOver)\n .on(\"mouseout\", handleMouseOut)\n .on(\"click\", handleMouseClick);\n function handleMouseClick(e) {\n const d = e.target.__data__;\n window.top.postMessage({ handler: \"click\", data: d.id }, \"*\");\n }\n function handleMouseOver(d) {\n d = d.target.__data__;\n // Highlight connected edges\n link.attr(\"stroke-opacity\", e => (e.source === d || e.target === d) ? 1 : 0.1);\n // Highlight connected nodes\n node.attr(\"opacity\", function (n) {\n return n === d || isConnected(d, n) ? 1: 0.3;\n });\n window.top.postMessage({ handler: \"mouseover\", data: d.id }, \"*\");\n}\nfunction handleMouseOut() {\n if (dragIsOn) {\n return;\n }\n // Reset edge and node styles\n link\n .attr(\"stroke-opacity\", 0.6);\n node.attr(\"opacity\", 1);\n window.top.postMessage({ handler: \"mouseout\", data: \"out\" }, \"*\");\n}\nfunction isConnected(a, b) {\n // Check if two nodes are connected\n return links.some(function (link) {\n return (link.source === a && link.target === b) || (link.source === b && link.target === a);\n });\n}\n // Set the position attributes of links and nodes each time the simulation ticks.\n function ticked() {\n link\n .attr(\"x1\", d => d.source.x)\n .attr(\"y1\", d => d.source.y)\n .attr(\"x2\", d => d.target.x)\n .attr(\"y2\", d => d.target.y);\n node.attr(\"transform\", d => \\`translate(\\${d.x}, \\${d.y})\\`)\n }\n // Reheat the simulation when drag starts, and fix the subject position.\n function dragstarted(event) {\n dragIsOn = true;\n if (!event.active) simulation.alphaTarget(0.3).restart();\n event.subject.fx = event.subject.x;\n event.subject.fy = event.subject.y;\n }\n // Update the subject (dragged node) position during drag.\n function dragged(event) {\n event.subject.fx = event.x;\n event.subject.fy = event.y;\n }\n // Restore the target alpha so the simulation cools after dragging ends.\n // Unfix the subject position now that it’s no longer being dragged.\n function dragended(event) {\n if (!event.active) simulation.alphaTarget(0);\n event.subject.fx = null;\n event.subject.fy = null;\n dragIsOn = false;\n handleMouseOut();\n }\n // When this cell is re-run, stop the previous simulation. (This doesn’t\n // really matter since the target alpha is zero and the simulation will\n // stop naturally, but it’s a good practice.)\n // invalidation.then(() => simulation.stop());\n return simulation;\n};\nlet simulation = null;\nwindow.addEventListener(\"message\", (event) => {\n if (simulation) {\n simulation.stop();\n d3.select(\"#graph\").selectAll(\"*\").remove();\n }\n if (event.data) {\n simulation = run(event.data);\n }\n});\n</script>\n`;\nconst [onMessage] = useState(() => {\n return (data) => {\n if (data) {\n switch (data.handler) {\n case \"click\":\n setSelectedAccountId(data.data);\n break;\n }\n }\n };\n});\nreturn (\n <>\n <GraphContainer height={height}>\n <iframe\n className=\"w-100 h-100\"\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n minHeight: \"325px\",\n maxWidth: \"888px\",\n width: \"100%\",\n }}\n srcDoc={code}\n message={message}\n onMessage={onMessage}\n />\n </GraphContainer>\n </>\n);\n" }, "explore.view.thing": { "": "const path = props.path; // every piece of data on social contract has a path\nconst blockHeight = props.blockHeight || \"final\"; // and a blockHeight (~version)\nconst templateOverride = props.templateOverride;\n// split the path\nconst parts = path.split(\"/\");\nconst creatorId = parts[0];\nlet type;\nif (parts.length === 1) {\n if (parts[0].charAt(0) === \"#\") {\n // hashtag\n type = \"hashtag\";\n } else {\n // every root of a path is an account\n type = \"account\";\n }\n} else {\n // otherwise the \"standard\" is the type (widget, post, type, thing...)\n // for thing, we'll extract the actual \"Type\" later\n type = parts[1];\n}\nState.init({\n view: \"THING\",\n});\nconst Container = styled.div`\n //border: 1px solid #ccc;\n height: fit-content;\n`;\nconst Header = styled.div`\n display: flex;\n align-items: center;\n justify-content: flex-end;\n //border-bottom: 1px solid #ccc;\n`;\nconst Content = styled.div`\n padding: 1px;\n min-height: 300px;\n`;\nfunction Thing() {\n // Renders the path according to type\n switch (type) {\n case \"thing\":\n {\n // get the thing data\n const thing = JSON.parse(Social.get(path, blockHeight) || \"null\");\n type = thing.type || null;\n // get the type data\n const typeObj = JSON.parse(Social.get(type, blockHeight) || \"null\");\n if (typeObj === null) {\n console.log(\n `edge case: thing ${path} had an invalid type: ${thingType}`\n );\n }\n // determine the widget to render this thing (is there a default view?)\n console.log(\"TemplateOverride\", templateOverride);\n const widgetSrc =\n templateOverride || thing.template?.src || typeObj?.widgets?.view;\n //Template\n //hard code until finding template override prop\n //const widgetSrc = \"harmonic1.near/widget/artist2\";\n return (\n <Widget\n src={widgetSrc}\n props={{ data: thing.data, path, blockHeight }}\n />\n );\n }\n // DEFAULT:\n return <p>The type: {type} is not yet supported.</p>;\n }\n}\n// <ButtonRow>\n// <Modifier />\n// </ButtonRow>\nreturn (\n <Container id={path}>\n <Content>\n <Thing />\n </Content>\n </Container>\n);\n" }, "page.profile": { "": "const profile = props.profile;\nconst cssFont = fetch(\n \"https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap\"\n).body;\nconst css = fetch(\n \"https://raw.githubusercontent.com/cryptosynk/near-social-profile/main/css/mainLight.css\"\n).body;\nconst theme = \"light\";\nconst Theme = styled.div`\n font-family: \"Open Sans\", sans-serif;\n ${cssFont}\n ${css}\n`;\nconst Container = styled.div`\n max-width: 100%;\n overflow: auto;\n border: 1px solid #dee2e6;\n padding: 1rem;\n margin-bottom: 1rem;\n`;\nreturn (\n <div className=\"container mt-3 p-3 border bg-light\">\n <div className=\"row\">\n <h1>Manage {context.accountId}'s Profile</h1>\n <p>\n <ul>\n <li>Edit basic profile info in the left sidebar.</li>\n <li>\n View widgets you've created and a heatmap of your on-chain activity.\n </li>\n <li>\n Explore social profiles, data trees, and delete \"keys\" for entries\n in your data tree.\n </li>\n </ul>\n </p>\n <hr />\n </div>\n <Theme>\n <div className=\"container\">\n <div className=\"content\">\n <Widget\n src=\"hyperbuild.near/widget/profile.sidebar\"\n props={{ accountId, profile, theme }}\n />\n <Widget\n src=\"hyperbuild.near/widget/profile.main\"\n props={{ accountId, profile, theme }}\n />\n </div>\n </div>\n <hr />\n </Theme>\n <div>\n <Widget src=\"hyperbuild.near/widget/profile.social\" props={{}} />\n <hr />\n <Container>\n <h2>Profile Cleanup</h2>\n <hr />\n <Widget src=\"hyperbuild.near/widget/profile.cleanup\" props={{}} />\n </Container>\n </div>\n </div>\n);\n" }, "profile.sidebar": { "": "const accountId = props.accountId || context.accountId;\nif (!accountId) return \"Login or send accountId in the props\";\nconst profile = Social.getr(`${accountId}/profile`);\nconst name = profile?.name;\nconst image = profile?.image;\nconst url = image.ipfs_cid\n ? `https://ipfs.near.social/ipfs/${image?.ipfs_cid}`\n : \"https://thewiki.io/static/media/sasha_anon.6ba19561.png\";\nconst cssFont = fetch(\n \"https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap\"\n).body;\nconst css = fetch(\n \"https://raw.githubusercontent.com/cryptosynk/near-social-profile/main/css/mainLight.css\"\n).body;\nconst Theme = styled.div`\n font-family: \"Open Sans\", sans-serif;\n ${cssFont}\n ${css}\n`;\nif (!cssFont || !css) return \"Loading fonts & css\";\nState.init({\n showEditProfile: false,\n});\nreturn (\n <Theme>\n <div className=\"leftSection\">\n <div>\n <div>\n <img className=\"profileImage\" src={url} alt=\"profile\" />\n <div style={{ paddingBlock: 10 }}>\n <h2>{name}</h2>\n <p>@{accountId}</p>\n </div>\n </div>\n <p className=\"description\">{profile?.description}</p>\n </div>\n {state.showEditProfile ? (\n <>\n <Widget\n src=\"zahidulislam.near/widget/Profile.Editor\"\n props={{ showEditProfile }}\n />\n <button\n style={{ marginBottom: 20 }}\n onClick={() => {\n State.update({\n showEditProfile: false,\n });\n }}\n >\n Cancel\n </button>\n </>\n ) : (\n <>\n <Widget\n src=\"zahidulislam.near/widget/Profile.SocialLinks\"\n props={{ profile }}\n />\n <button\n onClick={() => {\n State.update({\n showEditProfile: true,\n });\n }}\n >\n Edit Profile\n </button>\n <div style={{ display: \"flex\", flexDirection: \"column\", gap: 10 }}>\n <Widget src=\"mob.near/widget/FollowStats\" props={{ accountId }} />\n <Widget\n src=\"zahidulislam.near/widget/Profile.IconButton\"\n props={{\n icon: \"https://cdn-icons-png.flaticon.com/512/3179/3179068.png\",\n label: profile?.location ?? \"Add Location\",\n }}\n />\n </div>\n </>\n )}\n </div>\n </Theme>\n);\n" }, "page.explore": { "": "const [path, setPath] = useState(\"\");\nconst [accounts, setAccounts] = useState([]);\n// Function to handle updates based on predefined queries\nconst handleQueryChange = (query) => {\n const value = Social.get(query, \"final\");\n const accountsFromQuery = Object.keys(value);\n setAccounts(accountsFromQuery);\n setPath(query);\n};\nconst handlePathUpdate = (newPath) => {\n setPath(newPath);\n};\nreturn (\n <div className=\"container mt-3 p-3 border bg-light\">\n <div className=\"row\">\n <h1>Hyperfiles Explorer</h1>\n <p>\n <i>\n *View the\n <a href=\"https://opencann.notion.site/Hyperfiles-52cdfb892aff4d0ebe2178436c5edf6d\">\n docs\n </a>\n to learn more about how Hyperfiles data structures work.\n </i>\n </p>\n <p>\n <ul>\n <li>\n Search for fields, schemas, types, profiles, and other content\n metadata.\n </li>\n <li>\n Explore the network of related entities (data + creators) and\n actions (references + jobs).\n </li>\n </ul>\n </p>\n <hr />\n </div>\n <h2>Explore Social Graphs</h2>\n <div style={{ flex: 1 }}>\n <Widget src=\"hyperbuild.near/widget/explore.view.graph\" props={{}} />\n </div>\n <h2>Explore Data</h2>\n <div>\n <div>\n <Widget\n src=\"hyperbuild.near/widget/explore.view.path\"\n props={{\n path: \"hyperfiles.near/type/**\",\n }}\n />\n </div>\n </div>\n <h2>Explore Types</h2>\n <div style={{ display: \"flex\", flexDirection: \"row\" }}>\n <div style={{ flex: 1 }}>\n <Widget src=\"hyperbuild.near/widget/explore.types\" />\n </div>\n </div>\n </div>\n);\n" }, "create.thing": { "": "const item = props.item;\nconst onChange = props.onChange;\nconst Input = styled.input`\n height: 30px;\n`;\nconst Select = styled.select`\n height: 30px;\n`;\nconst Button = styled.button`\n text-transform: lowercase !important;\n padding: 8px;\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n`;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Label = styled.label``;\nState.init({\n ...item.value,\n});\nconst DynamicInput = ({ type, onChange, value, placeholder }) => {\n if (type === \"boolean\") {\n return (\n <Select onChange={onChange} value={value}>\n <option value=\"true\">true</option>\n <option value=\"false\">false</option>\n </Select>\n );\n } else {\n return (\n <Input\n type={type}\n onChange={onChange}\n value={value}\n placeholder={placeholder}\n />\n );\n }\n};\n// Primitive checks\nif ([\"string\", \"number\", \"date\", \"time\", \"boolean\"].includes(item.type)) {\n return (\n <DynamicInput\n type={item.type === \"string\" ? \"text\" : item.type}\n onChange={onChange}\n value={item.value}\n />\n );\n}\n// On-chain Type\nconst type = JSON.parse(Social.get(item.type, \"final\") || \"null\");\nconst properties = type.properties || [];\nconst createWidgetSrc = type.widgets?.create;\nconst handleInputChange = (name, value) => {\n State.update({ [name]: value });\n if (props.onChange) {\n props.onChange({ [name]: value });\n }\n};\nfunction Property({ property, value }) {\n // If property is multiple values\n if (property.isMulti === \"true\") {\n // Build an array (recursively calls this Widget)\n return (\n <Widget\n src=\"efiz.near/widget/every.array.build\"\n props={{\n item: { ...property, value },\n onChange: (val) => handleInputChange(property.name, val),\n }}\n />\n );\n }\n // Else check for primitives\n if ([\"string\", \"number\", \"date\", \"time\", \"boolean\"].includes(property.type)) {\n return (\n <DynamicInput\n type={property.type === \"string\" ? \"text\" : property.type}\n onChange={(e) => handleInputChange(property.name, e.target.value)}\n value={state[property.name] || \"\"}\n placeholder={property.name}\n />\n );\n } else {\n // This requires a specific type of creator\n // (like image upload)\n // TODO: I don't think this does what I want it to yet...\n const propertyType = JSON.parse(\n Social.get(property.type, \"final\") || \"null\"\n );\n const widgetSrc = propertyType?.widgets?.create;\n // it would be great to modify the onChange function\n return (\n <Widget\n src={widgetSrc}\n props={{ onChange: (e) => handleInputChange(property.name, e) }}\n />\n );\n }\n}\nreturn (\n <Container>\n {createWidgetSrc ? (\n <>\n <Widget src={createWidgetSrc} props={{ onChange }} />\n </>\n ) : (\n <>\n {properties?.map((property) => (\n <div key={property.name}>\n <Label>{property.name}</Label>\n <Row>\n <Property property={property} value={item.value[property.name]} />\n </Row>\n </div>\n ))}\n </>\n )}\n </Container>\n);\n" }, "explore.view.tree": { "": "const labelStyles = {\n fontFamily: \"Arial, sans-serif\",\n fontSize: \"1.2em\", // Slightly larger font size\n fontWeight: \"bold\", // Bold text\n marginRight: \"10px\",\n};\n/**\n * Takes in a rootPath and rootType\n */\nconst rootPath = props.rootPath || context.accountId || \"hyperfiles.near\";\nconst rootType = props.rootType || \"account\";\nconst rootNode = props.rootNode || {};\nconst [inputValue, setInputValue] = useState(\"\");\nState.init({\n path: rootPath,\n type: rootType,\n history: [rootPath],\n});\nfunction setPath(path) {\n State.update({ path });\n}\nfunction setHistory(history) {\n State.update({ history });\n}\nfunction setType(type) {\n State.update({ type });\n}\nfunction setRoot(newPath, newType) {\n State.update({\n path: newPath,\n type: newType,\n });\n}\nconst handleInputChange = (event) => {\n setInputValue(event.target.value);\n};\nconst handleExploreClick = () => {\n setPath(inputValue); // Assuming setPath updates the state as needed\n};\n// WHEN A NEW ROOT IS SET //\n// GET DATA AT THIS PATH //\nfunction getNode(path, type) {\n const parts = path.split(\"/\");\n let value = {};\n // ACCOUNT //\n if (type === \"account\") {\n if (parts.length > 1) {\n // GRAPH // FOLLOW // BACK TO ACCOUNT : WORKING\n setRoot(parts[3], \"account\");\n } else {\n if (parts[0] !== \"*\") {\n parts.push(\"**\");\n }\n value = Social.get(parts.join(\"/\"), \"final\");\n return value;\n }\n // THING //\n } else if (type === \"thing\") {\n // path: \"everything\"\n // type: \"thing\"\n return rootNode; // Or should \"everything\" be \"*\"?\n // PROFILE //\n } else if (type === \"profile\") {\n value = Social.get(parts.join(\"/\"), \"final\");\n // POST : WIP //\n } else if (type === \"post\") {\n value = path;\n // NAMETAG : WIP //\n } else if (type === \"nametag\") {\n if (parts.length > 2) {\n if (parts.length === 3) {\n // BACK TO ACCOUNT\n setRoot(parts[3], \"account\");\n } else if (parts.length === 4) {\n // ALL TAGS BY ACCOUNT\n value = Social.keys(`${parts[0]}/profile/tags/*`, \"final\");\n } else {\n // THIS TAG\n value = parts[5];\n }\n }\n } else {\n parts.push(\"**\");\n value = Social.get(parts.join(\"/\"), \"final\");\n return value;\n }\n}\nconst node = getNode(state.path, state.type);\nreturn (\n <div className=\"p-3 border bg-light\">\n <label htmlFor=\"pathInput\" style={labelStyles}>\n Enter Profile Account ID:\n </label>\n <div style={{ display: \"flex\", alignItems: \"center\" }}>\n <input\n id=\"pathInput\"\n type=\"text\"\n value={inputValue}\n onChange={handleInputChange}\n placeholder=\"e.g. hyperfiles.near\"\n />\n <button onClick={handleExploreClick}>Load Data Tree</button>\n </div>\n <hr />\n <Widget\n src=\"hyperbuild.near/widget/explore.view.node\"\n props={{\n label: state.path,\n node,\n type: state.type,\n path: state.path,\n setPath: setPath,\n history: state.history,\n setHistory: setHistory,\n setType: setType,\n isRoot: true,\n styles: {\n subject: {\n fontFamily: \"Arial, sans-serif\",\n fontSize: \"2em\",\n lineHeight: \"1.25\",\n fontWeight: 300,\n cursor: \"pointer\",\n },\n },\n }}\n />\n </div>\n);\n" }, "profile.links": { "": "const accountId = props.accountId ?? context.accountId;\nconst profile = props.profile ?? Social.getr(`${accountId}/profile`);\nconst linktree = profile.linktree;\nreturn (\n <div className=\"socialLinks\">\n {linktree &&\n Object.entries(linktree)?.map(([name, value], index) => (\n <>\n {(name === \"twitter\" && (\n <a\n className=\"socialIcon\"\n href={`https://twitter.com/${value}`}\n target=\"_blank\"\n >\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/733/733635.png\"\n alt=\"twitter\"\n />\n </a>\n )) ||\n (name === \"github\" && (\n <a\n className=\"socialIcon\"\n href={`https://github.com/${value}`}\n target=\"_blank\"\n >\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/2111/2111425.png\"\n alt=\"github\"\n />\n </a>\n )) ||\n (name === \"telegram\" && (\n <a\n className=\"socialIcon\"\n href={`https://t.me/${value}`}\n target=\"_blank\"\n >\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/2111/2111708.png\"\n alt=\"telegram\"\n />\n </a>\n )) ||\n (name === \"website\" && (\n <a className=\"socialIcon\" href={value} target=\"_blank\">\n <img\n className=\"invertColor\"\n style={{ height: 20, opacity: 0.5 }}\n src=\"https://cdn-icons-png.flaticon.com/512/1006/1006771.png\"\n alt=\"website\"\n />\n </a>\n ))}\n </>\n ))}\n </div>\n);\n" }, "tools.local.register": { "": "//props:\n//onRegisterComplete(secretKeyBase64)\nconst accountId = context.accountId;\nif (!accountId) {\n return \"Please sign in with NEAR wallet\";\n}\nif (!props.onRegisterComplete) {\n return \"send onRegisterComplete in props\";\n}\nconst registeredPublicKeyBase64 = Social.get(\n `${accountId}/private_message/public_key`\n);\nif (registeredPublicKeyBase64 === null) return \"Loading\";\nfunction randomKeyPairBase64() {\n const keyPair = nacl.box.keyPair();\n return {\n secretKey: Buffer.from(keyPair.secretKey).toString(\"base64\"),\n publicKey: Buffer.from(keyPair.publicKey).toString(\"base64\"),\n };\n}\nconst keyPair = randomKeyPairBase64();\nState.init({\n registeredPublicKeyBase64,\n secretKeyBase64: keyPair.secretKey,\n publicKeyBase64: keyPair.publicKey,\n});\nreturn (\n <div>\n {registeredPublicKeyBase64 && (\n <div class=\"mb-3\">\n {\n \"You're already registered. If your key is compromised you can re-register, but will lose access to old messages.\"\n }\n </div>\n )}\n <div class=\"mb-3\">\n <label for=\"inputSercetKey\" class=\"form-label\">\n Secret key:\n </label>\n <div class=\"mb-3 input-group\">\n <input\n type=\"text\"\n value={state.secretKeyBase64}\n class=\"form-control\"\n readonly=\"\"\n />\n <button\n class=\"btn btn-outline-primary\"\n disabled={state.registeredProsessing}\n onClick={() => {\n const keyPair = randomKeyPairBase64();\n //re-render\n State.update({\n secretKeyBase64: keyPair.secretKey,\n publicKeyBase64: keyPair.publicKey,\n });\n }}\n >\n Generate Random Key\n </button>\n </div>\n </div>\n <div class=\"mb-3 form-check\">\n <input\n onClick={() => {\n State.update({\n checkboxSaveSecretKey: !state.checkboxSaveSecretKey,\n });\n }}\n defaultChecked={state.checkboxSaveSecretKey}\n class=\"form-check-input\"\n type=\"checkbox\"\n id=\"flexCheckDefault\"\n />\n <label class=\"form-check-label\" for=\"flexCheckDefault\">\n <b>I SAVED MY SECRET KEY</b>\n </label>\n </div>\n <CommitButton\n disabled={!state.checkboxSaveSecretKey}\n onClick={() => {\n State.update({ processedSecretKey: state.secretKeyBase64 });\n }}\n onCommit={() => {\n State.update({\n registeredProsessing: false,\n });\n props.onRegisterComplete(state.processedSecretKey);\n }}\n data={{ private_message: { public_key: state.publicKeyBase64 } }}\n >\n Register\n </CommitButton>\n </div>\n);\n" }, "tools.files.index": { "": "const Container = styled.div`\n display: flex;\n height: 100vh;\n width: 100%;\n`;\nconst MainContent = styled.div`\n flex: 1;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n`;\nfunction Header({ path, goBack, goForward, setLayout, togglePreview }) {\n return (\n <Widget\n src=\"fastvault.near/widget/voyager.header.index\"\n props={{\n path,\n goBack,\n goForward,\n setLayout,\n togglePreview,\n }}\n />\n );\n}\nfunction Content({\n layout,\n path,\n setPath,\n setFilesSource,\n showPreview,\n selectedPath,\n setSelectedPath,\n decryptSk, // Ensure decryptSk is passed here\n}) {\n return (\n <Widget\n src=\"hyperbuild.near/widget/tools.files.content\"\n props={{\n layout,\n path,\n setPath,\n setFilesSource,\n showPreview,\n selectedPath,\n setSelectedPath,\n decryptSk, // Ensure decryptSk is passed here\n }}\n />\n );\n}\nfunction Sidebar({ setPath, setFilesSource, setHistory }) {\n return (\n <Widget\n src=\"fastvault.near/widget/voyager.sidebar.index\"\n props={{\n path,\n setPath,\n setFilesSource,\n setHistory,\n }}\n />\n );\n}\nreturn (\n <Widget\n src=\"hyperbuild.near/widget/tools.files.provider\"\n props={{\n path: props.path,\n setFilesSource: props.setFilesSource,\n Children: (p) => (\n <Container>\n <Sidebar {...p} />\n <MainContent>\n <Header {...p} />\n <Content {...p} />\n </MainContent>\n </Container>\n ),\n }}\n />\n);\n" }, "explore.select.type": { "": "const Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst Button = styled.button``;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Select = styled.select``;\nconst Label = styled.label``;\nconst Input = styled.input``;\nconst initialTypeSrc = props.typeSrc || \"hyperfiles.near\";\nconst [newTypeSrc, setNewTypeSrc] = useState(initialTypeSrc);\nconst [typeSrc, setTypeSrc] = useState(initialTypeSrc);\nconst [selectedType, setSelectedType] = useState(props.selectedType || \"\");\nconst [availableTypes, setAvailableTypes] = useState([]);\nconst [isLoading, setIsLoading] = useState(true);\nconst [fetchedData, setFetchedData] = useState({}); // State for debugging\nuseEffect(() => {\n setIsLoading(true);\n const fetchTypesList = () => {\n const query = typeSrc === \"*\" ? \"*/type/**\" : `${typeSrc}/type/**`;\n const types = Social.get(query, \"final\");\n setFetchedData(types); // Store raw data for debugging\n if (types) {\n let typesSet = new Set();\n if (typeSrc === \"*\") {\n // Collect types from all fetched data\n Object.values(types).forEach((accountTypes) => {\n Object.values(accountTypes).forEach((typeObj) => {\n Object.keys(typeObj).forEach((typeName) => {\n typesSet.add(typeName);\n });\n });\n });\n } else {\n // Types from a specific account\n Object.keys(types).forEach((key) => typesSet.add(key));\n }\n setAvailableTypes(Array.from(typesSet));\n } else {\n setAvailableTypes([]);\n }\n setIsLoading(false);\n };\n fetchTypesList();\n}, [typeSrc]);\nuseEffect(() => {\n setSelectedType(props.selectedType);\n}, [props.selectedType]);\nconst handleTypeChange = (event) => {\n setSelectedType(event.target.value);\n if (props.onSelectedTypeChange) {\n props.onSelectedTypeChange(event.target.value);\n }\n};\nconst handleTypeSrcChange = (event) => {\n setNewTypeSrc(event.target.value);\n};\nconst applyTypeSrc = () => {\n setTypeSrc(newTypeSrc);\n};\nconst showAllTypes = () => {\n setTypeSrc(\"*\");\n};\nreturn (\n <FormContainer>\n <Label>Import Type for Editing:</Label>\n <Row>\n <Input\n type=\"text\"\n value={state.newType}\n onChange={(e) => State.update({ newType: e.target.value })}\n placeholder={\"accountId/type/Type\"}\n />\n <Button onClick={loadType}>load</Button>\n </Row>\n <Label>Import Property Types:</Label>\n <Row>\n <Input\n type=\"text\"\n onChange={handleTypeSrcChange}\n value={newTypeSrc}\n placeholder=\"accountId\"\n />\n <Button onClick={applyTypeSrc}>Apply</Button>\n </Row>\n <Label>Select Type to Edit:</Label>\n <Row>\n {isLoading ? (\n <div>Loading...</div>\n ) : (\n <Select value={selectedType} onChange={handleTypeChange}>\n <option value=\"\">Choose a type</option>\n {availableTypes.map((type) => (\n <option key={type} value={type}>\n {type}\n </option>\n ))}\n </Select>\n )}\n <p />\n <Button onClick={showAllTypes}>Show All</Button>\n </Row>\n </FormContainer>\n);\n// <pre>{JSON.stringify(fetchedData, null, 2)}</pre> {/* Debug output */}\n" }, "create.metadata": { "": "const Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nfunction CreateMetadata({ name, setName, description, setDescription }) {\n return (\n <Form>\n <h3>Metadata</h3>\n <FormGroup>\n <Label>Name</Label>\n <Input\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n />\n </FormGroup>\n <FormGroup>\n <Label>Description</Label>\n <textarea\n className=\"form-control mb-3\"\n rows={5}\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n />\n </FormGroup>\n <FormGroup>\n <Label>Tags</Label>\n <Widget src=\"mob.near/widget/TagsEditor\" />\n </FormGroup>\n </Form>\n );\n}\n\nreturn { CreateMetadata };\n" }, "config.app": { "": "return {\n type: \"app\",\n routes: {\n home: {\n path: \"hyperbuild.near/widget/page.home\",\n blockHeight: \"final\",\n init: {\n name: \"Home\",\n },\n },\n create: {\n path: \"hyperbuild.near/widget/page.create\",\n blockHeight: \"final\",\n init: {\n name: \"Create\",\n },\n },\n explore: {\n path: \"hyperbuild.near/widget/page.explore\",\n blockHeight: \"final\",\n init: {\n name: \"Explore\",\n },\n },\n profile: {\n path: \"hyperbuild.near/widget/page.profile\",\n blockHeight: \"final\",\n init: {\n name: \"Profile\",\n },\n },\n tools: {\n path: \"hyperbuild.near/widget/page.tools\",\n blockHeight: \"final\",\n init: {\n name: \"Tools\",\n },\n },\n },\n};\n" }, "page.create": { "": "const { DataCreator } = VM.require(\"hyperbuild.near/widget/create.data\");\nconst { CreateHyperfile } = VM.require(\n \"hyperbuild.near/widget/create.hyperfiles\"\n);\n//const { GitHubAPIExample } = VM.require( \"create.near/widget/GitHub.API.Example\");\nconst { CreateMetadata } = VM.require(\"hyperbuild.near/widget/create.metadata\");\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst Button = styled.button``;\nconst Row = styled.div`\n display: flex;\n flex-direction: row;\n`;\nconst [rawData, setRawData] = useState(\"\");\nconst [source, setSource] = useState(\"\");\nconst [schema, setSchema] = useState(\"\");\nconst [adapter, setAdapter] = useState(\"\");\nconst [reference, setReference] = useState(undefined);\nconst [activeTab, setActiveTab] = useState(\"content\");\nconst [name, setName] = useState(props.name ?? \"\");\nconst [description, setDescription] = useState(props.description ?? \"\");\nconst [hyperfile, setHyperfile] = useState(\"\");\nconst [type, setType] = useState(\"\");\nconst [filePath, setFilePath] = useState(null);\nconst [defaultView, setDefaultView] =\n useState(\"HYPERFILE\") || props.defaultView;\nfunction generateUID() {\n const maxHex = 0xffffffff;\n const randomNumber = Math.floor(Math.random() * maxHex);\n return randomNumber.toString(16).padStart(8, \"0\");\n}\nconst handleCreate = () => {\n if (create) {\n console.log(\"it's something\", rawData);\n // store the data somewhere, based on the adapter\n create(rawData).then((reference) => {\n // now we have a reference to the data\n const thingId = generateUID();\n const hyperfile = {\n thing: {\n // which we store in the social contract\n [thingId]: {\n \"\": JSON.stringify({\n source: source,\n adapter: adapter,\n reference: reference,\n }),\n metadata: {\n name: name,\n description: description,\n schema: schema,\n },\n },\n },\n };\n setHyperfile(JSON.stringify(hyperfile, null, 2));\n });\n } else {\n console.log(\"invalid adapter\");\n }\n};\nconsole.log(\"source: \", source);\nconsole.log(\"schema: \", schema);\nconsole.log(\"data: \", rawData);\nconsole.log(\"adapter: \", adapter);\nreturn (\n <div className=\"container mt-3 p-3 border bg-light\">\n <div className=\"row\">\n <h1>Hyperfiles Creator</h1>\n <p>\n <i>\n *View the\n <a href=\"https://opencann.notion.site/Hyperfiles-52cdfb892aff4d0ebe2178436c5edf6d\">\n docs\n </a>\n to learn more about how Hyperfiles data structures work.\n </i>\n </p>\n <p>\n <ul>\n <li>\n Publish structured data objects, attest (add references) to data and\n reference objects, and run jobs (coming soon).\n </li>\n <li>\n Each schema contains an ordered list of types that describes the\n structure of corresponding data objects.\n </li>\n <li>\n Common types & schemas compose into a graph of related entities\n (data + creators) and actions (references + jobs).\n </li>\n </ul>\n </p>\n <hr />\n </div>\n <Row style={{ gap: \"10px\", marginBottom: \"16px\" }}>\n <h2>Create</h2>{\" \"}\n <Select\n value={state.defaultView}\n onChange={(e) => setDefaultView(e.target.value)}\n >\n <option value=\"HYPERFILE\">Data Object</option>\n <option value=\"ATTESTATION\">Attestation</option>\n <option value=\"SCHEMA\">Schema</option>\n <option value=\"TYPE\">Type</option>\n <option value=\"JOB\">Job</option>\n </Select>\n </Row>\n <ul className=\"nav nav-tabs\">\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"content\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"content\")}\n >\n Content\n </a>\n </li>\n <li className=\"nav-item\">\n <a\n className={`nav-link ${activeTab === \"metadata\" ? \"active\" : \"\"}`}\n onClick={() => setActiveTab(\"metadata\")}\n >\n Metadata\n </a>\n </li>\n </ul>\n <div className=\"row\">\n <TabContent>\n {defaultView === \"HYPERFILE\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.hyperfile\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"ATTESTATION\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.reference\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"SCHEMA\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.edit.schema\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"TYPE\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.edit.type\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n <TabContent>\n {defaultView === \"JOB\" && (\n <div className=\"row\">\n <TabContent>\n {activeTab === \"content\" && (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Widget\n src=\"hyperbuild.near/widget/create.job\"\n props={{}}\n />\n </div>\n </div>\n </div>\n )}\n </TabContent>\n <TabContent>\n {activeTab === \"metadata\" && (\n <CreateMetadata\n name={name}\n setName={setName}\n description={description}\n setDescription={setDescription}\n />\n )}\n </TabContent>\n </div>\n )}\n </TabContent>\n </div>\n </div>\n);\n" }, "tools.files.module.crypto": { "": "// Uint8Array -> Array\nconst array2buf = (array) => Array.from(array);\n// Uint8Array -> str\nconst arr2str = (array) => {\n var result = \"\";\n for (var i = 0; i < array.length; i++) {\n result += String.fromCharCode(array[i]);\n }\n return result;\n};\n// str -> Uint8Array\nconst str2array = (str) => {\n return new Uint8Array(Array.from(str).map((letter) => letter.charCodeAt(0)));\n};\n// accountId: str, password: str\nconst newSecretKey = (accountId, password) => {\n const hashed_id = nacl.hash(str2array(accountId));\n const hashed_pw = nacl.hash(str2array(password));\n const sk = new Uint8Array(nacl.secretbox.keyLength);\n for (var i = 0; i < hashed_id.length; i++) {\n const sk_i = i % sk.length;\n if (i >= sk.length) {\n sk[sk_i] = sk[sk_i] + (hashed_id[i] + hashed_pw[i]);\n } else {\n sk[sk_i] = hashed_id[i] + hashed_pw[i];\n }\n }\n return sk;\n};\nconst newNonce = (message) => {\n const hash = nacl.hash(message);\n const nonce = new Uint8Array(nacl.secretbox.nonceLength);\n for (var i = 0; i < hash.length; i++) {\n const n_i = i % nonce.length;\n if (i >= nonce.length) {\n nonce[n_i] += hash[i];\n } else {\n nonce[n_i] = i & hash[i];\n }\n }\n return nonce;\n};\n// message: Uint8Array\nconst encrypt = (message, storageSk) => {\n const nonce = newNonce(message);\n const ciphertext = nacl.secretbox(message, nonce, storageSk);\n return {\n nonce: Array.from(nonce),\n ciphertext: Array.from(ciphertext),\n };\n};\n// message: str\nconst encryptStr = (text, storageSk) => {\n return encrypt(str2array(text), storageSk);\n};\n// message: JS Object\nconst encryptObject = (obj, storageSk) => {\n return encrypt(str2array(JSON.stringify(obj)), storageSk);\n};\n// nonce: Uint8Array\n// ciphertext: Uint8Array\n// storageSk: Uint8Array\nconst decrypt = (nonce, ciphertext, storageSk) => {\n return nacl.secretbox.open(ciphertext, nonce, storageSk);\n};\n// message: JS Object\nconst decryptObject = (nonce, ciphertext, storageSk) => {\n return JSON.parse(arr2str(decrypt(nonce, ciphertext, storageSk)));\n};\nreturn {\n encrypt,\n encryptStr,\n encryptObject,\n decrypt,\n decryptObject,\n newSecretKey,\n};\n" }, "page.home": { "": "const { currentPath, page, ...passProps } = props;\nconst NavbarHeight = 70; // Assumed height of the Navbar\nconst Card3D = styled.div`\n perspective: 2000px;\n display: flex;\n align-items: center;\n justify-content: center;\n width: 100%;\n height: 100%;\n`;\nconst ScaleUp = {\n transform: \"scale(1.5)\", // Scale up by 25%\n paddingTop: `${NavbarHeight}px`, // Ensure content starts below the navbar\n marginTop: `-${NavbarHeight * 2}px`, // Offset the padding\n boxSizing: \"border-box\", // Include padding in the element's total width and height\n};\nconst CardContent = styled.div`\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: center;\n background-color: #fff;\n color: #000;\n padding: 2rem;\n`;\nconst Container = styled.div`\n display: flex;\n justify-content: center;\n align-items: center;\n margin-top: 1rem;\n`;\nconst Tagline = styled.p`\n text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.5), 2px 2px 2px rgba(0, 0, 0, 0.3);\n text-align: right; /* Right align the tagline */\n width: 100%;\n`;\nconst MainButton = styled.button`\n margin: 0.3em;\n text-decoration: none;\n`;\nconst { href } = VM.require(\"buildhub.near/widget/lib.url\") || {\n href: () => {},\n};\nconst ButtonLink = ({ to, children }) => (\n <Link\n key={to}\n style={{ textDecoration: \"none\" }}\n to={href({\n widgetSrc: \"hyperbuild.near/widget/app\",\n params: {\n page: to,\n },\n })}\n >\n {children}\n </Link>\n);\nreturn (\n <div className=\"vh-100 w-100\">\n <Card3D>\n <CardContent style={ScaleUp}>\n <h1\n className=\"display-4 font-weight-bold text-black mb-2\"\n style={{\n textShadow:\n \"1px 1px 1px rgba(0, 0, 0, 0.5), 4px 4px 4px rgba(0, 0, 0, 0.3)\",\n }}\n >\n hyperfiles\n </h1>\n <Tagline className=\"h5 text-success mb-4\">organize everything</Tagline>\n <Container>\n <ButtonLink to={\"create\"}>\n <MainButton key={\"create\"} variant={page === \"create\" && \"primary\"}>\n Create\n </MainButton>\n </ButtonLink>\n <ButtonLink to={\"explore\"}>\n <MainButton\n key={\"explore\"}\n variant={page === \"explore\" && \"primary\"}\n >\n Explore\n </MainButton>\n </ButtonLink>\n <ButtonLink to={\"tools\"}>\n <MainButton key={\"tools\"} variant={page === \"tools\" && \"primary\"}>\n Tools\n </MainButton>\n </ButtonLink>\n </Container>\n <Container>\n <div style={{ marginTop: \"1rem\", width: \"100%\" }}>\n <Widget\n src=\"hyperbuild.near/widget/profile.links\"\n props={{ accountId: \"hyperfiles.near\" }}\n />\n </div>\n </Container>\n </CardContent>\n </Card3D>\n </div>\n);\n" }, "explore.select.schema.array": { "": "const defaultOptions = [\n { name: \"Markdown\" },\n { name: \"JSON\" },\n { name: \"Other\" },\n];\n\nconst schemaPattern = props.schemaPattern ?? \"*/schema/*\";\nconst placeholder = props.placeholder ?? \"Schema\";\nconst initialSchemaObject = props.initialSchemaObject || {};\n\nconst schemaObject = Social.keys(schemaPattern, \"final\");\n\nif (schemaObject === null) {\n return \"Loading\";\n}\n\nconst normalizeProf = (prof) =>\n prof\n .replaceAll(/[- \\.]/g, \"_\")\n .replaceAll(/[^\\w]+/g, \"\")\n .replaceAll(/_+/g, \"-\")\n .replace(/^-+/, \"\")\n .replace(/-+$/, \"\")\n .toLowerCase()\n .trim(\"-\");\n\nconst schemaCount = {};\n\nconst processSchemaObject = (obj) => {\n Object.entries(obj).forEach(([key, value]) => {\n if (typeof value === \"object\") {\n processSchemaObject(value);\n } else {\n const prof = normalizeProf(key);\n schemaCount[prof] = (schemaCount[prof] || 0) + 1;\n }\n });\n};\n\nconst getSchema = () => {\n processSchemaObject(schemaObject);\n const schema = Object.entries(schemaCount);\n schema.sort((a, b) => b[1] - a[1]);\n return schema.map((t) => ({ name: t[0], count: t[1] }));\n};\n\nif (!state.allSchema) {\n initState({\n allSchema: getSchema().length > 0 ? getSchema() : schemaArray || [], // Fallback to empty array if schemaArray is undefined\n schema: Object.keys(initialSchemaObject).map((prof) => ({\n name: normalizeProf(prof),\n })),\n originalSchema: Object.fromEntries(\n Object.keys(initialSchemaObject).map((prof) => [prof, null])\n ),\n id: `schema-selector-${Date.now()}`,\n });\n}\n\nconst setSchema = (schema) => {\n schema = schema.map((o) => ({ name: normalizeProf(o.name) }));\n State.update({ schema });\n if (props.setSchemaObject) {\n props.setSchemaObject(\n Object.assign(\n {},\n state.originalSchema,\n Object.fromEntries(schema.map((prof) => [prof.name, \"\"]))\n )\n );\n }\n};\n\nreturn (\n <>\n <Typeahead\n id={state.id}\n labelKey=\"name\"\n onChange={setSchema}\n options={state.allSchema}\n placeholder={placeholder}\n selected={state.schema}\n positionFixed\n allowNew\n />\n {props.debug && (\n <div>\n Debugging schema:\n <pre>{JSON.stringify(state.schema)}</pre>\n </div>\n )}\n </>\n);\n" }, "create.new": { "": "const { NewThings } = VM.require(\"hyperbuild.near/widget/create.newthings\");\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst FormGroup = styled.div`\n margin-bottom: 10px;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Select = styled.select`\n height: 30px;\n margin-bottom: 10px;\n`;\nconst Button = styled.button`\n height: 30px;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n margin-top: 10px;\n`;\nconst Row = styled.div`\n display: flex;\n gap: 10px;\n`;\n// Initializing state and utility functions\nconst CreateNew = ({ initialData = {}, types, schemas }) => {\n const [data, setData] = useState(initialData);\n const [selectedTypeOrSchema, setSelectedTypeOrSchema] = useState(\"\");\n // Load available types or schemas\n const options = { ...types, ...schemas }; // Merging types and schemas into a single object\n const handleTypeOrSchemaChange = (e) => {\n setSelectedTypeOrSchema(e.target.value);\n setData({}); // Reset data when type or schema changes\n };\n const handleChange = (newData) => {\n setData(newData);\n };\n const handleSave = () => {\n console.log(\"Saving data:\", data);\n // Implement save functionality here\n };\n return (\n <Container>\n <FormGroup>\n <Label>Select Type or Schema:</Label>\n <Select\n value={selectedTypeOrSchema}\n onChange={handleTypeOrSchemaChange}\n >\n <option value=\"\">Select an option</option>\n {Object.keys(options).map((key) => (\n <option key={key} value={key}>\n {key}\n </option>\n ))}\n </Select>\n </FormGroup>\n {selectedTypeOrSchema && (\n <FormContainer>\n <NewThings\n item={{ type: options[selectedTypeOrSchema], value: data }}\n onChange={handleChange}\n />\n <Row>\n <Button onClick={handleSave}>Save</Button>\n </Row>\n </FormContainer>\n )}\n </Container>\n );\n};\nexport { CreateNew };\n" }, "create.data": { "": "const DataCreator = ({ initialData, onCreation, adapters, schema }) => {\n const [data, setData] = useState(initialData);\n const [selectedAdapter, setAdapter] = useState(adapters[0].value);\n\n const handleInputChange = (name, value) => {\n setData((prev) => ({ ...prev, [name]: value }));\n };\n\n const createData = async () => {\n const adapterScript = VM.require(selectedAdapter);\n const reference = await adapterScript.create(data);\n onCreation(reference);\n };\n\n return (\n <Form>\n {Object.entries(schema.properties).map(([name, spec]) => (\n <FormGroup key={name}>\n <Label>{spec.label}</Label>\n <Input\n type={spec.type}\n value={data[name]}\n onChange={(e) => handleInputChange(name, e.target.value)}\n />\n </FormGroup>\n ))}\n <Button onClick={createData}>Create</Button>\n </Form>\n );\n};\n" }, "create.hyperfiles": { "": "const Wrapper = styled.div`\n max-width: 400px;\n margin: 0 auto;\n`;\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Button = styled.button``;\nfunction CreateHyperfile(props) {\n // Initialize state\n let newSchemaSrc = props.schemaSrc || \"hyperfiles.near\";\n let schemaSrc = newSchemaSrc;\n let availableSchemas = [];\n let isLoading = true;\n let selectedSchema = props.selectedSchema || \"hyperfiles.near/schema/test\";\n let source = props.source || \"\";\n let adapter = props.adapters ? props.adapters[0].value : \"\";\n let reference = undefined;\n let filename = props.filename || \"\";\n let activeTab = \"data\";\n let name = props.name || \"\";\n let description = props.description || \"\";\n let json = props.data || \"\";\n let data = props.data || {};\n let hyperfile = \"\";\n // Functions to handle state changes\n function setState(newState) {\n Object.assign(state, newState);\n render();\n }\n function handleOnChange(value) {\n setState({ data: { ...state.data, ...value } });\n }\n function handleSchemaSrcChange(newSchemaSrc) {\n setState({ schemaSrc: newSchemaSrc, selectedSchema: \"\" });\n }\n function handleSelectedSchemaChange(newValue) {\n setState({ selectedSchema: newValue });\n }\n function handleThingUpdate(newData) {\n console.log(\"Thing Data Updated:\", newData);\n }\n function generateUID() {\n return (\n Math.random().toString(16).slice(2) +\n Date.now().toString(36) +\n Math.random().toString(16).slice(2)\n );\n }\n function handleCreate() {\n const isCreator = context.accountId === props.creatorId;\n const { create } = VM.require(adapter) || (() => {});\n if (create) {\n create(json).then((reference) => {\n const thingId = filename || generateUID();\n const hyperfileData = {\n [props.type]: {\n [thingId]: {\n \"\": JSON.stringify({\n schema: schema,\n source: source,\n adapter: adapter,\n reference: reference,\n metadata: {\n name: name,\n description: description,\n type: props.type,\n },\n }),\n },\n },\n };\n if (creatorId !== context.accountId) {\n hyperfileData.index = {\n notify: JSON.stringify({\n key: creatorId,\n value: {\n type: \"request\",\n data: {\n type: \"merge\",\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n origin: `${context.accountId}/${props.type}/${thingId}`,\n },\n },\n }),\n };\n hyperfileData[props.type][thingId].metadata = {\n ...hyperfileData[props.type][thingId].metadata,\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n };\n }\n hyperfile = JSON.stringify(hyperfileData);\n Social.set(hyperfileData, { force: true });\n });\n }\n }\n // Rendering function\n function render() {\n return (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Data</h3>\n <FormGroup>\n <Label>Source</Label>\n <Widget\n src={`hyperbuild.near/widget/profile.metadataEditor`}\n props={{\n initialMetadata: profile,\n onChange: (newValue) => {\n setSource(newValue);\n State.update({\n profile: { ...profile, source: newValue },\n });\n },\n value: source,\n options: {\n source: {\n sourcePattern: \"*/profile/source/*\",\n placeholder: \"Select a source\",\n },\n },\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Schema</Label>\n <p>{JSON.stringify(selectedSchema)}</p>\n <Widget\n src={`hyperbuild.near/widget/explore.select.schema`}\n props={{\n onSchemaSrcChange: handleSchemaSrcChange,\n onSelectedSchemaChange: handleSelectedSchemaChange,\n selectedSchema: selectedSchema,\n schemaSrc: schemaSrc,\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Input Your Data</Label>\n <FormContainer>\n <Widget\n src={`hyperbuild.near/widget/create.thing`}\n props={{\n item: {\n type: selectedSchema,\n value: data,\n },\n onChange: handleOnChange,\n }}\n />\n </FormContainer>\n </FormGroup>\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Storage</h3>\n <FormGroup>\n <Label>Adapter</Label>\n <Select\n value={adapter}\n onChange={(e) => setAdapter(e.target.value)}\n >\n {props.adapters &&\n props.adapters.map((o) => (\n <option key={o.value} value={o.value}>\n {o.title}\n </option>\n ))}\n </Select>\n </FormGroup>\n {rawAdapter && <>{parseAdapter(rawAdapter)}</>}\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <Button\n onClick={handleCreate}\n disabled={!adapter || !schema || !source || !json}\n >\n create reference\n </Button>\n {hyperfile !== \"\" && (\n <>\n <FormGroup>\n <textarea\n className=\"form-control\"\n value={hyperfile}\n disabled\n style={{ width: \"100%\", height: \"400px\" }}\n />\n </FormGroup>\n <Button\n onClick={() =>\n Social.set(JSON.parse(hyperfile), {\n force: true,\n })\n }\n >\n save\n </Button>\n </>\n )}\n </Form>\n </div>\n </div>\n </div>\n );\n }\n // Initial render call\n return render();\n}\nreturn { CreateHyperfile };\n" }, "profile.metadataEditor": { "": "const initialMetadata = props.initialMetadata ?? {};\nconst onChange = props.onChange;\nconst options = props.options;\nState.init({\n initialMetadata,\n metadata: initialMetadata,\n reportedMetadata: initialMetadata,\n linktree: initialMetadata.linktree ?? {},\n image: initialMetadata.image,\n backgroundImage: initialMetadata.backgroundImage,\n source: initialMetadata.source ?? {},\n schema: initialMetadata.schema ?? {},\n});\nconst metadata = {\n name: options.name ? state.metadata.name : undefined,\n description: options.name ? state.metadata.description : undefined,\n linktree:\n options.linktree && Object.keys(state.linktree).length > 0\n ? state.linktree\n : undefined,\n image:\n options.image && state.image && Object.keys(state.image).length > 0\n ? state.image\n : undefined,\n backgroundImage:\n options.backgroundImage &&\n state.backgroundImage &&\n Object.keys(state.backgroundImage).length > 0\n ? state.backgroundImage\n : undefined,\n tags: options.tags ? state.metadata.tags : undefined,\n source: options.source ? state.metadata.source : undefined,\n schema: options.schema ? state.metadata.schema : undefined,\n};\nif (\n onChange &&\n JSON.stringify(state.reportedMetadata) !== JSON.stringify(metadata)\n) {\n State.update({\n reportedMetadata: metadata,\n });\n onChange(metadata);\n}\nconst debounce = (func, wait) => {\n const pause = wait || 350;\n let timeout;\n return (args) => {\n const later = () => {\n clearTimeout(timeout);\n func(args);\n };\n clearTimeout(timeout);\n timeout = setTimeout(later, pause);\n };\n};\nconst onNameChange = debounce((e) => {\n State.update({\n metadata: {\n ...state.metadata,\n name: e.target.value,\n },\n });\n});\nconst onDescriptionChange = debounce((e) => {\n State.update({\n metadata: {\n ...state.metadata,\n description: e.target.value,\n },\n });\n});\nconst onLinkTreeChange = debounce((e) => {\n State.update({\n linktree: {\n ...state.linktree,\n [e.target.id]: e.target.value,\n },\n });\n});\nconst onSkillsChange = debounce((e) => {\n State.update({\n skills: {\n ...state.skills,\n [e.target.id]: e.target.value,\n },\n });\n});\nconst onSourceChange = debounce((e) => {\n State.update({\n source: {\n ...state.source,\n [e.target.id]: e.target.value,\n },\n });\n});\nconst onSchemaChange = debounce((e) => {\n State.update({\n schema: {\n ...state.schema,\n [e.target.id]: e.target.value,\n },\n });\n});\nreturn (\n <>\n {options.name && (\n <div className=\"mb-2\">\n {options.name.label ?? \"Name\"}\n <input\n type=\"text\"\n defaultValue={state.metadata.name}\n onChange={onNameChange}\n />\n </div>\n )}\n {options.image && (\n <div className=\"mb-2\">\n {options.image.label ?? \"Image\"}\n <Widget\n src=\"near/widget/ImageEditorTabs\"\n props={{\n image: state.image,\n onChange: (image) => State.update({ image }),\n }}\n />\n </div>\n )}\n {options.backgroundImage && (\n <div className=\"mb-2\">\n {options.backgroundImage.label ?? \"Background image\"}\n <Widget\n src=\"near/widget/ImageEditorTabs\"\n props={{\n image: state.backgroundImage,\n onChange: (backgroundImage) => State.update({ backgroundImage }),\n debounce,\n }}\n />\n </div>\n )}\n {options.description && (\n <div className=\"mb-2\">\n {options.description.label ?? \"Description\"}\n <span className=\"text-secondary\"> (supports markdown)</span>\n <textarea\n className=\"form-control\"\n rows={5}\n defaultValue={state.metadata.description}\n onChange={onDescriptionChange}\n />\n </div>\n )}\n {options.tags && (\n <div className=\"mb-2\">\n {options.tags.label ?? \"Tags\"}\n <Widget\n src=\"mob.near/widget/TagsEditor\"\n props={{\n initialTagsObject: metadata.tags,\n tagsPattern: options.tags.pattern,\n placeholder:\n options.tags.placeholder ??\n \"rust, engineer, artist, humanguild, nft, learner, founder\",\n setTagsObject: (tags) => {\n state.metadata.tags = tags;\n State.update();\n },\n }}\n />\n </div>\n )}\n {options.source && (\n <div className=\"mb-2\">\n <Widget\n src=\"hyperfiles.near/widget/source.edit\"\n props={{\n initialSourceObject: state.metadata.source,\n sourcePattern: options.source.pattern,\n placeholder: options.source.placeholder ?? \"\",\n setSourceObject: (source) => {\n state.metadata.source = source;\n State.update();\n onChange({ ...state.metadata, source }); // Trigger parent onChange with new metadata\n },\n }}\n />\n </div>\n )}\n {options.schema && (\n <div className=\"mb-2\">\n <Widget\n src=\"hyperfiles.near/widget/schema.array\"\n props={{\n initialSchemaObject: state.metadata.schema,\n schemaPattern: options.schema.pattern,\n placeholder: options.schema.placeholder ?? \"\",\n setSchemaObject: (schema) => {\n state.metadata.schema = schema;\n State.update();\n onChange({ ...state.metadata, schema }); // Trigger parent onChange with new metadata\n },\n }}\n />\n </div>\n )}\n {options.linktree &&\n (options.linktree.links ?? []).map((link) => (\n <div className=\"mb-2\">\n {link.label}\n <div className=\"input-group\">\n <span className=\"input-group-text\">{link.prefix}</span>\n <input\n type=\"text\"\n id={link.name}\n defaultValue={state.linktree[link.name]}\n onChange={onLinkTreeChange}\n />\n </div>\n </div>\n ))}\n </>\n);\n" }, "template.AppLayout": { "": "const StyledButton = styled.button`\n all: unset;\n display: ${(props) => (props.type === \"icon\" ? \"flex\" : \"inline-flex\")};\n width: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n height: ${(props) => (props.type === \"icon\" ? \"40px\" : \"auto\")};\n padding: ${(props) => (props.type === \"icon\" ? \"0\" : \"10px 20px\")};\n justify-content: center;\n align-items: center;\n gap: 4px;\n border-radius: ${(props) => (props.type === \"icon\" ? \"50%\" : \"8px\")};\n font-size: ${(props) => (props.type === \"icon\" ? \"16px\" : \"14px\")};\n font-weight: 600;\n font-family: \"Poppins\", sans-serif;\n background: var(--button-${props.variant}-bg, #23242b);\n color: var(--button-${props.variant}-color, #cdd0d5);\n border: ${(props) =>\n props.variant === \"outline\"\n ? \"1px solid rgba(255, 255, 255, 0.20)\"\n : \"none\"};\n transition: background 300ms, color 300ms;\n\n &:hover:not(:disabled) {\n background: var(--button-${props.variant}-hover-bg, #17181c);\n }\n &:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n`;\nconst Container = styled.div`\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n`;\nconst ContentContainer = styled.div`\n flex: 1;\n display: flex;\n flex-direction: column;\n align-items: center;\n width: 100%;\n height: 100%;\n`;\nconst Header = ({ page, routes, ...props }) => (\n <Widget\n src=\"hyperbuild.near/widget/navigation.Navbar\"\n props={{ page, routes, ...props }}\n />\n);\nconst Footer = (props) => {\n return <></>;\n};\nfunction AppLayout({ routes, page, children, ...props }) {\n return (\n <Container>\n <Header page={page} routes={routes} {...props} />\n <ContentContainer key={page}>{children}</ContentContainer>\n <Footer page={page} />\n </Container>\n );\n}\nreturn { AppLayout };\n" }, "tools.files.content": { "": "const Content = styled.div`\n flex: 1;\n padding: 20px;\n background-color: #f9f9f9;\n width: 100%;\n overflow: auto;\n`;\nconst Overlay = styled.div`\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n width: 50%;\n background-color: #fff;\n`;\nconst Grid = styled.div`\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n @media (min-width: 600px) {\n gap: 20px;\n }\n`;\nconst GridItem = styled.div`\n flex: 1 0 calc(33.333% - 10px);\n @media (min-width: 600px) {\n flex: 1 0 calc(25% - 20px);\n }\n`;\nconst Columns = styled.div`\n display: flex;\n`;\nconst Column = styled.div`\n min-width: 200px;\n border-right: 1px solid #e0e0e0;\n`;\nconst layout = props.layout || \"LIST\";\nconst setPath = props.setPath || (() => {});\nconst path = props.path || context.accountId;\nconst showPreview = props.showPreview || false;\nconst setSelectedPath = props.setSelectedPath || (() => {});\nconst selectedPath = props.selectedPath || \"\";\nconst decryptSk = props.decryptSk || \"\"; // Use decryptSk instead of password\nconst { newSecretKey, decryptObject } = VM.require(\n \"fastvault.near/widget/module.crypto\"\n);\nconst [storageSk, _] = useState(() => {\n if (decryptSk) {\n // decryptSk is available. use it instead of recovering\n console.log(\"Utilizing decryptSk over password\");\n return decryptSk;\n }\n const localSk = Storage.privateGet(\"storage_secret\");\n if (localSk && !password) {\n return localSk;\n }\n const sk = newSecretKey(context.accountId, password);\n console.log(\"recovered decryption key from local storage\");\n Storage.privateSet(\"storage_secret\", sk);\n return sk;\n});\n// --- FV START ---\nconst files = Social.index(\"fastvault_experimental\", \"add\", {\n accountId: context.accountId,\n});\nconsole.log(\"indexed\", files);\nlet data = {};\nif (files) {\n data = files.reduce((acc, file) => {\n const encryptedMetadata = file.value;\n if (!encryptedMetadata.nonce || !encryptedMetadata.ciphertext) {\n console.log(\"invalid file metadata to be decrypted\", file);\n return acc;\n }\n const metadata = decryptObject(\n new Uint8Array(encryptedMetadata.nonce),\n new Uint8Array(encryptedMetadata.ciphertext),\n storageSk\n );\n acc[metadata.filename] = {\n value: metadata.cid + \"|\" + (metadata.filetype ?? \"???\"),\n cid: metadata.cid,\n filetype: metadata.filetype,\n byteSize: metadata.byteSize,\n };\n return acc;\n }, {});\n}\n// --- FV END ---\nif (!data) {\n return <p>Loading...</p>;\n}\nState.init({\n activePath: [],\n selectedPath: \"\",\n showTextDialog: false,\n dataToDisplay: null,\n});\nfunction setActivePath(v) {\n State.update({ activePath: v });\n}\nconst ArrowIcon = styled.span`\n display: inline-block;\n width: 10px;\n height: 10px;\n border-top: 2px solid black;\n border-right: 2px solid black;\n transform: ${(props) =>\n props.isExpanded ? \"rotate(135deg)\" : \"rotate(45deg)\"};\n margin-right: 5px;\n`;\nconst ItemContainer = styled.span`\n display: flex;\n justify-content: space-between;\n align-items: center;\n cursor: pointer;\n font-size: 18px;\n`;\nconst ItemInfo = styled.span`\n display: flex;\n gap: 10px;\n width: 200px;\n justify-content: space-between;\n`;\nconst ItemDetails = styled.span`\n display: flex;\n gap: 4px;\n align-items: center;\n`;\nconst IconDiv = styled.div`\n background-color: white;\n border-radius: 8px;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n width: 5em;\n height: 5em;\n cursor: pointer;\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n &:hover {\n transform: scale(1.05);\n box-shadow: 0 6px 12px rgba(0, 0, 0, 0.2);\n }\n &:active {\n transform: scale(0.95);\n background-color: #f0f0f0;\n }\n`;\nconst { ContextMenu } = VM.require(\"efiz.near/widget/Module.ContextMenu\");\nContextMenu = ContextMenu || (() => <></>);\nfunction deleteFile(path) {\n function buildObjectWithLastNull(path) {\n const parts = path.split(\"/\").slice(1); // Remove the first part of the path\n let currentObj = {};\n let pointer = currentObj;\n parts.forEach((component, i) => {\n if (i === parts.length - 1) {\n pointer[component] = null;\n } else {\n pointer[component] = {};\n pointer = pointer[component];\n }\n });\n return currentObj;\n }\n const result = buildObjectWithLastNull(path);\n Social.set(result);\n}\nfunction deleteFolder(path, data) {\n function setLeavesToNull(obj) {\n Object.keys(obj).forEach((key) => {\n if (typeof obj[key] === \"object\" && obj[key] !== null) {\n obj[key] = setLeavesToNull(obj[key]);\n } else {\n obj[key] = null;\n }\n });\n return obj;\n }\n function buildObjectWithPath(path, data) {\n const parts = path.split(\"/\").slice(1);\n const value = parts.reduce(\n (current, part) => (current && current[part] ? current[part] : undefined),\n data\n );\n let currentObj = {};\n let pointer = currentObj;\n parts.forEach((component, i) => {\n if (i === parts.length - 1) {\n pointer[component] = setLeavesToNull(value);\n } else {\n pointer[component] = {};\n pointer = pointer[component];\n }\n });\n return currentObj;\n }\n const newData = buildObjectWithPath(path, data);\n Social.set(newData);\n}\nfunction calculateSize(data) {\n const str = typeof data === \"object\" ? JSON.stringify(data) : data;\n let sizeInBytes = 0;\n for (let i = 0; i < str.length; i++) {\n const charCode = str.charCodeAt(i);\n if (charCode <= 0x7f) {\n sizeInBytes += 1;\n } else if (charCode <= 0x7ff) {\n sizeInBytes += 2;\n } else if (charCode <= 0xffff) {\n sizeInBytes += 3;\n } else {\n sizeInBytes += 4;\n }\n }\n if (sizeInBytes < 1024) {\n return sizeInBytes + \" Bytes\";\n } else if (sizeInBytes < 1024 * 1024) {\n return (sizeInBytes / 1024).toFixed(2) + \" KB\";\n } else {\n return (sizeInBytes / (1024 * 1024)).toFixed(2) + \" MB\";\n }\n}\nfunction determineType(path, data) {\n const parts = path.split(\"/\");\n if (parts.length === 1) {\n return \"account\";\n } else {\n const v = parts[1];\n return v;\n }\n}\nconst iconMap = {\n nametag: \"bi bi-person-badge\",\n profile: \"bi bi-person-circle\",\n index: \"bi bi-list-ol\",\n graph: \"bi bi-graph-up\",\n widget: \"bi bi-layout-text-sidebar-reverse\",\n post: \"bi bi-file-post\",\n thing: \"bi bi-box\",\n type: \"bi bi-type\",\n settings: \"bi bi-gear\",\n};\nconst handleColumnClick = (key) => {\n setActivePath([...state.activePath, key]);\n};\nfunction RenderData({ data, layout }) {\n switch (layout) {\n case \"LIST\":\n const dataList =\n state.activePath.length === 0 ? data : getNestedData(data, activePath);\n return (\n <>\n {Object.keys(dataList).map((key) => (\n <div key={key}>\n <Widget\n src=\"fastvault.near/widget/voyager.item\"\n loading={<></>}\n props={{\n path: key,\n data: dataList[key],\n level: 0,\n eFile: ({ key, data, level }) => {\n const updatedPath = [path, key].join(\"/\");\n return (\n <ContextMenu\n Item={() => (\n <ItemContainer\n onDoubleClick={() => setPath(updatedPath)} // open file\n onClick={() => {\n if (data.filetype.includes(\"text\")) {\n console.log(\"clicked file ln 325\", data);\n data.key = key;\n State.update({ dataToDisplay: data });\n }\n }}\n style={{\n marginLeft: level * 20,\n backgroundColor:\n selectedPath === updatedPath\n ? \"#f0f0f0\"\n : \"transparent\",\n }}\n >\n <ItemDetails>\n <i className=\"bi bi-file\"></i>\n <span>{key.split(\"/\").pop()}</span>\n </ItemDetails>\n <ItemInfo>\n <span>{formatBytes(data.byteSize)}</span>\n <span>{data.filetype}</span>\n <span />\n </ItemInfo>\n </ItemContainer>\n )}\n passProps={{\n delete: { path: updatedPath, data },\n }}\n handlers={{\n delete: ({ path }) => {\n deleteFile(path);\n },\n }}\n items={{\n delete: () => (\n <>\n <i className=\"menu__item__icon bi bi-x-lg\" />\n Delete\n </>\n ),\n }}\n />\n );\n },\n eFolder: ({ toggleExpand, isExpanded, key, level }) => {\n const updatedPath = [path, key].join(\"/\");\n return (\n <ContextMenu\n Item={() => (\n <ItemContainer\n onDoubleClick={() => setPath(updatedPath)} // open folder\n onClick={() => {\n toggleExpand();\n }}\n style={{\n marginLeft: level * 20,\n }}\n >\n <ItemDetails>\n <ArrowIcon isExpanded={isExpanded} />\n <i className=\"bi bi-folder\"></i>\n <span>{key.split(\"/\").pop()}</span>{\" \"}\n </ItemDetails>\n <ItemInfo>\n <span>--</span>\n <span>Folder</span>\n <span />\n </ItemInfo>\n </ItemContainer>\n )}\n passProps={{\n delete: { path: updatedPath, data },\n }}\n handlers={{\n delete: ({ path, data }) => {\n deleteFolder(path, data);\n },\n }}\n items={{\n delete: () => (\n <>\n <i className=\"menu__item__icon bi bi-x-lg\" />\n Delete\n </>\n ),\n }}\n />\n );\n },\n }}\n />\n </div>\n ))}\n </>\n );\n case \"GRID\":\n return decryptSk ? (\n <Grid>\n {Object.keys(data).map((key) => {\n const updatedPath = [path, key].join(\"/\");\n return (\n <GridItem key={key}>\n <Widget\n src=\"fastvault.near/widget/EncryptedImage\"\n props={{\n decryptSk: decryptSk,\n image: { ipfs_cid: data[key].cid },\n style: { height: \"200px\", width: \"200px\" },\n fallbackUrl:\n \"https://ipfs.near.social/ipfs/bafkreihdxorcz6wflgfhrwtguibaf6pbizp7mpavkwuhqxniaqloq3f2ae\",\n }}\n />\n <p>{key}</p>\n </GridItem>\n );\n })}\n </Grid>\n ) : (\n <p>Password was not provided</p>\n );\n default:\n return null;\n }\n}\nfunction getNestedData(data, pathArray) {\n return pathArray.reduce((currentData, key) => currentData[key] || {}, data);\n}\n// --- FV START ---\n// https://stackoverflow.com/questions/15900485/correct-way-to-convert-size-in-bytes-to-kb-mb-gb-in-javascript\nfunction formatBytes(bytes) {\n const decimals = 2;\n if (!bytes) return \"0 Bytes\";\n const k = 1024;\n const dm = decimals < 0 ? 0 : decimals;\n const sizes = [\n \"Bytes\",\n \"KiB\",\n \"MiB\",\n \"GiB\",\n \"TiB\",\n \"PiB\",\n \"EiB\",\n \"ZiB\",\n \"YiB\",\n ];\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(dm))} ${sizes[i]}`;\n}\n// --- FV END ---\nreturn (\n <Content>\n <FileUpload\n onUploadIPFS={handleUploadIPFS}\n onUploadNEARFS={handleUploadNEARFS}\n />\n <RenderData layout={layout} data={data} />\n {showPreview && (\n <Overlay>\n <div key={selectedPath}>\n <p>lol it's way to slow to allow preview rn</p>\n </div>\n </Overlay>\n )}\n <Widget\n src=\"near/widget/DIG.Dialog\"\n props={{\n type: \"dialog\",\n open: !!state.dataToDisplay,\n confirmButtonText: \"Close\",\n actionButtons: <></>,\n content: (\n <Widget\n src=\"fastvault.near/widget/EncryptedText\"\n props={{\n decryptSk: decryptSk,\n cid: state.dataToDisplay?.cid,\n fileType: state.dataToDisplay?.filetype,\n key: state.dataToDisplay?.key,\n }}\n />\n ),\n onOpenChange: (value) => State.update({ dataToDisplay: null }),\n }}\n />\n </Content>\n);\n" }, "create.hyperfile": { "": "// const { NewThings } = VM.require('hyperbuild.near/widget/create.newthing');\n// <NewThings item={{ type: 'specificType', value: {} }} onChange={handleThingUpdate} />\nconst Wrapper = styled.div`\n max-width: 400px;\n margin: 0 auto;\n`;\nconst TabContent = styled.div`\n margin-top: 1rem;\n`;\nconst Form = styled.div`\n display: flex;\n flex-direction: column;\n gap: 4px;\n width: 100%;\n`;\nconst Label = styled.label`\n font-weight: bold;\n`;\nconst Input = styled.input`\n padding: 5px;\n`;\nconst Select = styled.select`\n padding: 8px;\n`;\nconst FormGroup = styled.div`\n display: flex;\n flex-direction: column;\n`;\nconst FormContainer = styled.div`\n border: 1px solid #ccc;\n padding: 20px;\n`;\nconst Button = styled.button``;\n// Define adapter array before initializing constants below\nconst adapters = [\n // these can come from the user (or app) settings\n // {\n // title: \"Local Storage\",\n // value: \"everycanvas.near/widget/adapter.local_storage\",\n // saveRef: false\n // },\n // {\n // title: \"SocialDB\",\n // value: \"everycanvas.near/widget/adapter.social\",\n // },\n {\n title: \"\",\n value: \"\",\n },\n {\n title: \"IPFS\",\n value: \"everycanvas.near/widget/adapter.ipfs\",\n refType: { cid: \"string\" },\n },\n // {\n // title: \"Custom\",\n // value: \"custom\",\n // },\n {\n title: \"GitHub\",\n value: \"hyperfiles.near/widget/adapter.github\",\n },\n // {\n // title: \"Obsidian\",\n // value: \"hack.near/widget/adapter.obsidian\",\n // },\n // {\n // title: \"Tldraw\",\n // value: \"hack.near/widget/adapter.tldraw\",\n // },\n];\n// Schema constants\nconst initialSchemaSrc = props.schemaSrc || \"hyperfiles.near\";\nconst [newSchemaSrc, setNewSchemaSrc] = useState(initialSchemaSrc);\nconst [schemaSrc, setSchemaSrc] = useState(initialSchemaSrc);\nconst [availableSchemas, setAvailableSchemas] = useState([]);\nconst [isLoading, setIsLoading] = useState(true);\nconst [selectedSchema, setSelectedSchema] = useState(\n props.selectedSchema || \"\"\n);\n// Creator constants\nconst defaultAdapter = adapters[0];\nconst { creatorId } = props;\nconst [source, setSource] = useState(props.source ?? \"\");\nconst [adapter, setAdapter] = useState(defaultAdapter.value ?? \"\");\nconst [reference, setReference] = useState(undefined);\nconst [filename, setFilename] = useState(props.filename ?? \"\");\nconst [activeTab, setActiveTab] = useState(\"data\");\nconst [name, setName] = useState(props.name ?? \"\");\nconst [description, setDescription] = useState(props.description ?? \"\");\nconst [json, setJson] = useState(props.data ?? \"\");\nconst [state, setState] = useState({\n data,\n});\nconst handleOnChange = (value) => {\n setState((prevState) => {\n const newData = { value };\n console.log(\"Current Data:\", newData);\n return {\n data: newData,\n };\n });\n};\nconst handleSchemaSrcChange = (newSchemaSrc) => {\n setSchemaSrc(newSchemaSrc);\n setSelectedSchema(\"\"); // Reset the selected schema when the source changes\n};\nconst handleSelectedSchemaChange = (newValue) => {\n const fullSchemaPath = `${schemaSrc}/schema/${newValue}`;\n setSelectedSchema(fullSchemaPath);\n console.log(\"Selected Schema Changed:\", fullSchemaPath);\n};\nconst handleThingUpdate = (newData) => {\n console.log(\"Thing Data Updated:\", newData);\n // Handle the new data, such as saving to a state or sending to a server\n};\nconst handleSelectRepository = (selectedFilePath) => {\n console.log(\"Selected repository:\", selectedFilePath);\n // Assuming you need the repository's file path or some specific identifier\n setFilePath(selectedFilePath); // or any specific attribute you need\n};\nconst rawAdapter =\n (adapter !== \"\" || adapter !== \"custom\") && Social.get(adapter, \"final\");\nconst { create } =\n ((adapter !== \"\" || adapter !== \"custom\") && VM.require(adapter)) ||\n (() => {});\nconst functionRegex = /function\\s+(\\w+)\\s*\\(([^)]*)\\)\\s*{([\\s\\S]*?)\\n}/g;\nfunction parseAdapter(code) {\n let match;\n const functions = [];\n while ((match = functionRegex.exec(code)) !== null) {\n const [_, functionName, params, content] = match;\n functions.push({ functionName, params, content });\n }\n return functions.map((func, index) => (\n <FormGroup key={index}>\n <Label>{func.functionName}</Label>\n <textarea\n className=\"form-control\"\n style={{ width: \"100%\", height: \"100%\" }}\n value={func.content.trim()}\n disabled\n />\n </FormGroup>\n ));\n}\n// TODO: Import keccak from ethers to hash Hyperfile contents\nfunction generateUID() {\n return (\n Math.random().toString(16).slice(2) +\n Date.now().toString(36) +\n Math.random().toString(16).slice(2)\n );\n}\nconst handleCreate = () => {\n const isCreator = context.accountId === creatorId;\n // load in the state.adapter (modules for IPFS, Arweave, Ceramic, Verida, On Machina... )\n const { create } = VM.require(adapter) || (() => {});\n if (create) {\n // store the data somewhere, based on the adapter\n create(json).then((reference) => {\n // now we have a reference to the data\n // we need to name it... are we the original creator or are we forking? We don't want to overwrite any of the users custom (or maybe we do!)\n const thingId = filename ?? generateUID();\n const hyperfile = {\n [props.type]: {\n // which we store in the social contract\n [thingId]: {\n \"\": JSON.stringify({\n schema: schema,\n source: source,\n adapter: adapter,\n reference: reference,\n metadata: {\n name: name,\n description: description,\n type: props.type,\n },\n }),\n },\n },\n };\n if (creatorId !== context.accountId) {\n // handle request merge\n hyperfile.index = {\n notify: JSON.stringify({\n key: creatorId,\n value: {\n type: \"request\",\n data: {\n type: \"merge\",\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n origin: `${context.accountId}/${props.type}/${thingId}`,\n },\n },\n }),\n };\n hyperfile[props.type][thingId].metadata = {\n ...hyperfile[props.type][thingId].metadata,\n upstream: `${creatorId}/${props.type}/${props.filename}`,\n };\n // I want to make a request to merge\n // set upstream and downstream\n }\n // sometimes we're not logged in, so it doesn't do anything!\n Social.set(hyperfile, { force: true });\n });\n }\n};\nreturn (\n <div className=\"row\">\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n {/* Save data source names to user profile */}\n <Form>\n <h3>Enter Content</h3>\n <FormGroup>\n <Label>Source</Label>\n <Widget\n src=\"hyperbuild.near/widget/profile.metadataEditor\"\n props={{\n initialMetadata: profile,\n onChange: (newValue) => {\n console.log(\"New Source:\", newValue);\n setSource(newValue); // Update local state\n State.update({\n profile: { ...profile, source: newValue }, // Update external state\n });\n },\n value: source,\n options: {\n source: {\n sourcePattern: \"*/profile/source/*\",\n placeholder: \"Select a source\",\n },\n },\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Schema</Label>\n <p>{selectedSchema}</p>\n <Widget\n src=\"hyperbuild.near/widget/explore.select.schema\"\n props={{\n onSchemaSrcChange: handleSchemaSrcChange,\n onSelectedSchemaChange: handleSelectedSchemaChange,\n selectedSchema: selectedSchema,\n schemaSrc: schemaSrc,\n }}\n />\n </FormGroup>\n <FormGroup>\n <Label>Input Data</Label>\n <FormContainer>\n {/*<near-social-viewer></near-social-viewer>*/}\n <Widget\n src=\"hyperbuild.near/widget/create.thing\"\n props={{\n item: {\n type: selectedSchema,\n value: state.data,\n },\n onChange: handleOnChange,\n }}\n />\n </FormContainer>\n </FormGroup>\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Select Storage</h3>\n <FormGroup>\n <Label>Adapter</Label>\n <Select\n value={adapter}\n onChange={(e) => setAdapter(e.target.value)}\n >\n {adapters.map((o) => (\n <option value={o.value}>{o.title}</option>\n ))}\n </Select>\n </FormGroup>\n {rawAdapter && <>{parseAdapter(rawAdapter)}</>}\n {adapter === \"hyperfiles.near/widget/adapter.github\" && (\n <Widget\n src=\"flowscience.near/widget/GitHubSearchSelect\"\n onSelectRepository={handleSelectRepository}\n ></Widget>\n )}\n </Form>\n </div>\n </div>\n <div className=\"col\">\n <div className=\"p-3 border bg-light\">\n <Form>\n <h3>Deploy It</h3>\n <Button\n onClick={handleCreate}\n disabled={!adapter || !selectedSchema || !source || !state.data}\n >\n Publish Data to `{adapter}`\n </Button>\n {hyperfile !== \"\" && (\n <>\n <FormGroup>\n <textarea\n className=\"form-control\"\n value={hyperfile}\n disabled\n style={{ width: \"100%\", height: \"400px\" }}\n />\n </FormGroup>\n <Button\n onClick={() =>\n Social.set(JSON.parse(hyperfile), { force: true })\n }\n >\n Save Reference\n </Button>\n </>\n )}\n </Form>\n </div>\n </div>\n </div>\n);\n" }, "tools.nearfs.imageUpload": { "": "// fork_Of: \"vlad.near/widget/NEARFSImageUpload\"\ninitState({\n img: null,\n});\n\nconst networkId = \"mainnet\";\nconst domain = {\n testnet: \"testnet.page\",\n mainnet: \"near.page\",\n}[networkId];\n\n// Code mostly taken from https://github.com/NearSocial/viewer/pull/97\n\nconst ipfsUrl = (cid) => `https://ipfs.web4.${domain}/ipfs/${cid}`;\n\nconst filesOnChange = (files) => {\n if (files?.length > 0) {\n State.update({\n img: {\n uploading: true,\n cid: null,\n },\n });\n const body = files[0];\n\n Near.call(\n \"social.near\",\n \"fs_store\",\n Uint8Array.from(body.arrayBuffer())\n ).then((res) => {\n // TODO: hash\n // const cid = res.body.cid;\n // State.update({\n // img: {\n // cid,\n // },\n // });\n });\n } else {\n State.update({\n img: null,\n });\n }\n};\n\nreturn (\n <div className=\"d-inline-block\">\n {state.img?.cid && (\n <div\n className=\"d-inline-block me-2 overflow-hidden align-middle\"\n style={{ width: \"2.5em\", height: \"2.5em\" }}\n >\n <img\n className=\"rounded w-100 h-100\"\n style={{ objectFit: \"cover\" }}\n src={ipfsUrl(state.img?.cid)}\n alt=\"upload preview\"\n />\n </div>\n )}\n <Files\n multiple={false}\n accepts={[\"image/*\"]}\n minFileSize={1}\n clickable\n className=\"btn btn-outline-primary\"\n onChange={filesOnChange}\n >\n {state.img?.uploading ? (\n <>{Loading} Uploading</>\n ) : state.img?.cid ? (\n \"Replace\"\n ) : (\n \"Upload an Image\"\n )}\n </Files>\n </div>\n);\n" }, "explore.types": { "": "const path = props.path || \"hack.near/widget/explore.things\";\nreturn (\n <>\n <Widget\n src={`hack.near/widget/explore.thing`}\n props={{\n path,\n }}\n />\n </>\n);\n" }, "docs": { "": "return (\n <iframe\n className=\"w-100 vh-100\"\n title=\"Hyperfiles | Documentation\"\n src=\"https://opencann-network.super.site/hyperfiles\"\n sandbox=\"allow-same-origin\"\n ></iframe>\n);\n" } } } } }
Result:
{ "block_height": "120166680" }
No logs
Receipt:
Predecessor ID:
Receiver ID:
Gas Burned:
223 Ggas
Tokens Burned:
0 
Transferred 0.17779  to hyperbuild.near
Empty result
No logs