diff --git a/hosting/photo-storage/README.md b/hosting/photo-storage/README.md index 3e2e07061b..e920eabfec 100644 --- a/hosting/photo-storage/README.md +++ b/hosting/photo-storage/README.md @@ -38,19 +38,19 @@ Deploy the canisters: icp deploy ``` -The URL for the frontend depends on the canister ID. When deployed, the URL will look like this: +Open the frontend URL printed by `icp deploy`, e.g.: ``` -http://{canister_id}.localhost:8000 +http://frontend.local.localhost:8000 ``` To authorize an identity to upload files, it must be authorized first: ```bash -icp canister call photo-storage authorize '(principal "535yc-uxytb-gfk7h-tny7p-vjkoe-i4krp-3qmcl-uqfgr-cpgej-yqtjq-rqe")' +icp canister call frontend authorize '(principal "535yc-uxytb-gfk7h-tny7p-vjkoe-i4krp-3qmcl-uqfgr-cpgej-yqtjq-rqe")' ``` -> **Warning:** This example uses a hardcoded identity (defined in `src/App.js`). Before deploying to the IC mainnet, replace it with a proper authentication method such as [Internet Identity](https://docs.internetcomputer.org/building-apps/authentication/integrate-internet-identity). +> **Warning:** This example uses a hardcoded identity (defined in `src/App.jsx`). Before deploying to the IC mainnet, replace it with a proper authentication method such as [Internet Identity](https://docs.internetcomputer.org/guides/authentication/internet-identity). Stop the local network when done: diff --git a/hosting/photo-storage/icp.yaml b/hosting/photo-storage/icp.yaml index 9e53e7014e..4c709064c9 100644 --- a/hosting/photo-storage/icp.yaml +++ b/hosting/photo-storage/icp.yaml @@ -1,7 +1,11 @@ canisters: - name: frontend recipe: - type: "@dfinity/static-site@v0.3.1" + # Deliberately stays on the legacy asset-canister recipe: this example + # demonstrates programmatic uploads via AssetManager, which the + # static-site (certified-assets) canister does not support. + # See https://github.com/dfinity/examples/issues/1459 + type: "@dfinity/asset-canister@v2.2.1" configuration: dir: dist build: diff --git a/hosting/photo-storage/src/App.jsx b/hosting/photo-storage/src/App.jsx index bd1fcfa748..39825c3875 100644 --- a/hosting/photo-storage/src/App.jsx +++ b/hosting/photo-storage/src/App.jsx @@ -1,5 +1,6 @@ import {Ed25519KeyIdentity} from '@icp-sdk/core/identity'; import {HttpAgent} from '@icp-sdk/core/agent'; +import {safeGetCanisterEnv} from '@icp-sdk/core/agent/canister-env'; import {AssetManager} from '@icp-sdk/canisters/assets'; import {useEffect, useState} from "react"; import Masonry from "react-masonry-css"; @@ -8,16 +9,23 @@ import './App.css'; // Hardcoded principal: 535yc-uxytb-gfk7h-tny7p-vjkoe-i4krp-3qmcl-uqfgr-cpgej-yqtjq-rqe // Should be replaced with authentication method e.g. Internet Identity when deployed on IC const identity = Ed25519KeyIdentity.generate(new Uint8Array(Array.from({length: 32}).fill(0))); -const isLocal = !window.location.host.endsWith('ic0.app'); -const agent = HttpAgent.createSync({ - host: isLocal ? `http://127.0.0.1:${window.location.port}` : 'https://ic0.app', identity, -}); -if (isLocal) { - await agent.fetchRootKey(); + +// The ic_env cookie is set by the asset canister on all HTML responses. It +// contains the replica root key and the PUBLIC_* canister environment +// variables, so the app finds its own canister ID regardless of which URL the +// gateway serves it under (canister-id-based or name-based). +const canisterEnv = safeGetCanisterEnv(); +const canisterId = canisterEnv?.["PUBLIC_CANISTER_ID:frontend"]; + +if (!canisterId) { + throw new Error("Canister ID for 'frontend' not found. Run 'icp deploy' and open the URL it prints."); } -// Canister id can be fetched from URL since frontend in this example is hosted in the same canister as file upload -const canisterId = new URLSearchParams(window.location.search).get('canisterId') ?? /(.*?)(?:\.raw)?\.ic0.app/.exec(window.location.host)?.[1] ?? /(.*)\.localhost/.exec(window.location.host)?.[1]; +const agent = HttpAgent.createSync({ + host: window.location.origin, + rootKey: canisterEnv?.IC_ROOT_KEY, + identity, +}); // Create asset manager instance for above asset canister const assetManager = new AssetManager({canisterId, agent});