{ "cells": [ { "cell_type": "code", "execution_count": 1, "id": "8aaee0bd-59fc-441c-8527-4edc3e0c37bb", "metadata": {}, "outputs": [], "source": [ "// simple log function\n", "const log: (s: T, prefix?: string) => void = (s, prefix?) =>\n", " console.log(\n", " (prefix ? prefix : \"\") + \": \" +\n", " JSON.stringify(s, null, 2),\n", " );\n", "\n", "//function logDocImpl(doc: DocImpl) {\n", "// console.log(\"docImpl: entityId=\" + doc.entityId + \", value=\" + doc.value + \", space=\" + doc.space + \", sourceCell=\" + doc.sourceCell + \", ephemeral=\" + doc.ephemeral);\n", "//}\n", "function logDocImpl(doc: DocImpl, prefix?: string) {\n", " let logString = \"docImpl: \\n\" +\n", " \" entityId=\" + JSON.stringify(doc.entityId) + \"\\n\" +\n", " \" space=\" + doc.space + \"\\n\" +\n", " \" sourceCell=\" + doc.sourceCell + \"\\n\" +\n", " \" ephemeral=\" + doc.ephemeral;\n", "\n", " // Check if value is an array and add each object individually to the log string\n", " if (Array.isArray(doc.value)) {\n", " logString += \"\\n value contains \" + doc.value.length + \" objects:\";\n", " doc.value.forEach((item, index) => {\n", " // Convert to JSON string with 2-space indentation\n", " const jsonString = JSON.stringify(item, null, 2);\n", "\n", " // Split the JSON string into lines\n", " const jsonLines = jsonString.split(\"\\n\");\n", "\n", " // Add the first line with the value[index] prefix\n", " logString += `\\n value[${index}]: ${jsonLines[0]}`;\n", "\n", " // For remaining lines, add 4 additional spaces to maintain consistent indentation\n", " for (let i = 1; i < jsonLines.length; i++) {\n", " logString += \"\\n \" + jsonLines[i];\n", " }\n", " });\n", " } else {\n", " // For non-array values, apply the same indentation logic\n", " const jsonString = JSON.stringify(doc.value, null, 2);\n", " const jsonLines = jsonString.split(\"\\n\");\n", "\n", " // Add the first line with the value: prefix\n", " logString += \"\\n value: \" + jsonLines[0];\n", "\n", " // For remaining lines, add proper indentation\n", " for (let i = 1; i < jsonLines.length; i++) {\n", " logString += \"\\n \" + jsonLines[i];\n", " }\n", " }\n", " console.log((prefix ? prefix : \"\") + \": \" + logString);\n", "}" ] }, { "cell_type": "markdown", "id": "8fe4a001-c69b-40fb-ae3f-917d41561f1b", "metadata": {}, "source": [ "### Introduction\n", "\n", "This exploration tries to show what the various \"parts\" of the system does. It\n", "tries to make explicit all the things that usually happen in the backgroun.\n", "\n", "This means we won't be using the highest level abstractions. I believe this will\n", "show what's really happening under the hood and give you a better idea of what's\n", "in the guts of the system.\n", "\n", "### List of Charms\n", "\n", "The first thing I'd like to do is be able to see a list of our charms, just like\n", "when you go to the toolshed common knowledge page.\n", "\n", "The call I'd like to do is `getDoc([], \"charms\", SPACE);`\n", "\n", "BUT before we can access charms, we need to set up our connection to the\n", "database. Let's do that. NOTE: notice that `signer` is undefined in the Storage\n", "object. We'll get back to that later." ] }, { "cell_type": "code", "execution_count": null, "id": "f7936edf-cc47-4f4e-a886-92faaedb3497", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "StorageImpl {\n", " storageProviders: Map(0) {},\n", " remoteStorageUrl: URL {\n", " href: \u001b[32m\"https://toolshed.saga-castor.ts.net/\"\u001b[39m,\n", " origin: \u001b[32m\"https://toolshed.saga-castor.ts.net\"\u001b[39m,\n", " protocol: \u001b[32m\"https:\"\u001b[39m,\n", " username: \u001b[32m\"\"\u001b[39m,\n", " password: \u001b[32m\"\"\u001b[39m,\n", " host: \u001b[32m\"toolshed.saga-castor.ts.net\"\u001b[39m,\n", " hostname: \u001b[32m\"toolshed.saga-castor.ts.net\"\u001b[39m,\n", " port: \u001b[32m\"\"\u001b[39m,\n", " pathname: \u001b[32m\"/\"\u001b[39m,\n", " hash: \u001b[32m\"\"\u001b[39m,\n", " search: \u001b[32m\"\"\u001b[39m\n", " },\n", " signer: \u001b[90mundefined\u001b[39m,\n", " docIsSyncing: Set(0) {},\n", " docIsLoading: Map(0) {},\n", " loadingPromises: Map(0) {},\n", " loadingResolves: Map(0) {},\n", " writeDependentDocs: Map(0) {},\n", " writeValues: Map(0) {},\n", " readDependentDocs: Map(0) {},\n", " readValues: Map(0) {},\n", " currentBatch: [],\n", " currentBatchProcessing: \u001b[33mfalse\u001b[39m,\n", " currentBatchResolve: \u001b[36m[Function (anonymous)]\u001b[39m,\n", " currentBatchPromise: Promise { \u001b[36m\u001b[39m },\n", " lastBatchTime: \u001b[33m0\u001b[39m,\n", " lastBatchDebounceCount: \u001b[33m0\u001b[39m,\n", " debounceTimeout: \u001b[1mnull\u001b[22m,\n", " batchStartTime: \u001b[33m0\u001b[39m,\n", " cancel: \u001b[36m[Function: cancelAll]\u001b[39m,\n", " addCancel: \u001b[36m[Function: addCancel]\u001b[39m\n", "}" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import { storage } from \"../runner/src/storage.ts\";\n", "\n", "// where our server is\n", "const API_URL = \"https://toolshed.saga-castor.ts.net/\";\n", "\n", "// `storage` is a singleton and you have to give it the server URL\n", "storage.setRemoteStorage(new URL(API_URL));\n", "storage; // notice signer is undefined" ] }, { "cell_type": "markdown", "id": "5558236d-0fe0-4013-9d31-e5f537ad5154", "metadata": {}, "source": [ "### Space\n", "\n", "Spaces are in flux and we'll have private and public spaces, but for now, we\n", "still have the ability to pass in a simple string for the space. We'll use\n", "\"common-knowledge\" which is our default space.\n", "\n", "### getDoc()\n", "\n", "Now we have storage set up \"enough\" to call getDoc(value, cause, space). The\n", "value we pass in here is basically the empty value `[]` which is the same as\n", "undefined. The cause is a special hardcoded string \"charms\" that we use.\n", "CharmManager has this hardcoded string in it. Lastly we pass in the space which\n", "we already talked about." ] }, { "cell_type": "code", "execution_count": 3, "id": "c8bddbac-278a-42de-90c3-aabc001b0663", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{\n", " get: \u001b[36m[Function: get]\u001b[39m,\n", " getAsQueryResult: \u001b[36m[Function: getAsQueryResult]\u001b[39m,\n", " asCell: \u001b[36m[Function: asCell]\u001b[39m,\n", " send: \u001b[36m[Function: send]\u001b[39m,\n", " updates: \u001b[36m[Function: updates]\u001b[39m,\n", " getAtPath: \u001b[36m[Function: getAtPath]\u001b[39m,\n", " setAtPath: \u001b[36m[Function: setAtPath]\u001b[39m,\n", " freeze: \u001b[36m[Function: freeze]\u001b[39m,\n", " isFrozen: \u001b[36m[Function: isFrozen]\u001b[39m,\n", " toJSON: \u001b[36m[Function: toJSON]\u001b[39m,\n", " value: \u001b[36m[Getter]\u001b[39m,\n", " entityId: \u001b[36m[Getter/Setter]\u001b[39m,\n", " space: \u001b[36m[Getter/Setter]\u001b[39m,\n", " sourceCell: \u001b[36m[Getter/Setter]\u001b[39m,\n", " ephemeral: \u001b[36m[Getter/Setter]\u001b[39m,\n", " copyTrap: \u001b[36m[Getter]\u001b[39m,\n", " registerSchemaUse: \u001b[36m[Function: registerSchemaUse]\u001b[39m,\n", " [\u001b[32mSymbol(toOpaqueRef)\u001b[39m]: \u001b[36m[Function: [toOpaqueRef]]\u001b[39m,\n", " [\u001b[32mSymbol(isDoc)\u001b[39m]: \u001b[33mtrue\u001b[39m\n", "}" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import { DocImpl, getDoc } from \"../runner/src/doc.ts\";\n", "import { createRef } from \"../runner/src/doc-map.ts\";\n", "\n", "// space is usually a did now, but it still accepts a string\n", "const SPACE = \"common-knowledge\";\n", "\n", "const allCharmsDoc: DocImpl = getDoc(\n", " [],\n", " \"charms\",\n", " SPACE,\n", ");\n", "allCharmsDoc;" ] }, { "cell_type": "markdown", "id": "ae00cac7-6470-4785-aa73-f60dda006386", "metadata": {}, "source": [ "### More on getDoc()\n", "\n", "How does getDoc() find the doc it's looking for? As we discussed, getDoc()\n", "received a `value` and `cause` parameters.\n", "\n", "Within getDoc(), we take these two parameters and create an `EntityId` from\n", "them. What this means is that if we call getDoc() with different value and cause\n", "parameters, we should get different `EntityId`s. Let's test this out. We'll get\n", "another \"well known\" document for the pinned charms. If we're right, the IDs\n", "will be different." ] }, { "cell_type": "code", "execution_count": 4, "id": "0fb9e20d-b098-43dd-8165-2bf42c38478f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "allCharmsDoc entity id: {\n", " \"/\": \"baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye\"\n", "}\n", "pinsDoc entity id: {\n", " \"/\": \"baedreihxpwcmhvzpf5weuf4ceow4zbahqikvu5ploox36ipeuvqnminyba\"\n", "}\n", "is the same?: false\n" ] } ], "source": [ "import { deepEqual } from \"../builder/src/utils.ts\";\n", "\n", "// get the pinned charms doc\n", "const pinsDoc: DocImpl = getDoc(\n", " [],\n", " \"pinned-charms\",\n", " SPACE,\n", ");\n", "\n", "// see that the entityId for both allCharmsDoc and pinsDoc are different\n", "log(allCharmsDoc.entityId, \"allCharmsDoc entity id\");\n", "log(pinsDoc.entityId, \"pinsDoc entity id\");\n", "log(deepEqual(allCharmsDoc, pinsDoc), \"is the same?\");" ] }, { "cell_type": "markdown", "id": "218d5164-2d6f-454a-80e2-756e935d68c8", "metadata": {}, "source": [ "### createRef\n", "\n", "Let's continue our detour, how do EntityIds get created. This uses the enigmatic\n", "merkle-reference. We don't need to understand how merkle-references are made,\n", "just that it creates a unique digital fingerprint of the Doc, like a hash.\n", "\n", "Let's recreate the allCharmsDocEntityId from the \"value\" and \"cause\" arugments\n", "to getDoc. As a reminder, this was our getDoc call:\n", "\n", "```ts\n", "const allCharmsDoc: DocImpl = getDoc(\n", " [],\n", " \"charms\",\n", " SPACE,\n", ");\n", "```\n", "\n", "So we should be able to pass in [] and \"charms\" to createRef() and get back the\n", "same entity ID. Let's try it." ] }, { "cell_type": "code", "execution_count": 5, "id": "9bba8a6b-b97b-45f6-9aaf-e03f1b228055", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "recreated allCharmsDoc entityid: {\n", " \"/\": \"baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye\"\n", "}\n", "original allCharmsDoc entityid: {\n", " \"/\": \"baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye\"\n", "}\n", "are they the same?: true\n" ] } ], "source": [ "const recreatedEntityId: EntityId = createRef([], \"charms\");\n", "log(recreatedEntityId, \"recreated allCharmsDoc entityid\");\n", "log(allCharmsDoc.entityId, \"original allCharmsDoc entityid\");\n", "log(deepEqual(recreatedEntityId, allCharmsDoc.entityId), \"are they the same?\");" ] }, { "cell_type": "markdown", "id": "2d16fb25-fa33-4bc6-b877-4501eb730a38", "metadata": {}, "source": [ "### Spaces dont matter\n", "\n", "Did you notice that we don't care about spaces when we make the id? If I use a\n", "different space for the original allCharmsDoc, I should get back the same\n", "EntityID from getDoc(). Let's verify!" ] }, { "cell_type": "code", "execution_count": 6, "id": "0239e733-15fe-4905-81a3-30cb4699bbe3", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "entityid for allCharmsDoc but with different space: {\n", " \"/\": \"baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye\"\n", "}\n", "entityid for original allCharmsDoc in the 'charms' space: {\n", " \"/\": \"baedreiahv63wxwgaem4hzjkizl4qncfgvca7pj5cvdon7cukumfon3ioye\"\n", "}\n", "are they the same?: true\n" ] } ], "source": [ "const differentSpaceDoc: DocImpl = getDoc(\n", " [],\n", " \"charms\",\n", " \"some other space\",\n", ");\n", "log(\n", " differentSpaceDoc.entityId,\n", " \"entityid for allCharmsDoc but with different space\",\n", ");\n", "log(\n", " allCharmsDoc.entityId,\n", " \"entityid for original allCharmsDoc in the 'charms' space\",\n", ");\n", "log(\n", " deepEqual(differentSpaceDoc.entityId, allCharmsDoc.entityId),\n", " \"are they the same?\",\n", ");" ] }, { "cell_type": "markdown", "id": "cc7a24ea-15ee-4555-8f6c-cb5bb18a1f75", "metadata": {}, "source": [ "To further demystify getDoc(), the parameters we pass in really can be anything." ] }, { "cell_type": "code", "execution_count": 7, "id": "904ac02f-9280-4573-a959-7a95788ff157", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "crazydoc: {\n", " \"/\": \"baedreiekup34zo6rx6l33orhkktrzxgnrxxt7p3rmlnqylb4dv2swcc4kq\"\n", "}\n" ] } ], "source": [ "const some_val = [\"arrays\", \"are\", { value: \"good\" }];\n", "const some_cause = { some: \"random\", value: 42 };\n", "const some_space = \"random string in here\";\n", "const crazyDoc = getDoc(some_val, some_cause, some_space);\n", "log(crazyDoc, \"crazydoc\");\n", "\n", "// can try changing val, cause, space and see that nested objects change merke-reference" ] }, { "cell_type": "code", "execution_count": 8, "id": "0f93ff4f-676c-4372-bb24-ed6c283d721e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ": docImpl: \n", " entityId={\"/\":\"baedreiekup34zo6rx6l33orhkktrzxgnrxxt7p3rmlnqylb4dv2swcc4kq\"}\n", " space=random string in here\n", " sourceCell=undefined\n", " ephemeral=false\n", " value contains 3 objects:\n", " value[0]: \"arrays\"\n", " value[1]: \"are\"\n", " value[2]: {\n", " \"value\": \"good\"\n", " }\n" ] } ], "source": [ "// let's see what this crazy doc looks like\n", "logDocImpl(crazyDoc);" ] }, { "cell_type": "code", "execution_count": 9, "id": "65af0146-ebee-4c2e-bb56-bf2522a60e99", "metadata": {}, "outputs": [], "source": [ "// we'll set this charmsDoc to the doc we want to use from here on to get the list of charms\n", "// either to pinsDoc or allCharmsDoc\n", "const charmsDoc = pinsDoc;" ] }, { "cell_type": "markdown", "id": "843c5bec-2653-4284-ad53-2cc51ca247d0", "metadata": {}, "source": [ "### Back on track\n", "\n", "Back from the short detour, we want to continue to get the charms list. Right\n", "now, we have `charmsDoc` that has an EntityID but we haven't loaded the doc from\n", "Storage yet (the database). So let's do that now. However, we are...\n", "\n", "### Stuck on Storage\n", "\n", "We're making a point to access data via the `Storage` interface rather than\n", "through CharmManager or other possibly more convenient methods. Thus, our next\n", "step is to call `Storage.syncCell(docImpl);` This would let us get the data for\n", "the doc. However, this would crash with an exception. Jake ran into this the\n", "hard way and the system somehow ate the exception.\n", "\n", "### Another short detour, questioning our Identity\n", "\n", "Remember when we saw the signer property was undefined in storage before? We\n", "have to set that now in order to call syncCell. What we need to call `setSigner`\n", "on `storage`. We create a signer via the Identity module." ] }, { "cell_type": "code", "execution_count": null, "id": "0714bfaa-cc87-420e-b64d-bb90bb89db48", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "user identity (looks empty but its just private fields: {}\n" ] }, { "data": { "text/plain": [ "StorageImpl {\n", " storageProviders: Map(0) {},\n", " remoteStorageUrl: URL {\n", " href: \u001b[32m\"https://toolshed.saga-castor.ts.net/\"\u001b[39m,\n", " origin: \u001b[32m\"https://toolshed.saga-castor.ts.net\"\u001b[39m,\n", " protocol: \u001b[32m\"https:\"\u001b[39m,\n", " username: \u001b[32m\"\"\u001b[39m,\n", " password: \u001b[32m\"\"\u001b[39m,\n", " host: \u001b[32m\"toolshed.saga-castor.ts.net\"\u001b[39m,\n", " hostname: \u001b[32m\"toolshed.saga-castor.ts.net\"\u001b[39m,\n", " port: \u001b[32m\"\"\u001b[39m,\n", " pathname: \u001b[32m\"/\"\u001b[39m,\n", " hash: \u001b[32m\"\"\u001b[39m,\n", " search: \u001b[32m\"\"\u001b[39m\n", " },\n", " signer: Identity {},\n", " docIsSyncing: Set(0) {},\n", " docIsLoading: Map(0) {},\n", " loadingPromises: Map(0) {},\n", " loadingResolves: Map(0) {},\n", " writeDependentDocs: Map(0) {},\n", " writeValues: Map(0) {},\n", " readDependentDocs: Map(0) {},\n", " readValues: Map(0) {},\n", " currentBatch: [],\n", " currentBatchProcessing: \u001b[33mfalse\u001b[39m,\n", " currentBatchResolve: \u001b[36m[Function (anonymous)]\u001b[39m,\n", " currentBatchPromise: Promise { \u001b[36m\u001b[39m },\n", " lastBatchTime: \u001b[33m0\u001b[39m,\n", " lastBatchDebounceCount: \u001b[33m0\u001b[39m,\n", " debounceTimeout: \u001b[1mnull\u001b[22m,\n", " batchStartTime: \u001b[33m0\u001b[39m,\n", " cancel: \u001b[36m[Function: cancelAll]\u001b[39m,\n", " addCancel: \u001b[36m[Function: addCancel]\u001b[39m\n", "}" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import { DIDKey, Identity } from \"../identity/src/index.ts\";\n", "\n", "// key system similar to mneumonic registration\n", "const user_identity: Identity = await Identity.fromPassphrase(\n", " \"some passphrase\",\n", ");\n", "\n", "// NOTE: we can use this key directly with storage, however, to better replicate\n", "// the long term goals, we derive a new key from the root key\n", "// this is a lot like how users will have their own keys for each of their spaces\n", "// we would normally pass in the space name (which is like the \"common-knowledge\" part of the URL)\n", "const space_key = await user_identity.derive(SPACE);\n", "\n", "// helper function? why not\n", "function initializeStorage(\n", " storage: Storage,\n", " remoteStorageURL: string,\n", " signer: Signer,\n", "): Storage {\n", " storage.setRemoteStorage(new URL(remoteStorageURL));\n", " storage.setSigner(signer);\n", " return storage;\n", "}\n", "\n", "// use `space_key` the derived space-based identity as the signer for the storage\n", "const myStorage = initializeStorage(storage, API_URL, space_key);\n", "\n", "log(user_identity, \"user identity (looks empty but its just private fields\");\n", "myStorage; // notice signer is no longer undefined" ] }, { "cell_type": "markdown", "id": "2fff337d-be9c-40cb-b8b3-f276f3375466", "metadata": {}, "source": [ "### Lessgo Sync!\n", "\n", "Now we are all clear to call syncCell! syncCell returns a Promise(), so we await\n", "on it before accessing the object.\n", "\n", "While it's called syncCell, it really syncs either DocImpls or Cells. We'll get\n", "into that more later.\n", "\n", "```ts\n", "interface Storage {\n", " syncCell(\n", " subject: DocImpl | Cell,\n", " expectedInStorage: boolean = false,\n", " ): Promise> | DocImpl \n", "}\n", "```" ] }, { "cell_type": "code", "execution_count": 11, "id": "ced12094-6ca1-415b-9b67-4e22690d7198", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "before syncCell: docImpl: \n", " entityId={\"/\":\"baedreihxpwcmhvzpf5weuf4ceow4zbahqikvu5ploox36ipeuvqnminyba\"}\n", " space=common-knowledge\n", " sourceCell=undefined\n", " ephemeral=false\n", " value contains 0 objects:\n", "after syncCell: docImpl: \n", " entityId={\"/\":\"baedreihxpwcmhvzpf5weuf4ceow4zbahqikvu5ploox36ipeuvqnminyba\"}\n", " space=common-knowledge\n", " sourceCell=undefined\n", " ephemeral=false\n", " value contains 4 objects:\n", " value[0]: {\n", " \"cell\": {\n", " \"/\": \"baedreietbxsdgmw67da47dp6aqervnk2zyppevhx4p4mn3pet6onvaxcmy\"\n", " },\n", " \"path\": []\n", " }\n", " value[1]: {\n", " \"cell\": {\n", " \"/\": \"baedreih6pdtzk4xvjuxlsp3htrugtipgndn6xtd4cwbdr6wgscb6fh2nlu\"\n", " },\n", " \"path\": []\n", " }\n", " value[2]: {\n", " \"cell\": {\n", " \"/\": \"baedreiel5fi755jovxnou5bpdsuvcylibayiaaipaysi2tiip26ik3b6ya\"\n", " },\n", " \"path\": []\n", " }\n", " value[3]: {\n", " \"cell\": {\n", " \"/\": \"baedreid2qh2k6gcie4ezckqukkplpeqlz7jnxirt7aehxdcw4sfg5aszh4\"\n", " },\n", " \"path\": []\n", " }\n" ] } ], "source": [ "// start syncing on this document\n", "// notice that we call syncCell on a DocImpl\n", "// also, we have to await on this before accessing otherwise we may get a race condition!\n", "logDocImpl(charmsDoc, \"before syncCell\");\n", "await myStorage.syncCell(charmsDoc);\n", "logDocImpl(charmsDoc, \"after syncCell\");" ] }, { "cell_type": "markdown", "id": "3965fe43-6723-4a97-ab94-7f5118ac34d7", "metadata": {}, "source": [ "### Document Loaded but not the Charms\n", "\n", "We have retrieved the document now, however, it doesn't actually contain the\n", "charms, just references to them as you can see via the `value` fields. Each\n", "element in the value array\n", "\n", "We have to look at each of the elements in the `value` array and load each one.\n", "Each one has the format:\n", "\n", "```ts\n", "{\n", " \"cell\": {\n", " \"/\": \"baedreid2qh2k6gcie4ezckqukkplpeqlz7jnxirt7aehxdcw4sfg5aszh4\"\n", " },\n", " \"path\": []\n", "}\n", "```\n", "\n", "This is a CellLink, which you can find in runner/src/cell.ts:\n", "\n", "```ts\n", "/**\n", " * Cell link.\n", " *\n", " * A cell link is a doc and a path within that doc.\n", " */\n", "export type CellLink = {\n", " space?: string;\n", " cell: DocImpl;\n", " path: PropertyKey[];\n", "};\n", "```\n", "\n", "We sometimes call these DocLinks, they are the same thing. In cell.ts, you'll\n", "still see\n", "\n", "```\n", "* @method getAsDocLink Returns a document link for the cell.\n", "* @returns {CellLink}\n", "```\n", "\n", "We'll take each of the CellLinks and call getDocByEntityId(), this will load the\n", "docImpl for us. This time we do _NOT_ need to sync on each child because the\n", "first syncCell also sync'd on all the child cells. NOTE: this logic of loading\n", "dependencies happens in `runner/src/storage.ts:_processCurrentBatch()`" ] }, { "cell_type": "code", "execution_count": 12, "id": "3be96f91-33dc-47de-bee2-64886dc77793", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ ": docImpl: \n", " entityId={\"/\":\"baedreietbxsdgmw67da47dp6aqervnk2zyppevhx4p4mn3pet6onvaxcmy\"}\n", " space=common-knowledge\n", " sourceCell=[object Object]\n", " ephemeral=false\n", " value: {\n", " \"$NAME\": \"Common Time\",\n", " \"$UI\": {\n", " \"type\": \"vnode\",\n", " \"name\": \"common-iframe\",\n", " \"props\": {\n", " \"src\": \"\\n\\n\\n\\n\\n\\n\\nCommon Time\\n\\n\\n
\\n\\n\\n\",\n", " \"$context\": {\n", " \"$alias\": {\n", " \"cell\": {\n", " \"/\": \"baedreig6yfypxumwytzlmw4wbvwcdxcfroa4lj46qrcoxck3lptmfa5y2u\"\n", " },\n", " \"path\": [\n", " \"argument\"\n", " ]\n", " }\n", " }\n", " },\n", " \"children\": []\n", " }\n", " }\n", ": docImpl: \n", " entityId={\"/\":\"baedreih6pdtzk4xvjuxlsp3htrugtipgndn6xtd4cwbdr6wgscb6fh2nlu\"}\n", " space=common-knowledge\n", " sourceCell=[object Object]\n", " ephemeral=false\n", " value: {\n", " \"$NAME\": \"Exercise Tracker\",\n", " \"$UI\": {\n", " \"type\": \"vnode\",\n", " \"name\": \"common-iframe\",\n", " \"props\": {\n", " \"src\": \"\\n\\n\\n\\n\\n\\n\\nExercise Tracker\\n\\n\\n
\\n\\n\\n\",\n", " \"$context\": {\n", " \"$alias\": {\n", " \"cell\": {\n", " \"/\": \"baedreiedh6j73hk3cx65jrw2d26h3spgidiqkcv436ehocl5dqh2mavyvy\"\n", " },\n", " \"path\": [\n", " \"argument\"\n", " ]\n", " }\n", " }\n", " },\n", " \"children\": []\n", " }\n", " }\n", ": docImpl: \n", " entityId={\"/\":\"baedreiel5fi755jovxnou5bpdsuvcylibayiaaipaysi2tiip26ik3b6ya\"}\n", " space=common-knowledge\n", " sourceCell=[object Object]\n", " ephemeral=false\n", " value: {\n", " \"$NAME\": \"Multi-User Chat App\",\n", " \"$UI\": {\n", " \"type\": \"vnode\",\n", " \"name\": \"common-iframe\",\n", " \"props\": {\n", " \"src\": \"\\n\\n\\n\\n\\n\\n\\nMulti-User Chat App\\n\\n\\n
\\n\\n\\n\",\n", " \"$context\": {\n", " \"$alias\": {\n", " \"cell\": {\n", " \"/\": \"baedreiewvjjphy2id2dqsubt4aim66b2sleps4cs7n2mae6hftgthgcc2a\"\n", " },\n", " \"path\": [\n", " \"argument\"\n", " ]\n", " }\n", " }\n", " },\n", " \"children\": []\n", " }\n", " }\n", ": docImpl: \n", " entityId={\"/\":\"baedreid2qh2k6gcie4ezckqukkplpeqlz7jnxirt7aehxdcw4sfg5aszh4\"}\n", " space=common-knowledge\n", " sourceCell=[object Object]\n", " ephemeral=false\n", " value: {\n", " \"$NAME\": \"Origami Visualizer\",\n", " \"$UI\": {\n", " \"type\": \"vnode\",\n", " \"name\": \"common-iframe\",\n", " \"props\": {\n", " \"src\": \"\\n\\n\\n\\n\\n\\n\\nOrigami Visualizer\\n\\n\\n
\\n\\n\\n\",\n", " \"$context\": {\n", " \"$alias\": {\n", " \"cell\": {\n", " \"/\": \"baedreib3n7bscm5fre6c5rskgpa7xzbd6fx6g3fbmiv7fwor5nsqk4s5au\"\n", " },\n", " \"path\": [\n", " \"argument\"\n", " ]\n", " }\n", " }\n", " },\n", " \"children\": []\n", " }\n", " }\n" ] } ], "source": [ "import { getDocByEntityId } from \"../runner/src/doc-map.ts\";\n", "\n", "// lets load and look at each charm in the charms arrays\n", "const allCharmsArray: CellLink[] = charmsDoc.value;\n", "allCharmsArray.forEach(async (charmRef) => {\n", " // pull out the entity id from each element of the array\n", " const charmCellId: EntityId = charmRef[\"cell\"];\n", "\n", " // create the empty docImpl that has the EntityId in it\n", " const charmCellDoc = getDocByEntityId(SPACE, charmCellId);\n", " logDocImpl(charmCellDoc);\n", "});" ] }, { "cell_type": "code", "execution_count": 16, "id": "c29819f8-0a4b-4b8c-bc8f-5c5dc677127a", "metadata": { "scrolled": true }, "outputs": [ { "ename": "ReferenceError", "evalue": "manager is not defined", "output_type": "error", "traceback": [ "Stack trace:", "ReferenceError: manager is not defined", " at :3:1" ] } ], "source": [ "// lets see what the $UI.props.$context.$alias is about\n", "\n", "//log(charm); //charm[\"$UI\"]//.props[\"$context\"][\"$alias\"]\n", "manager.runPersistent(allCharmsArray[0].cell.value, undefined, \"foo\");" ] }, { "cell_type": "code", "execution_count": null, "id": "44a2494d-feab-4db1-bce1-7ec8a7fc98be", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "382aeb8b-d07f-468e-a37f-63b32f85455c", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "f03a0bcb-6c5d-47f1-a0d5-3c3c211da20e", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "6231d245-6e6e-4929-aae0-6d808a7153f4", "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "id": "dd377c84-2a3e-4b24-91b0-083e623caa61", "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Deno", "language": "typescript", "name": "deno" }, "language_info": { "codemirror_mode": "typescript", "file_extension": ".ts", "mimetype": "text/x.typescript", "name": "typescript", "nbconvert_exporter": "script", "pygments_lexer": "typescript", "version": "5.7.3" } }, "nbformat": 4, "nbformat_minor": 5 }