├── .gitignore ├── README.md ├── generator ├── index.js └── templates │ └── simple │ ├── Procfile │ ├── dna │ └── simple │ │ ├── Cargo.toml │ │ ├── LICENSE │ │ ├── simple.dna.workdir │ │ └── dna.json │ │ ├── tests │ │ ├── package.json │ │ ├── src │ │ │ ├── index.ts │ │ │ └── thing │ │ │ │ └── index.ts │ │ └── tsconfig.json │ │ └── zomes │ │ └── simple │ │ ├── Cargo.toml │ │ └── src │ │ ├── entries.rs │ │ ├── entries │ │ └── thing │ │ │ ├── handlers.rs │ │ │ └── mod.rs │ │ ├── error.rs │ │ └── lib.rs │ ├── public │ └── robots.txt │ └── src │ ├── App.vue │ ├── assets │ └── holochain-halo.png │ ├── layouts │ └── basic │ │ ├── Index.vue │ │ └── View.vue │ ├── plugins │ └── vuetify.js │ ├── router │ ├── index.js │ └── routes │ │ ├── index.js │ │ ├── public.routes.js │ │ └── simple.routes.js │ ├── store │ ├── index.js │ └── modules │ │ ├── index.js │ │ └── simple.store.js │ └── views │ ├── home │ └── Index.vue │ └── things │ └── Index.vue ├── index.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-cli-plugin-holochain-simple 2 | Vue cli plugin and preset for a simple Holochain app. 3 | -------------------------------------------------------------------------------- /generator/index.js: -------------------------------------------------------------------------------- 1 | // Imports 2 | const fs = require('fs') 3 | 4 | module.exports = (api, options) => { 5 | if (!api.hasPlugin('vuetify')) { 6 | console.log('`@vuetify/presets` requires the `vue-cli-plugin-vuetify` package.') 7 | return 8 | } 9 | 10 | try { 11 | api.render(`./templates/simple`) 12 | } catch (e) { 13 | console.log(e, options) 14 | } 15 | const files = { './src/App.vue': `../generator/templates/simple/src/App.vue` } 16 | try { 17 | api.render(files) 18 | } catch (e) { 19 | console.log(e, options) 20 | } 21 | 22 | api.extendPackage({ 23 | dependencies: { 24 | '@holochain/conductor-api': '^0.0.1-dev.15', 25 | 'byte-base64': '^1.1.0', 26 | 'dexie': '^3.0.3-rc.4', 27 | '@mdi/font': '^5.8.55' 28 | }, 29 | devDependencies: { 30 | 'rimraf': '^3.0.2', 31 | 'foreman': '^3.0.1', 32 | 'eslint-config-vuetify': '^0.6.1', 33 | 'eslint-plugin-vue': '^6.2.2', 34 | 'eslint-plugin-vuetify': '^1.0.0-beta.6', 35 | 'lodash': '^4.17.15' 36 | }, 37 | scripts: { 38 | 'serve:agent1': 'vue-cli-service serve --port 44001', 39 | 'serve:agent2': 'vue-cli-service serve --port 44002', 40 | 'serve:agent3': 'vue-cli-service serve --port 44003', 41 | 'serve:agent4': 'vue-cli-service serve --port 44004', 42 | 'start': 'nf start' 43 | } 44 | }) 45 | 46 | api.onCreateComplete(() => { 47 | const presetName = `Holochain Simple Application preset` 48 | const projectName = api.rootOptions.projectName 49 | 50 | const home = api.resolve('src/views/Home.vue') 51 | if (fs.existsSync(home)) fs.unlinkSync(home) 52 | const about = api.resolve('src/views/About.vue') 53 | if (fs.existsSync(about)) fs.unlinkSync(about) 54 | 55 | api.exitLog(`🍣 Successfully generated ${projectName} from the ${presetName}.\n`) 56 | api.exitLog(`Make sure you have holochain installed.`) 57 | api.exitLog(`yarn start`) 58 | }) 59 | } 60 | -------------------------------------------------------------------------------- /generator/templates/simple/Procfile: -------------------------------------------------------------------------------- 1 | agent1: yarn serve:agent1 2 | agent2: yarn serve:agent2 3 | agent3: yarn serve:agent3 4 | agent4: yarn serve:agent4 -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "zomes/simple", 4 | ] 5 | 6 | [profile.dev] 7 | opt-level = "z" 8 | 9 | [profile.release] 10 | opt-level = "z" 11 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/LICENSE: -------------------------------------------------------------------------------- 1 | # Cryptographic Autonomy License version 1.0 2 | 3 | *This Cryptographic Autonomy License (the “License”) applies to any Work whose owner has marked it with any of the following notices:* 4 | 5 | *“Licensed under the Cryptographic Autonomy License version 1.0,” or* 6 | 7 | *“SPDX-License-Identifier: CAL-1.0,” or* 8 | 9 | *“Licensed under the Cryptographic Autonomy License version 1.0, with Combined Work Exception,” or* 10 | 11 | *“SPDX-License-Identifier: CAL-1.0 with Combined-Work-Exception.”* 12 | 13 | ------ 14 | 15 | ## 1. Purpose 16 | 17 | This License gives You unlimited permission to use and modify the software to which it applies (the “Work”), either as-is or in modified form, for Your private purposes, while protecting the owners and contributors to the software from liability. 18 | 19 | This License also strives to protect the freedom and autonomy of third parties who receive the Work from you. If any non-affiliated third party receives any part, aspect, or element of the Work from You, this License requires that You provide that third party all the permissions and materials needed to independently use and modify the Work without that third party having a loss of data or capability due to your actions. 20 | 21 | The full permissions, conditions, and other terms are laid out below. 22 | 23 | ## 2. Receiving a License 24 | 25 | In order to receive this License, You must agree to its rules. The rules of this License are both obligations of Your agreement with the Licensor and conditions to your License. You must not do anything with the Work that triggers a rule You cannot or will not follow. 26 | 27 | ### 2.1. Application 28 | 29 | The terms of this License apply to the Work as you receive it from Licensor, as well as to any modifications, elaborations, or implementations created by You that contain any licenseable portion of the Work (a “Modified Work”). Unless specified, any reference to the Work also applies to a Modified Work. 30 | 31 | ### 2.2. Offer and Acceptance 32 | 33 | This License is automatically offered to every person and organization. You show that you accept this License and agree to its conditions by taking any action with the Work that, absent this License, would infringe any intellectual property right held by Licensor. 34 | 35 | ### 2.3. Compliance and Remedies 36 | 37 | Any failure to act according to the terms and conditions of this License places Your use of the Work outside the scope of the License and infringes the intellectual property rights of the Licensor. In the event of infringement, the terms and conditions of this License may be enforced by Licensor under the intellectual property laws of any jurisdiction to which You are subject. You also agree that either the Licensor or a Recipient (as an intended third-party beneficiary) may enforce the terms and conditions of this License against You via specific performance. 38 | 39 | ## 3. Permissions and Conditions 40 | 41 | ### 3.1. Permissions Granted 42 | 43 | Conditioned on compliance with section 4, and subject to the limitations of section 3.2, Licensor grants You the world-wide, royalty-free, non-exclusive permission to: 44 | 45 | > a) Take any action with the Work that would infringe the non-patent intellectual property laws of any jurisdiction to which You are subject; and 46 | > 47 | > b) Take any action with the Work that would infringe any patent claims that Licensor can license or becomes able to license, to the extent that those claims are embodied in the Work as distributed by Licensor. 48 | 49 | ### 3.2. Limitations on Permissions Granted 50 | 51 | The following limitations apply to the permissions granted in section 3.1: 52 | 53 | > a) Licensor does not grant any patent license for claims that are only infringed due to modification of the Work as provided by Licensor, or the combination of the Work as provided by Licensor, directly or indirectly, with any other component, including other software or hardware. 54 | > 55 | > b) Licensor does not grant any license to the trademarks, service marks, or logos of Licensor, except to the extent necessary to comply with the attribution conditions in section 4.1 of this License. 56 | 57 | ## 4. Conditions 58 | 59 | If You exercise any permission granted by this License, such that the Work, or any part, aspect, or element of the Work, is distributed, communicated, made available, or made perceptible to a non-Affiliate third party (a “Recipient”), either via physical delivery or via a network connection to the Recipient, You must comply with the following conditions: 60 | 61 | ### 4.1. Provide Access to Source Code 62 | 63 | Subject to the exception in section 4.4, You must provide to each Recipient a copy of, or no-charge unrestricted network access to, the Source Code corresponding to the Work. 64 | 65 | The “Source Code” of the Work means the form of the Work preferred for making modifications, including any comments, configuration information, documentation, help materials, installation instructions, cryptographic seeds or keys, and any information reasonably necessary for the Recipient to independently compile and use the Source Code and to have full access to the functionality contained in the Work. 66 | 67 | #### 4.1.1. Providing Network Access to the Source Code 68 | 69 | Network access to the Notices and Source Code may be provided by You or by a third party, such as a public software repository, and must persist during the same period in which You exercise any of the permissions granted to You under this License and for at least one year thereafter. 70 | 71 | #### 4.1.2. Source Code for a Modified Work 72 | 73 | Subject to the exception in section 4.5, You must provide to each Recipient of a Modified Work Access to Source Code corresponding to those portions of the Work remaining in the Modified Work as well as the modifications used by You to create the Modified Work. The Source Code corresponding to the modifications in the Modified Work must be provided to the Recipient either a) under this License, or b) under a Compatible Open Source License. 74 | 75 | A “Compatible Open Source License” means a license accepted by the Open Source Initiative that allows object code created using both Source Code provided under this License and Source Code provided under the other open source license to be distributed together as a single work. 76 | 77 | #### 4.1.3. Coordinated Disclosure of Security Vulnerabilities 78 | 79 | You may delay providing the Source Code corresponding to a particular modification of the Work for up to ninety (90) days (the “Embargo Period”) if: a) the modification is intended to address a newly-identified vulnerability or a security flaw in the Work, b) disclosure of the vulnerability or security flaw before the end of the Embargo Period would put the data, identity, or autonomy of one or more Recipients of the Work at significant risk, c) You are participating in a coordinated disclosure of the vulnerability or security flaw with one or more additional Licensees, and d) Access to the Source Code pertaining to the modification is provided to all Recipients at the end of the Embargo Period. 80 | 81 | ### 4.2. Maintain User Autonomy 82 | 83 | In addition to providing each Recipient the opportunity to have Access to the Source Code, You cannot use the permissions given under this License to interfere with a Recipient’s ability to fully use an independent copy of the Work generated from the Source Code You provide with the Recipient’s own User Data. 84 | 85 | “User Data” means any data that is an input to or an output from the Work, where the presence of the data is necessary for substantially identical use of the Work in an equivalent context chosen by the Recipient, and where the Recipient has an existing ownership interest, an existing right to possess, or where the data has been generated by, for, or has been assigned to the Recipient. 86 | 87 | #### 4.2.1. No Withholding User Data 88 | 89 | Throughout any period in which You exercise any of the permissions granted to You under this License, You must also provide to any Recipient to whom you provide services via the Work, a no-charge copy, provided in a commonly used electronic form, of the Recipient’s User Data in your possession, to the extent that such User Data is available to You for use in conjunction with the Work. 90 | 91 | #### 4.2.2. No Technical Measures that Limit Access 92 | 93 | You may not, by the use of cryptographic methods applied to anything provided to the Recipient, by possession or control of cryptographic keys, seeds, or hashes, by other technological protection measures, or by any other method, limit a Recipient's ability to access any functionality present in the Recipient's independent copy of the Work, or deny a Recipient full control of the Recipient's User Data. 94 | 95 | #### 4.2.3. No Legal or Contractual Measures that Limit Access 96 | 97 | You may not contractually restrict a Recipient's ability to independently exercise the permissions granted under this License. You waive any legal power to forbid circumvention of technical protection measures that include use of the Work, and You waive any claim that the capabilities of the Work were limited or modified as a means of enforcing the legal rights of third parties against Recipients. 98 | 99 | ### 4.3. Provide Notices and Attribution 100 | 101 | You must retain all licensing, authorship, or attribution notices contained in the Source Code (the “Notices”), and provide all such Notices to each Recipient, together with a statement acknowledging the use of the Work. Notices may be provided directly to a Recipient or via an easy-to-find hyperlink to an Internet location also providing Access to Source Code. 102 | 103 | ### 4.4. Scope of Conditions in this License 104 | 105 | You are required to uphold the conditions of this License only relative to those who are Recipients of the Work from You. Other than providing Recipients with the applicable Notices, Access to Source Code, and a copy of and full control of their User Data, nothing in this License requires You to provide processing services to or engage in network interactions with anyone. 106 | 107 | ### 4.5. Combined Work Exception 108 | 109 | As an exception to condition that You provide Recipients Access to Source Code, any Source Code files marked by the Licensor as having the “Combined Work Exception,” or any object code exclusively resulting from Source Code files so marked, may be combined with other Software into a “Larger Work.” So long as you comply with the requirements to provide Recipients the applicable Notices and Access to the Source Code provided to You by Licensor, and you provide Recipients access to their User Data and do not limit Recipient’s ability to independently work with their User Data, any other Software in the Larger Work as well as the Larger Work as a whole may be licensed under the terms of your choice. 110 | 111 | ## 5. Term and Termination 112 | 113 | The term of this License begins when You receive the Work, and continues until terminated for any of the reasons described herein, or until all Licensor’s intellectual property rights in the Software expire, whichever comes first (“Term”). This License cannot be revoked, only terminated for the reasons listed below. 114 | 115 | ### 5.1. Effect of Termination 116 | 117 | If this License is terminated for any reason, all permissions granted to You under Section 3 by any Licensor automatically terminate. You will immediately cease exercising any permissions granted in this License relative to the Work, including as part of any Modified Work. 118 | 119 | ### 5.2. Termination for Non-Compliance; Reinstatement 120 | 121 | This License terminates automatically if You fail to comply with any of the conditions in section 4. As a special exception to termination for non-compliance, Your permissions for the Work under this License will automatically be reinstated if You come into compliance with all the conditions in section 2 within sixty (60) days of being notified by Licensor or an intended third party beneficiary of Your noncompliance. You are eligible for reinstatement of permissions for the Work one time only, and only for the sixty days immediately after becoming aware of noncompliance. Loss of permissions granted for the Work under this License due to either a) sustained noncompliance lasting more than sixty days or b) subsequent termination for noncompliance after reinstatement, is permanent, unless rights are specifically restored by Licensor in writing. 122 | 123 | ### 5.3 Termination Due to Litigation 124 | 125 | If You initiate litigation against Licensor, or any Recipient of the Work, either direct or indirect, asserting that the Work directly or indirectly infringes any patent, then all permissions granted to You by this License shall terminate. In the event of termination due to litigation, all permissions validly granted by You under this License, directly or indirectly, shall survive termination. Administrative review procedures, declaratory judgment actions, counterclaims in response to patent litigation, and enforcement actions against former Licensees terminated under this section do not cause termination due to litigation. 126 | 127 | ## 6. Disclaimer of Warranty and Limit on Liability 128 | 129 | As far as the law allows, the Work comes AS-IS, without any warranty of any kind, and no Licensor or contributor will be liable to anyone for any damages related to this software or this license, under any kind of legal claim, or for any type of damages, including indirect, special, incidental, or consequential damages of any type arising as a result of this License or the use of the Work including, without limitation, damages for loss of goodwill, work stoppage, computer failure or malfunction, loss of profits, revenue, or any and all other commercial damages or losses. 130 | 131 | ## 7. Other Provisions 132 | 133 | ### 7.1. Affiliates 134 | 135 | An “Affiliate” means any other entity that, directly or indirectly through one or more intermediaries, controls, is controlled by, or is under common control with, the Licensee. Employees of a Licensee and natural persons acting as contractors exclusively providing services to Licensee are also Affiliates. 136 | 137 | ### 7.2. Choice of Jurisdiction and Governing Law 138 | 139 | A Licensor may require that any action or suit by a Licensee relating to a Work provided by Licensor under this License may be brought only in the courts of a particular jurisdiction and under the laws of a particular jurisdiction (excluding its conflict-of-law provisions), if Licensor provides conspicuous notice of the particular jurisdiction to all Licensees. 140 | 141 | ### 7.3. No Sublicensing 142 | 143 | This License is not sublicensable. Each time You provide the Work or a Modified Work to a Recipient, the Recipient automatically receives a license under the terms described in this License. You may not impose any further reservations, conditions, or other provisions on any Recipients’ exercise of the permissions granted herein. 144 | 145 | ### 7.4. Attorneys' Fees 146 | 147 | In any action to enforce the terms of this License, or seeking damages relating thereto, including by an intended third party beneficiary, the prevailing party shall be entitled to recover its costs and expenses, including, without limitation, reasonable attorneys' fees and costs incurred in connection with such action, including any appeal of such action. A “prevailing party” is the party that achieves, or avoids, compliance with this License, including through settlement. This section shall survive the termination of this License. 148 | 149 | ### 7.5. No Waiver 150 | 151 | Any failure by Licensor to enforce any provision of this License will not constitute a present or future waiver of such provision nor limit Licensor’s ability to enforce such provision at a later time. 152 | 153 | ### 7.6. Severability 154 | 155 | If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any invalid or unenforceable portion will be interpreted to the effect and intent of the original portion. If such a construction is not possible, the invalid or unenforceable portion will be severed from this License but the rest of this License will remain in full force and effect. 156 | 157 | ### 7.7. License for the Text of this License 158 | 159 | The text of this license is released under the Creative Commons Attribution-ShareAlike 4.0 International License, with the caveat that any modifications of this license may not use the name “Cryptographic Autonomy License” or any name confusingly similar thereto to describe any derived work of this License. 160 | 161 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/simple.dna.workdir/dna.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "uuid": "", 4 | "properties": null, 5 | "zomes": { 6 | "simple": { 7 | "wasm_path": "../target/wasm32-unknown-unknown/release/simple.wasm" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "simple", 3 | "version": "0.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "build": "CARGO_TARGET_DIR=../target cargo build --release --target wasm32-unknown-unknown && dna-util -c ../simple.dna.workdir", 8 | "test": "CARGO_TARGET_DIR=../target cargo build --release --target wasm32-unknown-unknown && dna-util -c ../simple.dna.workdir && TRYORAMA_LOG_LEVEL=info RUST_BACKTRACE=1 TRYORAMA_HOLOCHAIN_PATH=\"holochain\" ts-node src/index.ts" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "@holochain/tryorama": "^0.4.0-dev.4", 14 | "lodash": "^4.17.19", 15 | "tape": "^5.0.1", 16 | "ts-node": "^8.10.2", 17 | "typescript": "^3.9.6", 18 | "uuidv4": "^6.2.3" 19 | }, 20 | "devDependencies": { 21 | "@types/lodash": "^4.14.158", 22 | "@types/node": "^14.0.14" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/tests/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Orchestrator } from '@holochain/tryorama' 2 | 3 | const orchestrator = new Orchestrator() 4 | 5 | require('./thing')(orchestrator) 6 | 7 | orchestrator.run() 8 | 9 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/tests/src/thing/index.ts: -------------------------------------------------------------------------------- 1 | import { Config, InstallAgentsHapps } from '@holochain/tryorama' 2 | import * as _ from 'lodash' 3 | import { v4 as uuidv4 } from 'uuid' 4 | import * as path from 'path' 5 | 6 | const delay = ms => new Promise(r => setTimeout(r, ms)) 7 | const simpleDna = path.join(__dirname, '../../../simple.dna.gz') 8 | console.log('simpleDna', simpleDna) 9 | 10 | const installation: InstallAgentsHapps = [ 11 | [ 12 | [simpleDna] 13 | ] 14 | ] 15 | 16 | const conductorConfig = Config.gen() 17 | 18 | module.exports = (orchestrator) => { 19 | orchestrator.registerScenario('Create a thing', async (s, t) => { 20 | const [alice] = await s.players([conductorConfig]) 21 | const [[alice_simple_happ]] = await alice.installAgentsHapps(installation) 22 | const thing = await alice_simple_happ.cells[0].call('simple', 'create_thing', { uuid: uuidv4(), name: 'Test Client 1', location: 'Australia', parent: 'Things' }) 23 | console.log('thing', thing) 24 | t.notEqual(thing.entryHash, null) 25 | }) 26 | orchestrator.registerScenario('Create, then list things', async (s, t) => { 27 | const [alice] = await s.players([conductorConfig]) 28 | const [[alice_simple_happ]] = await alice.installAgentsHapps(installation) 29 | const thing1 = await alice_simple_happ.cells[0].call('simple', 'create_thing', { uuid: uuidv4(), name: 'Test Client 1', location: 'Australia', parent: 'Things' }); 30 | const thing2 = await alice_simple_happ.cells[0].call('simple', 'create_thing', { uuid: uuidv4(), name: 'Test Client 2', location: 'Australia', parent: 'Things' }); 31 | console.log('thing1', thing1) 32 | console.log('thing2', thing2) 33 | const thingList = await alice_simple_happ.cells[0].call('simple', 'list_things', { parent: 'Things' }); 34 | console.log('thingList', thingList) 35 | t.deepEqual(thingList.things.length, 2) 36 | }) 37 | orchestrator.registerScenario('Create then delete a thing', async (s, t) => { 38 | const [alice] = await s.players([conductorConfig]) 39 | const [[alice_simple_happ]] = await alice.installAgentsHapps(installation) 40 | const thing = await alice_simple_happ.cells[0].call('simple', 'create_thing', { uuid: uuidv4(), name: 'Test Client 1', location: 'Australia', parent: 'Things' }); 41 | console.log('thing', thing) 42 | const thing2 = await alice_simple_happ.cells[0].call('simple', 'create_thing', { uuid: uuidv4(), name: 'Test Client 2', location: 'Australia', parent: 'Things' }); 43 | console.log('thing', thing2) 44 | const deletedClient = await alice_simple_happ.cells[0].call('simple', 'delete_thing', thing); 45 | console.log('deletedClient', deletedClient) 46 | // await delay(2000) 47 | const thingList = await alice_simple_happ.cells[0].call('simple', 'list_things', { parent: 'Things' }); 48 | console.log('thingList', thingList) 49 | t.deepEqual(thingList.things.length, 1) 50 | }) 51 | } 52 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | /* Basic Options */ 5 | // "incremental": true, /* Enable incremental compilation */ 6 | "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 7 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 8 | // "lib": [], /* Specify library files to be included in the compilation. */ 9 | // "allowJs": true, /* Allow javascript files to be compiled. */ 10 | // "checkJs": true, /* Report errors in .js files. */ 11 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 12 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 13 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 14 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 15 | // "outFile": "./", /* Concatenate and emit output to single file. */ 16 | // "outDir": "./", /* Redirect output structure to the directory. */ 17 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 18 | // "composite": true, /* Enable project compilation */ 19 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 20 | // "removeComments": true, /* Do not emit comments to output. */ 21 | // "noEmit": true, /* Do not emit outputs. */ 22 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 23 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 24 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 25 | /* Strict Type-Checking Options */ 26 | "strict": true, /* Enable all strict type-checking options. */ 27 | "noImplicitAny": false, /* Raise error on expressions and declarations with an implied 'any' type. */ 28 | // "strictNullChecks": true, /* Enable strict null checks. */ 29 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 30 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 31 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 32 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 33 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 34 | /* Additional Checks */ 35 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 36 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 37 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 38 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 39 | /* Module Resolution Options */ 40 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 41 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 42 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 43 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 44 | // "typeRoots": [], /* List of folders to include type definitions from. */ 45 | // "types": [], /* Type declaration files to be included in compilation. */ 46 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 47 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 48 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 49 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 50 | /* Source Map Options */ 51 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 52 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 53 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 54 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 55 | /* Experimental Options */ 56 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 57 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 58 | /* Advanced Options */ 59 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 60 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/zomes/simple/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "simple" 3 | version = "0.0.1" 4 | authors = [ "philip.beadle@holo.host", "lisa.jetton@holo.host" ] 5 | edition = "2018" 6 | 7 | [lib] 8 | name = "simple" 9 | crate-type = [ "cdylib", "rlib" ] 10 | 11 | [dependencies] 12 | hdk3 = { git = "https://github.com/holochain/holochain.git", branch = "develop" } 13 | serde = "=1.0.104" 14 | chrono = { version = "0.4", features = ['alloc', 'std']} 15 | derive_more = "0.99.9" 16 | thiserror = "1.0.20" 17 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/zomes/simple/src/entries.rs: -------------------------------------------------------------------------------- 1 | pub mod thing; 2 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/zomes/simple/src/entries/thing/handlers.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | error::SimpleResult, 3 | thing::{Thing, ThingEntry} 4 | }; 5 | use hdk3::prelude::*; 6 | 7 | use super::{ThingListInput, ThingList}; 8 | 9 | /// Create a new thing 10 | pub(crate) fn create_thing(thing_entry: ThingEntry) -> SimpleResult { 11 | let ThingEntry { parent, uuid, .. } = thing_entry.clone(); 12 | let path: Path = Path::from(format!("{}.{}", parent, uuid)); 13 | path.ensure()?; 14 | create_entry(&thing_entry)?; 15 | let entry_hash = hash_entry(&thing_entry)?; 16 | let _thing_link: HeaderHash = create_link(path.hash()?, entry_hash.clone(), ())?; 17 | Thing::new(thing_entry, entry_hash) 18 | } 19 | 20 | pub(crate) fn delete_thing(thing: Thing) -> SimpleResult<()> { 21 | // This is a workaround for now 22 | if let Some(Details::Entry(metadata::EntryDetails{headers,..})) = get_details(thing.entry_hash, GetOptions::default())?{ 23 | if let Some(header) = headers.first(){ 24 | delete_entry(header.header_address().clone())?; 25 | } 26 | } 27 | Ok(()) 28 | } 29 | 30 | pub(crate) fn list_things(input: ThingListInput) -> SimpleResult { 31 | let parent_path = Path::from(input.parent); 32 | let thing_path_links = parent_path.children()?.into_inner(); 33 | let mut things = Vec::with_capacity(thing_path_links.len()); 34 | for thing_uuid in thing_path_links.into_iter().map(|link| link.target) { 35 | debug!(line!()); 36 | let mut links = get_links(thing_uuid, None)?.into_inner(); 37 | debug!(line!()); 38 | links.sort_by_key(|l|l.timestamp); 39 | debug!(format!("{:?}", links)); 40 | if let Some(thing_link_last) = links.last() { 41 | if let Some(element) = get(thing_link_last.target.clone(), GetOptions::default())? { 42 | debug!(line!()); 43 | if let Some(thing) = element.into_inner().1.to_app_option::()? { 44 | debug!(line!()); 45 | things.push(Thing::new(thing.clone(), hash_entry(&thing)?)?); 46 | debug!(line!()); 47 | } 48 | } 49 | } 50 | } 51 | Ok(things.into()) 52 | } 53 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/zomes/simple/src/entries/thing/mod.rs: -------------------------------------------------------------------------------- 1 | use hdk3::prelude::*; 2 | use crate::{ 3 | error::SimpleResult 4 | }; 5 | pub mod handlers; 6 | 7 | /// The actual thing data that is saved into the DHT 8 | /// This is the data that can change. 9 | #[hdk_entry(id = "thing_entry")] 10 | #[derive(Debug, Clone)] 11 | #[serde(rename_all = "camelCase")] 12 | pub struct ThingEntry { 13 | uuid: String, 14 | name: String, 15 | location: String, 16 | parent: String, 17 | } 18 | 19 | /// A channel is consists of the category it belongs to 20 | /// and a unique id 21 | #[derive(Debug, Clone, Serialize, Deserialize, SerializedBytes)] 22 | #[serde(rename_all = "camelCase")] 23 | pub struct Thing { 24 | uuid: String, 25 | name: String, 26 | location: String, 27 | parent: String, 28 | entry_hash: EntryHash, 29 | } 30 | 31 | /// Input to the list things call 32 | #[derive(Serialize, Deserialize, SerializedBytes)] 33 | pub struct ThingListInput { 34 | parent: String, 35 | } 36 | 37 | /// The things returned from list things 38 | #[derive(Serialize, Deserialize, SerializedBytes, derive_more::From)] 39 | pub struct ThingList { 40 | things: Vec, 41 | } 42 | 43 | impl Thing { 44 | pub fn new(entry: ThingEntry, entry_hash: EntryHash) -> SimpleResult { 45 | Ok(Thing{ 46 | uuid: entry.uuid, 47 | name: entry.name, 48 | location: entry.location, 49 | parent: entry.parent, 50 | entry_hash, 51 | }) 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/zomes/simple/src/error.rs: -------------------------------------------------------------------------------- 1 | use hdk3::prelude::*; 2 | 3 | #[derive(thiserror::Error, Debug)] 4 | pub enum SimpleError { 5 | #[error(transparent)] 6 | Serialization(#[from] SerializedBytesError), 7 | #[error(transparent)] 8 | EntryError(#[from] EntryError), 9 | #[error(transparent)] 10 | Wasm(#[from] WasmError), 11 | #[error(transparent)] 12 | HdkError(#[from] HdkError), 13 | #[error("Header that was just committed is missing. This means some went really wrong")] 14 | MissingLocalHeader, 15 | #[error("Tried to use a header without an entry as for where it only makes sense to use a new entry header")] 16 | WrongHeaderType, 17 | #[error("Thing at path {0} doesn't exist")] 18 | MissingThing(String), 19 | #[error("Some is fatally wrong with this app\n Please post a bug report on the repo\n Error: {0}")] 20 | DataFormatError(&'static str), 21 | } 22 | 23 | pub type SimpleResult = Result; 24 | -------------------------------------------------------------------------------- /generator/templates/simple/dna/simple/zomes/simple/src/lib.rs: -------------------------------------------------------------------------------- 1 | use entries::thing; 2 | use error::SimpleResult; 3 | use hdk3::prelude::Path; 4 | use hdk3::prelude::*; 5 | use thing::{ThingEntry, Thing, ThingListInput, ThingList}; 6 | 7 | mod entries; 8 | mod error; 9 | 10 | entry_defs![Path::entry_def(), ThingEntry::entry_def()]; 11 | 12 | #[hdk_extern] 13 | fn create_thing(thing_entry: ThingEntry) -> SimpleResult { 14 | thing::handlers::create_thing(thing_entry) 15 | } 16 | 17 | #[hdk_extern] 18 | fn delete_thing(thing: Thing) -> SimpleResult<()> { 19 | thing::handlers::delete_thing(thing) 20 | } 21 | 22 | #[hdk_extern] 23 | fn list_things(parent: ThingListInput) -> SimpleResult { 24 | thing::handlers::list_things(parent) 25 | } 26 | -------------------------------------------------------------------------------- /generator/templates/simple/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Allow: / 3 | -------------------------------------------------------------------------------- /generator/templates/simple/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 26 | -------------------------------------------------------------------------------- /generator/templates/simple/src/assets/holochain-halo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/holochain/vue-cli-plugin-holochain-app-simple/8a9d1d4eff1b53dcbdca7c1b471c951c4cf53832/generator/templates/simple/src/assets/holochain-halo.png -------------------------------------------------------------------------------- /generator/templates/simple/src/layouts/basic/Index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | -------------------------------------------------------------------------------- /generator/templates/simple/src/layouts/basic/View.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | -------------------------------------------------------------------------------- /generator/templates/simple/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuetify from 'vuetify' 3 | import 'vuetify/dist/vuetify.min.css' 4 | 5 | Vue.use(Vuetify) 6 | 7 | export default new Vuetify({ 8 | theme: { 9 | themes: { 10 | light: { 11 | primary: '#6a1b9a', 12 | secondary: '#424242', 13 | accent: '#82B1FF', 14 | error: '#FF5252', 15 | info: '#2196F3', 16 | success: '#4CAF50', 17 | warning: '#FFC107' 18 | } 19 | } 20 | } 21 | }) 22 | -------------------------------------------------------------------------------- /generator/templates/simple/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import routes from './routes' 4 | Vue.use(VueRouter) 5 | 6 | const router = new VueRouter({ 7 | mode: 'history', 8 | base: process.env.BASE_URL, 9 | routes 10 | }) 11 | 12 | export default router 13 | -------------------------------------------------------------------------------- /generator/templates/simple/src/router/routes/index.js: -------------------------------------------------------------------------------- 1 | // https://medium.com/locale-ai/architecting-vuex-store-for-large-scale-vue-js-applications-24c36137e251 2 | const requireRoutes = require.context('.', false, /\.routes\.js$/) 3 | let routes = [] 4 | requireRoutes.keys().forEach(filename => { 5 | routes = routes.concat(requireRoutes(filename).default) 6 | }) 7 | export default routes 8 | -------------------------------------------------------------------------------- /generator/templates/simple/src/router/routes/public.routes.js: -------------------------------------------------------------------------------- 1 | const routes = [ 2 | { 3 | path: '/', 4 | component: () => import('@/layouts/basic/Index.vue'), 5 | children: [ 6 | { 7 | path: '', 8 | name: 'Home', 9 | component: () => import('@/views/home/Index.vue') 10 | } 11 | ] 12 | } 13 | ] 14 | 15 | export default routes 16 | -------------------------------------------------------------------------------- /generator/templates/simple/src/router/routes/simple.routes.js: -------------------------------------------------------------------------------- 1 | const routes = [ 2 | { 3 | path: '/things', 4 | component: () => import('@/layouts/basic/Index.vue'), 5 | children: [ 6 | { 7 | path: '', 8 | name: 'Things', 9 | component: () => import('@/views/things/Index.vue') 10 | } 11 | ] 12 | } 13 | ] 14 | 15 | export default routes 16 | -------------------------------------------------------------------------------- /generator/templates/simple/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import modules from './modules' 4 | 5 | Vue.use(Vuex) 6 | 7 | export default new Vuex.Store({ 8 | state: {}, 9 | actions: {}, 10 | mutations: {}, 11 | modules 12 | }) 13 | -------------------------------------------------------------------------------- /generator/templates/simple/src/store/modules/index.js: -------------------------------------------------------------------------------- 1 | // https://medium.com/locale-ai/architecting-vuex-store-for-large-scale-vue-js-applications-24c36137e251 2 | const requireModule = require.context('.', false, /\.store\.js$/) 3 | const modules = {} 4 | requireModule.keys().forEach(filename => { 5 | const moduleName = filename.replace(/(\.\/|\.store\.js)/g, '') 6 | modules[moduleName] = requireModule(filename).default || requireModule(filename) 7 | }) 8 | export default modules 9 | -------------------------------------------------------------------------------- /generator/templates/simple/src/store/modules/simple.store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import * as base64 from 'byte-base64' 4 | import Dexie from 'dexie' 5 | import { AppWebsocket } from '@holochain/conductor-api' 6 | 7 | Vue.use(Vuex) 8 | 9 | export default { 10 | namespaced: true, 11 | state: { 12 | agentPubKey: '', 13 | simpleCellId: '', 14 | things: [] 15 | }, 16 | actions: { 17 | async initialise ({ state, commit }) { 18 | state.db = new Dexie('simple') 19 | state.db.version(1).stores({ 20 | things: 'uuid' 21 | }) 22 | state.db.open().catch(function (e) { 23 | console.error('Open failed: ' + e) 24 | }) 25 | AppWebsocket.connect(`ws://localhost:${localStorage.getItem('port')}`) 26 | .then(socket => { 27 | commit('hcClient', socket) 28 | }) 29 | commit('agentPubKey', base64.base64ToBytes(decodeURIComponent(localStorage.getItem('agentPubKey')))) 30 | commit('simpleCellId', base64.base64ToBytes(decodeURIComponent(localStorage.getItem('simpleCellId')))) 31 | }, 32 | fetchThings ({ state, commit }) { 33 | console.log(state.simpleCellId) 34 | state.db.things.toArray(things => { 35 | commit('setThings', things) 36 | state.hcClient 37 | .callZome({ 38 | cap: null, 39 | cell_id: [state.simpleCellId, state.agentPubKey], 40 | zome_name: 'simple', 41 | fn_name: 'list_things', 42 | provenance: state.agentPubKey, 43 | payload: { parent: 'Things' } 44 | }) 45 | .then(result => { 46 | console.log('🚀 ~ file: simple.store.js ~ line 46 ~ fetchThings ~ result', result) 47 | result.things.forEach(thing => { 48 | state.db.things.put(thing).then((result) => console.log(result)) 49 | }) 50 | commit('setThings', result.things) 51 | }) 52 | .catch(err => console.log(err)) 53 | }) 54 | }, 55 | saveThing ({ state, commit }, payload) { 56 | const thing = { ...payload.thing, parent: 'Things' } 57 | state.db.things.put(thing) 58 | if (payload.action === 'create') { 59 | commit('createThing', thing) 60 | } else { 61 | commit('updateThing', thing) 62 | } 63 | if (thing.entryHash) { 64 | state.hcClient 65 | .callZome({ 66 | cap: null, 67 | cell_id: [state.simpleCellId, state.agentPubKey], 68 | zome_name: 'simple', 69 | fn_name: 'delete_thing', 70 | provenance: state.agentPubKey, 71 | payload: thing 72 | }) 73 | } 74 | state.hcClient 75 | .callZome({ 76 | cap: null, 77 | cell_id: [state.simpleCellId, state.agentPubKey], 78 | zome_name: 'simple', 79 | fn_name: 'create_thing', 80 | provenance: state.agentPubKey, 81 | payload: thing 82 | }) 83 | .then(committedThing => { 84 | committedThing.entryHash = base64.bytesToBase64(committedThing.entryHash) 85 | state.db.things.put(committedThing) 86 | commit('updateThing', committedThing) 87 | }) 88 | }, 89 | deleteThing ({ state, commit }, payload) { 90 | const thing = payload.thing 91 | state.db.things.delete(thing.uuid) 92 | commit('deleteThing', thing) 93 | state.hcClient 94 | .callZome({ 95 | cap: null, 96 | cell_id: [state.simpleCellId, state.agentPubKey], 97 | zome_name: 'simple', 98 | fn_name: 'delete_thing', 99 | provenance: state.agentPubKey, 100 | payload: thing 101 | }) 102 | } 103 | }, 104 | mutations: { 105 | agentPubKey (state, payload) { 106 | state.agentPubKey = payload 107 | }, 108 | simpleCellId (state, payload) { 109 | state.simpleCellId = payload 110 | }, 111 | hcClient (state, payload) { 112 | state.hcClient = payload 113 | }, 114 | setThings (state, payload) { 115 | const things = payload 116 | state.things = things 117 | }, 118 | createThing (state, payload) { 119 | state.things.splice(0, 0, payload) 120 | }, 121 | updateThing (state, payload) { 122 | state.things = state.things.map(thing => 123 | thing.uuid !== payload.uuid ? thing : { ...thing, ...payload } 124 | ) 125 | }, 126 | deleteThing (state, payload) { 127 | state.things = state.things.filter(c => c.uuid !== payload.uuid) 128 | } 129 | }, 130 | modules: {} 131 | } 132 | -------------------------------------------------------------------------------- /generator/templates/simple/src/views/home/Index.vue: -------------------------------------------------------------------------------- 1 | 175 | 176 | 205 | -------------------------------------------------------------------------------- /generator/templates/simple/src/views/things/Index.vue: -------------------------------------------------------------------------------- 1 | 112 | 113 | 197 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = () => {} 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-cli-plugin-holochain-app-simple", 3 | "version": "0.0.7", 4 | "description": "A simple Holocahin app showing how it all fits together.", 5 | "author": "Philip Beadle ", 6 | "license": "MIT", 7 | "scripts": { 8 | "lint": "eslint --ext .js,.vue ." 9 | }, 10 | "dependencies": { 11 | "semver": "^7.1.2" 12 | }, 13 | "peerDependenciesMeta": { 14 | "sass-loader": { 15 | "optional": true 16 | } 17 | }, 18 | "publishConfig": { 19 | "access": "public" 20 | } 21 | } 22 | --------------------------------------------------------------------------------