diff --git a/.github/workflows/photo_gallery.yml b/.github/workflows/photo_gallery.yml new file mode 100644 index 0000000000..ea58b73630 --- /dev/null +++ b/.github/workflows/photo_gallery.yml @@ -0,0 +1,29 @@ +name: photo_gallery + +on: + push: + branches: + - master + pull_request: + paths: + - rust/photo_gallery/** + - .github/workflows/photo_gallery.yml + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + rust-photo_gallery: + runs-on: ubuntu-24.04 + container: ghcr.io/dfinity/icp-dev-env-rust:1.0.0 + env: + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - name: Deploy and test + working-directory: rust/photo_gallery + run: | + icp network start -d + icp deploy + make test diff --git a/rust/photo_gallery/.devcontainer/devcontainer.json b/rust/photo_gallery/.devcontainer/devcontainer.json deleted file mode 100644 index ebb0b8bcc6..0000000000 --- a/rust/photo_gallery/.devcontainer/devcontainer.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "name": "ICP Dev Environment", - "image": "ghcr.io/dfinity/icp-dev-env-slim:22", - "forwardPorts": [4943, 5173], - "portsAttributes": { - "4943": { - "label": "dfx", - "onAutoForward": "ignore" - }, - "5173": { - "label": "vite", - "onAutoForward": "openBrowser" - } - }, - "customizations": { - "vscode": { - "extensions": ["dfinity-foundation.vscode-motoko"] - } - } -} diff --git a/rust/photo_gallery/.gitignore b/rust/photo_gallery/.gitignore index 49c89a1c95..63b067ed93 100644 --- a/rust/photo_gallery/.gitignore +++ b/rust/photo_gallery/.gitignore @@ -7,11 +7,8 @@ .DS_Store **/.DS_Store -# dfx temporary files -.dfx/ - # generated files -**/declarations/ +frontend/src/bindings/ # rust target/ @@ -19,7 +16,6 @@ target/ # frontend code node_modules/ dist/ -.svelte-kit/ # environment variables .env diff --git a/rust/photo_gallery/BUILD.md b/rust/photo_gallery/BUILD.md deleted file mode 100644 index 2a8a7688ee..0000000000 --- a/rust/photo_gallery/BUILD.md +++ /dev/null @@ -1,113 +0,0 @@ -# Continue building locally - -Projects deployed through ICP Ninja are temporary; they will only be live for 20 minutes before they are removed. The command-line tool `dfx` can be used to continue building your ICP Ninja project locally and deploy it to the mainnet. - -To migrate your ICP Ninja project off of the web browser and develop it locally, follow these steps. - -### 1. Install developer tools. - -You can install the developer tools natively or use Dev Containers. - -#### Option 1: Natively install developer tools - -> Installing `dfx` natively is currently only supported on macOS and Linux systems. On Windows, it is recommended to use the Dev Containers option. - -1. Install `dfx` with the following command: - -``` - -sh -ci "$(curl -fsSL https://internetcomputer.org/install.sh)" - -``` - -> On Apple Silicon (e.g., Apple M1 chip), make sure you have Rosetta installed (`softwareupdate --install-rosetta`). - -2. [Install NodeJS](https://nodejs.org/en/download/package-manager). - -3. For Rust projects, you will also need to: - -- Install [Rust](https://doc.rust-lang.org/cargo/getting-started/installation.html#install-rust-and-cargo): `curl https://sh.rustup.rs -sSf | sh` - -- Install [candid-extractor](https://crates.io/crates/candid-extractor): `cargo install candid-extractor` - -4. For Motoko projects, you will also need to: - -- Install the Motoko package manager [Mops](https://docs.mops.one/quick-start#2-install-mops-cli): `npm i -g ic-mops` - -Lastly, navigate into your project's directory that you downloaded from ICP Ninja. - -#### Option 2: Dev Containers - -Continue building your projects locally by installing the [Dev Container extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) for VS Code and [Docker](https://docs.docker.com/engine/install/). - -Make sure Docker is running, then navigate into your project's directory that you downloaded from ICP Ninja and start the Dev Container by selecting `Dev-Containers: Reopen in Container` in VS Code's command palette (F1 or Ctrl/Cmd+Shift+P). - -> Note that local development ports (e.g. the ports used by `dfx` or `vite`) are forwarded from the Dev Container to your local machine. In the VS code terminal, use Ctrl/Cmd+Click on the displayed local URLs to open them in your browser. To view the current port mappings, click the "Ports" tab in the VS Code terminal window. - -### 2. Start the local development environment. - -``` -dfx start --background -``` - -### 3. Create a local developer identity. - -To manage your project's canisters, it is recommended that you create a local [developer identity](https://internetcomputer.org/docs/building-apps/getting-started/identities) rather than use the `dfx` default identity that is not stored securely. - -To create a new identity, run the commands: - -``` - -dfx identity new IDENTITY_NAME - -dfx identity use IDENTITY_NAME - -``` - -Replace `IDENTITY_NAME` with your preferred identity name. The first command `dfx start --background` starts the local `dfx` processes, then `dfx identity new` will create a new identity and return your identity's seed phase. Be sure to save this in a safe, secure location. - -The third command `dfx identity use` will tell `dfx` to use your new identity as the active identity. Any canister smart contracts created after running `dfx identity use` will be owned and controlled by the active identity. - -Your identity will have a principal ID associated with it. Principal IDs are used to identify different entities on ICP, such as users and canisters. - -[Learn more about ICP developer identities](https://internetcomputer.org/docs/building-apps/getting-started/identities). - -### 3. Deploy the project locally. - -Deploy your project to your local developer environment with: - -``` -npm install -dfx deploy - -``` - -Your project will be hosted on your local machine. The local canister URLs for your project will be shown in the terminal window as output of the `dfx deploy` command. You can open these URLs in your web browser to view the local instance of your project. - -### 4. Obtain cycles. - -To deploy your project to the mainnet for long-term public accessibility, first you will need [cycles](https://internetcomputer.org/docs/building-apps/getting-started/tokens-and-cycles). Cycles are used to pay for the resources your project uses on the mainnet, such as storage and compute. - -> This cost model is known as ICP's [reverse gas model](https://internetcomputer.org/docs/building-apps/essentials/gas-cost), where developers pay for their project's gas fees rather than users pay for their own gas fees. This model provides an enhanced end user experience since they do not need to hold tokens or sign transactions when using a dapp deployed on ICP. - -> Learn how much a project may cost by using the [pricing calculator](https://internetcomputer.org/docs/building-apps/essentials/cost-estimations-and-examples). - -Cycles can be obtained through [converting ICP tokens into cycles using `dfx`](https://internetcomputer.org/docs/building-apps/developer-tools/dfx/dfx-cycles#dfx-cycles-convert). - -### 5. Deploy to the mainnet. - -Once you have cycles, run the command: - -``` - -dfx deploy --network ic - -``` - -After your project has been deployed to the mainnet, it will continuously require cycles to pay for the resources it uses. You will need to [top up](https://internetcomputer.org/docs/building-apps/canister-management/topping-up) your project's canisters or set up automatic cycles management through a service such as [CycleOps](https://cycleops.dev/). - -> If your project's canisters run out of cycles, they will be removed from the network. - -## Additional examples - -Additional code examples and sample applications can be found in the [DFINITY examples repo](https://github.com/dfinity/examples). diff --git a/rust/photo_gallery/Cargo.lock b/rust/photo_gallery/Cargo.lock index 8d0157b40c..117cb3c308 100644 --- a/rust/photo_gallery/Cargo.lock +++ b/rust/photo_gallery/Cargo.lock @@ -479,12 +479,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "pictures-site-backend" +name = "backend" version = "0.1.0" dependencies = [ "candid", "ic-cdk", - "ic-cdk-timers", "ic-http-certification", "regex", "serde", diff --git a/rust/photo_gallery/Makefile b/rust/photo_gallery/Makefile new file mode 100644 index 0000000000..5eeeb2684d --- /dev/null +++ b/rust/photo_gallery/Makefile @@ -0,0 +1,41 @@ +.PHONY: test + +test: + @echo "=== Test 1: list_images returns empty list initially ===" + @result=$$(icp canister call --query backend list_images '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'vec {}' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 2: upload_image stores an image and returns an ID ===" + @result=$$(icp canister call backend upload_image '("test.png", "image/png", blob "\89\50\4e\47")') && \ + echo "$$result" && \ + echo "$$result" | grep -qE '^\(([0-9]+) : nat64\)$$' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 3: list_images includes the uploaded image ===" + @result=$$(icp canister call --query backend list_images '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'test.png' && \ + echo "$$result" | grep -q 'image/png' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 4: upload a second image and list_images returns both ===" + @icp canister call backend upload_image '("photo.jpg", "image/jpeg", blob "\ff\d8\ff")' > /dev/null + @result=$$(icp canister call --query backend list_images '()') && \ + echo "$$result" && \ + echo "$$result" | grep -q 'test.png' && \ + echo "$$result" | grep -q 'photo.jpg' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 5: http_request serves uploaded image by ID ===" + @result=$$(icp canister call --query backend http_request '(record { method = "GET"; url = "/image/1"; headers = vec {}; body = blob "" })') && \ + echo "$$result" && \ + echo "$$result" | grep -q '200' && \ + echo "PASS" || (echo "FAIL" && exit 1) + + @echo "=== Test 6: http_request returns 404 for missing image ===" + @result=$$(icp canister call --query backend http_request '(record { method = "GET"; url = "/image/9999"; headers = vec {}; body = blob "" })') && \ + echo "$$result" && \ + echo "$$result" | grep -q '404' && \ + echo "PASS" || (echo "FAIL" && exit 1) diff --git a/rust/photo_gallery/README.md b/rust/photo_gallery/README.md index 76db45ce12..63912e874f 100644 --- a/rust/photo_gallery/README.md +++ b/rust/photo_gallery/README.md @@ -1,41 +1,57 @@ -# Photo gallery +# Photo Gallery -A decentralized photo gallery application built on the Internet Computer blockchain. Users can upload, view, and manage their photos in a decentralized environment. +A decentralized photo gallery application built on the Internet Computer. Users can upload and view photos stored directly on-chain, served via the HTTP gateway with browser-cacheable responses. -**WARNING:** This is meant primarily as a demo to show how the response verification library and HTTP gateways can be used to serve images with cache headers. It is not making use of authentication or certification. Use it at your own risk. +**Note:** This example is primarily a demo showing how the [response verification library](https://docs.internetcomputer.org/references/http-gateway-protocol-spec) and HTTP gateways can serve images with long-lived `Cache-Control` headers. It does not implement authentication or per-user access control. Use it at your own risk. -## Deploying from ICP Ninja +## Overview -[![](https://icp.ninja/assets/open.svg)](https://icp.ninja/editor?g=https://github.com/dfinity/examples/rust/photo_gallery) +The backend canister stores images in memory and exposes three methods: -## Build and deploy from the command-line +- `upload_image(name, content_type, data)` — stores an image blob and returns its numeric ID. +- `list_images()` — returns metadata (ID, name, content type) for all stored images. +- `http_request(request)` — serves images at `/image/` via the HTTP gateway, including skip-certification headers and `Cache-Control: public, max-age=31536000, immutable` so browsers cache images after the first fetch. -### 1. [Download and install the IC SDK.](https://internetcomputer.org/docs/building-apps/getting-started/install) +The frontend is a React + Vite application that uploads images and renders the gallery by constructing HTTP gateway URLs for each image ID, allowing the browser to fetch and cache image data directly. -### 2. Download your project from ICP Ninja using the 'Download files' button on the upper left corner, or [clone the GitHub examples repository.](https://github.com/dfinity/examples/) +## Build and deploy from the command line -### 3. Navigate into the project's directory. +### Prerequisites -### 4. Deploy the project to your local environment: +- [Node.js](https://nodejs.org/en/download/) +- icp-cli: `npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm` -``` -dfx start --background --clean && dfx deploy -``` +### Install +```bash +git clone https://github.com/dfinity/examples +cd examples/rust/photo_gallery +``` -#### 5. Generate Candid interfaces after making changes to the backend: +### Deploy and test -``` -npm run generate +```bash +icp network start -d +icp deploy +make test +icp network stop ``` -#### 6. Deploy frontend development server (if needed): +To run the Vite dev server with hot reload during frontend development: +```bash +npm run dev ``` -npm start + +## Updating the Candid interface + +If you modify the backend's public API, rebuild the canister and regenerate the `.did` file: + +```bash +icp build backend +candid-extractor target/wasm32-unknown-unknown/release/backend.wasm > backend/backend.did ``` ## Security considerations and best practices -If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://internetcomputer.org/docs/building-apps/security/overview) for developing on ICP. This example may not implement all the best practices. - +If you base your application on this example, it is recommended that you familiarize yourself with and adhere to the [security best practices](https://docs.internetcomputer.org/guides/security/overview) for developing on ICP. This example may not implement all the best practices. diff --git a/rust/photo_gallery/backend/Cargo.toml b/rust/photo_gallery/backend/Cargo.toml index fc1f16ba43..4bcc58c965 100644 --- a/rust/photo_gallery/backend/Cargo.toml +++ b/rust/photo_gallery/backend/Cargo.toml @@ -1,18 +1,15 @@ [package] -name = "pictures-site-backend" +name = "backend" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [lib] crate-type = ["cdylib"] path = "lib.rs" [dependencies] candid = "0.10" -ic-cdk = "0.17" -ic-cdk-timers = "0.11" # Feel free to remove this dependency if you don't need timers +ic-cdk = "0.20" serde = { version = "1.0", features = ["derive"] } ic-http-certification = "3.0.3" regex = "1.11.1" diff --git a/rust/photo_gallery/backend/pictures-site-backend.did b/rust/photo_gallery/backend/backend.did similarity index 100% rename from rust/photo_gallery/backend/pictures-site-backend.did rename to rust/photo_gallery/backend/backend.did diff --git a/rust/photo_gallery/dfx.json b/rust/photo_gallery/dfx.json deleted file mode 100644 index 7480076088..0000000000 --- a/rust/photo_gallery/dfx.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "canisters": { - "backend": { - "candid": "backend/pictures-site-backend.did", - "package": "pictures-site-backend", - "type": "rust" - }, - "frontend": { - "dependencies": ["backend"], - "source": ["frontend/dist"], - "type": "assets", - "workspace": "frontend" - } - }, - "output_env_file": ".env", - "version": 1 -} diff --git a/rust/photo_gallery/frontend/package.json b/rust/photo_gallery/frontend/package.json index 29a03a0f0d..97e8ebd702 100644 --- a/rust/photo_gallery/frontend/package.json +++ b/rust/photo_gallery/frontend/package.json @@ -1,14 +1,11 @@ { - "name": "pictures-site-frontend", + "name": "frontend", "private": true, - "version": "0.0.0", "type": "module", "scripts": { - "setup": "npm i && dfx canister create backend && dfx generate backend && dfx deploy", - "start": "vite --port 3000", - "prebuild": "npm i --include=dev && dfx generate", + "prebuild": "npm i --include=dev", "build": "tsc && vite build", - "format": "prettier --write \"src/**/*.{json,js,jsx,ts,tsx,css,scss}\"" + "dev": "vite" }, "dependencies": { "@icp-sdk/core": "~5.2.0", @@ -16,15 +13,11 @@ "react-dom": "^18.2.0" }, "devDependencies": { - "@types/node": "^20.4.2", + "@icp-sdk/bindgen": "~0.2.2", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.6", "@vitejs/plugin-react": "^4.0.1", - "dotenv": "^16.3.1", - "prettier": "^3.0.0", - "sass": "^1.63.6", "typescript": "^5.1.3", - "vite": "^6.3.5", - "vite-plugin-environment": "^1.1.3" + "vite": "^6.3.5" } } diff --git a/rust/photo_gallery/frontend/public/index.html b/rust/photo_gallery/frontend/public/index.html deleted file mode 100644 index 6291d2111d..0000000000 --- a/rust/photo_gallery/frontend/public/index.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - Photo Gallery - - - -
- - \ No newline at end of file diff --git a/rust/photo_gallery/frontend/src/App.tsx b/rust/photo_gallery/frontend/src/App.tsx index 192cfc404b..e2f267b392 100644 --- a/rust/photo_gallery/frontend/src/App.tsx +++ b/rust/photo_gallery/frontend/src/App.tsx @@ -1,5 +1,6 @@ import React, { useState, useEffect } from 'react'; -import { backend } from '../../src/declarations/backend'; +import { safeGetCanisterEnv } from '@icp-sdk/core/agent/canister-env'; +import { backend } from './actor.js'; import './App.css'; interface ImageInfo { @@ -71,7 +72,7 @@ function App() { return (
-

📸 Photo Gallery

+

Photo Gallery

Upload New Image

@@ -119,26 +120,31 @@ function ImageCard({ image }: ImageCardProps) { const [error, setError] = useState(false); const getImageUrl = (imageId: bigint) => { - // Use HTTP gateway URL to load images directly from backend canister - // The variables will be replaced by vite - const canisterId = import.meta.env.CANISTER_ID_BACKEND; - const network = import.meta.env.DFX_NETWORK; - - let urlSuffix: string; - - switch(network) { - case 'playground': - case 'mainnet': - case 'ic': - urlSuffix = "icp0.io"; - break; - default: - urlSuffix = "localhost:4943"; - break; + // Use HTTP gateway URL to load images directly from the backend canister. + // The backend serves images via http_request at /image/, with + // long-lived Cache-Control headers so browsers cache images after first load. + const canisterEnv = safeGetCanisterEnv(); + const canisterId = + canisterEnv?.['PUBLIC_CANISTER_ID:backend'] ?? + process.env.CANISTER_ID_BACKEND; + + // On mainnet the HTTP gateway host is .icp0.io. + // Locally (icp-cli or dfx) the replica listens on localhost:8000 / 4943 + // and serves the same path under the canister subdomain. + const origin = window.location.origin; + const isLocal = + origin.includes('localhost') || origin.includes('127.0.0.1'); + + let imageUrl: string; + if (isLocal) { + // Local replica: use the current origin's host with the canister subdomain + const port = window.location.port || '8000'; + imageUrl = `http://${canisterId}.localhost:${port}/image/${imageId}`; + } else { + imageUrl = `https://${canisterId}.icp0.io/image/${imageId}`; } - let imageUrl = `http://${canisterId}.${urlSuffix}/image/${imageId}`; - console.debug(`Getting url: ${imageUrl} for network: ${network}`); + console.debug(`Getting url: ${imageUrl}`); return imageUrl; }; diff --git a/rust/photo_gallery/frontend/src/actor.js b/rust/photo_gallery/frontend/src/actor.js new file mode 100644 index 0000000000..66d14e7853 --- /dev/null +++ b/rust/photo_gallery/frontend/src/actor.js @@ -0,0 +1,26 @@ +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; +import { createActor } from "./bindings/backend"; + +// The ic_env cookie is set by the asset canister (SDK >=0.30.2) on all HTML +// responses. It contains the replica root key and any PUBLIC_* canister +// environment variables. In dev mode the vite dev server sets the same cookie +// via Set-Cookie header (see vite.config.js). +const canisterEnv = safeGetCanisterEnv(); + +// Resolve canister ID: cookie (icp-cli + dev server) → env var (dfx build-time) +const canisterId = + canisterEnv?.["PUBLIC_CANISTER_ID:backend"] ?? + process.env.CANISTER_ID_BACKEND; + +if (!canisterId) { + throw new Error( + "Canister ID for 'backend' not found. Run 'icp deploy' or 'dfx deploy' first." + ); +} + +export const backend = createActor(canisterId, { + agentOptions: { + host: window.location.origin, + rootKey: canisterEnv?.IC_ROOT_KEY, + }, +}); diff --git a/rust/photo_gallery/frontend/tsconfig.json b/rust/photo_gallery/frontend/tsconfig.json index 39a545e919..d498e4dc90 100644 --- a/rust/photo_gallery/frontend/tsconfig.json +++ b/rust/photo_gallery/frontend/tsconfig.json @@ -3,7 +3,7 @@ "target": "ESNext", "useDefineForClassFields": true, "lib": ["DOM", "DOM.Iterable", "ESNext"], - "allowJs": false, + "allowJs": true, "skipLibCheck": true, "esModuleInterop": false, "allowSyntheticDefaultImports": true, diff --git a/rust/photo_gallery/frontend/vite.config.js b/rust/photo_gallery/frontend/vite.config.js index 2b9be940b5..de551a1021 100644 --- a/rust/photo_gallery/frontend/vite.config.js +++ b/rust/photo_gallery/frontend/vite.config.js @@ -1,40 +1,88 @@ -import { fileURLToPath, URL } from 'url'; -import react from '@vitejs/plugin-react'; -import { defineConfig } from 'vite'; -// This is needed to translate `process.env.` variables -import environment from 'vite-plugin-environment'; -import dotenv from 'dotenv'; +import { defineConfig, loadEnv } from "vite"; +import { execSync } from "child_process"; +import react from "@vitejs/plugin-react"; +import { icpBindgen } from "@icp-sdk/bindgen/plugins/vite"; -dotenv.config({ path: '../.env' }); -console.log("Loaded env:", process.env.DFX_NETWORK); +function getDevServerConfig() { + // Try icp-cli first + try { + const canisterId = execSync("icp canister status backend -e local -i", { + encoding: "utf-8", + stdio: "pipe", + }).trim(); + const networkStatus = JSON.parse( + execSync("icp network status --json", { + encoding: "utf-8", + stdio: "pipe", + }) + ); + return { + headers: { + "Set-Cookie": `ic_env=${encodeURIComponent( + `ic_root_key=${networkStatus.root_key}&PUBLIC_CANISTER_ID:backend=${canisterId}` + )}; SameSite=Lax;`, + }, + proxy: { + "/api": { target: "http://127.0.0.1:8000", changeOrigin: true }, + }, + }; + } catch {} -export default defineConfig({ - build: { - emptyOutDir: true, - minify: false, - }, - optimizeDeps: { - esbuildOptions: { - define: { - global: "globalThis", + // Try dfx + try { + const pingResult = JSON.parse( + execSync("dfx ping", { encoding: "utf-8", stdio: "pipe" }) + ); + const rootKeyHex = Buffer.from(pingResult.root_key).toString("hex"); + const canisterId = execSync("dfx canister id backend", { + encoding: "utf-8", + stdio: "pipe", + }).trim(); + return { + headers: { + "Set-Cookie": `ic_env=${encodeURIComponent( + `ic_root_key=${rootKeyHex}&PUBLIC_CANISTER_ID:backend=${canisterId}` + )}; SameSite=Lax;`, }, - }, - }, - server: { - proxy: { - "/api": { - target: "http://127.0.0.1:4943", - changeOrigin: true, + proxy: { + "/api": { + target: "http://127.0.0.1:4943", + changeOrigin: true, + }, }, + host: "127.0.0.1", + }; + } catch {} + + throw new Error( + "No local network running. Start with:\n icp network start -d && icp deploy\nor:\n dfx start --background && dfx deploy" + ); +} + +export default defineConfig(({ command, mode }) => { + // dfx generates ../.env with CANISTER_ID_* vars on deploy. Bake them into the + // bundle so actor.js can fall back to them when the ic_env cookie does not + // contain canister IDs (dfx does not inject PUBLIC_CANISTER_ID:* env vars + // into the asset canister, unlike icp-cli). + const env = loadEnv(mode, "..", ["CANISTER_"]); + + return { + base: "./", + plugins: [ + react(), + icpBindgen({ + didFile: "../backend/backend.did", + outDir: "./src/bindings", + }), + ], + define: { + "process.env.CANISTER_ID_BACKEND": JSON.stringify( + env.CANISTER_ID_BACKEND + ), + }, + optimizeDeps: { + esbuildOptions: { define: { global: "globalThis" } }, }, - }, - plugins: [ - react(), - environment("all", { prefix: "CANISTER_" }), - environment("all", { prefix: "DFX_" }), - ], - resolve: { - dedupe: ['@dfinity/agent'], - }, - envPrefix: ['VITE_', 'DFX_', 'CANISTER_'], // use to interpolate `import.meta.env` variables + server: command === "serve" ? getDevServerConfig() : undefined, + }; }); diff --git a/rust/photo_gallery/icp.yaml b/rust/photo_gallery/icp.yaml new file mode 100644 index 0000000000..c329eab309 --- /dev/null +++ b/rust/photo_gallery/icp.yaml @@ -0,0 +1,19 @@ +networks: + - name: local + mode: managed + +canisters: + - name: backend + recipe: + type: "@dfinity/rust@v3.3.0" + configuration: + candid: backend/backend.did + + - name: frontend + recipe: + type: "@dfinity/asset-canister@v2.2.1" + configuration: + dir: frontend/dist + build: + - npm install --prefix frontend + - npm run build --prefix frontend diff --git a/rust/photo_gallery/package.json b/rust/photo_gallery/package.json index d5ce52c366..59eee587db 100644 --- a/rust/photo_gallery/package.json +++ b/rust/photo_gallery/package.json @@ -1,21 +1,12 @@ { - "engines": { - "node": ">=16.0.0", - "npm": ">=7.0.0" - }, - "name": "pictures-site", + "name": "photo_gallery", "scripts": { "build": "npm run build --workspaces --if-present", "prebuild": "npm run prebuild --workspaces --if-present", - "pretest": "npm run prebuild --workspaces --if-present", - "start": "npm start --workspaces --if-present", - "test": "npm test --workspaces --if-present" + "dev": "npm run dev --workspaces --if-present" }, "type": "module", "workspaces": [ "frontend" - ], - "devDependencies": { - "vite": "^6.3.5" - } + ] } diff --git a/rust/photo_gallery/rust-toolchain.toml b/rust/photo_gallery/rust-toolchain.toml new file mode 100644 index 0000000000..990104f055 --- /dev/null +++ b/rust/photo_gallery/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +targets = ["wasm32-unknown-unknown"] diff --git a/rust/photo_gallery/tsconfig.json b/rust/photo_gallery/tsconfig.json deleted file mode 100644 index f4629166d9..0000000000 --- a/rust/photo_gallery/tsconfig.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "compilerOptions": { - "strict": true, - "target": "ES2020", - "experimentalDecorators": true, - "strictPropertyInitialization": false, - "moduleResolution": "node", - "allowJs": true, - "outDir": "HACK_BECAUSE_OF_ALLOW_JS" - } -}