diff --git a/package.json b/package.json index 9b4bef7..c622a86 100644 --- a/package.json +++ b/package.json @@ -7,18 +7,20 @@ "we-applet" ], "scripts": { - "start": "npm run network 2", - "network": "hc s clean && npm run build:test-happ && concurrently-repeat \"npm run start:agent\"", + "start": "AGENTS=1 npm run network", + "network": "hc s clean && npm run build:test-happ && concurrently \"npm run build:watch -w ui\" \"npm run launch:happ\"", "start:agent": "cross-env HC_PORT=$(port) HC_ADMIN_PORT=$(port) concurrently -k \"npm run start:happ\" \"sleep 5 && npm run start -w ui\"", + "launch:happ": "RUST_LOG=warn echo \"pass\" | hc launch --piped -n $AGENTS ./workdir/sensemaker-enabled/provider-sensemaker.happ -w --ui-path ui/dist network mdns", "test": "npm run build:happ && npm t -w tests", "start:happ": "concurrently \"RUST_LOG=warn echo \"pass\" | hc s --piped -f=$HC_ADMIN_PORT generate ./workdir/sensemaker-enabled/provider-sensemaker.happ --run=$HC_PORT -a provider network mdns\" \"npm run playground\"", - "package": "npm run build:happ && npm run package:ui -w we-applet && hc web-app pack workdir", + "package": "npm run build:happ && npm run build:ui && npm run package:ui -w we-applet && hc web-app pack workdir", "build:happ": "npm run build:dnas && hc app pack ./workdir", "build:test-happ": "npm run build:dnas && hc app pack ./workdir/sensemaker-enabled", "build:dnas": "npm run build:zomes && hc dna pack ./dna/workdir", "build:zomes": "CARGO_TARGET_DIR=target cargo build --release --target wasm32-unknown-unknown", + "build:ui": "npm run ts-build -w ui", "playground": "run-singleton \"holochain-playground\"", - "download-sensemaker": "rimraf workdir/sensemaker.dna && curl -L --output workdir/sensemaker.dna https://github.com/neighbour-hoods/sensemaker-lite/releases/download/v0.0.2-alpha/sensemaker.dna", + "download-sensemaker": "rimraf workdir/sensemaker.dna && curl -L --output workdir/sensemaker.dna https://github.com/neighbour-hoods/sensemaker-lite/releases/download/v0.0.3-alpha/sensemaker.dna", "start:ui": "npm run start -w ui" }, "devDependencies": { diff --git a/tests/package.json b/tests/package.json index 58a31e7..77a146a 100644 --- a/tests/package.json +++ b/tests/package.json @@ -20,12 +20,11 @@ "uuidv4": "^6.2.11" }, "devDependencies": { - "@holochain/client": "0.8.0", - "@holochain/tryorama": "0.7.0", + "@holochain/client": "0.11.9", + "@holochain/tryorama": "^0.10.4", "@types/lodash": "^4.14.158", "@types/node": "^14.0.14", - "tape-promise": "^4.0.0", - "@holochain-open-dev/utils": "^0.4.3" + "tape-promise": "^4.0.0" }, "type": "module" } diff --git a/tests/src/provider.ts b/tests/src/provider.ts index b20c600..d0112e8 100644 --- a/tests/src/provider.ts +++ b/tests/src/provider.ts @@ -1,19 +1,18 @@ -import { DnaSource, Record, ActionHash, EntryHash } from "@holochain/client"; +import { AppBundleSource } from "@holochain/client"; import { pause, runScenario } from "@holochain/tryorama"; import { decode } from '@msgpack/msgpack'; import pkg from 'tape-promise/tape'; const { test } = pkg; -import { providerDna } from "./utils"; -import { serializeHash } from "@holochain-open-dev/utils"; +import { providerHapp } from "./utils"; export default () => test("provider CRUD tests", async (t) => { await runScenario(async scenario => { - const dnas: DnaSource[] = [{ path: providerDna }]; + const appBundleSource: AppBundleSource = { path: providerHapp }; - const [alice, bob] = await scenario.addPlayersWithHapps([dnas, dnas]); + const [alice, bob] = await scenario.addPlayersWithApps([{ appBundleSource }, { appBundleSource }]); await scenario.shareAllAgents(); }); diff --git a/tests/src/utils.ts b/tests/src/utils.ts index 2c9e584..d4bcfc3 100644 --- a/tests/src/utils.ts +++ b/tests/src/utils.ts @@ -3,7 +3,7 @@ import { fileURLToPath } from "url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -export const providerDna = path.join(__dirname, "../../dna/workdir/provider.dna"); +export const providerHapp = path.join(__dirname, "../../dna/workdir/provider.happ"); diff --git a/ui/index.html b/ui/index.html index 1999c08..4c05fec 100644 --- a/ui/index.html +++ b/ui/index.html @@ -23,10 +23,6 @@ - + diff --git a/ui/package.json b/ui/package.json index b5b346f..4f80d5c 100644 --- a/ui/package.json +++ b/ui/package.json @@ -12,21 +12,19 @@ "scripts": { "lint": "eslint --ext .ts,.html . --ignore-path .gitignore && prettier \"**/*.ts\" --check --ignore-path .gitignore", "format": "eslint --ext .ts,.html . --fix --ignore-path .gitignore && prettier \"**/*.ts\" --write --ignore-path .gitignore", - "build": "rimraf dist && tsc && rollup -c rollup.config.js", + "build": "rimraf dist && rimraf tsconfig.tsbuildinfo && tsc && rollup -c rollup.config.js", "ts-build": "tsc", - "build:watch": "run-singleton \"tsc --watch --preserveWatchOutput\"", + "build:watch": "rimraf dist && rimraf tsconfig.tsbuildinfo && tsc && rollup -c rollup.config.js -w", "start": "tsc && concurrently -r \"npm run build:watch\" \"wds\"", "package": "npm run build && cd dist && bestzip ../dist.zip *" }, "dependencies": { - "@holochain-open-dev/cell-client": "^0.8.0", - "@holochain-open-dev/utils": "^0.5.6", - "@holochain/client": "^0.9.2", + "@holochain/client": "0.11.9", "@lit-labs/context": "^0.1.2", "@material/mwc-button": "^0.25.3", "@material/mwc-circular-progress": "^0.25.3", "@msgpack/msgpack": "^2.7.2", - "@neighbourhoods/sensemaker-lite-types": "0.0.3", + "@neighbourhoods/sensemaker-lite-types": "0.1.0", "@type-craft/content": "^0.0.7", "@type-craft/title": "^0.0.8", "lit": "^2.0.2" @@ -39,6 +37,7 @@ "@rollup/plugin-commonjs": "18.0.0", "@rollup/plugin-node-resolve": "^13.0.4", "@rollup/plugin-replace": "^3.0.0", + "@rollup/plugin-typescript": "^10.0.1", "@typescript-eslint/eslint-plugin": "^4.29.2", "@typescript-eslint/parser": "^4.29.2", "@web/dev-server": "0.1.21", diff --git a/ui/rollup.config.js b/ui/rollup.config.js index 935bb7b..cb33574 100644 --- a/ui/rollup.config.js +++ b/ui/rollup.config.js @@ -1,83 +1,69 @@ -import nodeResolve from '@rollup/plugin-node-resolve'; -import commonjs from '@rollup/plugin-commonjs'; -import babel from '@rollup/plugin-babel'; -import html from '@web/rollup-plugin-html'; -import { importMetaAssets } from '@web/rollup-plugin-import-meta-assets'; -import { terser } from 'rollup-plugin-terser'; -import replace from '@rollup/plugin-replace'; +import nodeResolve from "@rollup/plugin-node-resolve"; +import commonjs from "@rollup/plugin-commonjs"; +import replace from "@rollup/plugin-replace"; + +import babel from "@rollup/plugin-babel"; +import html from "@web/rollup-plugin-html"; +import { importMetaAssets } from "@web/rollup-plugin-import-meta-assets"; +import { terser } from "rollup-plugin-terser"; +import typescript from '@rollup/plugin-typescript'; + +const production = !process.env.ROLLUP_WATCH; export default { - input: 'index.html', + input: "index.html", output: { - entryFileNames: '[hash].js', - chunkFileNames: '[hash].js', - assetFileNames: '[hash][extname]', - format: 'es', - dir: 'dist', + entryFileNames: "[hash].js", + chunkFileNames: "[hash].js", + assetFileNames: "[hash][extname]", + format: "es", + dir: "dist", }, - preserveEntrySignatures: false, - watch: { clearScreen: false, }, plugins: [ /** Enable using HTML as rollup entrypoint */ - replace({ - 'process.env.HC_PORT': '8888', - delimiters: ['', ''], - }), html({ minify: true, - injectServiceWorker: true, - serviceWorkerPath: 'dist/sw.js', }), /** Resolve bare module imports */ nodeResolve({ browser: true, + preferBuiltins: false, + }), + replace({ + "process.env.NODE_ENV": '"production"', + "process.env.ENV": `"${process.env.ENV}"`, // :TODO: this seems like a possible security issue, should we be sending this? + "process.env.HC_PORT": JSON.stringify(process.env.HC_PORT) || `undefined`, + "process.env.ADMIN_PORT": JSON.stringify(process.env.ADMIN_PORT) || `undefined`, + }), + commonjs({}), + typescript({ + sourceMap: !production, + inlineSources: !production, }), - commonjs(), /** Minify JS */ terser(), /** Bundle assets references via import.meta.url */ importMetaAssets(), /** Compile JS to a lower language target */ babel({ - babelHelpers: 'bundled', + exclude: /node_modules/, + + babelHelpers: "bundled", presets: [ [ - require.resolve('@babel/preset-env'), + require.resolve("@babel/preset-env"), { - targets: [ - 'last 3 Chrome major versions', - 'last 3 Firefox major versions', - 'last 3 Edge major versions', - 'last 3 Safari major versions', - ], + targets: ['defaults', 'not IE 11', 'safari >13', 'not op_mini all', 'last 3 Chrome versions'], modules: false, bugfixes: true, }, ], ], - plugins: [ - [ - require.resolve('babel-plugin-template-html-minifier'), - { - modules: { - lit: ['html', { name: 'css', encapsulation: 'style' }], - }, - failOnError: false, - strictCSS: true, - htmlMinifier: { - collapseWhitespace: true, - conservativeCollapse: true, - removeComments: true, - caseSensitive: true, - minifyCSS: true, - }, - }, - ], - ], + plugins: [], }), ], }; diff --git a/ui/src/appletConfig.ts b/ui/src/appletConfig.ts index 06d2d9c..a10a7da 100644 --- a/ui/src/appletConfig.ts +++ b/ui/src/appletConfig.ts @@ -27,7 +27,7 @@ const totalImportanceDimension = { const taskItemResourceType: ConfigResourceType = { "name": "task_item", - "base_types": [{ "id": 0, "zome_id": 0, "visibility": { "Public": null } }], + "base_types": [{ "entry_index": 0, "zome_index": 0, "visibility": { "Public": null } }], "dimensions": [importanceDimension] } diff --git a/ui/src/provider-app-test-harness.ts b/ui/src/provider-app-test-harness.ts index 3e861e7..2c716b2 100644 --- a/ui/src/provider-app-test-harness.ts +++ b/ui/src/provider-app-test-harness.ts @@ -1,23 +1,31 @@ import { LitElement, css, html } from 'lit'; -import { property, state } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import { + AppAgentWebsocket, AppWebsocket, + CellInfo, CellType, + InstalledCell, ActionHash, - InstalledAppInfo, + AppInfo, AdminWebsocket, - InstalledCell, EntryHash, + encodeHashToBase64, } from '@holochain/client'; import '@material/mwc-circular-progress'; import { ScopedElementsMixin } from '@open-wc/scoped-elements'; -import { HolochainClient, CellClient } from '@holochain-open-dev/cell-client'; import { get } from 'svelte/store'; import { ProviderStore } from './provider-store'; import { SensemakerService, SensemakerStore } from '@neighbourhoods/nh-we-applet'; -import { serializeHash } from '@holochain-open-dev/utils'; import { ProviderApp } from './index'; import appletConfig from './appletConfig' +const HC_APP_SOCKET_URI = process.env.HC_PORT ? `ws://localhost:${process.env.HC_PORT}` : ``; +const HC_ADMIN_SOCKET_URI = process.env.ADMIN_PORT ? `ws://localhost:${process.env.ADMIN_PORT}` : ``; + +const SENSEMAKER_ROLE_NAME = "sensemaker" +const PROVIDER_ROLE_NAME = "provider" + +@customElement('provider-app-test-harness') export class ProviderAppTestHarness extends ScopedElementsMixin(LitElement) { @state() loading = true; @state() actionHash: ActionHash | undefined; @@ -30,7 +38,7 @@ export class ProviderAppTestHarness extends ScopedElementsMixin(LitElement) { adminWebsocket!: AdminWebsocket; @property({ type: Object }) - appInfo!: InstalledAppInfo; + appInfo!: AppInfo; @property() _providerStore!: ProviderStore; @@ -38,68 +46,80 @@ export class ProviderAppTestHarness extends ScopedElementsMixin(LitElement) { @property() _sensemakerStore!: SensemakerStore; - // on the first update, setup any networking connections required for app execution - async firstUpdated() { - - // connect to the conductor - await this.connectHolochain() - const installedCells = this.appInfo.cell_data; - const client = new HolochainClient(this.appWebsocket); - - // check if sensemaker has been cloned yet - let clonedSensemakerCell: InstalledCell | undefined - clonedSensemakerCell = installedCells.find( - // when a cell is cloned, the role_id is appended with the number of the clone - c => c.role_id === 'sensemaker.0' - ); - // if it hasn't been cloned yet, clone it - if (!clonedSensemakerCell) { - const sensemakerCell = installedCells.find( - c => c.role_id === 'sensemaker' - ) as InstalledCell; - - clonedSensemakerCell = await this.appWebsocket.createCloneCell({ - app_id: 'provider', - role_id: "sensemaker", - modifiers: { - network_seed: '', - properties: { - community_activator: serializeHash(sensemakerCell.cell_id[1]) + async firstUpdated(): Promise { + let detectedSensemakerCell: InstalledCell | undefined; + let installedCells: InstalledCell[]; + + try { + // connect to the conductor + await this.connectHolochain() + installedCells = this.getInstalledCells(); + + // check if sensemaker has been cloned yet + detectedSensemakerCell = installedCells.find( + // when a cell is cloned, the role_name is appended with the number of the clone + (c: InstalledCell) => c.role_name === `${SENSEMAKER_ROLE_NAME}.0` + ); + // if it hasn't been cloned yet, clone it + if (!detectedSensemakerCell) { + console.debug(`Cloning new Cell for ${SENSEMAKER_ROLE_NAME}`) + + const sensemakerCell = installedCells.find( + //@ts-ignore + c => c.name === SENSEMAKER_ROLE_NAME + ) as InstalledCell; + detectedSensemakerCell = await this.appWebsocket.createCloneCell({ + app_id: 'provider-sensemaker', + role_name: SENSEMAKER_ROLE_NAME, + modifiers: { + network_seed: '', + properties: { + community_activator: encodeHashToBase64(sensemakerCell.cell_id[1]) + }, + origin_time: Date.now(), }, - origin_time: Date.now(), - }, - name: 'sensemaker-clone', - }); + name: 'sensemaker-clone', + }); + + // now that we've cloned, refresh our cache of appInfo + await this.refreshAppInfo(); + } + } catch (e) { + // log and throw any connection error + console.error(e); + throw e; } - + // construct the sensemaker store - const sensemakerCellClient = new CellClient(client, clonedSensemakerCell); - const sensemakerService = new SensemakerService(sensemakerCellClient); + const sensemakerService = new SensemakerService(await AppAgentWebsocket.connect( + this.appWebsocket, + this.appInfo.installed_app_id, + ), detectedSensemakerCell.role_name!); this._sensemakerStore = new SensemakerStore(sensemakerService); - let appInfos = await this.appWebsocket.appInfo({ - installed_app_id: 'provider', - }); - // register the applet config await this._sensemakerStore.registerApplet(appletConfig) - const providerCell = installedCells.find( - c => c.role_id === 'provider' - ) as InstalledCell; + const providerCell = installedCells + .find(c => c.role_name === PROVIDER_ROLE_NAME); // construct the provider store - this._providerStore = new ProviderStore( - new HolochainClient(this.appWebsocket), - providerCell, - ); - - // fetch all resources to initialize the provider store - const allResources = await this._providerStore.fetchAllResources() + if (providerCell) { + this._providerStore = new ProviderStore(await AppAgentWebsocket.connect( + this.appWebsocket, + this.appInfo.installed_app_id, + ), providerCell); + } else { + throw new Error("Unable to detect provider cell") + } + + // register the applet config + await this._sensemakerStore.registerApplet(appletConfig) // initialize the sensemaker store so that the UI knows about assessments and other sensemaker data - await this.updateSensemakerState() + await this.updateSensemakerState(); + this.loading = false; } @@ -118,15 +138,19 @@ export class ProviderAppTestHarness extends ScopedElementsMixin(LitElement) { } async connectHolochain() { - this.adminWebsocket = await AdminWebsocket.connect( - `ws://localhost:${process.env.HC_ADMIN_PORT}` - ); + this.adminWebsocket = await AdminWebsocket.connect(HC_ADMIN_SOCKET_URI); + this.appWebsocket = await AppWebsocket.connect(HC_APP_SOCKET_URI); - this.appWebsocket = await AppWebsocket.connect( - `ws://localhost:${process.env.HC_PORT}` - ); - + await this.refreshAppInfo(); + } + + private getInstalledCells(): InstalledCell[] { + return (this.appInfo as AppInfo).cell_info[SENSEMAKER_ROLE_NAME] + // @ts-ignore + .map((c: CellInfo) => (c[CellType.Provisioned] || c[CellType.Cloned]) as InstalledCell) + } + async refreshAppInfo() { this.appInfo = await this.appWebsocket.appInfo({ installed_app_id: 'provider', }); @@ -142,7 +166,7 @@ export class ProviderAppTestHarness extends ScopedElementsMixin(LitElement) { }) } } - + static get scopedElements() { return { 'provider-app': ProviderApp, diff --git a/ui/src/provider-service.ts b/ui/src/provider-service.ts index e21d1d4..3676872 100644 --- a/ui/src/provider-service.ts +++ b/ui/src/provider-service.ts @@ -1,10 +1,10 @@ -import { CellClient } from '@holochain-open-dev/cell-client'; -import { Dictionary } from '@holochain-open-dev/core-types'; -import { EntryHash } from '@holochain/client'; +import { EntryHash, AppAgentWebsocket, CellId } from '@holochain/client'; + +const PROVIDER_ZOME_NAME = 'provider' // the ProviderService object handles the zome calls export class ProviderService { - constructor(public cellClient: CellClient, public zomeName = 'provider') {} + constructor(public cellClient: AppAgentWebsocket, public cellId: CellId) {} async createNewResource(input: string): Promise { return this.callZome('create_new_resource', input); @@ -12,10 +12,16 @@ export class ProviderService { async allProviderResourceEntryHashes(): Promise> { return this.callZome('all_provider_resource_entry_hashes', null); } - async fetchAllResources(): Promise> { + async fetchAllResources(): Promise<{}> { return this.callZome('fetch_all_resources', null); } private callZome(fnName: string, payload: any) { - return this.cellClient.callZome(this.zomeName, fnName, payload); + return this.cellClient.callZome({ + cell_id: this.cellId, + zome_name: PROVIDER_ZOME_NAME, + fn_name: fnName, + payload, + provenance: this.cellId[1], + }); } } diff --git a/ui/src/provider-store.ts b/ui/src/provider-store.ts index 220e160..79cf2f1 100644 --- a/ui/src/provider-store.ts +++ b/ui/src/provider-store.ts @@ -1,11 +1,12 @@ -import { CellClient, HolochainClient } from '@holochain-open-dev/cell-client'; +import { Writable, writable } from 'svelte/store'; import { + AppAgentWebsocket, + EntryHash, AgentPubKeyB64, - Dictionary, -} from '@holochain-open-dev/core-types'; -import { serializeHash } from '@holochain-open-dev/utils'; -import { Writable, writable } from 'svelte/store'; -import { EntryHash, InstalledCell, Record } from '@holochain/client'; + InstalledCell, + Record, + encodeHashToBase64, +} from '@holochain/client'; import { ProviderService } from './provider-service'; // the ProviderStore manages the Writable svelte/store object, like accessing and updating it @@ -14,20 +15,20 @@ export class ProviderStore { // this private field is meant to store the data from the provider dna in a structure that is helpful to the UI // you could create additional fields depending on what makes the most sense for your application data model - #providerData: Writable>> = writable({}); + #providerData: Writable<{ [any: string]: Array }> = writable({}); get myAgentPubKey(): AgentPubKeyB64 { - return serializeHash(this.providerCell.cell_id[1]); + return encodeHashToBase64(this.providerCell.cell_id[1]); } constructor( - protected client: HolochainClient, + protected client: AppAgentWebsocket, protected providerCell: InstalledCell, zomeName: string = 'provider' ) { this.service = new ProviderService( - new CellClient(client, providerCell), - zomeName + client, + providerCell.cell_id ); } diff --git a/ui/src/utils.ts b/ui/src/utils.ts index 134bbce..58a4fe0 100644 --- a/ui/src/utils.ts +++ b/ui/src/utils.ts @@ -1,16 +1,13 @@ import { Task, WrappedEntry, WrappedTaskWithAssessment } from "./types"; -import { - Dictionary, - } from '@holochain-open-dev/core-types'; +import { encodeHashToBase64 } from '@holochain/client' import { Assessment } from "@neighbourhoods/sensemaker-lite-types"; -import { serializeHash } from "@holochain-open-dev/utils"; -function addMyAssessmentsToTasks(myPubKey: string, tasks: WrappedEntry[], assessments: Dictionary>): WrappedTaskWithAssessment[] { +function addMyAssessmentsToTasks(myPubKey: string, tasks: WrappedEntry[], assessments: Record>): WrappedTaskWithAssessment[] { const tasksWithMyAssessments = tasks.map(task => { - const assessmentsForTask = assessments[serializeHash(task.entry_hash)] + const assessmentsForTask = assessments[encodeHashToBase64(task.entry_hash)] let myAssessment if (assessmentsForTask) { - myAssessment = assessmentsForTask.find(assessment => serializeHash(assessment.author) === myPubKey) + myAssessment = assessmentsForTask.find(assessment => encodeHashToBase64(assessment.author) === myPubKey) } else { myAssessment = undefined @@ -23,4 +20,4 @@ function addMyAssessmentsToTasks(myPubKey: string, tasks: WrappedEntry[], return tasksWithMyAssessments } - export { addMyAssessmentsToTasks } \ No newline at end of file + export { addMyAssessmentsToTasks } diff --git a/ui/tsconfig.json b/ui/tsconfig.json index ea7c66d..abb8ffa 100644 --- a/ui/tsconfig.json +++ b/ui/tsconfig.json @@ -10,13 +10,13 @@ "allowSyntheticDefaultImports": true, "experimentalDecorators": true, "importHelpers": true, - "outDir": "dist", + "outDir": "./dist", "sourceMap": true, "inlineSources": true, - "rootDir": "src", + "rootDir": "./src", "declaration": true, "incremental": true, "skipLibCheck": true }, - "include": ["src/**/*.ts"] + "include": ["src/*.ts", "src/**/*.ts"] } diff --git a/we-applet/package.json b/we-applet/package.json index 2fbab2c..7f1537c 100644 --- a/we-applet/package.json +++ b/we-applet/package.json @@ -5,7 +5,7 @@ "start": "npm run build:happ && cross-env HC_PORT=$(port) ADMIN_PORT=$(port) concurrently \"npm run start:happ\" \"npm run start:ui\"", "start:ui": "concurrently -k --names tsc,dev-server \"npm run build:watch\" \"wds --config ./web-dev-server.config.mjs\"", "start:happ": "RUST_LOG=warn WASM_LOG=debug echo \"pass\" | hc s --piped -f=$ADMIN_PORT generate ./workdir/provider_applet-applet.happ --run=$HC_PORT -a provider_applet-applet network mdns", - "build": "rimraf dist && tsc && rollup --config rollup.config.js", + "build": "rimraf out-tsc && rimraf dist && rimraf tsconfig.tsbuildinfo && tsc && rollup --config rollup.config.js", "build:watch": "tsc -w --preserveWatchOutput", "package": "npm run package:ui && hc web-app pack ./workdir", "package:ui": "rimraf ui.zip && npm run build && cd ./dist && bestzip ../ui.zip * ", @@ -14,15 +14,15 @@ "build:zomes": "CARGO_TARGET_DIR=target cargo build --release --target wasm32-unknown-unknown" }, "dependencies": { - "@holochain-open-dev/profiles": "^0.6.0", - "@holochain/client": "^0.9.2", - "@neighbourhoods/nh-we-applet": "0.0.4", + "@holochain-open-dev/profiles": "^0.9.4", + "@holochain/client": "0.11.9", + "@neighbourhoods/nh-we-applet": "^0.0.5", "@lit-labs/context": "^0.1.1", "@open-wc/scoped-elements": "^2.1.1", "@scoped-elements/material-web": "^0.0.19", "lit": "^2.2.0", "@neighbourhoods/provider-applet": "file:../ui", - "@neighbourhoods/sensemaker-lite-types": "0.0.3" + "@neighbourhoods/sensemaker-lite-types": "0.1.0" }, "devDependencies": { "@babel/preset-env": "^7.15.0", diff --git a/we-applet/rollup.config.js b/we-applet/rollup.config.js index d92e0f1..4636236 100644 --- a/we-applet/rollup.config.js +++ b/we-applet/rollup.config.js @@ -1,3 +1,4 @@ +import path from 'path'; import nodeResolve from "@rollup/plugin-node-resolve"; import commonjs from "@rollup/plugin-commonjs"; import replace from "@rollup/plugin-replace"; @@ -8,7 +9,7 @@ import { importMetaAssets } from "@web/rollup-plugin-import-meta-assets"; import { terser } from "rollup-plugin-terser"; export default { - input: "out-tsc/index.js", + input: "out-tsc/we-applet/src/index.js", output: { format: "es", dir: "dist", @@ -26,6 +27,7 @@ export default { nodeResolve({ browser: true, preferBuiltins: false, + modulePaths: [path.resolve(__dirname, './out-tsc'), path.resolve(__dirname, './dist')], }), replace({ "process.env.NODE_ENV": '"production"', diff --git a/we-applet/src/index.ts b/we-applet/src/index.ts index 322f4a2..aee680a 100644 --- a/we-applet/src/index.ts +++ b/we-applet/src/index.ts @@ -2,35 +2,50 @@ import { AdminWebsocket, AppWebsocket, InstalledCell, + AppInfo, } from "@holochain/client"; import { WeApplet, AppletRenderers, WeServices, - InstalledAppletInfo, + AppletInfo, } from "@neighbourhoods/nh-we-applet"; import { ProviderStore } from "@neighbourhoods/provider-applet"; import { ProviderApplet } from "./provider-applet"; -import { HolochainClient } from '@holochain-open-dev/cell-client'; +import { AppAgentWebsocket } from '@holochain/client'; + +const PROVIDER_ROLE_NAME = 'provider' const providerApplet: WeApplet = { async appletRenderers( appWebsocket: AppWebsocket, adminWebsocket: AdminWebsocket, weStore: WeServices, - appletAppInfo: InstalledAppletInfo[] + appletAppInfo: AppletInfo[] ): Promise { + const appId = appletAppInfo[0].appInfo.installed_app_id + const installedCells = appletAppInfo[0].appInfo.cell_info[PROVIDER_ROLE_NAME] + .map((c: CellInfo) => ((c as { [CellType.Provisioned as string]: Cell }).Provisioned || (c as { [CellType.Cloned as string]: Cell }).Cloned) as InstalledCell); + const providerCell = installedCells + .find(c => c.role_name === PROVIDER_ROLE_NAME) + + let providerStore?: ProviderStore; + if (providerCell) { + const appWs = await AppAgentWebsocket.connect( + appWebsocket.client.socket.url, + PROVIDER_ROLE_NAME, + ); + providerStore = new ProviderStore(appWs, providerCell); + } else { + throw new Error("Unable to render WeApplet: no provider Cell detected") + } + return { full(element: HTMLElement, registry: CustomElementRegistry) { registry.define("provider-applet", ProviderApplet); element.innerHTML = ``; const appletElement = element.querySelector("provider-applet") as any; - const providerCell = appletAppInfo[0].installedAppInfo.cell_data.find(c => c.role_id === 'provider') as InstalledCell; - const providerStore = new ProviderStore( - new HolochainClient(appWebsocket), - providerCell, - ) appletElement.providerStore = providerStore; appletElement.appletAppInfo = appletAppInfo; appletElement.sensemakerStore = weStore.sensemakerStore; diff --git a/we-applet/tsconfig.json b/we-applet/tsconfig.json index a21960c..00f83d6 100644 --- a/we-applet/tsconfig.json +++ b/we-applet/tsconfig.json @@ -13,10 +13,10 @@ "sourceMap": true, "inlineSources": true, "incremental": true, - "outDir": "out-tsc", - "rootDir": "./src", + "outDir": "./out-tsc", + "rootDir": "../", "declaration": true, "skipLibCheck": true, }, - "include": ["src/**/*.ts"] + "include": ["src/*.ts", "src/**/*.ts", "../ui/src", "../ui/src/*.ts"] }