From 88bdad962d514da152dd435e9719ec78556938a2 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 13:16:47 +0200 Subject: [PATCH 01/24] feat(frontend): migrate @dfinity/vetkeys library from @dfinity/* to @icp-sdk/core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace @dfinity/agent, @dfinity/candid, @dfinity/principal, @dfinity/identity with @icp-sdk/core - DefaultEncryptedMapsClient and DefaultKeyManagerClient constructors now accept HttpAgent directly instead of HttpAgentOptions (BREAKING — see CHANGELOG.md) - Remove generated index.js/index.d.ts wrappers, import idlFactory directly - Update test helpers to use HttpAgent.create() from @icp-sdk/core/agent - Update local dev network port from 4943 to 8000 - Test scripts migrated from dfx CLI to icp CLI Co-Authored-By: Claude Sonnet 4.6 --- frontend/ic_vetkeys/CHANGELOG.md | 14 + frontend/ic_vetkeys/make_did_bindings.sh | 11 +- frontend/ic_vetkeys/package.json | 15 +- ...c_vetkeys_encrypted_maps_canister.did.d.ts | 18 +- .../ic_vetkeys_encrypted_maps_canister.did.js | 14 +- .../ic_vetkeys_encrypted_maps_canister.ts | 410 ++++++++++++++++++ .../ic_vetkeys_manager_canister.did.d.ts | 18 +- .../ic_vetkeys_manager_canister.did.js | 14 +- .../ic_vetkeys_manager_canister.ts | 250 +++++++++++ .../encrypted_maps_canister.test.ts | 7 +- .../encrypted_maps/encrypted_maps_canister.ts | 11 +- .../ic_vetkeys/src/encrypted_maps/index.ts | 2 +- frontend/ic_vetkeys/src/key_manager/index.ts | 4 +- .../key_manager/key_manager_canister.test.ts | 9 +- .../src/key_manager/key_manager_canister.ts | 11 +- frontend/ic_vetkeys/src/utils/utils.ts | 2 +- 16 files changed, 762 insertions(+), 48 deletions(-) create mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.ts create mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.ts diff --git a/frontend/ic_vetkeys/CHANGELOG.md b/frontend/ic_vetkeys/CHANGELOG.md index e8c8c7db..66dc91d8 100644 --- a/frontend/ic_vetkeys/CHANGELOG.md +++ b/frontend/ic_vetkeys/CHANGELOG.md @@ -12,6 +12,20 @@ ### Changed +- **BREAKING** `DefaultEncryptedMapsClient` and `DefaultKeyManagerClient` + constructors now accept an `HttpAgent` (from `@icp-sdk/core/agent`) instead of + `HttpAgentOptions`. Since `HttpAgent.create()` is async, the agent must be + created by the caller before being passed in — this avoids relying on the + deprecated `HttpAgent.createSync()` and allows full configuration upfront, + including providing the network's root key for local development: + ```ts + const agent = await HttpAgent.create({ + host, + identity, + ...(rootKey ? { rootKey } : {}), // rootKey from ic_env cookie in local dev + }); + new DefaultEncryptedMapsClient(agent, canisterId); + ``` - Make `DerivedKeyMaterial.deriveAesGcmCryptoKey` `@internal`. diff --git a/frontend/ic_vetkeys/make_did_bindings.sh b/frontend/ic_vetkeys/make_did_bindings.sh index 6d6dc291..cf88d0dd 100755 --- a/frontend/ic_vetkeys/make_did_bindings.sh +++ b/frontend/ic_vetkeys/make_did_bindings.sh @@ -3,15 +3,16 @@ set -ex function make_and_copy_declarations () { DIR=$1 NAME=$2 + DID_FILE=$3 pushd "$DIR""$NAME" make extract-candid - dfx generate $NAME popd - rm -r "src/declarations/$NAME" - mv "$DIR/""$NAME""/src/declarations/""$NAME" "src/declarations/" + rm -rf "src/declarations/$NAME" + mkdir -p "src/declarations/$NAME" + npx @icp-sdk/bindgen --did-file "$DIR$NAME/$DID_FILE" --out-dir "src/declarations/$NAME" --declarations-flat --force } -make_and_copy_declarations "../../backend/rs/canisters/" "ic_vetkeys_manager_canister" -make_and_copy_declarations "../../backend/rs/canisters/" "ic_vetkeys_encrypted_maps_canister" +make_and_copy_declarations "../../backend/rs/canisters/" "ic_vetkeys_manager_canister" "ic_vetkeys_manager_canister.did" +make_and_copy_declarations "../../backend/rs/canisters/" "ic_vetkeys_encrypted_maps_canister" "ic_vetkeys_encrypted_maps_canister.did" diff --git a/frontend/ic_vetkeys/package.json b/frontend/ic_vetkeys/package.json index be24eb93..4292b7e9 100644 --- a/frontend/ic_vetkeys/package.json +++ b/frontend/ic_vetkeys/package.json @@ -57,13 +57,10 @@ "module": "dist/lib/index.es.js", "typings": "dist/types/index.d.ts", "dependencies": { - "@dfinity/agent": "^3.4.0", - "@dfinity/candid": "^3.4.0", - "@dfinity/principal": "^3.4.0", + "@icp-sdk/core": "^5.2.1", "idb-keyval": "^6.2.1" }, "devDependencies": { - "@dfinity/identity": "^3.4.0", "@eslint/js": "^9.22.0", "@types/node": "^24.0.4", "@vitest/coverage-v8": "^3.0.5", @@ -84,15 +81,15 @@ "scripts": { "build": "tsc && vite build", "prepare": "npm run build", - "coverage": "npm run test:deploy_all && export $(cat .test1.env .test2.env | xargs) && vitest run --coverage", + "coverage": "npm run test:deploy_all && CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER=$(cd $(git rev-parse --show-toplevel)/backend/rs/canisters && icp canister status ic_vetkeys_manager_canister -e local --id-only) CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER=$(cd $(git rev-parse --show-toplevel)/backend/rs/canisters && icp canister status ic_vetkeys_encrypted_maps_canister -e local --id-only) vitest run --coverage", "lint": "eslint", "make:docs": "mkdir -p $(git rev-parse --show-toplevel)/docs/key_manager && mkdir -p $(git rev-parse --show-toplevel)/docs/encrypted_maps && typedoc --out $(git rev-parse --show-toplevel)/docs", "prettier": "prettier --write .", "prettier-check": "prettier --check .", "test_utils": "vitest utils", - "test": "npm run test:deploy_all && export $(cat .test1.env .test2.env | xargs) && vitest --sequence.concurrent", - "test:deploy_all": "npm run test:deploy_key_manager_canister && npm run test:deploy_encrypted_maps_canister", - "test:deploy_key_manager_canister": "cd $(git rev-parse --show-toplevel)/backend/rs/canisters/ic_vetkeys_manager_canister && dfx start --clean --background; dfx deploy --argument '(\"dfx_test_key\")' ic_vetkeys_manager_canister && grep CANISTER_ID .env > $(git rev-parse --show-toplevel)/frontend/ic_vetkeys/.test1.env", - "test:deploy_encrypted_maps_canister": "cd $(git rev-parse --show-toplevel)/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister && dfx start --clean --background; dfx deploy --argument '(\"dfx_test_key\")' ic_vetkeys_encrypted_maps_canister && grep CANISTER_ID .env > $(git rev-parse --show-toplevel)/frontend/ic_vetkeys/.test2.env" + "test": "npm run test:deploy_all && CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER=$(cd $(git rev-parse --show-toplevel)/backend/rs/canisters && icp canister status ic_vetkeys_manager_canister -e local --id-only) CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER=$(cd $(git rev-parse --show-toplevel)/backend/rs/canisters && icp canister status ic_vetkeys_encrypted_maps_canister -e local --id-only) vitest run --sequence.concurrent", + "test:deploy_all": "cd $(git rev-parse --show-toplevel)/backend/rs/canisters && (icp network stop || true) && icp network start -d && icp deploy ic_vetkeys_manager_canister -e local && icp deploy ic_vetkeys_encrypted_maps_canister -e local", + "test:deploy_key_manager_canister": "cd $(git rev-parse --show-toplevel)/backend/rs/canisters && (icp network stop || true) && icp network start -d && icp deploy ic_vetkeys_manager_canister -e local", + "test:deploy_encrypted_maps_canister": "cd $(git rev-parse --show-toplevel)/backend/rs/canisters && (icp network stop || true) && icp network start -d && icp deploy ic_vetkeys_encrypted_maps_canister -e local" } } diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.d.ts b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.d.ts index 88495747..1d802fa0 100644 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.d.ts +++ b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.d.ts @@ -1,11 +1,19 @@ -import type { Principal } from '@dfinity/principal'; -import type { ActorMethod } from '@dfinity/agent'; -import type { IDL } from '@dfinity/candid'; +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.3.0. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import type { ActorMethod } from '@icp-sdk/core/agent'; +import type { IDL } from '@icp-sdk/core/candid'; +import type { Principal } from '@icp-sdk/core/principal'; export type AccessRights = { 'Read' : null } | { 'ReadWrite' : null } | { 'ReadWriteManage' : null }; -export interface ByteBuf { 'inner' : Uint8Array | number[] } +export interface ByteBuf { 'inner' : Uint8Array } export interface EncryptedMapData { 'access_control' : Array<[Principal, AccessRights]>, 'keyvals' : Array<[ByteBuf, ByteBuf]>, @@ -60,4 +68,4 @@ export interface _SERVICE { >, } export declare const idlFactory: IDL.InterfaceFactory; -export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; \ No newline at end of file diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.js b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.js index db02c948..fb281ec5 100644 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.js +++ b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.js @@ -1,3 +1,13 @@ +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.3.0. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { IDL } from '@icp-sdk/core/candid'; + export const idlFactory = ({ IDL }) => { const ByteBuf = IDL.Record({ 'inner' : IDL.Vec(IDL.Nat8) }); const AccessRights = IDL.Variant({ @@ -26,6 +36,7 @@ export const idlFactory = ({ IDL }) => { 'Err' : IDL.Text, }); const Result_5 = IDL.Variant({ 'Ok' : IDL.Vec(ByteBuf), 'Err' : IDL.Text }); + return IDL.Service({ 'get_accessible_shared_map_names' : IDL.Func( [], @@ -103,4 +114,5 @@ export const idlFactory = ({ IDL }) => { ), }); }; -export const init = ({ IDL }) => { return []; }; + +export const init = ({ IDL }) => { return [IDL.Text]; }; \ No newline at end of file diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.ts b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.ts new file mode 100644 index 00000000..6d33f5bc --- /dev/null +++ b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.ts @@ -0,0 +1,410 @@ +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.3.0. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Actor, HttpAgent, type HttpAgentOptions, type ActorConfig, type Agent, type ActorSubclass } from "@icp-sdk/core/agent"; +import type { Principal } from "@icp-sdk/core/principal"; +import { idlFactory, type _SERVICE } from "./ic_vetkeys_encrypted_maps_canister.did"; +export interface Some { + __kind__: "Some"; + value: T; +} +export interface None { + __kind__: "None"; +} +export type Option = Some | None; +function some(value: T): Some { + return { + __kind__: "Some", + value: value + }; +} +function none(): None { + return { + __kind__: "None" + }; +} +function isNone(option: Option): option is None { + return option.__kind__ === "None"; +} +function isSome(option: Option): option is Some { + return option.__kind__ === "Some"; +} +function unwrap(option: Option): T { + if (isNone(option)) { + throw new Error("unwrap: none"); + } + return option.value; +} +function candid_some(value: T): [T] { + return [ + value + ]; +} +function candid_none(): [] { + return []; +} +function record_opt_to_undefined(arg: T | null): T | undefined { + return arg == null ? undefined : arg; +} +export type Result_4 = { + __kind__: "Ok"; + Ok: AccessRights | null; +} | { + __kind__: "Err"; + Err: string; +}; +export type Result_2 = { + __kind__: "Ok"; + Ok: ByteBuf; +} | { + __kind__: "Err"; + Err: string; +}; +export type Result = { + __kind__: "Ok"; + Ok: ByteBuf | null; +} | { + __kind__: "Err"; + Err: string; +}; +export type Result_3 = { + __kind__: "Ok"; + Ok: Array<[Principal, AccessRights]>; +} | { + __kind__: "Err"; + Err: string; +}; +export interface EncryptedMapData { + access_control: Array<[Principal, AccessRights]>; + keyvals: Array<[ByteBuf, ByteBuf]>; + map_name: ByteBuf; + map_owner: Principal; +} +export type Result_5 = { + __kind__: "Ok"; + Ok: Array; +} | { + __kind__: "Err"; + Err: string; +}; +export interface ByteBuf { + inner: Uint8Array; +} +export type Result_1 = { + __kind__: "Ok"; + Ok: Array<[ByteBuf, ByteBuf]>; +} | { + __kind__: "Err"; + Err: string; +}; +export enum AccessRights { + Read = "Read", + ReadWrite = "ReadWrite", + ReadWriteManage = "ReadWriteManage" +} +export interface ic_vetkeys_encrypted_maps_canisterInterface { + get_accessible_shared_map_names(): Promise>; + get_all_accessible_encrypted_maps(): Promise>; + get_all_accessible_encrypted_values(): Promise]>>; + get_encrypted_value(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise; + get_encrypted_values_for_map(arg0: Principal, arg1: ByteBuf): Promise; + get_encrypted_vetkey(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise; + get_owned_non_empty_map_names(): Promise>; + get_shared_user_access_for_map(arg0: Principal, arg1: ByteBuf): Promise; + get_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise; + get_vetkey_verification_key(): Promise; + insert_encrypted_value(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf, arg3: ByteBuf): Promise; + remove_encrypted_value(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise; + remove_map_values(arg0: Principal, arg1: ByteBuf): Promise; + remove_user(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise; + set_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal, arg3: AccessRights): Promise; +} +import type { AccessRights as _AccessRights, ByteBuf as _ByteBuf, EncryptedMapData as _EncryptedMapData, Result as _Result, Result_1 as _Result_1, Result_2 as _Result_2, Result_3 as _Result_3, Result_4 as _Result_4, Result_5 as _Result_5 } from "./ic_vetkeys_encrypted_maps_canister.did"; +export class Ic_vetkeys_encrypted_maps_canister implements ic_vetkeys_encrypted_maps_canisterInterface { + constructor(private actor: ActorSubclass<_SERVICE>){} + async get_accessible_shared_map_names(): Promise> { + const result = await this.actor.get_accessible_shared_map_names(); + return result; + } + async get_all_accessible_encrypted_maps(): Promise> { + const result = await this.actor.get_all_accessible_encrypted_maps(); + return from_candid_vec_n1(result); + } + async get_all_accessible_encrypted_values(): Promise]>> { + const result = await this.actor.get_all_accessible_encrypted_values(); + return result; + } + async get_encrypted_value(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise { + const result = await this.actor.get_encrypted_value(arg0, arg1, arg2); + return from_candid_Result_n8(result); + } + async get_encrypted_values_for_map(arg0: Principal, arg1: ByteBuf): Promise { + const result = await this.actor.get_encrypted_values_for_map(arg0, arg1); + return from_candid_Result_1_n11(result); + } + async get_encrypted_vetkey(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise { + const result = await this.actor.get_encrypted_vetkey(arg0, arg1, arg2); + return from_candid_Result_2_n13(result); + } + async get_owned_non_empty_map_names(): Promise> { + const result = await this.actor.get_owned_non_empty_map_names(); + return result; + } + async get_shared_user_access_for_map(arg0: Principal, arg1: ByteBuf): Promise { + const result = await this.actor.get_shared_user_access_for_map(arg0, arg1); + return from_candid_Result_3_n15(result); + } + async get_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise { + const result = await this.actor.get_user_rights(arg0, arg1, arg2); + return from_candid_Result_4_n17(result); + } + async get_vetkey_verification_key(): Promise { + const result = await this.actor.get_vetkey_verification_key(); + return result; + } + async insert_encrypted_value(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf, arg3: ByteBuf): Promise { + const result = await this.actor.insert_encrypted_value(arg0, arg1, arg2, arg3); + return from_candid_Result_n8(result); + } + async remove_encrypted_value(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise { + const result = await this.actor.remove_encrypted_value(arg0, arg1, arg2); + return from_candid_Result_n8(result); + } + async remove_map_values(arg0: Principal, arg1: ByteBuf): Promise { + const result = await this.actor.remove_map_values(arg0, arg1); + return from_candid_Result_5_n20(result); + } + async remove_user(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise { + const result = await this.actor.remove_user(arg0, arg1, arg2); + return from_candid_Result_4_n17(result); + } + async set_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal, arg3: AccessRights): Promise { + const result = await this.actor.set_user_rights(arg0, arg1, arg2, to_candid_AccessRights_n22(arg3)); + return from_candid_Result_4_n17(result); + } +} +function from_candid_AccessRights_n6(value: _AccessRights): AccessRights { + return from_candid_variant_n7(value); +} +function from_candid_EncryptedMapData_n2(value: _EncryptedMapData): EncryptedMapData { + return from_candid_record_n3(value); +} +function from_candid_Result_1_n11(value: _Result_1): Result_1 { + return from_candid_variant_n12(value); +} +function from_candid_Result_2_n13(value: _Result_2): Result_2 { + return from_candid_variant_n14(value); +} +function from_candid_Result_3_n15(value: _Result_3): Result_3 { + return from_candid_variant_n16(value); +} +function from_candid_Result_4_n17(value: _Result_4): Result_4 { + return from_candid_variant_n18(value); +} +function from_candid_Result_5_n20(value: _Result_5): Result_5 { + return from_candid_variant_n21(value); +} +function from_candid_Result_n8(value: _Result): Result { + return from_candid_variant_n9(value); +} +function from_candid_opt_n10(value: [] | [_ByteBuf]): ByteBuf | null { + return value.length === 0 ? null : value[0]; +} +function from_candid_opt_n19(value: [] | [_AccessRights]): AccessRights | null { + return value.length === 0 ? null : from_candid_AccessRights_n6(value[0]); +} +function from_candid_record_n3(value: { + access_control: Array<[Principal, _AccessRights]>; + keyvals: Array<[_ByteBuf, _ByteBuf]>; + map_name: _ByteBuf; + map_owner: Principal; +}): { + access_control: Array<[Principal, AccessRights]>; + keyvals: Array<[ByteBuf, ByteBuf]>; + map_name: ByteBuf; + map_owner: Principal; +} { + return { + access_control: from_candid_vec_n4(value.access_control), + keyvals: value.keyvals, + map_name: value.map_name, + map_owner: value.map_owner + }; +} +function from_candid_tuple_n5(value: [Principal, _AccessRights]): [Principal, AccessRights] { + return [ + value[0], + from_candid_AccessRights_n6(value[1]) + ]; +} +function from_candid_variant_n12(value: { + Ok: Array<[_ByteBuf, _ByteBuf]>; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: Array<[ByteBuf, ByteBuf]>; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: value.Ok + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n14(value: { + Ok: _ByteBuf; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: ByteBuf; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: value.Ok + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n16(value: { + Ok: Array<[Principal, _AccessRights]>; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: Array<[Principal, AccessRights]>; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: from_candid_vec_n4(value.Ok) + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n18(value: { + Ok: [] | [_AccessRights]; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: AccessRights | null; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: from_candid_opt_n19(value.Ok) + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n21(value: { + Ok: Array<_ByteBuf>; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: Array; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: value.Ok + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n7(value: { + Read: null; +} | { + ReadWrite: null; +} | { + ReadWriteManage: null; +}): AccessRights { + return "Read" in value ? AccessRights.Read : "ReadWrite" in value ? AccessRights.ReadWrite : "ReadWriteManage" in value ? AccessRights.ReadWriteManage : value; +} +function from_candid_variant_n9(value: { + Ok: [] | [_ByteBuf]; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: ByteBuf | null; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: from_candid_opt_n10(value.Ok) + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_vec_n1(value: Array<_EncryptedMapData>): Array { + return value.map((x)=>from_candid_EncryptedMapData_n2(x)); +} +function from_candid_vec_n4(value: Array<[Principal, _AccessRights]>): Array<[Principal, AccessRights]> { + return value.map((x)=>from_candid_tuple_n5(x)); +} +function to_candid_AccessRights_n22(value: AccessRights): _AccessRights { + return to_candid_variant_n23(value); +} +function to_candid_variant_n23(value: AccessRights): { + Read: null; +} | { + ReadWrite: null; +} | { + ReadWriteManage: null; +} { + return value == AccessRights.Read ? { + Read: null + } : value == AccessRights.ReadWrite ? { + ReadWrite: null + } : value == AccessRights.ReadWriteManage ? { + ReadWriteManage: null + } : value; +} +export interface CreateActorOptions { + agent?: Agent; + agentOptions?: HttpAgentOptions; + actorOptions?: ActorConfig; +} +export function createActor(canisterId: string, options: CreateActorOptions = {}): Ic_vetkeys_encrypted_maps_canister { + const agent = options.agent || HttpAgent.createSync({ + ...options.agentOptions + }); + if (options.agent && options.agentOptions) { + console.warn("Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent."); + } + const actor = Actor.createActor<_SERVICE>(idlFactory, { + agent, + canisterId: canisterId, + ...options.actorOptions + }); + return new Ic_vetkeys_encrypted_maps_canister(actor); +} diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.d.ts b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.d.ts index abdd5914..a4ff0e4a 100644 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.d.ts +++ b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.d.ts @@ -1,11 +1,19 @@ -import type { Principal } from '@dfinity/principal'; -import type { ActorMethod } from '@dfinity/agent'; -import type { IDL } from '@dfinity/candid'; +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.3.0. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import type { ActorMethod } from '@icp-sdk/core/agent'; +import type { IDL } from '@icp-sdk/core/candid'; +import type { Principal } from '@icp-sdk/core/principal'; export type AccessRights = { 'Read' : null } | { 'ReadWrite' : null } | { 'ReadWriteManage' : null }; -export interface ByteBuf { 'inner' : Uint8Array | number[] } +export interface ByteBuf { 'inner' : Uint8Array } export type Result = { 'Ok' : ByteBuf } | { 'Err' : string }; export type Result_1 = { 'Ok' : Array<[Principal, AccessRights]> } | @@ -31,4 +39,4 @@ export interface _SERVICE { >, } export declare const idlFactory: IDL.InterfaceFactory; -export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; +export declare const init: (args: { IDL: typeof IDL }) => IDL.Type[]; \ No newline at end of file diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js index 86162e2d..5633526a 100644 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js +++ b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js @@ -1,3 +1,13 @@ +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.3.0. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { IDL } from '@icp-sdk/core/candid'; + export const idlFactory = ({ IDL }) => { const ByteBuf = IDL.Record({ 'inner' : IDL.Vec(IDL.Nat8) }); const Result = IDL.Variant({ 'Ok' : ByteBuf, 'Err' : IDL.Text }); @@ -14,6 +24,7 @@ export const idlFactory = ({ IDL }) => { 'Ok' : IDL.Opt(AccessRights), 'Err' : IDL.Text, }); + return IDL.Service({ 'get_accessible_shared_key_ids' : IDL.Func( [], @@ -48,4 +59,5 @@ export const idlFactory = ({ IDL }) => { ), }); }; -export const init = ({ IDL }) => { return []; }; + +export const init = ({ IDL }) => { return [IDL.Text]; }; \ No newline at end of file diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.ts b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.ts new file mode 100644 index 00000000..cfb8b481 --- /dev/null +++ b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.ts @@ -0,0 +1,250 @@ +/* eslint-disable */ + +// @ts-nocheck + +// This file was automatically generated by @icp-sdk/bindgen@0.3.0. +// You should NOT make any changes in this file as it will be overwritten. +// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified. + +import { Actor, HttpAgent, type HttpAgentOptions, type ActorConfig, type Agent, type ActorSubclass } from "@icp-sdk/core/agent"; +import type { Principal } from "@icp-sdk/core/principal"; +import { idlFactory, type _SERVICE } from "./ic_vetkeys_manager_canister.did"; +export interface Some { + __kind__: "Some"; + value: T; +} +export interface None { + __kind__: "None"; +} +export type Option = Some | None; +function some(value: T): Some { + return { + __kind__: "Some", + value: value + }; +} +function none(): None { + return { + __kind__: "None" + }; +} +function isNone(option: Option): option is None { + return option.__kind__ === "None"; +} +function isSome(option: Option): option is Some { + return option.__kind__ === "Some"; +} +function unwrap(option: Option): T { + if (isNone(option)) { + throw new Error("unwrap: none"); + } + return option.value; +} +function candid_some(value: T): [T] { + return [ + value + ]; +} +function candid_none(): [] { + return []; +} +function record_opt_to_undefined(arg: T | null): T | undefined { + return arg == null ? undefined : arg; +} +export type Result_2 = { + __kind__: "Ok"; + Ok: AccessRights | null; +} | { + __kind__: "Err"; + Err: string; +}; +export type Result = { + __kind__: "Ok"; + Ok: ByteBuf; +} | { + __kind__: "Err"; + Err: string; +}; +export interface ByteBuf { + inner: Uint8Array; +} +export type Result_1 = { + __kind__: "Ok"; + Ok: Array<[Principal, AccessRights]>; +} | { + __kind__: "Err"; + Err: string; +}; +export enum AccessRights { + Read = "Read", + ReadWrite = "ReadWrite", + ReadWriteManage = "ReadWriteManage" +} +export interface ic_vetkeys_manager_canisterInterface { + get_accessible_shared_key_ids(): Promise>; + get_encrypted_vetkey(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise; + get_shared_user_access_for_key(arg0: Principal, arg1: ByteBuf): Promise; + get_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise; + get_vetkey_verification_key(): Promise; + remove_user(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise; + set_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal, arg3: AccessRights): Promise; +} +import type { AccessRights as _AccessRights, ByteBuf as _ByteBuf, Result as _Result, Result_1 as _Result_1, Result_2 as _Result_2 } from "./ic_vetkeys_manager_canister.did"; +export class Ic_vetkeys_manager_canister implements ic_vetkeys_manager_canisterInterface { + constructor(private actor: ActorSubclass<_SERVICE>){} + async get_accessible_shared_key_ids(): Promise> { + const result = await this.actor.get_accessible_shared_key_ids(); + return result; + } + async get_encrypted_vetkey(arg0: Principal, arg1: ByteBuf, arg2: ByteBuf): Promise { + const result = await this.actor.get_encrypted_vetkey(arg0, arg1, arg2); + return from_candid_Result_n1(result); + } + async get_shared_user_access_for_key(arg0: Principal, arg1: ByteBuf): Promise { + const result = await this.actor.get_shared_user_access_for_key(arg0, arg1); + return from_candid_Result_1_n3(result); + } + async get_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise { + const result = await this.actor.get_user_rights(arg0, arg1, arg2); + return from_candid_Result_2_n9(result); + } + async get_vetkey_verification_key(): Promise { + const result = await this.actor.get_vetkey_verification_key(); + return result; + } + async remove_user(arg0: Principal, arg1: ByteBuf, arg2: Principal): Promise { + const result = await this.actor.remove_user(arg0, arg1, arg2); + return from_candid_Result_2_n9(result); + } + async set_user_rights(arg0: Principal, arg1: ByteBuf, arg2: Principal, arg3: AccessRights): Promise { + const result = await this.actor.set_user_rights(arg0, arg1, arg2, to_candid_AccessRights_n12(arg3)); + return from_candid_Result_2_n9(result); + } +} +function from_candid_AccessRights_n7(value: _AccessRights): AccessRights { + return from_candid_variant_n8(value); +} +function from_candid_Result_1_n3(value: _Result_1): Result_1 { + return from_candid_variant_n4(value); +} +function from_candid_Result_2_n9(value: _Result_2): Result_2 { + return from_candid_variant_n10(value); +} +function from_candid_Result_n1(value: _Result): Result { + return from_candid_variant_n2(value); +} +function from_candid_opt_n11(value: [] | [_AccessRights]): AccessRights | null { + return value.length === 0 ? null : from_candid_AccessRights_n7(value[0]); +} +function from_candid_tuple_n6(value: [Principal, _AccessRights]): [Principal, AccessRights] { + return [ + value[0], + from_candid_AccessRights_n7(value[1]) + ]; +} +function from_candid_variant_n10(value: { + Ok: [] | [_AccessRights]; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: AccessRights | null; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: from_candid_opt_n11(value.Ok) + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n2(value: { + Ok: _ByteBuf; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: ByteBuf; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: value.Ok + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n4(value: { + Ok: Array<[Principal, _AccessRights]>; +} | { + Err: string; +}): { + __kind__: "Ok"; + Ok: Array<[Principal, AccessRights]>; +} | { + __kind__: "Err"; + Err: string; +} { + return "Ok" in value ? { + __kind__: "Ok", + Ok: from_candid_vec_n5(value.Ok) + } : "Err" in value ? { + __kind__: "Err", + Err: value.Err + } : value; +} +function from_candid_variant_n8(value: { + Read: null; +} | { + ReadWrite: null; +} | { + ReadWriteManage: null; +}): AccessRights { + return "Read" in value ? AccessRights.Read : "ReadWrite" in value ? AccessRights.ReadWrite : "ReadWriteManage" in value ? AccessRights.ReadWriteManage : value; +} +function from_candid_vec_n5(value: Array<[Principal, _AccessRights]>): Array<[Principal, AccessRights]> { + return value.map((x)=>from_candid_tuple_n6(x)); +} +function to_candid_AccessRights_n12(value: AccessRights): _AccessRights { + return to_candid_variant_n13(value); +} +function to_candid_variant_n13(value: AccessRights): { + Read: null; +} | { + ReadWrite: null; +} | { + ReadWriteManage: null; +} { + return value == AccessRights.Read ? { + Read: null + } : value == AccessRights.ReadWrite ? { + ReadWrite: null + } : value == AccessRights.ReadWriteManage ? { + ReadWriteManage: null + } : value; +} +export interface CreateActorOptions { + agent?: Agent; + agentOptions?: HttpAgentOptions; + actorOptions?: ActorConfig; +} +export function createActor(canisterId: string, options: CreateActorOptions = {}): Ic_vetkeys_manager_canister { + const agent = options.agent || HttpAgent.createSync({ + ...options.agentOptions + }); + if (options.agent && options.agentOptions) { + console.warn("Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent."); + } + const actor = Actor.createActor<_SERVICE>(idlFactory, { + agent, + canisterId: canisterId, + ...options.actorOptions + }); + return new Ic_vetkeys_manager_canister(actor); +} diff --git a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts index 9aeab0ba..ab75c0a3 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts @@ -1,8 +1,8 @@ -import { HttpAgent } from "@dfinity/agent"; import { DefaultEncryptedMapsClient } from "./encrypted_maps_canister"; import { expect, test } from "vitest"; import fetch from "isomorphic-fetch"; -import { Ed25519KeyIdentity } from "@dfinity/identity"; +import { Ed25519KeyIdentity } from "@icp-sdk/core/identity"; +import { HttpAgent } from "@icp-sdk/core/agent"; import { EncryptedMaps } from "./index"; import { randomBytes } from "node:crypto"; @@ -17,11 +17,10 @@ function ids(): [Ed25519KeyIdentity, Ed25519KeyIdentity] { async function newEncryptedMaps( id: Ed25519KeyIdentity, ): Promise { - const host = "http://localhost:4943"; const agent = await HttpAgent.create({ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment fetch, - host, + host: "http://localhost:8000", identity: id, shouldFetchRootKey: true, }); diff --git a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts index 1b425e5f..4010d53b 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts @@ -1,6 +1,6 @@ -import { Principal } from "@dfinity/principal"; -import { ActorSubclass, HttpAgent } from "@dfinity/agent"; -import { createActor } from "../declarations/ic_vetkeys_encrypted_maps_canister/index"; +import { Principal } from "@icp-sdk/core/principal"; +import { Actor, ActorSubclass, HttpAgent } from "@icp-sdk/core/agent"; +import { idlFactory } from "../declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did"; import { _SERVICE as _DEFAULT_ENCRYPTED_MAPS_SERVICE, AccessRights, @@ -13,7 +13,10 @@ export class DefaultEncryptedMapsClient implements EncryptedMapsClient { actor: ActorSubclass<_DEFAULT_ENCRYPTED_MAPS_SERVICE>; constructor(agent: HttpAgent, canisterId: string) { - this.actor = createActor(canisterId, { agent: agent }); + this.actor = Actor.createActor(idlFactory, { + agent, + canisterId, + }); } get_accessible_shared_map_names(): Promise<[Principal, ByteBuf][]> { diff --git a/frontend/ic_vetkeys/src/encrypted_maps/index.ts b/frontend/ic_vetkeys/src/encrypted_maps/index.ts index 6edff81e..02fe5db8 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/index.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/index.ts @@ -4,7 +4,7 @@ * @description See { @link EncryptedMaps }. */ -import { Principal } from "@dfinity/principal"; +import { Principal } from "@icp-sdk/core/principal"; import { get, set } from "idb-keyval"; import { TransportSecretKey, diff --git a/frontend/ic_vetkeys/src/key_manager/index.ts b/frontend/ic_vetkeys/src/key_manager/index.ts index 9c7c4df4..c04085d0 100644 --- a/frontend/ic_vetkeys/src/key_manager/index.ts +++ b/frontend/ic_vetkeys/src/key_manager/index.ts @@ -5,7 +5,7 @@ * */ -import { Principal } from "@dfinity/principal"; +import { Principal } from "@icp-sdk/core/principal"; import { TransportSecretKey, EncryptedVetKey, @@ -367,5 +367,5 @@ export interface KeyManagerClient { } function arrayToByteBuf(a: Uint8Array): ByteBuf { - return { inner: Array.from(a) }; + return { inner: a }; } diff --git a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts index 6d1388c1..e6c3b0cd 100644 --- a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts +++ b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts @@ -1,9 +1,9 @@ -import { HttpAgent } from "@dfinity/agent"; -import { Ed25519KeyIdentity } from "@dfinity/identity"; +import { Ed25519KeyIdentity } from "@icp-sdk/core/identity"; import fetch from "isomorphic-fetch"; import { expect, test } from "vitest"; import { KeyManager } from "./index"; import { DefaultKeyManagerClient } from "./key_manager_canister"; +import { HttpAgent } from "@icp-sdk/core/agent"; import { randomBytes } from "node:crypto"; function randomId(): Ed25519KeyIdentity { @@ -15,15 +15,12 @@ function ids(): [Ed25519KeyIdentity, Ed25519KeyIdentity] { } async function newKeyManager(id: Ed25519KeyIdentity): Promise { - const host = "http://127.0.0.1:4943"; const agent = await HttpAgent.create({ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment fetch, - host, + host: "http://127.0.0.1:8000", identity: id, shouldFetchRootKey: true, - }).catch((err) => { - throw err; }); const canisterId = process.env.CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER; return new KeyManager(new DefaultKeyManagerClient(agent, canisterId)); diff --git a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts index bd4a9899..b9523379 100644 --- a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts +++ b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts @@ -1,6 +1,6 @@ -import { Principal } from "@dfinity/principal"; -import { ActorSubclass, HttpAgent } from "@dfinity/agent"; -import { createActor } from "../declarations/ic_vetkeys_manager_canister/index.js"; +import { Principal } from "@icp-sdk/core/principal"; +import { Actor, ActorSubclass, HttpAgent } from "@icp-sdk/core/agent"; +import { idlFactory } from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js"; import { _SERVICE as _DEFAULT_KEY_MANAGER_SERVICE, AccessRights, @@ -15,7 +15,10 @@ export class DefaultKeyManagerClient implements KeyManagerClient { constructor(agent: HttpAgent, canisterId: string) { this.canisterId = canisterId; - this.actor = createActor(canisterId, { agent }); + this.actor = Actor.createActor(idlFactory, { + agent, + canisterId, + }); } get_accessible_shared_key_ids(): Promise<[Principal, ByteBuf][]> { diff --git a/frontend/ic_vetkeys/src/utils/utils.ts b/frontend/ic_vetkeys/src/utils/utils.ts index 3dbce019..a3ba58ef 100644 --- a/frontend/ic_vetkeys/src/utils/utils.ts +++ b/frontend/ic_vetkeys/src/utils/utils.ts @@ -5,7 +5,7 @@ import { hash_to_field, Opts } from "@noble/curves/abstract/hash-to-curve"; import { shake256 } from "@noble/hashes/sha3"; import { hkdf } from "@noble/hashes/hkdf"; import { sha256 } from "@noble/hashes/sha256"; -import type { Principal } from "@dfinity/principal"; +import type { Principal } from "@icp-sdk/core/principal"; export type G1Point = ProjPointType; export type G2Point = ProjPointType; From d3fb0f73c92987c0d6e3228521b94d475445bd4e Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 13:17:19 +0200 Subject: [PATCH 02/24] chore: migrate from dfx to icp-cli - Replace dfx install with icp-cli in provision-darwin.sh and provision-linux.sh - Add actions/setup-node v22 step to frontend.yml and all example workflows (required by icp-cli which needs Node.js >=22) - Replace dfx.json with icp.yaml in backend Motoko and Rust canisters - Update backend Makefiles to use icp instead of dfx - Update Rust integration tests to use icp canister IDs - Remove root dfx.json Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/frontend.yml | 14 +- .../workflows/provision-frontend-darwin.sh | 17 ++ .github/workflows/provision-frontend-linux.sh | 21 +++ .gitignore | 1 + .../Makefile | 5 +- .../dfx.json | 14 -- .../icp.yaml | 7 + .../mops.toml | 3 + .../ic_vetkeys_manager_canister/Makefile | 5 +- .../ic_vetkeys_manager_canister/dfx.json | 14 -- .../ic_vetkeys_manager_canister/icp.yaml | 7 + .../ic_vetkeys_manager_canister/mops.toml | 5 +- .../ic_vetkeys_manager_canister/src/Main.mo | 5 +- .../Makefile | 7 +- .../dfx.json | 10 - .../tests/tests.rs | 12 +- .../ic_vetkeys_manager_canister/Makefile | 6 +- .../ic_vetkeys_manager_canister/dfx.json | 10 - .../tests/tests.rs | 12 +- backend/rs/canisters/icp.yaml | 19 ++ .../rs/canisters/tests/tests/sign_with_bls.rs | 12 +- dfx.json | 8 - package-lock.json | 171 +++++++++++------- 23 files changed, 243 insertions(+), 142 deletions(-) create mode 100644 .github/workflows/provision-frontend-darwin.sh create mode 100644 .github/workflows/provision-frontend-linux.sh delete mode 100644 backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json create mode 100644 backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/icp.yaml delete mode 100644 backend/mo/canisters/ic_vetkeys_manager_canister/dfx.json create mode 100644 backend/mo/canisters/ic_vetkeys_manager_canister/icp.yaml delete mode 100644 backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json delete mode 100644 backend/rs/canisters/ic_vetkeys_manager_canister/dfx.json create mode 100644 backend/rs/canisters/icp.yaml delete mode 100644 dfx.json diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 52e0224d..fa897476 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -12,8 +12,8 @@ on: - package.json - package-lock.json - .github/workflows/frontend_ic_vetkeys.yml - - .github/workflows/provision-darwin.sh - - .github/workflows/provision-linux.sh + - .github/workflows/provision-frontend-darwin.sh + - .github/workflows/provision-frontend-linux.sh concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -24,8 +24,11 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux - run: bash .github/workflows/provision-linux.sh + run: bash .github/workflows/provision-frontend-linux.sh - name: Frontend Tests and Lint run: | set -eExuo pipefail @@ -40,9 +43,12 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | - bash .github/workflows/provision-darwin.sh + bash .github/workflows/provision-frontend-darwin.sh - name: Frontend Tests and Lint run: | set -eExuo pipefail diff --git a/.github/workflows/provision-frontend-darwin.sh b/.github/workflows/provision-frontend-darwin.sh new file mode 100644 index 00000000..495c1d7d --- /dev/null +++ b/.github/workflows/provision-frontend-darwin.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +set -ex + +# Enter temporary directory. +pushd /tmp + +# Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). +npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm + +# Install rust +curl --location --output install-rustup.sh "https://sh.rustup.rs" +bash install-rustup.sh -y +rustup target add wasm32-unknown-unknown + +# Exit temporary directory. +popd diff --git a/.github/workflows/provision-frontend-linux.sh b/.github/workflows/provision-frontend-linux.sh new file mode 100644 index 00000000..210b1b50 --- /dev/null +++ b/.github/workflows/provision-frontend-linux.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +set -ex + +# Enter temporary directory. +pushd /tmp + +# Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). +npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm + +# Install rust +wget --output-document install-rustup.sh "https://sh.rustup.rs" +sudo bash install-rustup.sh -y +rustup target add wasm32-unknown-unknown + +# Set environment variables. +echo "$HOME/bin" >>$GITHUB_PATH +echo "$HOME/.cargo/bin" >>$GITHUB_PATH + +# Exit temporary directory. +popd diff --git a/.gitignore b/.gitignore index 5e612e4b..d4e93430 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ target/ .idea/ **/.dfx/* +**/.icp/cache **/deps/* backend/**/declarations examples/**/declarations diff --git a/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/Makefile b/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/Makefile index f4f69946..ffaeb964 100644 --- a/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/Makefile +++ b/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/Makefile @@ -3,11 +3,12 @@ PWD:=$(shell pwd) .PHONY: compile-wasm .SILENT: compile-wasm compile-wasm: - dfx build --check + icp build # Test the APIs of this canister using the respective Rust canister tests. # This has the advantage that the tests are consistent (less room for bugs by having only one implementation of the tests) and the checked expected behavior is consistent across Rust and Motoko. .PHONY: test .SILENT: test test: compile-wasm - CUSTOM_WASM_PATH=$(PWD)/.dfx/local/canisters/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.wasm cargo test -p ic-vetkeys-encrypted-maps-canister + @echo "Testing Motoko canister WASM: $(PWD)/.icp/cache/artifacts/ic_vetkeys_encrypted_maps_canister" + CUSTOM_WASM_PATH=$(PWD)/.icp/cache/artifacts/ic_vetkeys_encrypted_maps_canister cargo test -p ic-vetkeys-encrypted-maps-canister diff --git a/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json b/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json deleted file mode 100644 index a5ce3952..00000000 --- a/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "canisters": { - "ic_vetkeys_encrypted_maps_canister": { - "main": "src/Main.mo", - "type": "motoko", - "args": "--enhanced-orthogonal-persistence" - } - }, - "defaults": { - "build": { - "packtool": "npx ic-mops sources" - } - } -} diff --git a/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/icp.yaml b/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/icp.yaml new file mode 100644 index 00000000..b4101fe9 --- /dev/null +++ b/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/icp.yaml @@ -0,0 +1,7 @@ +canisters: + - name: ic_vetkeys_encrypted_maps_canister + recipe: + type: "@dfinity/motoko@v4.1.0" + configuration: + main: src/Main.mo + args: --enhanced-orthogonal-persistence diff --git a/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/mops.toml b/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/mops.toml index d2194c57..8cc38c25 100644 --- a/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/mops.toml +++ b/backend/mo/canisters/ic_vetkeys_encrypted_maps_canister/mops.toml @@ -1,3 +1,6 @@ +[toolchain] +moc = "1.5.0" + [package] name = "ic-vetkeys-encrypted-maps-canister" version = "0.1.0" diff --git a/backend/mo/canisters/ic_vetkeys_manager_canister/Makefile b/backend/mo/canisters/ic_vetkeys_manager_canister/Makefile index 6ae7faa1..6c40a81c 100644 --- a/backend/mo/canisters/ic_vetkeys_manager_canister/Makefile +++ b/backend/mo/canisters/ic_vetkeys_manager_canister/Makefile @@ -3,11 +3,12 @@ PWD:=$(shell pwd) .PHONY: compile-wasm .SILENT: compile-wasm compile-wasm: - dfx build --check + icp build # Test the APIs of this canister using the respective Rust canister tests. # This has the advantage that the tests are consistent (less room for bugs by having only one implementation of the tests) and the checked expected behavior is consistent across Rust and Motoko. .PHONY: test .SILENT: test test: compile-wasm - CUSTOM_WASM_PATH=$(PWD)/.dfx/local/canisters/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.wasm cargo test -p ic-vetkeys-manager-canister + @echo "Testing Motoko canister WASM: $(PWD)/.icp/cache/artifacts/ic_vetkeys_manager_canister" + CUSTOM_WASM_PATH=$(PWD)/.icp/cache/artifacts/ic_vetkeys_manager_canister cargo test -p ic-vetkeys-manager-canister diff --git a/backend/mo/canisters/ic_vetkeys_manager_canister/dfx.json b/backend/mo/canisters/ic_vetkeys_manager_canister/dfx.json deleted file mode 100644 index e5d0d9d0..00000000 --- a/backend/mo/canisters/ic_vetkeys_manager_canister/dfx.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "canisters": { - "ic_vetkeys_manager_canister": { - "main": "src/Main.mo", - "type": "motoko", - "args": "--enhanced-orthogonal-persistence" - } - }, - "defaults": { - "build": { - "packtool": "npx ic-mops sources" - } - } -} diff --git a/backend/mo/canisters/ic_vetkeys_manager_canister/icp.yaml b/backend/mo/canisters/ic_vetkeys_manager_canister/icp.yaml new file mode 100644 index 00000000..e13873f5 --- /dev/null +++ b/backend/mo/canisters/ic_vetkeys_manager_canister/icp.yaml @@ -0,0 +1,7 @@ +canisters: + - name: ic_vetkeys_manager_canister + recipe: + type: "@dfinity/motoko@v4.1.0" + configuration: + main: src/Main.mo + args: --enhanced-orthogonal-persistence diff --git a/backend/mo/canisters/ic_vetkeys_manager_canister/mops.toml b/backend/mo/canisters/ic_vetkeys_manager_canister/mops.toml index 74f870e3..32c634f0 100644 --- a/backend/mo/canisters/ic_vetkeys_manager_canister/mops.toml +++ b/backend/mo/canisters/ic_vetkeys_manager_canister/mops.toml @@ -1,3 +1,6 @@ +[toolchain] +moc = "1.5.0" + [package] name = "ic-vetkeys-manager-canister" version = "0.1.0" @@ -10,4 +13,4 @@ license = "Apache-2.0" [dependencies] base = "0.14.6" -ic-vetkeys = "0.3.0" \ No newline at end of file +ic-vetkeys = "0.4.0" diff --git a/backend/mo/canisters/ic_vetkeys_manager_canister/src/Main.mo b/backend/mo/canisters/ic_vetkeys_manager_canister/src/Main.mo index 255c7d34..70a26d69 100644 --- a/backend/mo/canisters/ic_vetkeys_manager_canister/src/Main.mo +++ b/backend/mo/canisters/ic_vetkeys_manager_canister/src/Main.mo @@ -6,8 +6,9 @@ import Blob "mo:base/Blob"; import Result "mo:base/Result"; import Array "mo:base/Array"; -actor class (keyName : Text) { - var keyManager = IcVetkeys.KeyManager.KeyManager({ curve = #bls12_381_g2; name = keyName }, "key manager", Types.accessRightsOperations()); +persistent actor class (keyName : Text) { + let keyManagerState = IcVetkeys.KeyManager.newKeyManagerState({ curve = #bls12_381_g2; name = keyName }, "key manager"); + transient let keyManager = IcVetkeys.KeyManager.KeyManager(keyManagerState, Types.accessRightsOperations()); /// In this canister, we use the `ByteBuf` type to represent blobs. The reason is that we want to be consistent with the Rust canister implementation. /// Unfortunately, the `Blob` type cannot be serialized/deserialized in the current Rust implementation efficiently without nesting it in another type. public type ByteBuf = { inner : Blob }; diff --git a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/Makefile b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/Makefile index d3da2e3f..b6dc7595 100644 --- a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/Makefile +++ b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/Makefile @@ -5,6 +5,11 @@ ROOT_DIR := $(shell git rev-parse --show-toplevel) compile-wasm: cargo build --release --target wasm32-unknown-unknown +.PHONY: test +.SILENT: test +test: compile-wasm + cargo test -p ic-vetkeys-encrypted-maps-canister + .PHONY: extract-candid .SILENT: extract-candid extract-candid: compile-wasm @@ -14,4 +19,4 @@ extract-candid: compile-wasm .SILENT: clean clean: cargo clean - rm -rf .dfx \ No newline at end of file + rm -rf .icp/cache \ No newline at end of file diff --git a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json deleted file mode 100644 index 4bf39944..00000000 --- a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/dfx.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "canisters": { - "ic_vetkeys_encrypted_maps_canister": { - "candid": "ic_vetkeys_encrypted_maps_canister.did", - "package": "ic-vetkeys-encrypted-maps-canister", - "type": "rust" - } - }, - "output_env_file": ".env" -} \ No newline at end of file diff --git a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs index 31ddff23..65d034b3 100644 --- a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs +++ b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs @@ -1032,14 +1032,20 @@ impl TestEnvironment { fn load_encrypted_maps_example_canister_wasm() -> Vec { let wasm_path_string = match std::env::var("CUSTOM_WASM_PATH") { - Ok(path) if !path.is_empty() => path, + Ok(path) if !path.is_empty() => { + assert!( + Path::new(&path).exists(), + "CUSTOM_WASM_PATH is set to '{}' but the file does not exist; run `make compile-wasm` first", + path + ); + path + } _ => format!( "{}/target/wasm32-unknown-unknown/release/ic_vetkeys_encrypted_maps_canister.wasm", git_root_dir() ), }; - let wasm_path = Path::new(&wasm_path_string); - std::fs::read(wasm_path) + std::fs::read(&wasm_path_string) .expect("wasm does not exist - run `cargo build --release --target wasm32-unknown-unknown`") } diff --git a/backend/rs/canisters/ic_vetkeys_manager_canister/Makefile b/backend/rs/canisters/ic_vetkeys_manager_canister/Makefile index b569ce1a..d82f5d38 100644 --- a/backend/rs/canisters/ic_vetkeys_manager_canister/Makefile +++ b/backend/rs/canisters/ic_vetkeys_manager_canister/Makefile @@ -5,8 +5,12 @@ ROOT_DIR := $(shell git rev-parse --show-toplevel) compile-wasm: cargo build --release --target wasm32-unknown-unknown +.PHONY: test +.SILENT: test +test: compile-wasm + cargo test -p ic-vetkeys-manager-canister + .PHONY: extract-candid .SILENT: extract-candid extract-candid: compile-wasm candid-extractor $(ROOT_DIR)/target/wasm32-unknown-unknown/release/ic_vetkeys_manager_canister.wasm > ic_vetkeys_manager_canister.did - diff --git a/backend/rs/canisters/ic_vetkeys_manager_canister/dfx.json b/backend/rs/canisters/ic_vetkeys_manager_canister/dfx.json deleted file mode 100644 index 63815584..00000000 --- a/backend/rs/canisters/ic_vetkeys_manager_canister/dfx.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "canisters": { - "ic_vetkeys_manager_canister": { - "candid": "ic_vetkeys_manager_canister.did", - "package": "ic-vetkeys-manager-canister", - "type": "rust" - } - }, - "output_env_file": ".env" - } \ No newline at end of file diff --git a/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs b/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs index 1d53381d..40332726 100644 --- a/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs +++ b/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs @@ -579,14 +579,20 @@ impl TestEnvironment { fn load_key_manager_example_canister_wasm() -> Vec { let wasm_path_string = match std::env::var("CUSTOM_WASM_PATH") { - Ok(path) if !path.is_empty() => path, + Ok(path) if !path.is_empty() => { + assert!( + Path::new(&path).exists(), + "CUSTOM_WASM_PATH is set to '{}' but the file does not exist; run `make compile-wasm` first", + path + ); + path + } _ => format!( "{}/target/wasm32-unknown-unknown/release/ic_vetkeys_manager_canister.wasm", git_root_dir() ), }; - let wasm_path = Path::new(&wasm_path_string); - std::fs::read(wasm_path) + std::fs::read(&wasm_path_string) .expect("wasm does not exist - run `cargo build --release --target wasm32-unknown-unknown`") } diff --git a/backend/rs/canisters/icp.yaml b/backend/rs/canisters/icp.yaml new file mode 100644 index 00000000..36c737bf --- /dev/null +++ b/backend/rs/canisters/icp.yaml @@ -0,0 +1,19 @@ +canisters: + - name: ic_vetkeys_manager_canister + recipe: + type: "@dfinity/rust@v3.2.0" + configuration: + package: ic-vetkeys-manager-canister + candid: ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did + init_args: + type: text + value: "(\"dfx_test_key\")" + - name: ic_vetkeys_encrypted_maps_canister + recipe: + type: "@dfinity/rust@v3.2.0" + configuration: + package: ic-vetkeys-encrypted-maps-canister + candid: ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did + init_args: + type: text + value: "(\"dfx_test_key\")" diff --git a/backend/rs/canisters/tests/tests/sign_with_bls.rs b/backend/rs/canisters/tests/tests/sign_with_bls.rs index 8cf6ac49..2e1b3f5e 100644 --- a/backend/rs/canisters/tests/tests/sign_with_bls.rs +++ b/backend/rs/canisters/tests/tests/sign_with_bls.rs @@ -114,14 +114,20 @@ impl TestEnvironment { fn load_canister_wasm() -> Vec { let wasm_path_string = match std::env::var("CUSTOM_WASM_PATH") { - Ok(path) if !path.is_empty() => path, + Ok(path) if !path.is_empty() => { + assert!( + Path::new(&path).exists(), + "CUSTOM_WASM_PATH is set to '{}' but the file does not exist; run `make compile-wasm` first", + path + ); + path + } _ => format!( "{}/target/wasm32-unknown-unknown/release/ic_vetkeys_canisters_tests.wasm", git_root_dir() ), }; - let wasm_path = Path::new(&wasm_path_string); - std::fs::read(wasm_path) + std::fs::read(&wasm_path_string) .expect("wasm does not exist - run `cargo build --release --target wasm32-unknown-unknown`") } diff --git a/dfx.json b/dfx.json deleted file mode 100644 index 7d7f8cac..00000000 --- a/dfx.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "canisters": { - "docs": { - "type": "assets", - "source": ["docs"] - } - } -} diff --git a/package-lock.json b/package-lock.json index 91dda179..f66bb744 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,13 +16,10 @@ "version": "0.4.0", "license": "Apache-2.0", "dependencies": { - "@dfinity/agent": "^3.1.0", - "@dfinity/candid": "^3.1.0", - "@dfinity/principal": "^3.1.0", + "@icp-sdk/core": "^5.2.1", "idb-keyval": "^6.2.1" }, "devDependencies": { - "@dfinity/identity": "^3.1.0", "@eslint/js": "^9.22.0", "@types/node": "^24.0.4", "@vitest/coverage-v8": "^3.0.5", @@ -115,59 +112,12 @@ "node": ">=18" } }, - "node_modules/@dfinity/agent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-3.1.0.tgz", - "integrity": "sha512-4ktWU9KoB+Y0y84i0c2up9xmek2WjwSsbh4zGUK+o3VwZyqH8Cck4Fh4eiTa5jOve/vtfSVDbUVNFXsaS3Gttw==", - "license": "Apache-2.0", - "dependencies": { - "@dfinity/cbor": "^0.2.2", - "@noble/curves": "^1.9.2" - }, - "peerDependencies": { - "@dfinity/candid": "3.1.0", - "@dfinity/principal": "3.1.0", - "@noble/hashes": "^1.8.0" - } - }, - "node_modules/@dfinity/candid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-3.1.0.tgz", - "integrity": "sha512-YwZJROFmzPa4GCJJyGCoOYJ2pKmp9rboixGQSbLPekX0n0oU0mcEbuVKJFu6HY6CnoDoI8YKc9x+jlqh4n0u5A==", - "license": "Apache-2.0", - "peerDependencies": { - "@dfinity/principal": "3.1.0" - } - }, "node_modules/@dfinity/cbor": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@dfinity/cbor/-/cbor-0.2.2.tgz", "integrity": "sha512-GPJpH73kDEKbUBdUjY80lz7cq9l0vm1h/7ppejPV6O0ZTqCLrYspssYvqjRmK4aNnJ/SKXsP0rg9LYX7zpegaA==", "license": "Apache-2.0" }, - "node_modules/@dfinity/identity": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-3.1.0.tgz", - "integrity": "sha512-XI4UuzBaPh7BNaZBsQthvtrVk2S3tS24BYjKO//9+AdkNcxH3iZlzYkn6RejVaisnmztM7L0BMK3ECmGqy+OSw==", - "dev": true, - "license": "Apache-2.0", - "peerDependencies": { - "@dfinity/agent": "3.1.0", - "@dfinity/candid": "3.1.0", - "@dfinity/principal": "3.1.0", - "@noble/curves": "^1.9.2", - "@noble/hashes": "^1.8.0" - } - }, - "node_modules/@dfinity/principal": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-3.1.0.tgz", - "integrity": "sha512-ef2JbgwQGtam0s19bH9CaR8ztpuoNx10eC6/kBjR/R8VC2eIBlaJHvD0lXDrBWGtOPZGzEy/XAugeBr3raxZ8A==", - "license": "Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.8.0" - } - }, "node_modules/@dfinity/vetkeys": { "resolved": "frontend/ic_vetkeys", "link": true @@ -835,6 +785,20 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@icp-sdk/core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@icp-sdk/core/-/core-5.2.1.tgz", + "integrity": "sha512-FImRjnayCarov7vfr52QU3BO8tPAprbyl4O+0KWz4v7h8ZbKq15fhtdb53M6+ltUsCbWkP/lEgrQ4t1WhIAHjQ==", + "license": "Apache-2.0", + "dependencies": { + "@dfinity/cbor": "^0.2.2", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "asn1js": "^3.0.7" + } + }, "node_modules/@isaacs/balanced-match": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", @@ -1066,9 +1030,9 @@ "license": "MIT" }, "node_modules/@noble/curves": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.6.tgz", - "integrity": "sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" @@ -1508,6 +1472,7 @@ "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "json-schema-traverse": "^1.0.0", @@ -1639,6 +1604,42 @@ "sprintf-js": "~1.0.2" } }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@shikijs/engine-oniguruma": { "version": "3.9.2", "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.9.2.tgz", @@ -1742,6 +1743,7 @@ "integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.10.0" } @@ -1796,6 +1798,7 @@ "integrity": "sha512-XGwIabPallYipmcOk45DpsBSgLC64A0yvdAkrwEzwZ2viqGqRUJ8eEYoPz0CWnutgAFbNMPdsGGvzjSmcWVlEA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.27.0", "@typescript-eslint/types": "8.27.0", @@ -2251,6 +2254,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2376,11 +2380,24 @@ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">= 0.4" } }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", @@ -2409,7 +2426,6 @@ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", "dev": true, "license": "Apache-2.0", - "peer": true, "engines": { "node": ">= 0.4" } @@ -2515,7 +2531,6 @@ "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@types/estree": "^1.0.1", @@ -2586,7 +2601,6 @@ "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mdn-data": "2.0.30", "source-map-js": "^1.0.1" @@ -2732,6 +2746,7 @@ "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -2793,6 +2808,7 @@ "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -3448,7 +3464,6 @@ "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "^1.0.6" } @@ -3666,8 +3681,7 @@ "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", "dev": true, - "license": "MIT", - "peer": true + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", @@ -3781,8 +3795,7 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", "dev": true, - "license": "CC0-1.0", - "peer": true + "license": "CC0-1.0" }, "node_modules/mdurl": { "version": "2.0.0", @@ -4075,7 +4088,6 @@ "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/estree": "^1.0.0", "estree-walker": "^3.0.0", @@ -4159,6 +4171,7 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -4202,6 +4215,24 @@ "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/quansync": { "version": "0.2.10", "resolved": "https://registry.npmjs.org/quansync/-/quansync-0.2.10.tgz", @@ -4298,6 +4329,7 @@ "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -4768,6 +4800,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -4838,6 +4871,12 @@ "typescript": ">=4.8.4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -4907,6 +4946,7 @@ "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4985,6 +5025,7 @@ "integrity": "sha512-cJBdq0/u+8rgstg9t7UkBilf8ipLmeXJO30NxD5HAHOivnj10ocV8YtR/XBvd2wQpN3TmcaxNKaHX3tN7o5F5A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.6", @@ -5125,6 +5166,7 @@ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -5138,6 +5180,7 @@ "integrity": "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", From e8be6b0d6c94e139c74894e04e902ee1e8d1f1d1 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 14:26:05 +0200 Subject: [PATCH 03/24] fix(ci): fix vite .did import and motoko backend icp-cli setup - Fix explicit .js extension on idlFactory import in encrypted_maps_canister.ts (vite resolved extensionless ".did" to the raw Candid file instead of the generated .did.js binding) - Update backend-motoko.yml to use provision-frontend-*.sh (icp-cli) and add setup-node@22, required for `icp build` in the Makefiles Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/backend-motoko.yml | 14 ++++++++++---- .../src/encrypted_maps/encrypted_maps_canister.ts | 4 ++-- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/backend-motoko.yml b/.github/workflows/backend-motoko.yml index 8ba91d76..53fff82a 100644 --- a/.github/workflows/backend-motoko.yml +++ b/.github/workflows/backend-motoko.yml @@ -13,8 +13,8 @@ on: - backend/rs/canisters/** - Cargo.toml - Cargo.lock - - .github/workflows/provision-linux.sh - - .github/workflows/provision-darwin.sh + - .github/workflows/provision-frontend-linux.sh + - .github/workflows/provision-frontend-darwin.sh - .github/workflows/backend-motoko.yml jobs: @@ -24,11 +24,14 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - uses: ZenVoich/setup-mops@3e94e453352269b34137b5ce49f09a8df81bed7d # v1.4.1 with: mops-version: 1 - name: Provision Linux - run: bash .github/workflows/provision-linux.sh + run: bash .github/workflows/provision-frontend-linux.sh - name: Run MOPS Test Linux run: | set -eExuo pipefail @@ -45,11 +48,14 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - uses: ZenVoich/setup-mops@3e94e453352269b34137b5ce49f09a8df81bed7d # v1.4.1 with: mops-version: 1 - name: Provision Darwin - run: bash .github/workflows/provision-darwin.sh + run: bash .github/workflows/provision-frontend-darwin.sh - name: Run MOPS Test Darwin run: | set -eExuo pipefail diff --git a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts index 4010d53b..caa5db15 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts @@ -1,12 +1,12 @@ import { Principal } from "@icp-sdk/core/principal"; import { Actor, ActorSubclass, HttpAgent } from "@icp-sdk/core/agent"; -import { idlFactory } from "../declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did"; +import { idlFactory } from "../declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.js"; import { _SERVICE as _DEFAULT_ENCRYPTED_MAPS_SERVICE, AccessRights, ByteBuf, EncryptedMapData, -} from "../declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did"; +} from "../declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.js"; import { EncryptedMapsClient } from "./index"; export class DefaultEncryptedMapsClient implements EncryptedMapsClient { From 343eb434c4c929574cfacfbbd180a823ef1046cb Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 14:36:34 +0200 Subject: [PATCH 04/24] fix(ci): add mops toolchain, GITHUB_TOKEN for icp rate limiting - Add [toolchain] moc = "1.5.0" to backend/mo/ic_vetkeys/mops.toml so mops test resolves the compiler without falling back to dfx cache show - Set GITHUB_TOKEN env on test steps in frontend.yml and backend-motoko.yml to avoid 403 rate limiting when icp fetches the network launcher version from the GitHub API Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/backend-motoko.yml | 4 ++++ .github/workflows/frontend.yml | 4 ++++ backend/mo/ic_vetkeys/mops.toml | 3 +++ 3 files changed, 11 insertions(+) diff --git a/.github/workflows/backend-motoko.yml b/.github/workflows/backend-motoko.yml index 53fff82a..04fa8705 100644 --- a/.github/workflows/backend-motoko.yml +++ b/.github/workflows/backend-motoko.yml @@ -33,6 +33,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-frontend-linux.sh - name: Run MOPS Test Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd backend/mo/ic_vetkeys @@ -57,6 +59,8 @@ jobs: - name: Provision Darwin run: bash .github/workflows/provision-frontend-darwin.sh - name: Run MOPS Test Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd backend/mo/ic_vetkeys diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index fa897476..7f76f60c 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -30,6 +30,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-frontend-linux.sh - name: Frontend Tests and Lint + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail npm install @@ -50,6 +52,8 @@ jobs: run: | bash .github/workflows/provision-frontend-darwin.sh - name: Frontend Tests and Lint + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail npm install diff --git a/backend/mo/ic_vetkeys/mops.toml b/backend/mo/ic_vetkeys/mops.toml index 10ef53ed..6e8b1c85 100644 --- a/backend/mo/ic_vetkeys/mops.toml +++ b/backend/mo/ic_vetkeys/mops.toml @@ -1,3 +1,6 @@ +[toolchain] +moc = "1.5.0" + [package] name = "ic-vetkeys" version = "0.4.0" From 91cd42965083f34af52d092c90b8b57309dbd2ca Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 22:03:55 +0200 Subject: [PATCH 05/24] fix(frontend): address Copilot review comments and remove stale dfx artifacts - Remove dfx-generated index.js, index.d.ts, and raw .did files from both declaration directories (ic_vetkeys_encrypted_maps_canister and ic_vetkeys_manager_canister). These used @dfinity/agent and dfx-specific env vars (DFX_NETWORK, CANISTER_ID_*) and are no longer needed now that the library uses @icp-sdk/core. - Fix encrypted_maps_canister.ts: split idlFactory (value import) from _SERVICE/AccessRights/ByteBuf/EncryptedMapData (type-only imports via import type). The .did.js module only exports idlFactory and init at runtime; importing types as values would fail under strict ESM. - Fix key_manager/index.ts: change import source from the raw Candid text file (.did) to the generated JS module (.did.js), and use import type for type-only symbols. - Fix make_did_bindings.sh: add explicit / path separator between DIR and NAME so the function is robust if DIR is passed without a trailing slash. - Fix provision-frontend-linux.sh: remove sudo from rustup install; sudo installs into root's home while subsequent steps add $HOME/.cargo/bin (runner's home) to PATH, causing cargo to not be found. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/provision-frontend-linux.sh | 2 +- frontend/ic_vetkeys/make_did_bindings.sh | 4 +- .../ic_vetkeys_encrypted_maps_canister.did | 41 --------------- .../index.d.ts | 50 ------------------- .../index.js | 42 ---------------- .../ic_vetkeys_manager_canister.did | 19 ------- .../ic_vetkeys_manager_canister/index.d.ts | 50 ------------------- .../ic_vetkeys_manager_canister/index.js | 42 ---------------- .../encrypted_maps/encrypted_maps_canister.ts | 2 +- frontend/ic_vetkeys/src/key_manager/index.ts | 6 +-- 10 files changed, 7 insertions(+), 251 deletions(-) delete mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did delete mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.d.ts delete mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.js delete mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did delete mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.d.ts delete mode 100644 frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.js diff --git a/.github/workflows/provision-frontend-linux.sh b/.github/workflows/provision-frontend-linux.sh index 210b1b50..9b0ca393 100644 --- a/.github/workflows/provision-frontend-linux.sh +++ b/.github/workflows/provision-frontend-linux.sh @@ -10,7 +10,7 @@ npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm # Install rust wget --output-document install-rustup.sh "https://sh.rustup.rs" -sudo bash install-rustup.sh -y +bash install-rustup.sh -y rustup target add wasm32-unknown-unknown # Set environment variables. diff --git a/frontend/ic_vetkeys/make_did_bindings.sh b/frontend/ic_vetkeys/make_did_bindings.sh index cf88d0dd..efe3acbb 100755 --- a/frontend/ic_vetkeys/make_did_bindings.sh +++ b/frontend/ic_vetkeys/make_did_bindings.sh @@ -5,13 +5,13 @@ function make_and_copy_declarations () { NAME=$2 DID_FILE=$3 - pushd "$DIR""$NAME" + pushd "$DIR/$NAME" make extract-candid popd rm -rf "src/declarations/$NAME" mkdir -p "src/declarations/$NAME" - npx @icp-sdk/bindgen --did-file "$DIR$NAME/$DID_FILE" --out-dir "src/declarations/$NAME" --declarations-flat --force + npx @icp-sdk/bindgen --did-file "$DIR/$NAME/$DID_FILE" --out-dir "src/declarations/$NAME" --declarations-flat --force } make_and_copy_declarations "../../backend/rs/canisters/" "ic_vetkeys_manager_canister" "ic_vetkeys_manager_canister.did" diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did deleted file mode 100644 index af877ce5..00000000 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did +++ /dev/null @@ -1,41 +0,0 @@ -type AccessRights = variant { Read; ReadWrite; ReadWriteManage }; -type ByteBuf = record { inner : blob }; -type EncryptedMapData = record { - access_control : vec record { principal; AccessRights }; - keyvals : vec record { ByteBuf; ByteBuf }; - map_name : ByteBuf; - map_owner : principal; -}; -type Result = variant { Ok : opt ByteBuf; Err : text }; -type Result_1 = variant { Ok : vec record { ByteBuf; ByteBuf }; Err : text }; -type Result_2 = variant { Ok : ByteBuf; Err : text }; -type Result_3 = variant { - Ok : vec record { principal; AccessRights }; - Err : text; -}; -type Result_4 = variant { Ok : opt AccessRights; Err : text }; -type Result_5 = variant { Ok : vec ByteBuf; Err : text }; -service : { - get_accessible_shared_map_names : () -> ( - vec record { principal; ByteBuf }, - ) query; - get_all_accessible_encrypted_maps : () -> (vec EncryptedMapData) query; - get_all_accessible_encrypted_values : () -> ( - vec record { - record { principal; ByteBuf }; - vec record { ByteBuf; ByteBuf }; - }, - ) query; - get_encrypted_value : (principal, ByteBuf, ByteBuf) -> (Result) query; - get_encrypted_values_for_map : (principal, ByteBuf) -> (Result_1) query; - get_encrypted_vetkey : (principal, ByteBuf, ByteBuf) -> (Result_2); - get_owned_non_empty_map_names : () -> (vec ByteBuf) query; - get_shared_user_access_for_map : (principal, ByteBuf) -> (Result_3) query; - get_user_rights : (principal, ByteBuf, principal) -> (Result_4) query; - get_vetkey_verification_key : () -> (ByteBuf); - insert_encrypted_value : (principal, ByteBuf, ByteBuf, ByteBuf) -> (Result); - remove_encrypted_value : (principal, ByteBuf, ByteBuf) -> (Result); - remove_map_values : (principal, ByteBuf) -> (Result_5); - remove_user : (principal, ByteBuf, principal) -> (Result_4); - set_user_rights : (principal, ByteBuf, principal, AccessRights) -> (Result_4); -} diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.d.ts b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.d.ts deleted file mode 100644 index 17f4897e..00000000 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { - ActorSubclass, - HttpAgentOptions, - ActorConfig, - Agent, -} from "@dfinity/agent"; -import type { Principal } from "@dfinity/principal"; -import type { IDL } from "@dfinity/candid"; - -import { _SERVICE } from './ic_vetkeys_encrypted_maps_canister.did'; - -export declare const idlFactory: IDL.InterfaceFactory; -export declare const canisterId: string; - -export declare interface CreateActorOptions { - /** - * @see {@link Agent} - */ - agent?: Agent; - /** - * @see {@link HttpAgentOptions} - */ - agentOptions?: HttpAgentOptions; - /** - * @see {@link ActorConfig} - */ - actorOptions?: ActorConfig; -} - -/** - * Intializes an {@link ActorSubclass}, configured with the provided SERVICE interface of a canister. - * @constructs {@link ActorSubClass} - * @param {string | Principal} canisterId - ID of the canister the {@link Actor} will talk to - * @param {CreateActorOptions} options - see {@link CreateActorOptions} - * @param {CreateActorOptions["agent"]} options.agent - a pre-configured agent you'd like to use. Supercedes agentOptions - * @param {CreateActorOptions["agentOptions"]} options.agentOptions - options to set up a new agent - * @see {@link HttpAgentOptions} - * @param {CreateActorOptions["actorOptions"]} options.actorOptions - options for the Actor - * @see {@link ActorConfig} - */ -export declare const createActor: ( - canisterId: string | Principal, - options?: CreateActorOptions -) => ActorSubclass<_SERVICE>; - -/** - * Intialized Actor using default settings, ready to talk to a canister using its candid interface - * @constructs {@link ActorSubClass} - */ -export declare const ic_vetkeys_encrypted_maps_canister: ActorSubclass<_SERVICE>; diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.js b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.js deleted file mode 100644 index c32644d9..00000000 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_encrypted_maps_canister/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import { Actor, HttpAgent } from "@dfinity/agent"; - -// Imports and re-exports candid interface -import { idlFactory } from "./ic_vetkeys_encrypted_maps_canister.did.js"; -export { idlFactory } from "./ic_vetkeys_encrypted_maps_canister.did.js"; - -/* CANISTER_ID is replaced by webpack based on node environment - * Note: canister environment variable will be standardized as - * process.env.CANISTER_ID_ - * beginning in dfx 0.15.0 - */ -export const canisterId = - process.env.CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER; - -export const createActor = (canisterId, options = {}) => { - const agent = options.agent || new HttpAgent({ ...options.agentOptions }); - - if (options.agent && options.agentOptions) { - console.warn( - "Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent." - ); - } - - // Fetch root key for certificate validation during development - if (process.env.DFX_NETWORK !== "ic") { - agent.fetchRootKey().catch((err) => { - console.warn( - "Unable to fetch root key. Check to ensure that your local replica is running" - ); - console.error(err); - }); - } - - // Creates an actor with using the candid interface and the HttpAgent - return Actor.createActor(idlFactory, { - agent, - canisterId, - ...options.actorOptions, - }); -}; - -export const ic_vetkeys_encrypted_maps_canister = canisterId ? createActor(canisterId) : undefined; diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did deleted file mode 100644 index af35433b..00000000 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did +++ /dev/null @@ -1,19 +0,0 @@ -type AccessRights = variant { Read; ReadWrite; ReadWriteManage }; -type ByteBuf = record { inner : blob }; -type Result = variant { Ok : ByteBuf; Err : text }; -type Result_1 = variant { - Ok : vec record { principal; AccessRights }; - Err : text; -}; -type Result_2 = variant { Ok : opt AccessRights; Err : text }; -service : { - get_accessible_shared_key_ids : () -> ( - vec record { principal; ByteBuf }, - ) query; - get_encrypted_vetkey : (principal, ByteBuf, ByteBuf) -> (Result); - get_shared_user_access_for_key : (principal, ByteBuf) -> (Result_1) query; - get_user_rights : (principal, ByteBuf, principal) -> (Result_2) query; - get_vetkey_verification_key : () -> (ByteBuf); - remove_user : (principal, ByteBuf, principal) -> (Result_2); - set_user_rights : (principal, ByteBuf, principal, AccessRights) -> (Result_2); -} diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.d.ts b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.d.ts deleted file mode 100644 index 5016b780..00000000 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.d.ts +++ /dev/null @@ -1,50 +0,0 @@ -import type { - ActorSubclass, - HttpAgentOptions, - ActorConfig, - Agent, -} from "@dfinity/agent"; -import type { Principal } from "@dfinity/principal"; -import type { IDL } from "@dfinity/candid"; - -import { _SERVICE } from './ic_vetkeys_manager_canister.did'; - -export declare const idlFactory: IDL.InterfaceFactory; -export declare const canisterId: string; - -export declare interface CreateActorOptions { - /** - * @see {@link Agent} - */ - agent?: Agent; - /** - * @see {@link HttpAgentOptions} - */ - agentOptions?: HttpAgentOptions; - /** - * @see {@link ActorConfig} - */ - actorOptions?: ActorConfig; -} - -/** - * Intializes an {@link ActorSubclass}, configured with the provided SERVICE interface of a canister. - * @constructs {@link ActorSubClass} - * @param {string | Principal} canisterId - ID of the canister the {@link Actor} will talk to - * @param {CreateActorOptions} options - see {@link CreateActorOptions} - * @param {CreateActorOptions["agent"]} options.agent - a pre-configured agent you'd like to use. Supercedes agentOptions - * @param {CreateActorOptions["agentOptions"]} options.agentOptions - options to set up a new agent - * @see {@link HttpAgentOptions} - * @param {CreateActorOptions["actorOptions"]} options.actorOptions - options for the Actor - * @see {@link ActorConfig} - */ -export declare const createActor: ( - canisterId: string | Principal, - options?: CreateActorOptions -) => ActorSubclass<_SERVICE>; - -/** - * Intialized Actor using default settings, ready to talk to a canister using its candid interface - * @constructs {@link ActorSubClass} - */ -export declare const ic_vetkeys_manager_canister: ActorSubclass<_SERVICE>; diff --git a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.js b/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.js deleted file mode 100644 index 6c09cbee..00000000 --- a/frontend/ic_vetkeys/src/declarations/ic_vetkeys_manager_canister/index.js +++ /dev/null @@ -1,42 +0,0 @@ -import { Actor, HttpAgent } from "@dfinity/agent"; - -// Imports and re-exports candid interface -import { idlFactory } from "./ic_vetkeys_manager_canister.did.js"; -export { idlFactory } from "./ic_vetkeys_manager_canister.did.js"; - -/* CANISTER_ID is replaced by webpack based on node environment - * Note: canister environment variable will be standardized as - * process.env.CANISTER_ID_ - * beginning in dfx 0.15.0 - */ -export const canisterId = - process.env.CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER; - -export const createActor = (canisterId, options = {}) => { - const agent = options.agent || new HttpAgent({ ...options.agentOptions }); - - if (options.agent && options.agentOptions) { - console.warn( - "Detected both agent and agentOptions passed to createActor. Ignoring agentOptions and proceeding with the provided agent." - ); - } - - // Fetch root key for certificate validation during development - if (process.env.DFX_NETWORK !== "ic") { - agent.fetchRootKey().catch((err) => { - console.warn( - "Unable to fetch root key. Check to ensure that your local replica is running" - ); - console.error(err); - }); - } - - // Creates an actor with using the candid interface and the HttpAgent - return Actor.createActor(idlFactory, { - agent, - canisterId, - ...options.actorOptions, - }); -}; - -export const ic_vetkeys_manager_canister = canisterId ? createActor(canisterId) : undefined; diff --git a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts index caa5db15..b9b72b4e 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.ts @@ -1,7 +1,7 @@ import { Principal } from "@icp-sdk/core/principal"; import { Actor, ActorSubclass, HttpAgent } from "@icp-sdk/core/agent"; import { idlFactory } from "../declarations/ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did.js"; -import { +import type { _SERVICE as _DEFAULT_ENCRYPTED_MAPS_SERVICE, AccessRights, ByteBuf, diff --git a/frontend/ic_vetkeys/src/key_manager/index.ts b/frontend/ic_vetkeys/src/key_manager/index.ts index c04085d0..5f4bcdae 100644 --- a/frontend/ic_vetkeys/src/key_manager/index.ts +++ b/frontend/ic_vetkeys/src/key_manager/index.ts @@ -11,16 +11,16 @@ import { EncryptedVetKey, DerivedPublicKey, } from "../utils/utils"; -import { +import type { AccessRights, ByteBuf, -} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did"; +} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js"; export { DefaultKeyManagerClient } from "./key_manager_canister"; export type { AccessRights, ByteBuf, -} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did"; +} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js"; /** * The **`KeyManager`** frontend library facilitates interaction with a [**`KeyManager`-enabled canister**](https://docs.rs/ic-vetkeys/latest/ic_vetkeys/key_manager/struct.KeyManager.html) on the **Internet Computer (ICP)**. From d01ed07b2f794f7415c94c617b07c3d6acbf126d Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 22:09:00 +0200 Subject: [PATCH 06/24] fix(ci): use ICP_CLI_GITHUB_TOKEN in frontend workflow to avoid icp rate limits npm run test calls icp network start + icp deploy; icp-cli reads ICP_CLI_GITHUB_TOKEN (not GITHUB_TOKEN) when fetching the network launcher. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/frontend.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 7f76f60c..d84a6d51 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -31,7 +31,7 @@ jobs: run: bash .github/workflows/provision-frontend-linux.sh - name: Frontend Tests and Lint env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail npm install @@ -53,7 +53,7 @@ jobs: bash .github/workflows/provision-frontend-darwin.sh - name: Frontend Tests and Lint env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail npm install From 913fcf1b1d3126244598f4c534eb6988cddac85c Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 22:14:30 +0200 Subject: [PATCH 07/24] fix(frontend): use import type for type-only symbols from .did.js files key_manager_canister.ts and encrypted_maps/index.ts were importing type-only symbols (_SERVICE, AccessRights, ByteBuf) as runtime values from .did.js files that only export idlFactory and init. Also fixes encrypted_maps/index.ts which was still referencing the bare .did file instead of .did.js. Co-Authored-By: Claude Sonnet 4.6 --- frontend/ic_vetkeys/src/encrypted_maps/index.ts | 6 +++--- frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/ic_vetkeys/src/encrypted_maps/index.ts b/frontend/ic_vetkeys/src/encrypted_maps/index.ts index 02fe5db8..843a72b6 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/index.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/index.ts @@ -12,16 +12,16 @@ import { EncryptedVetKey, DerivedPublicKey, } from "../utils/utils"; -import { +import type { AccessRights, ByteBuf, -} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did"; +} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js"; export { DefaultEncryptedMapsClient } from "./encrypted_maps_canister"; export type { AccessRights, ByteBuf, -} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did"; +} from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js"; /** * The **EncryptedMaps** frontend library facilitates interaction with an [**EncryptedMaps-enabled canister**](https://docs.rs/ic-vetkeys/latest/ic_vetkeys/encrypted_maps/struct.EncryptedMaps.html) on the **Internet Computer (ICP)**. diff --git a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts index b9523379..718f5493 100644 --- a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts +++ b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.ts @@ -1,7 +1,7 @@ import { Principal } from "@icp-sdk/core/principal"; import { Actor, ActorSubclass, HttpAgent } from "@icp-sdk/core/agent"; import { idlFactory } from "../declarations/ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did.js"; -import { +import type { _SERVICE as _DEFAULT_KEY_MANAGER_SERVICE, AccessRights, ByteBuf, From 0a7138e9551f2ea31e551b01d284a25159c187f2 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 23:03:28 +0200 Subject: [PATCH 08/24] fix(ci,tests): fix workflow self-trigger path and missing canister id guards - .github/workflows/frontend.yml: path filter pointed at non-existent `frontend_ic_vetkeys.yml`; change to `frontend.yml` so the workflow re-triggers on changes to itself. - test files: process.env.CANISTER_ID_* is `string | undefined`; add explicit guard that throws a clear error when the env var is missing instead of passing undefined to the constructor. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/frontend.yml | 2 +- .../src/encrypted_maps/encrypted_maps_canister.test.ts | 1 + .../ic_vetkeys/src/key_manager/key_manager_canister.test.ts | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index d84a6d51..c270fdac 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -11,7 +11,7 @@ on: - backend/**/canisters/** - package.json - package-lock.json - - .github/workflows/frontend_ic_vetkeys.yml + - .github/workflows/frontend.yml - .github/workflows/provision-frontend-darwin.sh - .github/workflows/provision-frontend-linux.sh concurrency: diff --git a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts index ab75c0a3..22b4a197 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts @@ -26,6 +26,7 @@ async function newEncryptedMaps( }); const canisterId = process.env.CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER; + if (!canisterId) throw new Error("CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER is not set"); return new EncryptedMaps(new DefaultEncryptedMapsClient(agent, canisterId)); } diff --git a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts index e6c3b0cd..3223d7f1 100644 --- a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts +++ b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts @@ -23,6 +23,7 @@ async function newKeyManager(id: Ed25519KeyIdentity): Promise { shouldFetchRootKey: true, }); const canisterId = process.env.CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER; + if (!canisterId) throw new Error("CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER is not set"); return new KeyManager(new DefaultKeyManagerClient(agent, canisterId)); } From 2323844b78381c54a11982deca1a416d2c2160a9 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 23:06:16 +0200 Subject: [PATCH 09/24] fix(changelog): correct deprecated API reference in 0.5.0 entry HttpAgent.createSync() is not deprecated; only the new HttpAgent(options) constructor is. Update the wording accordingly. Co-Authored-By: Claude Sonnet 4.6 --- frontend/ic_vetkeys/CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/ic_vetkeys/CHANGELOG.md b/frontend/ic_vetkeys/CHANGELOG.md index 66dc91d8..9ac94e8d 100644 --- a/frontend/ic_vetkeys/CHANGELOG.md +++ b/frontend/ic_vetkeys/CHANGELOG.md @@ -15,8 +15,8 @@ - **BREAKING** `DefaultEncryptedMapsClient` and `DefaultKeyManagerClient` constructors now accept an `HttpAgent` (from `@icp-sdk/core/agent`) instead of `HttpAgentOptions`. Since `HttpAgent.create()` is async, the agent must be - created by the caller before being passed in — this avoids relying on the - deprecated `HttpAgent.createSync()` and allows full configuration upfront, + created by the caller before being passed in — this avoids the deprecated + `new HttpAgent(options)` constructor and allows full configuration upfront, including providing the network's root key for local development: ```ts const agent = await HttpAgent.create({ From a34a5c2f456a99ca8f60513ea47683c9d80019b2 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 23:11:33 +0200 Subject: [PATCH 10/24] style(frontend): run prettier on ic_vetkeys Co-Authored-By: Claude Sonnet 4.6 --- frontend/ic_vetkeys/CHANGELOG.md | 21 ++++---- frontend/ic_vetkeys/eslint.config.mjs | 50 +++++++++---------- .../encrypted_maps_canister.test.ts | 5 +- .../key_manager/key_manager_canister.test.ts | 3 +- frontend/ic_vetkeys/tsconfig.json | 42 +++++++--------- frontend/ic_vetkeys/tsconfig.tests.json | 8 +-- frontend/ic_vetkeys/typedoc.json | 2 +- frontend/ic_vetkeys/vite.config.ts | 34 +++++++------ 8 files changed, 84 insertions(+), 81 deletions(-) diff --git a/frontend/ic_vetkeys/CHANGELOG.md b/frontend/ic_vetkeys/CHANGELOG.md index 9ac94e8d..625016ff 100644 --- a/frontend/ic_vetkeys/CHANGELOG.md +++ b/frontend/ic_vetkeys/CHANGELOG.md @@ -18,14 +18,15 @@ created by the caller before being passed in — this avoids the deprecated `new HttpAgent(options)` constructor and allows full configuration upfront, including providing the network's root key for local development: - ```ts - const agent = await HttpAgent.create({ - host, - identity, - ...(rootKey ? { rootKey } : {}), // rootKey from ic_env cookie in local dev - }); - new DefaultEncryptedMapsClient(agent, canisterId); - ``` + + ```ts + const agent = await HttpAgent.create({ + host, + identity, + ...(rootKey ? { rootKey } : {}), // rootKey from ic_env cookie in local dev + }); + new DefaultEncryptedMapsClient(agent, canisterId); + ``` - Make `DerivedKeyMaterial.deriveAesGcmCryptoKey` `@internal`. @@ -41,7 +42,7 @@ ### Changed - - Bump `@dfinity` agent-related packages to major version `3`. +- Bump `@dfinity` agent-related packages to major version `3`. ## [0.3.0] - 2025-06-30 @@ -58,9 +59,11 @@ ## [0.2.0] - 2025-06-08 ### Fixed + - Links in code docs. ### Changed + - The code docs now live on github.io. - Replaces some instances of `window` with `globalThis` in a few places for better node compatibility. diff --git a/frontend/ic_vetkeys/eslint.config.mjs b/frontend/ic_vetkeys/eslint.config.mjs index 078b4d76..078939ef 100644 --- a/frontend/ic_vetkeys/eslint.config.mjs +++ b/frontend/ic_vetkeys/eslint.config.mjs @@ -3,8 +3,8 @@ import eslint from "@eslint/js"; import tseslint from "typescript-eslint"; import eslintPluginPrettierRecommended from "eslint-plugin-prettier/recommended"; -import { fileURLToPath } from 'url'; -import path from 'path'; +import { fileURLToPath } from "url"; +import path from "path"; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -13,30 +13,30 @@ export default tseslint.config( tseslint.configs.recommendedTypeChecked, eslintPluginPrettierRecommended, { - languageOptions: { - parserOptions: { - project: path.resolve(__dirname, "tsconfig.tests.json"), - tsconfigRootDir: __dirname, + languageOptions: { + parserOptions: { + project: path.resolve(__dirname, "tsconfig.tests.json"), + tsconfigRootDir: __dirname, + }, + }, + rules: { + "@typescript-eslint/naming-convention": [ + "error", + { + selector: "variableLike", + format: ["camelCase"], + }, + { + selector: "variable", + modifiers: ["const"], + format: ["camelCase", "UPPER_CASE"], + }, + { + selector: "typeLike", + format: ["PascalCase"], + }, + ], }, - }, - rules: { - '@typescript-eslint/naming-convention': [ - 'error', - { - selector: 'variableLike', - format: ['camelCase'], - }, - { - selector: 'variable', - modifiers: ['const'], - format: ['camelCase', 'UPPER_CASE'], - }, - { - selector: 'typeLike', - format: ['PascalCase'], - }, - ], - }, }, { ignores: [ diff --git a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts index 22b4a197..ed8769ef 100644 --- a/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts +++ b/frontend/ic_vetkeys/src/encrypted_maps/encrypted_maps_canister.test.ts @@ -26,7 +26,10 @@ async function newEncryptedMaps( }); const canisterId = process.env.CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER; - if (!canisterId) throw new Error("CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER is not set"); + if (!canisterId) + throw new Error( + "CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER is not set", + ); return new EncryptedMaps(new DefaultEncryptedMapsClient(agent, canisterId)); } diff --git a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts index 3223d7f1..65fd545c 100644 --- a/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts +++ b/frontend/ic_vetkeys/src/key_manager/key_manager_canister.test.ts @@ -23,7 +23,8 @@ async function newKeyManager(id: Ed25519KeyIdentity): Promise { shouldFetchRootKey: true, }); const canisterId = process.env.CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER; - if (!canisterId) throw new Error("CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER is not set"); + if (!canisterId) + throw new Error("CANISTER_ID_IC_VETKEYS_MANAGER_CANISTER is not set"); return new KeyManager(new DefaultKeyManagerClient(agent, canisterId)); } diff --git a/frontend/ic_vetkeys/tsconfig.json b/frontend/ic_vetkeys/tsconfig.json index cac60269..f49ac81c 100644 --- a/frontend/ic_vetkeys/tsconfig.json +++ b/frontend/ic_vetkeys/tsconfig.json @@ -1,25 +1,19 @@ { - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "module": "ES2020", - "declaration": true, - "outDir": "dist/types", - "lib": [ - "ES2020", - "DOM", - "DOM.Iterable" - ], - "skipLibCheck": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "isolatedModules": true, - "moduleDetection": "force", - "noEmit": true, - "noUncheckedSideEffectImports": true, - }, - "include": [ - "src" - ], -} \ No newline at end of file + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ES2020", + "declaration": true, + "outDir": "dist/types", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "noUncheckedSideEffectImports": true + }, + "include": ["src"] +} diff --git a/frontend/ic_vetkeys/tsconfig.tests.json b/frontend/ic_vetkeys/tsconfig.tests.json index cd763b40..76af6298 100644 --- a/frontend/ic_vetkeys/tsconfig.tests.json +++ b/frontend/ic_vetkeys/tsconfig.tests.json @@ -1,9 +1,5 @@ // tsconfig.tests.json (for lint/type-checking) { - "extends": "./tsconfig.json", - "include": [ - "src", - "src/**/*.test.ts", - "test/**/*.ts" - ] + "extends": "./tsconfig.json", + "include": ["src", "src/**/*.test.ts", "test/**/*.ts"] } diff --git a/frontend/ic_vetkeys/typedoc.json b/frontend/ic_vetkeys/typedoc.json index cb1115cd..0985c1d0 100644 --- a/frontend/ic_vetkeys/typedoc.json +++ b/frontend/ic_vetkeys/typedoc.json @@ -6,5 +6,5 @@ ], "excludeInternal": true, "excludeExternals": true, - "includeVersion": true, + "includeVersion": true } diff --git a/frontend/ic_vetkeys/vite.config.ts b/frontend/ic_vetkeys/vite.config.ts index 2706766d..e9a05010 100644 --- a/frontend/ic_vetkeys/vite.config.ts +++ b/frontend/ic_vetkeys/vite.config.ts @@ -1,26 +1,32 @@ -import { defineConfig } from 'vite'; -import path from 'path'; -import dts from 'vite-plugin-dts' +import { defineConfig } from "vite"; +import path from "path"; +import dts from "vite-plugin-dts"; export default defineConfig({ - plugins: [dts({ outDir: 'dist/types' })], + plugins: [dts({ outDir: "dist/types" })], build: { lib: { entry: { - index: path.resolve(__dirname, 'src/index.ts'), - key_manager: path.resolve(__dirname, 'src/key_manager/index.ts'), - encrypted_maps: path.resolve(__dirname, 'src/encrypted_maps/index.ts'), + index: path.resolve(__dirname, "src/index.ts"), + key_manager: path.resolve( + __dirname, + "src/key_manager/index.ts", + ), + encrypted_maps: path.resolve( + __dirname, + "src/encrypted_maps/index.ts", + ), }, - name: 'ic_vetkeys', - formats: ['es'], + name: "ic_vetkeys", + formats: ["es"], fileName: (format, entryName) => `${entryName}.${format}.js`, }, - outDir: 'dist/lib', - emptyOutDir: true + outDir: "dist/lib", + emptyOutDir: true, }, test: { environment: "happy-dom", - setupFiles: ['test/setup.ts'], - testTimeout: 120000 - } + setupFiles: ["test/setup.ts"], + testTimeout: 120000, + }, }); From 96d77cea1e6b8806f8ae98ef1dff120119fa891d Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 23:19:41 +0200 Subject: [PATCH 11/24] fix(tests): prevent flaky should_access_map_values test on key collision Use BTreeMap instead of Vec for keyvals so that if random_map_key generates a duplicate key, the expected value is updated to match the last insert (which is what the canister stores). Previously a collision caused the Vec to hold two entries for the same key with different expected values, making the per-key assertion fail non-deterministically. Co-Authored-By: Claude Sonnet 4.6 --- .../ic_vetkeys_encrypted_maps_canister/tests/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs index 65d034b3..e3264013 100644 --- a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs +++ b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs @@ -665,7 +665,7 @@ fn should_access_map_values() { let map_name = random_map_name(rng); let mut authorized_users = vec![(caller, AccessRights::ReadWriteManage)]; - let mut keyvals = vec![]; + let mut keyvals: BTreeMap = BTreeMap::new(); for _ in 0..3 { let map_key = random_map_key(rng); @@ -697,7 +697,7 @@ fn should_access_map_values() { authorized_users.push((user_to_be_added, access_rights)); } - keyvals.push((map_key, encrypted_value)); + keyvals.insert(map_key, encrypted_value); } for (map_key, encrypted_value) in keyvals.clone() { @@ -714,7 +714,7 @@ fn should_access_map_values() { } for (user, _access_rights) in authorized_users.clone() { - let expected_map = BTreeMap::from_iter(keyvals.clone()); + let expected_map = keyvals.clone(); let computed_map_single = BTreeMap::from_iter( env.query::, String>>( user, From f6427060fd618127d1ebc1a15d033ac246a571dc Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 23:39:16 +0200 Subject: [PATCH 12/24] chore: use test_key_1 instead of dfx_test_key in icp.yaml and canister tests Standardise on the icp-cli/PocketIC key name now that dfx is no longer used. The library retains backward-compatible handling of dfx_test_key for existing deployments. Co-Authored-By: Claude Sonnet 4.6 --- .../ic_vetkeys_encrypted_maps_canister/tests/tests.rs | 2 +- .../rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs | 2 +- backend/rs/canisters/icp.yaml | 4 ++-- backend/rs/canisters/tests/tests/sign_with_bls.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs index e3264013..97a75821 100644 --- a/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs +++ b/backend/rs/canisters/ic_vetkeys_encrypted_maps_canister/tests/tests.rs @@ -984,7 +984,7 @@ impl TestEnvironment { pic.install_canister( example_canister_id, example_wasm_bytes, - encode_one("dfx_test_key").unwrap(), + encode_one("test_key_1").unwrap(), None, ); diff --git a/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs b/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs index 40332726..3fc7e2e8 100644 --- a/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs +++ b/backend/rs/canisters/ic_vetkeys_manager_canister/tests/tests.rs @@ -531,7 +531,7 @@ impl TestEnvironment { pic.install_canister( example_canister_id, example_wasm_bytes, - encode_one("dfx_test_key").unwrap(), + encode_one("test_key_1").unwrap(), None, ); diff --git a/backend/rs/canisters/icp.yaml b/backend/rs/canisters/icp.yaml index 36c737bf..08b15663 100644 --- a/backend/rs/canisters/icp.yaml +++ b/backend/rs/canisters/icp.yaml @@ -7,7 +7,7 @@ canisters: candid: ic_vetkeys_manager_canister/ic_vetkeys_manager_canister.did init_args: type: text - value: "(\"dfx_test_key\")" + value: "(\"test_key_1\")" - name: ic_vetkeys_encrypted_maps_canister recipe: type: "@dfinity/rust@v3.2.0" @@ -16,4 +16,4 @@ canisters: candid: ic_vetkeys_encrypted_maps_canister/ic_vetkeys_encrypted_maps_canister.did init_args: type: text - value: "(\"dfx_test_key\")" + value: "(\"test_key_1\")" diff --git a/backend/rs/canisters/tests/tests/sign_with_bls.rs b/backend/rs/canisters/tests/tests/sign_with_bls.rs index 2e1b3f5e..3b73b96c 100644 --- a/backend/rs/canisters/tests/tests/sign_with_bls.rs +++ b/backend/rs/canisters/tests/tests/sign_with_bls.rs @@ -14,7 +14,7 @@ fn bls_signature_should_be_valid_and_equal_to_decrypted_vetkey() { let context = random_bytes(rng, 10); let key_id = VetKDKeyId { curve: VetKDCurve::Bls12_381_G2, - name: "dfx_test_key".to_string(), + name: "test_key_1".to_string(), }; let transport_secret_key = random_transport_key(rng); let transport_public_key = transport_secret_key.public_key(); @@ -56,7 +56,7 @@ fn bls_public_key_should_be_equal_to_verification_key() { let context = random_bytes(rng, 10); let key_id = VetKDKeyId { curve: VetKDCurve::Bls12_381_G2, - name: "dfx_test_key".to_string(), + name: "test_key_1".to_string(), }; let bls_public_key: Vec = env.update( Principal::anonymous(), From a2e4524cd67db58ef2488027fee2331f2c5ce671 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:17:31 +0200 Subject: [PATCH 13/24] feat(examples): migrate all 7 example frontends to @icp-sdk/core Replace @dfinity/auth-client and @dfinity/principal dependencies with @icp-sdk/auth and @icp-sdk/core across all 7 example frontends. Reference @dfinity/vetkeys via local file: path pending npm release. Also add dev:motoko / dev:rust npm scripts, update vite configs to use canister environment from @icp-sdk/core, update gen_bindings.sh scripts to use icp-cli, refresh package-lock.json files, update declaration files and encrypted_maps_canister.ts to match current backend interface, remove deprecated baseUrl from tsconfig, rename tailwind.config.cjs to .mjs in password_manager examples (package.json has "type":"module"), and remove window.global polyfill (no longer needed with icp-sdk). Co-Authored-By: Claude Sonnet 4.6 --- .../frontend/package-lock.json | 439 +- .../basic_bls_signing/frontend/package.json | 10 +- .../frontend/scripts/gen_bindings.sh | 11 +- .../basic_bls_signing/frontend/vite.config.ts | 74 +- examples/basic_ibe/frontend/package-lock.json | 439 +- examples/basic_ibe/frontend/package.json | 10 +- .../frontend/scripts/gen_bindings.sh | 9 +- examples/basic_ibe/frontend/vite.config.ts | 74 +- .../frontend/package-lock.json | 440 +- .../basic_timelock_ibe/frontend/package.json | 7 +- .../frontend/scripts/gen_bindings.sh | 10 +- .../frontend/vite.config.ts | 69 +- .../encrypted_chat/frontend/package-lock.json | 236 +- examples/encrypted_chat/frontend/package.json | 9 +- .../frontend/scripts/gen_bindings.sh | 18 +- .../encrypted_chat/frontend/vite.config.ts | 91 +- .../frontend/package-lock.json | 23358 ++-------------- .../frontend/package.json | 72 +- .../frontend/rollup.config.js | 121 - .../frontend/scripts/gen_bindings.sh | 15 +- .../frontend/src/global.d.ts | 2 +- .../frontend/tailwind.config.js | 10 - .../frontend/tsconfig.json | 22 +- .../frontend/vite.config.ts | 61 + .../frontend/package-lock.json | 524 +- .../password_manager/frontend/package.json | 16 +- .../frontend/tailwind.config.cjs | 6 - .../password_manager/frontend/vite.config.ts | 110 +- .../frontend/package-lock.json | 445 +- .../frontend/package.json | 13 +- .../frontend/scripts/gen_bindings.sh | 18 +- .../frontend/tailwind.config.cjs | 9 - .../frontend/vite.config.js | 65 +- 33 files changed, 4209 insertions(+), 22604 deletions(-) delete mode 100644 examples/encrypted_notes_dapp_vetkd/frontend/rollup.config.js delete mode 100644 examples/encrypted_notes_dapp_vetkd/frontend/tailwind.config.js create mode 100644 examples/encrypted_notes_dapp_vetkd/frontend/vite.config.ts delete mode 100644 examples/password_manager/frontend/tailwind.config.cjs delete mode 100644 examples/password_manager_with_metadata/frontend/tailwind.config.cjs diff --git a/examples/basic_bls_signing/frontend/package-lock.json b/examples/basic_bls_signing/frontend/package-lock.json index 21557e27..97f74d0d 100644 --- a/examples/basic_bls_signing/frontend/package-lock.json +++ b/examples/basic_bls_signing/frontend/package-lock.json @@ -8,9 +8,9 @@ "name": "basic_bls_signing_frontend", "version": "0.0.0", "dependencies": { - "@dfinity/auth-client": "^2.4.1", - "@dfinity/principal": "^2.4.1", - "@dfinity/vetkeys": "^0.3.0" + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1" }, "devDependencies": { "@eslint/js": "^9.24.0", @@ -26,83 +26,42 @@ "vite-plugin-environment": "^1.1.3" } }, - "node_modules/@dfinity/agent": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-2.4.1.tgz", - "integrity": "sha512-IczFFOUDGfMTdQ83yiCvGtvHr1IIB80lWBP0ZYRLogs6NVt8t6HYcMlu1sgT+9VivhT7iwX4pktPFxxOkO3COw==", - "license": "Apache-2.0", - "dependencies": { - "@noble/curves": "^1.4.0", - "@noble/hashes": "^1.3.1", - "base64-arraybuffer": "^0.2.0", - "borc": "^2.1.1", - "buffer": "^6.0.3", - "simple-cbor": "^0.4.1" - }, - "peerDependencies": { - "@dfinity/candid": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/auth-client": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-2.4.1.tgz", - "integrity": "sha512-osKgBWwMsMyQUNYhFxPqj14R2RhgdYVD0PoTGDig2sl1Hy4mQzPalCWbkW9R50vsZGmoMi/uiopvnXy036EyqA==", - "license": "Apache-2.0", - "dependencies": { - "idb": "^7.0.2" - }, - "peerDependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/identity": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/candid": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-2.4.1.tgz", - "integrity": "sha512-kOaIKfhR2PYN8vD4M0Pc4s/7wb1nKjlTJUw+5E9jh26T03fITIZmaafIuwlX+wmdxwIT9Xoy7PlsxOEpzv203A==", - "license": "Apache-2.0", - "peerDependencies": { - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/identity": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-2.4.1.tgz", - "integrity": "sha512-CXhTmdtqkA0vE6ue2GaF9ZwD0OQ5OinrGj77Eg0dX0zPZpxJQ+NCjyYNWkaIvsKxmnCaW+5yrCcchN8Sqk8uIA==", + "../../../frontend/ic_vetkeys": { + "name": "@dfinity/vetkeys", + "version": "0.4.0", "license": "Apache-2.0", - "peer": true, "dependencies": { - "@noble/curves": "^1.2.0", - "@noble/hashes": "^1.3.1", - "borc": "^2.1.1" + "@icp-sdk/core": "^5.2.1", + "idb-keyval": "^6.2.1" }, - "peerDependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/principal": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-2.4.1.tgz", - "integrity": "sha512-Cz6XQVOwq0TXDBClPbcidDd4SqK1lfr1/Kn34ruDD13xVQ4iaP1iCntzS9O97+vGpY/6jwDtKd32Gn5YJ9BQNw==", - "license": "Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.3.1" - } + "devDependencies": { + "@eslint/js": "^9.22.0", + "@types/node": "^24.0.4", + "@vitest/coverage-v8": "^3.0.5", + "eslint": "^9.22", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.2.6", + "fake-indexeddb": "^6.0.0", + "happy-dom": "^20.0.2", + "isomorphic-fetch": "3.0.0", + "prettier": "^3.5.3", + "typedoc": "^0.28.3", + "typescript": "^5.7.3", + "typescript-eslint": "8.27", + "vite": "^7.0.8", + "vite-plugin-dts": "^4.5.3", + "vitest": "^3.0.5" + } + }, + "node_modules/@dfinity/cbor": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@dfinity/cbor/-/cbor-0.2.2.tgz", + "integrity": "sha512-GPJpH73kDEKbUBdUjY80lz7cq9l0vm1h/7ppejPV6O0ZTqCLrYspssYvqjRmK4aNnJ/SKXsP0rg9LYX7zpegaA==", + "license": "Apache-2.0" }, "node_modules/@dfinity/vetkeys": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@dfinity/vetkeys/-/vetkeys-0.3.0.tgz", - "integrity": "sha512-28Phonh5BkMNL2Fkw5wwLR2NH5/+0q5Dapbwyz0RdddJYQALB5YlnQh7mTmmaY2zMkHsK25D5lyd90g/FcrMpQ==", - "license": "Apache-2.0", - "dependencies": { - "@dfinity/agent": "^2.3.0", - "@dfinity/candid": "^2.3.0", - "@dfinity/principal": "^2.3.0", - "idb-keyval": "^6.2.1" - } + "resolved": "../../../frontend/ic_vetkeys", + "link": true }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.5", @@ -749,10 +708,37 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@icp-sdk/auth": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@icp-sdk/auth/-/auth-5.0.0.tgz", + "integrity": "sha512-TaPfdaELT7s0vTIFOmCnlCmhPdL7kABA7+2Q0YNAUWIa/FFiwq6ffGPLvr0U0+2zFLaLQ4l7UCB2zf7vo6PFPQ==", + "license": "Apache-2.0", + "dependencies": { + "idb": "^7.1.1" + }, + "peerDependencies": { + "@icp-sdk/core": "^5" + } + }, + "node_modules/@icp-sdk/core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@icp-sdk/core/-/core-5.2.1.tgz", + "integrity": "sha512-FImRjnayCarov7vfr52QU3BO8tPAprbyl4O+0KWz4v7h8ZbKq15fhtdb53M6+ltUsCbWkP/lEgrQ4t1WhIAHjQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@dfinity/cbor": "^0.2.2", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "asn1js": "^3.0.7" + } + }, "node_modules/@noble/curves": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", - "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" @@ -1157,6 +1143,42 @@ "win32" ] }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1177,6 +1199,7 @@ "integrity": "sha512-ENHwaH+JIRTDIEEbDK6QSQntAYGtbvdDXnMXnZaZ6k13Du1dPMmprkEHIL7ok2Wl2aZevetwTAb5S+7yIF+enA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.8.0" } @@ -1227,6 +1250,7 @@ "integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.35.1", "@typescript-eslint/types": "8.35.1", @@ -1444,6 +1468,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1501,6 +1526,20 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1508,85 +1547,6 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-arraybuffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", - "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", - "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/borc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", - "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0", - "buffer": "^5.5.0", - "commander": "^2.15.0", - "ieee754": "^1.1.13", - "iso-url": "~0.4.7", - "json-text-sequence": "~0.1.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/borc/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1611,30 +1571,6 @@ "node": ">=8" } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1682,12 +1618,6 @@ "dev": true, "license": "MIT" }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1735,12 +1665,6 @@ "dev": true, "license": "MIT" }, - "node_modules/delimit-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", - "integrity": "sha512-a02fiQ7poS5CnjiJBAsjGLPp5EwVoGHNeu9sziBd9huppRfsAFIpv5zNLv0V1gbop53ilngAf5Kf331AwcoRBQ==", - "license": "BSD-2-Clause" - }, "node_modules/esbuild": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", @@ -1801,6 +1725,7 @@ "integrity": "sha512-iN/SiPxmQu6EVkf+m1qpBxzUhE12YqFLOSySuOyVLJLEF9nzTf+h/1AJYc1JWzCnktggeNrjvQGLngDzXirU6g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -1862,6 +1787,7 @@ "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -2238,32 +2164,6 @@ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", "license": "ISC" }, - "node_modules/idb-keyval": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", - "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", - "license": "Apache-2.0" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2301,12 +2201,6 @@ "node": ">=0.8.19" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -2363,15 +2257,6 @@ "dev": true, "license": "ISC" }, - "node_modules/iso-url": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", - "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -2406,15 +2291,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-text-sequence": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", - "integrity": "sha512-L3mEegEWHRekSHjc7+sc8eJhba9Clq1PZ8kMkzf8OxElhXc8O4TS5MwcVlj9aEbm5dr81N90WHC5nAz3UO971w==", - "license": "MIT", - "dependencies": { - "delimit-stream": "0.1.0" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2734,6 +2610,24 @@ "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2755,20 +2649,6 @@ ], "license": "MIT" }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -2817,6 +2697,7 @@ "integrity": "sha512-x8H8aPvD+xbl0Do8oez5f5o8eMS3trfCghc4HhLAnCkj7Vl0d1JWGs0UF/D886zLW2rOj2QymV/JcSSsw+XDNg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -2875,26 +2756,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -2931,12 +2792,6 @@ "node": ">=8" } }, - "node_modules/simple-cbor": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", - "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==", - "license": "ISC" - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2947,15 +2802,6 @@ "node": ">=0.10.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3058,7 +2904,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/type-check": { @@ -3080,6 +2925,7 @@ "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3128,18 +2974,13 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, "node_modules/vite": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", diff --git a/examples/basic_bls_signing/frontend/package.json b/examples/basic_bls_signing/frontend/package.json index f103fde2..8e35ba2e 100644 --- a/examples/basic_bls_signing/frontend/package.json +++ b/examples/basic_bls_signing/frontend/package.json @@ -4,7 +4,9 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "npm run build:bindings && vite", + "dev": "printf '\\nNo backend specified. Use one of:\\n\\n npm run dev:motoko\\n npm run dev:rust\\n\\n' && exit 1", + "dev:motoko": "npm run build:bindings && BACKEND=motoko vite", + "dev:rust": "npm run build:bindings && BACKEND=rust vite", "build": "npm run build:bindings && tsc && vite build", "build:bindings": "cd scripts && ./gen_bindings.sh", "preview": "vite preview", @@ -24,8 +26,8 @@ "vite-plugin-environment": "^1.1.3" }, "dependencies": { - "@dfinity/auth-client": "^2.4.1", - "@dfinity/principal": "^2.4.1", - "@dfinity/vetkeys": "^0.3.0" + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1" } } diff --git a/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh b/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh index edfbc222..e15c3899 100755 --- a/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh +++ b/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh @@ -1,11 +1,12 @@ #!/bin/bash -cd ../../backend && make extract-candid +# Bindings are always generated from the Rust backend since both backends +# expose the same Candid interface. +cd ../../rust/backend && make extract-candid -cd .. && dfx generate basic_bls_signing || exit 1 +cd ../.. -rm -r frontend/src/declarations/basic_bls_signing > /dev/null 2>&1 || true +rm -rf frontend/src/declarations/basic_bls_signing mkdir -p frontend/src/declarations/basic_bls_signing -mv src/declarations/basic_bls_signing frontend/src/declarations -rmdir -p src/declarations > /dev/null 2>&1 || true \ No newline at end of file +npx @icp-sdk/bindgen --did-file rust/backend/backend.did --out-dir frontend/src/declarations/basic_bls_signing --declarations-flat --force diff --git a/examples/basic_bls_signing/frontend/vite.config.ts b/examples/basic_bls_signing/frontend/vite.config.ts index 27bf8157..0615cf57 100644 --- a/examples/basic_bls_signing/frontend/vite.config.ts +++ b/examples/basic_bls_signing/frontend/vite.config.ts @@ -1,27 +1,51 @@ -import { defineConfig } from 'vite' -import typescript from '@rollup/plugin-typescript'; -import environment from 'vite-plugin-environment'; -import path from 'path'; +import { defineConfig } from "vite"; +import { execSync } from "child_process"; -// https://vite.dev/config/ -export default defineConfig({ - plugins: [ - typescript({ - inlineSources: true, - }), - environment("all", { prefix: "CANISTER_" }), - environment("all", { prefix: "DFX_" }), - ], - build: { - sourcemap: true, - rollupOptions: { - output: { - inlineDynamicImports: true, - }, +const environment = process.env.ICP_ENVIRONMENT || "local"; +const CANISTER_NAMES = ["basic_bls_signing"]; + +function getDevServerConfig() { + const backend = process.env.BACKEND; + if (!backend) { + throw new Error( + "BACKEND env var is required. Use `npm run dev:motoko` or `npm run dev:rust`.", + ); + } + + const networkStatus = JSON.parse( + execSync(`icp network status -e ${environment} --json --project-root-override ../${backend}`, { + encoding: "utf-8", + }), + ); + const canisterParams = CANISTER_NAMES.map((name) => { + const id = execSync( + `icp canister status ${name} -e ${environment} --id-only --project-root-override ../${backend}`, + { encoding: "utf-8", stdio: "pipe" }, + ).trim(); + return `PUBLIC_CANISTER_ID:${name}=${id}`; + }).join("&"); + return { + headers: { + "Set-Cookie": `ic_env=${encodeURIComponent( + `${canisterParams}&ic_root_key=${networkStatus.root_key}`, + )}; SameSite=Lax;`, + }, + proxy: { + "/api": { target: networkStatus.api_url, changeOrigin: true }, + }, + hmr: false, + }; +} + +export default defineConfig(({ command }) => ({ + build: { + sourcemap: true, + rollupOptions: { + output: { + inlineDynamicImports: true, + }, + }, }, - }, - root: "./", - server: { - hmr: false - } -}) \ No newline at end of file + root: "./", + ...(command === "serve" ? { server: getDevServerConfig() } : {}), +})); diff --git a/examples/basic_ibe/frontend/package-lock.json b/examples/basic_ibe/frontend/package-lock.json index 12938df3..d0009ab3 100644 --- a/examples/basic_ibe/frontend/package-lock.json +++ b/examples/basic_ibe/frontend/package-lock.json @@ -8,9 +8,9 @@ "name": "basic-ibe-frontend", "version": "0.0.0", "dependencies": { - "@dfinity/auth-client": "^2.4.1", - "@dfinity/principal": "^2.4.1", - "@dfinity/vetkeys": "^0.3.0" + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1" }, "devDependencies": { "@eslint/js": "^9.24.0", @@ -26,83 +26,42 @@ "vite-plugin-environment": "^1.1.3" } }, - "node_modules/@dfinity/agent": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-2.4.1.tgz", - "integrity": "sha512-IczFFOUDGfMTdQ83yiCvGtvHr1IIB80lWBP0ZYRLogs6NVt8t6HYcMlu1sgT+9VivhT7iwX4pktPFxxOkO3COw==", - "license": "Apache-2.0", - "dependencies": { - "@noble/curves": "^1.4.0", - "@noble/hashes": "^1.3.1", - "base64-arraybuffer": "^0.2.0", - "borc": "^2.1.1", - "buffer": "^6.0.3", - "simple-cbor": "^0.4.1" - }, - "peerDependencies": { - "@dfinity/candid": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/auth-client": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-2.4.1.tgz", - "integrity": "sha512-osKgBWwMsMyQUNYhFxPqj14R2RhgdYVD0PoTGDig2sl1Hy4mQzPalCWbkW9R50vsZGmoMi/uiopvnXy036EyqA==", - "license": "Apache-2.0", - "dependencies": { - "idb": "^7.0.2" - }, - "peerDependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/identity": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/candid": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-2.4.1.tgz", - "integrity": "sha512-kOaIKfhR2PYN8vD4M0Pc4s/7wb1nKjlTJUw+5E9jh26T03fITIZmaafIuwlX+wmdxwIT9Xoy7PlsxOEpzv203A==", - "license": "Apache-2.0", - "peerDependencies": { - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/identity": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-2.4.1.tgz", - "integrity": "sha512-CXhTmdtqkA0vE6ue2GaF9ZwD0OQ5OinrGj77Eg0dX0zPZpxJQ+NCjyYNWkaIvsKxmnCaW+5yrCcchN8Sqk8uIA==", + "../../../frontend/ic_vetkeys": { + "name": "@dfinity/vetkeys", + "version": "0.4.0", "license": "Apache-2.0", - "peer": true, "dependencies": { - "@noble/curves": "^1.2.0", - "@noble/hashes": "^1.3.1", - "borc": "^2.1.1" + "@icp-sdk/core": "^5.2.1", + "idb-keyval": "^6.2.1" }, - "peerDependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/principal": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-2.4.1.tgz", - "integrity": "sha512-Cz6XQVOwq0TXDBClPbcidDd4SqK1lfr1/Kn34ruDD13xVQ4iaP1iCntzS9O97+vGpY/6jwDtKd32Gn5YJ9BQNw==", - "license": "Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.3.1" - } + "devDependencies": { + "@eslint/js": "^9.22.0", + "@types/node": "^24.0.4", + "@vitest/coverage-v8": "^3.0.5", + "eslint": "^9.22", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.2.6", + "fake-indexeddb": "^6.0.0", + "happy-dom": "^20.0.2", + "isomorphic-fetch": "3.0.0", + "prettier": "^3.5.3", + "typedoc": "^0.28.3", + "typescript": "^5.7.3", + "typescript-eslint": "8.27", + "vite": "^7.0.8", + "vite-plugin-dts": "^4.5.3", + "vitest": "^3.0.5" + } + }, + "node_modules/@dfinity/cbor": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@dfinity/cbor/-/cbor-0.2.2.tgz", + "integrity": "sha512-GPJpH73kDEKbUBdUjY80lz7cq9l0vm1h/7ppejPV6O0ZTqCLrYspssYvqjRmK4aNnJ/SKXsP0rg9LYX7zpegaA==", + "license": "Apache-2.0" }, "node_modules/@dfinity/vetkeys": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@dfinity/vetkeys/-/vetkeys-0.3.0.tgz", - "integrity": "sha512-28Phonh5BkMNL2Fkw5wwLR2NH5/+0q5Dapbwyz0RdddJYQALB5YlnQh7mTmmaY2zMkHsK25D5lyd90g/FcrMpQ==", - "license": "Apache-2.0", - "dependencies": { - "@dfinity/agent": "^2.3.0", - "@dfinity/candid": "^2.3.0", - "@dfinity/principal": "^2.3.0", - "idb-keyval": "^6.2.1" - } + "resolved": "../../../frontend/ic_vetkeys", + "link": true }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.5", @@ -749,10 +708,37 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@icp-sdk/auth": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@icp-sdk/auth/-/auth-5.0.0.tgz", + "integrity": "sha512-TaPfdaELT7s0vTIFOmCnlCmhPdL7kABA7+2Q0YNAUWIa/FFiwq6ffGPLvr0U0+2zFLaLQ4l7UCB2zf7vo6PFPQ==", + "license": "Apache-2.0", + "dependencies": { + "idb": "^7.1.1" + }, + "peerDependencies": { + "@icp-sdk/core": "^5" + } + }, + "node_modules/@icp-sdk/core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@icp-sdk/core/-/core-5.2.1.tgz", + "integrity": "sha512-FImRjnayCarov7vfr52QU3BO8tPAprbyl4O+0KWz4v7h8ZbKq15fhtdb53M6+ltUsCbWkP/lEgrQ4t1WhIAHjQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@dfinity/cbor": "^0.2.2", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "asn1js": "^3.0.7" + } + }, "node_modules/@noble/curves": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", - "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" @@ -1157,6 +1143,42 @@ "win32" ] }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1177,6 +1199,7 @@ "integrity": "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.8.0" } @@ -1227,6 +1250,7 @@ "integrity": "sha512-3MyiDfrfLeK06bi/g9DqJxP5pV74LNv4rFTyvGDmT3x2p1yp1lOd+qYZfiRPIOf/oON+WRZR5wxxuF85qOar+w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.35.1", "@typescript-eslint/types": "8.35.1", @@ -1444,6 +1468,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1501,6 +1526,20 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1508,85 +1547,6 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-arraybuffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", - "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", - "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/borc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", - "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0", - "buffer": "^5.5.0", - "commander": "^2.15.0", - "ieee754": "^1.1.13", - "iso-url": "~0.4.7", - "json-text-sequence": "~0.1.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/borc/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1611,30 +1571,6 @@ "node": ">=8" } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1682,12 +1618,6 @@ "dev": true, "license": "MIT" }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1735,12 +1665,6 @@ "dev": true, "license": "MIT" }, - "node_modules/delimit-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", - "integrity": "sha512-a02fiQ7poS5CnjiJBAsjGLPp5EwVoGHNeu9sziBd9huppRfsAFIpv5zNLv0V1gbop53ilngAf5Kf331AwcoRBQ==", - "license": "BSD-2-Clause" - }, "node_modules/esbuild": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", @@ -1801,6 +1725,7 @@ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -1862,6 +1787,7 @@ "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -2238,32 +2164,6 @@ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", "license": "ISC" }, - "node_modules/idb-keyval": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", - "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", - "license": "Apache-2.0" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2301,12 +2201,6 @@ "node": ">=0.8.19" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -2363,15 +2257,6 @@ "dev": true, "license": "ISC" }, - "node_modules/iso-url": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", - "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", @@ -2406,15 +2291,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-text-sequence": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", - "integrity": "sha512-L3mEegEWHRekSHjc7+sc8eJhba9Clq1PZ8kMkzf8OxElhXc8O4TS5MwcVlj9aEbm5dr81N90WHC5nAz3UO971w==", - "license": "MIT", - "dependencies": { - "delimit-stream": "0.1.0" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2734,6 +2610,24 @@ "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2755,20 +2649,6 @@ ], "license": "MIT" }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -2817,6 +2697,7 @@ "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -2875,26 +2756,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -2931,12 +2792,6 @@ "node": ">=8" } }, - "node_modules/simple-cbor": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", - "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==", - "license": "ISC" - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -2947,15 +2802,6 @@ "node": ">=0.10.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3058,7 +2904,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/type-check": { @@ -3078,6 +2923,7 @@ "version": "5.7.3", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3126,18 +2972,13 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, "node_modules/vite": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", diff --git a/examples/basic_ibe/frontend/package.json b/examples/basic_ibe/frontend/package.json index ca7932ea..595c5007 100644 --- a/examples/basic_ibe/frontend/package.json +++ b/examples/basic_ibe/frontend/package.json @@ -4,7 +4,9 @@ "version": "0.0.0", "type": "module", "scripts": { - "dev": "npm run build:bindings && vite", + "dev": "printf '\\nNo backend specified. Use one of:\\n\\n npm run dev:motoko\\n npm run dev:rust\\n\\n' && exit 1", + "dev:motoko": "npm run build:bindings && BACKEND=motoko vite", + "dev:rust": "npm run build:bindings && BACKEND=rust vite", "build": "npm run build:bindings && tsc && vite build", "build:bindings": "cd scripts && ./gen_bindings.sh", "preview": "vite preview", @@ -24,8 +26,8 @@ "vite-plugin-environment": "^1.1.3" }, "dependencies": { - "@dfinity/auth-client": "^2.4.1", - "@dfinity/principal": "^2.4.1", - "@dfinity/vetkeys": "^0.3.0" + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1" } } diff --git a/examples/basic_ibe/frontend/scripts/gen_bindings.sh b/examples/basic_ibe/frontend/scripts/gen_bindings.sh index 6d7bb2fa..487c8be0 100755 --- a/examples/basic_ibe/frontend/scripts/gen_bindings.sh +++ b/examples/basic_ibe/frontend/scripts/gen_bindings.sh @@ -1,11 +1,10 @@ #!/bin/bash -cd ../../backend && make extract-candid +cd ../../rust/backend && make extract-candid -cd .. && dfx generate basic_ibe || exit 1 +cd ../.. -rm -r frontend/src/declarations/basic_ibe > /dev/null 2>&1 || true +rm -rf frontend/src/declarations/basic_ibe mkdir -p frontend/src/declarations/basic_ibe -mv src/declarations/basic_ibe frontend/src/declarations -rmdir -p src/declarations > /dev/null 2>&1 || true \ No newline at end of file +npx @icp-sdk/bindgen --did-file rust/backend/backend.did --out-dir frontend/src/declarations/basic_ibe --declarations-flat --force diff --git a/examples/basic_ibe/frontend/vite.config.ts b/examples/basic_ibe/frontend/vite.config.ts index 27bf8157..be565c16 100644 --- a/examples/basic_ibe/frontend/vite.config.ts +++ b/examples/basic_ibe/frontend/vite.config.ts @@ -1,27 +1,51 @@ -import { defineConfig } from 'vite' -import typescript from '@rollup/plugin-typescript'; -import environment from 'vite-plugin-environment'; -import path from 'path'; +import { defineConfig } from "vite"; +import { execSync } from "child_process"; -// https://vite.dev/config/ -export default defineConfig({ - plugins: [ - typescript({ - inlineSources: true, - }), - environment("all", { prefix: "CANISTER_" }), - environment("all", { prefix: "DFX_" }), - ], - build: { - sourcemap: true, - rollupOptions: { - output: { - inlineDynamicImports: true, - }, +const environment = process.env.ICP_ENVIRONMENT || "local"; +const CANISTER_NAMES = ["basic_ibe"]; + +function getDevServerConfig() { + const backend = process.env.BACKEND; + if (!backend) { + throw new Error( + "BACKEND env var is required. Use `npm run dev:motoko` or `npm run dev:rust`.", + ); + } + + const networkStatus = JSON.parse( + execSync(`icp network status -e ${environment} --json --project-root-override ../${backend}`, { + encoding: "utf-8", + }), + ); + const canisterParams = CANISTER_NAMES.map((name) => { + const id = execSync( + `icp canister status ${name} -e ${environment} --id-only --project-root-override ../${backend}`, + { encoding: "utf-8", stdio: "pipe" }, + ).trim(); + return `PUBLIC_CANISTER_ID:${name}=${id}`; + }).join("&"); + return { + headers: { + "Set-Cookie": `ic_env=${encodeURIComponent( + `${canisterParams}&ic_root_key=${networkStatus.root_key}`, + )}; SameSite=Lax;`, + }, + proxy: { + "/api": { target: networkStatus.api_url, changeOrigin: true }, + }, + hmr: false, + }; +} + +export default defineConfig(({ command }) => ({ + build: { + sourcemap: true, + rollupOptions: { + output: { + inlineDynamicImports: true, + }, + }, }, - }, - root: "./", - server: { - hmr: false - } -}) \ No newline at end of file + root: "./", + ...(command === "serve" ? { server: getDevServerConfig() } : {}), +})); diff --git a/examples/basic_timelock_ibe/frontend/package-lock.json b/examples/basic_timelock_ibe/frontend/package-lock.json index f0f4aaae..13cdd33d 100644 --- a/examples/basic_timelock_ibe/frontend/package-lock.json +++ b/examples/basic_timelock_ibe/frontend/package-lock.json @@ -8,10 +8,9 @@ "name": "basic-timelock-ibe-frontend", "version": "0.0.0", "dependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/auth-client": "^2.4.1", - "@dfinity/principal": "^2.4.1", - "@dfinity/vetkeys": "^0.3.0" + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1" }, "devDependencies": { "@eslint/js": "^9.24.0", @@ -27,83 +26,42 @@ "vite-plugin-environment": "^1.1.3" } }, - "node_modules/@dfinity/agent": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-2.4.1.tgz", - "integrity": "sha512-IczFFOUDGfMTdQ83yiCvGtvHr1IIB80lWBP0ZYRLogs6NVt8t6HYcMlu1sgT+9VivhT7iwX4pktPFxxOkO3COw==", - "license": "Apache-2.0", - "dependencies": { - "@noble/curves": "^1.4.0", - "@noble/hashes": "^1.3.1", - "base64-arraybuffer": "^0.2.0", - "borc": "^2.1.1", - "buffer": "^6.0.3", - "simple-cbor": "^0.4.1" - }, - "peerDependencies": { - "@dfinity/candid": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/auth-client": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-2.4.1.tgz", - "integrity": "sha512-osKgBWwMsMyQUNYhFxPqj14R2RhgdYVD0PoTGDig2sl1Hy4mQzPalCWbkW9R50vsZGmoMi/uiopvnXy036EyqA==", - "license": "Apache-2.0", - "dependencies": { - "idb": "^7.0.2" - }, - "peerDependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/identity": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/candid": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-2.4.1.tgz", - "integrity": "sha512-kOaIKfhR2PYN8vD4M0Pc4s/7wb1nKjlTJUw+5E9jh26T03fITIZmaafIuwlX+wmdxwIT9Xoy7PlsxOEpzv203A==", - "license": "Apache-2.0", - "peerDependencies": { - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/identity": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-2.4.1.tgz", - "integrity": "sha512-CXhTmdtqkA0vE6ue2GaF9ZwD0OQ5OinrGj77Eg0dX0zPZpxJQ+NCjyYNWkaIvsKxmnCaW+5yrCcchN8Sqk8uIA==", + "../../../frontend/ic_vetkeys": { + "name": "@dfinity/vetkeys", + "version": "0.4.0", "license": "Apache-2.0", - "peer": true, "dependencies": { - "@noble/curves": "^1.2.0", - "@noble/hashes": "^1.3.1", - "borc": "^2.1.1" + "@icp-sdk/core": "^5.2.1", + "idb-keyval": "^6.2.1" }, - "peerDependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/principal": "^2.4.1" - } - }, - "node_modules/@dfinity/principal": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-2.4.1.tgz", - "integrity": "sha512-Cz6XQVOwq0TXDBClPbcidDd4SqK1lfr1/Kn34ruDD13xVQ4iaP1iCntzS9O97+vGpY/6jwDtKd32Gn5YJ9BQNw==", - "license": "Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.3.1" - } + "devDependencies": { + "@eslint/js": "^9.22.0", + "@types/node": "^24.0.4", + "@vitest/coverage-v8": "^3.0.5", + "eslint": "^9.22", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.2.6", + "fake-indexeddb": "^6.0.0", + "happy-dom": "^20.0.2", + "isomorphic-fetch": "3.0.0", + "prettier": "^3.5.3", + "typedoc": "^0.28.3", + "typescript": "^5.7.3", + "typescript-eslint": "8.27", + "vite": "^7.0.8", + "vite-plugin-dts": "^4.5.3", + "vitest": "^3.0.5" + } + }, + "node_modules/@dfinity/cbor": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/@dfinity/cbor/-/cbor-0.2.2.tgz", + "integrity": "sha512-GPJpH73kDEKbUBdUjY80lz7cq9l0vm1h/7ppejPV6O0ZTqCLrYspssYvqjRmK4aNnJ/SKXsP0rg9LYX7zpegaA==", + "license": "Apache-2.0" }, "node_modules/@dfinity/vetkeys": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@dfinity/vetkeys/-/vetkeys-0.3.0.tgz", - "integrity": "sha512-28Phonh5BkMNL2Fkw5wwLR2NH5/+0q5Dapbwyz0RdddJYQALB5YlnQh7mTmmaY2zMkHsK25D5lyd90g/FcrMpQ==", - "license": "Apache-2.0", - "dependencies": { - "@dfinity/agent": "^2.3.0", - "@dfinity/candid": "^2.3.0", - "@dfinity/principal": "^2.3.0", - "idb-keyval": "^6.2.1" - } + "resolved": "../../../frontend/ic_vetkeys", + "link": true }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.5", @@ -750,10 +708,37 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@icp-sdk/auth": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@icp-sdk/auth/-/auth-5.0.0.tgz", + "integrity": "sha512-TaPfdaELT7s0vTIFOmCnlCmhPdL7kABA7+2Q0YNAUWIa/FFiwq6ffGPLvr0U0+2zFLaLQ4l7UCB2zf7vo6PFPQ==", + "license": "Apache-2.0", + "dependencies": { + "idb": "^7.1.1" + }, + "peerDependencies": { + "@icp-sdk/core": "^5" + } + }, + "node_modules/@icp-sdk/core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@icp-sdk/core/-/core-5.2.1.tgz", + "integrity": "sha512-FImRjnayCarov7vfr52QU3BO8tPAprbyl4O+0KWz4v7h8ZbKq15fhtdb53M6+ltUsCbWkP/lEgrQ4t1WhIAHjQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@dfinity/cbor": "^0.2.2", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "asn1js": "^3.0.7" + } + }, "node_modules/@noble/curves": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.2.tgz", - "integrity": "sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" @@ -1228,6 +1213,42 @@ "win32" ] }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -1248,6 +1269,7 @@ "integrity": "sha512-ulyqAkrhnuNq9pB76DRBTkcS6YsmDALy6Ua63V8OhrOBgbcYt6IOdzpw5P1+dyRIyMerzLkeYWBeOXPpA9GMAA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~7.8.0" } @@ -1298,6 +1320,7 @@ "integrity": "sha512-6sMvZePQrnZH2/cJkwRpkT7DxoAWh+g6+GFRK6bV3YQo7ogi3SX5rgF6099r5Q53Ma5qeT7LGmOmuIutF4t3lA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.35.0", "@typescript-eslint/types": "8.35.0", @@ -1515,6 +1538,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1572,6 +1596,20 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1579,85 +1617,6 @@ "dev": true, "license": "MIT" }, - "node_modules/base64-arraybuffer": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.2.0.tgz", - "integrity": "sha512-7emyCsu1/xiBXgQZrscw/8KPRT44I4Yq9Pe6EGs3aPRTsWuggML1/1DTuZUuIaJPIm1FTDUVXl4x/yW8s0kQDQ==", - "engines": { - "node": ">= 0.6.0" - } - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", - "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/borc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/borc/-/borc-2.1.2.tgz", - "integrity": "sha512-Sy9eoUi4OiKzq7VovMn246iTo17kzuyHJKomCfpWMlI6RpfN1gk95w7d7gH264nApVLg0HZfcpz62/g4VH1Y4w==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0", - "buffer": "^5.5.0", - "commander": "^2.15.0", - "ieee754": "^1.1.13", - "iso-url": "~0.4.7", - "json-text-sequence": "~0.1.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/borc/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, "node_modules/brace-expansion": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", @@ -1682,30 +1641,6 @@ "node": ">=8" } }, - "node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1753,12 +1688,6 @@ "dev": true, "license": "MIT" }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT" - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1806,12 +1735,6 @@ "dev": true, "license": "MIT" }, - "node_modules/delimit-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/delimit-stream/-/delimit-stream-0.1.0.tgz", - "integrity": "sha512-a02fiQ7poS5CnjiJBAsjGLPp5EwVoGHNeu9sziBd9huppRfsAFIpv5zNLv0V1gbop53ilngAf5Kf331AwcoRBQ==", - "license": "BSD-2-Clause" - }, "node_modules/esbuild": { "version": "0.25.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", @@ -1872,6 +1795,7 @@ "integrity": "sha512-GsGizj2Y1rCWDu6XoEekL3RLilp0voSePurjZIkxL3wlm5o5EC9VpgaP7lrCvjnkuLvzFBQWB3vWB3K5KQTveQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -1933,6 +1857,7 @@ "integrity": "sha512-zc1UmCpNltmVY34vuLRV61r1K27sWuX39E+uyUnY8xS2Bex88VV9cugG+UZbRSRGtGyFboj+D8JODyme1plMpw==", "dev": true, "license": "MIT", + "peer": true, "bin": { "eslint-config-prettier": "bin/cli.js" }, @@ -2309,32 +2234,6 @@ "integrity": "sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==", "license": "ISC" }, - "node_modules/idb-keyval": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/idb-keyval/-/idb-keyval-6.2.2.tgz", - "integrity": "sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==", - "license": "Apache-2.0" - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -2372,12 +2271,6 @@ "node": ">=0.8.19" } }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -2434,15 +2327,6 @@ "dev": true, "license": "ISC" }, - "node_modules/iso-url": { - "version": "0.4.7", - "resolved": "https://registry.npmjs.org/iso-url/-/iso-url-0.4.7.tgz", - "integrity": "sha512-27fFRDnPAMnHGLq36bWTpKET+eiXct3ENlCcdcMdk+mjXrb2kw3mhBUg1B7ewAC0kVzlOPhADzQgz1SE6Tglog==", - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/js-yaml": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.1.tgz", @@ -2477,15 +2361,6 @@ "dev": true, "license": "MIT" }, - "node_modules/json-text-sequence": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/json-text-sequence/-/json-text-sequence-0.1.1.tgz", - "integrity": "sha512-L3mEegEWHRekSHjc7+sc8eJhba9Clq1PZ8kMkzf8OxElhXc8O4TS5MwcVlj9aEbm5dr81N90WHC5nAz3UO971w==", - "license": "MIT", - "dependencies": { - "delimit-stream": "0.1.0" - } - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2805,6 +2680,24 @@ "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -2826,20 +2719,6 @@ ], "license": "MIT" }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/resolve": { "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", @@ -2888,6 +2767,7 @@ "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -2951,26 +2831,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -3007,12 +2867,6 @@ "node": ">=8" } }, - "node_modules/simple-cbor": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/simple-cbor/-/simple-cbor-0.4.1.tgz", - "integrity": "sha512-rijcxtwx2b4Bje3sqeIqw5EeW7UlOIC4YfOdwqIKacpvRQ/D78bWg/4/0m5e0U91oKvlGh7LlJuZCu07ISCC7w==", - "license": "ISC" - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -3023,15 +2877,6 @@ "node": ">=0.10.0" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -3134,7 +2979,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, "license": "0BSD" }, "node_modules/type-check": { @@ -3154,6 +2998,7 @@ "version": "5.7.3", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -3202,18 +3047,13 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "license": "MIT" - }, "node_modules/vite": { "version": "6.4.1", "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz", "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.25.0", "fdir": "^6.4.4", diff --git a/examples/basic_timelock_ibe/frontend/package.json b/examples/basic_timelock_ibe/frontend/package.json index 45ea14ca..318d0fa7 100644 --- a/examples/basic_timelock_ibe/frontend/package.json +++ b/examples/basic_timelock_ibe/frontend/package.json @@ -24,9 +24,8 @@ "vite-plugin-environment": "^1.1.3" }, "dependencies": { - "@dfinity/agent": "^2.4.1", - "@dfinity/auth-client": "^2.4.1", - "@dfinity/principal": "^2.4.1", - "@dfinity/vetkeys": "^0.3.0" + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1" } } diff --git a/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh b/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh index eb52796f..5a978e29 100755 --- a/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh +++ b/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh @@ -1,4 +1,10 @@ #!/bin/bash -cd ../../backend && make extract-candid && dfx generate basic_timelock_ibe && cd ../frontend && rm -r ./src/declarations >> /dev/null 2>&1 -mv ../src/declarations ./src && rmdir ../src \ No newline at end of file +cd ../../backend && make extract-candid + +cd .. + +rm -rf frontend/src/declarations/basic_timelock_ibe + +mkdir -p frontend/src/declarations/basic_timelock_ibe +npx @icp-sdk/bindgen --did-file backend/backend.did --out-dir frontend/src/declarations/basic_timelock_ibe --declarations-flat --force diff --git a/examples/basic_timelock_ibe/frontend/vite.config.ts b/examples/basic_timelock_ibe/frontend/vite.config.ts index 044e5ebf..3c2797ce 100644 --- a/examples/basic_timelock_ibe/frontend/vite.config.ts +++ b/examples/basic_timelock_ibe/frontend/vite.config.ts @@ -1,26 +1,47 @@ -import { defineConfig } from 'vite' -import typescript from '@rollup/plugin-typescript'; -import environment from 'vite-plugin-environment'; +import { defineConfig } from "vite"; +import { execSync } from "child_process"; -// https://vite.dev/config/ -export default defineConfig({ - plugins: [ - typescript({ - inlineSources: true, - }), - environment("all", { prefix: "CANISTER_" }), - environment("all", { prefix: "DFX_" }), - ], - build: { - sourcemap: true, - rollupOptions: { - output: { - inlineDynamicImports: true, - }, +const environment = process.env.ICP_ENVIRONMENT || "local"; +const CANISTER_NAMES = ["basic_timelock_ibe"]; + +function getCanisterId(name: string): string { + return execSync( + `icp canister status ${name} -e ${environment} --id-only`, + { encoding: "utf-8", stdio: "pipe" }, + ).trim(); +} + +function getDevServerConfig() { + const networkStatus = JSON.parse( + execSync(`icp network status -e ${environment} --json`, { + encoding: "utf-8", + }), + ); + const canisterParams = CANISTER_NAMES.map( + (name) => `PUBLIC_CANISTER_ID:${name}=${getCanisterId(name)}`, + ).join("&"); + return { + headers: { + "Set-Cookie": `ic_env=${encodeURIComponent( + `${canisterParams}&ic_root_key=${networkStatus.root_key}`, + )}; SameSite=Lax;`, + }, + proxy: { + "/api": { target: networkStatus.api_url, changeOrigin: true }, + }, + hmr: false, + }; +} + +export default defineConfig(({ command }) => ({ + build: { + sourcemap: true, + rollupOptions: { + output: { + inlineDynamicImports: true, + }, + }, }, - }, - root: "./", - server: { - hmr: false - } -}) \ No newline at end of file + root: "./", + ...(command === "serve" ? { server: getDevServerConfig() } : {}), +})); diff --git a/examples/encrypted_chat/frontend/package-lock.json b/examples/encrypted_chat/frontend/package-lock.json index c89dfdf8..815a7731 100644 --- a/examples/encrypted_chat/frontend/package-lock.json +++ b/examples/encrypted_chat/frontend/package-lock.json @@ -8,9 +8,9 @@ "name": "svelte-latest", "version": "0.0.1", "dependencies": { - "@dfinity/agent": "^3.1.0", - "@dfinity/auth-client": "^3.1.0", - "@dfinity/vetkeys": "^0.4.0", + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1", "@melt-ui/svelte": "^0.86.6", "@skeletonlabs/skeleton": "^3.1.7", "@skeletonlabs/tw-plugin": "^0.4.1", @@ -48,8 +48,34 @@ "tslib": "^2.8.1", "typescript": "^5.0.0", "typescript-eslint": "^8.20.0", - "vite": "^7.3.1", - "vite-plugin-environment": "^1.1.3" + "vite": "^7.3.1" + } + }, + "../../../frontend/ic_vetkeys": { + "name": "@dfinity/vetkeys", + "version": "0.4.0", + "license": "Apache-2.0", + "dependencies": { + "@icp-sdk/core": "^5.2.1", + "idb-keyval": "^6.2.1" + }, + "devDependencies": { + "@eslint/js": "^9.22.0", + "@types/node": "^24.0.4", + "@vitest/coverage-v8": "^3.0.5", + "eslint": "^9.22", + "eslint-config-prettier": "^10.1.5", + "eslint-plugin-prettier": "^5.2.6", + "fake-indexeddb": "^6.0.0", + "happy-dom": "^20.0.2", + "isomorphic-fetch": "3.0.0", + "prettier": "^3.5.3", + "typedoc": "^0.28.3", + "typescript": "^5.7.3", + "typescript-eslint": "8.27", + "vite": "^7.0.8", + "vite-plugin-dts": "^4.5.3", + "vitest": "^3.0.5" } }, "node_modules/@ampproject/remapping": { @@ -144,84 +170,15 @@ "win32" ] }, - "node_modules/@dfinity/agent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/agent/-/agent-3.1.0.tgz", - "integrity": "sha512-4ktWU9KoB+Y0y84i0c2up9xmek2WjwSsbh4zGUK+o3VwZyqH8Cck4Fh4eiTa5jOve/vtfSVDbUVNFXsaS3Gttw==", - "license": "Apache-2.0", - "dependencies": { - "@dfinity/cbor": "^0.2.2", - "@noble/curves": "^1.9.2" - }, - "peerDependencies": { - "@dfinity/candid": "3.1.0", - "@dfinity/principal": "3.1.0", - "@noble/hashes": "^1.8.0" - } - }, - "node_modules/@dfinity/auth-client": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/auth-client/-/auth-client-3.1.0.tgz", - "integrity": "sha512-Ww92+pX6G1M5v3Dl30AalBjsro3KLkEyj5vecp2m+jh6sJWg/nxPexREvf4JlshowpMHkAIvg6GHEg+w4881Eg==", - "license": "Apache-2.0", - "dependencies": { - "idb": "^7.0.2" - }, - "peerDependencies": { - "@dfinity/agent": "3.1.0", - "@dfinity/identity": "3.1.0", - "@dfinity/principal": "3.1.0" - } - }, - "node_modules/@dfinity/candid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/candid/-/candid-3.1.0.tgz", - "integrity": "sha512-YwZJROFmzPa4GCJJyGCoOYJ2pKmp9rboixGQSbLPekX0n0oU0mcEbuVKJFu6HY6CnoDoI8YKc9x+jlqh4n0u5A==", - "license": "Apache-2.0", - "peerDependencies": { - "@dfinity/principal": "3.1.0" - } - }, "node_modules/@dfinity/cbor": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/@dfinity/cbor/-/cbor-0.2.2.tgz", "integrity": "sha512-GPJpH73kDEKbUBdUjY80lz7cq9l0vm1h/7ppejPV6O0ZTqCLrYspssYvqjRmK4aNnJ/SKXsP0rg9LYX7zpegaA==", "license": "Apache-2.0" }, - "node_modules/@dfinity/identity": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/identity/-/identity-3.1.0.tgz", - "integrity": "sha512-XI4UuzBaPh7BNaZBsQthvtrVk2S3tS24BYjKO//9+AdkNcxH3iZlzYkn6RejVaisnmztM7L0BMK3ECmGqy+OSw==", - "license": "Apache-2.0", - "peer": true, - "peerDependencies": { - "@dfinity/agent": "3.1.0", - "@dfinity/candid": "3.1.0", - "@dfinity/principal": "3.1.0", - "@noble/curves": "^1.9.2", - "@noble/hashes": "^1.8.0" - } - }, - "node_modules/@dfinity/principal": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@dfinity/principal/-/principal-3.1.0.tgz", - "integrity": "sha512-ef2JbgwQGtam0s19bH9CaR8ztpuoNx10eC6/kBjR/R8VC2eIBlaJHvD0lXDrBWGtOPZGzEy/XAugeBr3raxZ8A==", - "license": "Apache-2.0", - "dependencies": { - "@noble/hashes": "^1.8.0" - } - }, "node_modules/@dfinity/vetkeys": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@dfinity/vetkeys/-/vetkeys-0.4.0.tgz", - "integrity": "sha512-MLa5UvseEOVB6HgcKYtIDOZc6De0tdRm61dZlmAVKKqjnZuXoUJqypDbMe30EnofH0JMjvGQP2jGvxGRKC6nGQ==", - "license": "Apache-2.0", - "dependencies": { - "@dfinity/agent": "^3.1.0", - "@dfinity/candid": "^3.1.0", - "@dfinity/principal": "^3.1.0", - "idb-keyval": "^6.2.1" - } + "resolved": "../../../frontend/ic_vetkeys", + "link": true }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.2", @@ -902,6 +859,33 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@icp-sdk/auth": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@icp-sdk/auth/-/auth-5.0.0.tgz", + "integrity": "sha512-TaPfdaELT7s0vTIFOmCnlCmhPdL7kABA7+2Q0YNAUWIa/FFiwq6ffGPLvr0U0+2zFLaLQ4l7UCB2zf7vo6PFPQ==", + "license": "Apache-2.0", + "dependencies": { + "idb": "^7.1.1" + }, + "peerDependencies": { + "@icp-sdk/core": "^5" + } + }, + "node_modules/@icp-sdk/core": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@icp-sdk/core/-/core-5.2.1.tgz", + "integrity": "sha512-FImRjnayCarov7vfr52QU3BO8tPAprbyl4O+0KWz4v7h8ZbKq15fhtdb53M6+ltUsCbWkP/lEgrQ4t1WhIAHjQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@dfinity/cbor": "^0.2.2", + "@noble/curves": "^1.9.7", + "@noble/hashes": "^1.8.0", + "@scure/bip32": "^1.7.0", + "@scure/bip39": "^1.6.0", + "asn1js": "^3.0.7" + } + }, "node_modules/@internationalized/date": { "version": "3.8.2", "resolved": "https://registry.npmjs.org/@internationalized/date/-/date-3.8.2.tgz", @@ -1005,9 +989,9 @@ } }, "node_modules/@noble/curves": { - "version": "1.9.6", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.6.tgz", - "integrity": "sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA==", + "version": "1.9.7", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.7.tgz", + "integrity": "sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==", "license": "MIT", "dependencies": { "@noble/hashes": "1.8.0" @@ -1710,6 +1694,42 @@ "win32" ] }, + "node_modules/@scure/base": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.2.6.tgz", + "integrity": "sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==", + "license": "MIT", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.7.0.tgz", + "integrity": "sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==", + "license": "MIT", + "dependencies": { + "@noble/curves": "~1.9.0", + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.6.0.tgz", + "integrity": "sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "~1.8.0", + "@scure/base": "~1.2.5" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@skeletonlabs/skeleton": { "version": "3.1.7", "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton/-/skeleton-3.1.7.tgz", @@ -1767,6 +1787,7 @@ "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.53.4.tgz", "integrity": "sha512-iAIPEahFgDJJyvz8g0jP08KvqnM6JvdW8YfsygZ+pMeMvyM2zssWMltcsotETvjSZ82G3VlitgDtBIvpQSZrTA==", "license": "MIT", + "peer": true, "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", @@ -1808,6 +1829,7 @@ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-6.1.0.tgz", "integrity": "sha512-+U6lz1wvGEG/BvQyL4z/flyNdQ9xDNv5vrh+vWBWTHaebqT0c9RNggpZTo/XSPoHsSCWBlYaTlRX8pZ9GATXCw==", "license": "MIT", + "peer": true, "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^5.0.0-next.1", "debug": "^4.4.1", @@ -2265,6 +2287,7 @@ "integrity": "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.39.0", "@typescript-eslint/types": "8.39.0", @@ -2482,6 +2505,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -2548,6 +2572,20 @@ "node": ">= 0.4" } }, + "node_modules/asn1js": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/asn1js/-/asn1js-3.0.7.tgz", + "integrity": "sha512-uLvq6KJu04qoQM6gvBfKFjlh6Gl0vOKQuR5cJMDHQkmwfMOQeN3F3SHCv9SNYSL+CRoHvOGFfllDlVz03GQjvQ==", + "license": "BSD-3-Clause", + "dependencies": { + "pvtsutils": "^1.3.6", + "pvutils": "^1.1.3", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -2896,6 +2934,7 @@ "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -4194,6 +4233,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -4327,6 +4367,7 @@ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin/prettier.cjs" }, @@ -4343,6 +4384,7 @@ "integrity": "sha512-pn1ra/0mPObzqoIQn/vUTR3ZZI6UuZ0sHqMK5x2jMLGrs53h0sXhkVuDcrlssHwIMk7FYrMjHBPoUSyyEEDlBQ==", "dev": true, "license": "MIT", + "peer": true, "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" @@ -4445,6 +4487,24 @@ "node": ">=6" } }, + "node_modules/pvtsutils": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/pvtsutils/-/pvtsutils-1.3.6.tgz", + "integrity": "sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.8.1" + } + }, + "node_modules/pvutils": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/pvutils/-/pvutils-1.1.5.tgz", + "integrity": "sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==", + "license": "MIT", + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -4526,6 +4586,7 @@ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", "license": "MIT", + "peer": true, "dependencies": { "@types/estree": "1.0.8" }, @@ -4618,6 +4679,7 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.90.0.tgz", "integrity": "sha512-9GUyuksjw70uNpb1MTYWsH9MQHOHY6kwfnkafC24+7aOMZn9+rVMBxRbLvw756mrBFbIsFg6Xw9IkR2Fnn3k+Q==", "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -4742,6 +4804,7 @@ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.53.6.tgz", "integrity": "sha512-lP5DGF3oDDI9fhHcSpaBiJEkFLuS16h92DhM1L5K1lFm0WjOmUh1i2sNkBBk8rkxJRpob0dBE75jRfUzGZUOGA==", "license": "MIT", + "peer": true, "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", @@ -4827,7 +4890,8 @@ "version": "4.1.11", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/tapable": { "version": "2.2.2", @@ -4938,6 +5002,7 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -4992,6 +5057,7 @@ "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", "license": "MIT", + "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -5061,16 +5127,6 @@ } } }, - "node_modules/vite-plugin-environment": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/vite-plugin-environment/-/vite-plugin-environment-1.1.3.tgz", - "integrity": "sha512-9LBhB0lx+2lXVBEWxFZC+WO7PKEyE/ykJ7EPWCq95NEcCpblxamTbs5Dm3DLBGzwODpJMEnzQywJU8fw6XGGGA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "vite": ">= 2.7" - } - }, "node_modules/vite/node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", diff --git a/examples/encrypted_chat/frontend/package.json b/examples/encrypted_chat/frontend/package.json index ece26206..18fa864c 100644 --- a/examples/encrypted_chat/frontend/package.json +++ b/examples/encrypted_chat/frontend/package.json @@ -40,13 +40,12 @@ "tslib": "^2.8.1", "typescript": "^5.0.0", "typescript-eslint": "^8.20.0", - "vite": "^7.3.1", - "vite-plugin-environment": "^1.1.3" + "vite": "^7.3.1" }, "dependencies": { - "@dfinity/agent": "^3.1.0", - "@dfinity/auth-client": "^3.1.0", - "@dfinity/vetkeys": "^0.4.0", + "@dfinity/vetkeys": "file:../../../frontend/ic_vetkeys", + "@icp-sdk/auth": "^5.0.0", + "@icp-sdk/core": "^5.2.1", "@melt-ui/svelte": "^0.86.6", "@skeletonlabs/skeleton": "^3.1.7", "@skeletonlabs/tw-plugin": "^0.4.1", diff --git a/examples/encrypted_chat/frontend/scripts/gen_bindings.sh b/examples/encrypted_chat/frontend/scripts/gen_bindings.sh index 0ff62bd1..b600743c 100755 --- a/examples/encrypted_chat/frontend/scripts/gen_bindings.sh +++ b/examples/encrypted_chat/frontend/scripts/gen_bindings.sh @@ -1,11 +1,15 @@ #!/bin/bash +# Bindings are always generated from the Rust backend since both backends +# expose the same Candid interface. -cd ../../backend && make extract-candid - -cd .. && dfx generate encrypted_chat || exit 1 - -rm -r frontend/src/declarations/encrypted_chat > /dev/null 2>&1 || true +# Resolve the physical path of this script so that navigating up works +# correctly even when frontend/ is reached via a symlink (e.g. motoko/frontend). +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd -P) +cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +cd "$SCRIPT_DIR/../.." +rm -rf frontend/src/declarations/encrypted_chat mkdir -p frontend/src/declarations/encrypted_chat -mv src/declarations/encrypted_chat frontend/src/declarations -rmdir -p src/declarations > /dev/null 2>&1 || true \ No newline at end of file +npx @icp-sdk/bindgen --did-file rust/backend/backend.did \ + --out-dir frontend/src/declarations/encrypted_chat \ + --declarations-flat --force diff --git a/examples/encrypted_chat/frontend/vite.config.ts b/examples/encrypted_chat/frontend/vite.config.ts index 24886d00..f6fbb4bc 100644 --- a/examples/encrypted_chat/frontend/vite.config.ts +++ b/examples/encrypted_chat/frontend/vite.config.ts @@ -1,26 +1,77 @@ import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; +import { defineConfig, type Plugin } from 'vite'; import tailwindcss from '@tailwindcss/vite'; -import environment from 'vite-plugin-environment'; -import typescript from '@rollup/plugin-typescript'; +import { execSync } from 'child_process'; -export default defineConfig({ - plugins: [ - typescript(), - tailwindcss(), - sveltekit(), - environment('all', { prefix: 'CANISTER_' }), - environment('all', { prefix: 'DFX_' }) - ], - server: { - proxy: { - '/api': { - target: 'http://localhost:4943', - changeOrigin: true - } +const environment = process.env.ICP_ENVIRONMENT || 'local'; +const CANISTER_NAMES = ['encrypted_chat']; + +function buildDevConfig() { + const networkStatus = JSON.parse( + execSync(`icp network status -e ${environment} --json --project-root-override ../rust`, { + encoding: 'utf-8' + }) + ); + const canisterParams = CANISTER_NAMES.map((name) => { + const id = execSync( + `icp canister status ${name} -e ${environment} --id-only --project-root-override ../rust`, + { encoding: 'utf-8', stdio: 'pipe' } + ).trim(); + return `PUBLIC_CANISTER_ID:${name}=${id}`; + }).join('&'); + + return { + cookie: `ic_env=${encodeURIComponent( + `${canisterParams}&ic_root_key=${networkStatus.root_key}` + )}; SameSite=Lax`, + apiUrl: networkStatus.api_url as string + }; +} + +// SvelteKit's SSR handler intercepts requests before Vite's built-in header +// middleware can set response headers, so `server.headers` is not reliable for +// delivering the ic_env cookie on page responses. This plugin sets it two ways: +// 1. HTTP middleware – covers static-asset responses served directly by Vite. +// 2. Injected diff --git a/examples/encrypted_notes_dapp_vetkd/frontend/src/components/Note.svelte b/examples/encrypted_notes_dapp_vetkd/frontend/src/components/Note.svelte index 9b1f9ee7..8beb46ba 100644 --- a/examples/encrypted_notes_dapp_vetkd/frontend/src/components/Note.svelte +++ b/examples/encrypted_notes_dapp_vetkd/frontend/src/components/Note.svelte @@ -1,7 +1,9 @@ diff --git a/examples/password_manager/frontend/src/components/Vault.svelte b/examples/password_manager/frontend/src/components/Vault.svelte index 5c578a5f..c539f188 100644 --- a/examples/password_manager/frontend/src/components/Vault.svelte +++ b/examples/password_manager/frontend/src/components/Vault.svelte @@ -3,10 +3,10 @@ import { link, location } from "svelte-spa-router"; import { onDestroy } from "svelte"; import { vaultsStore } from "../store/vaults"; - import { Principal } from "@dfinity/principal"; + import { Principal } from "@icp-sdk/core/principal"; import Header from "./Header.svelte"; import Spinner from "./Spinner.svelte"; - // @ts-expect-error: svelte-icons have some problems with ts declarations + // @ts-ignore: svelte-icons have no type declarations import GiOpenTreasureChest from "svelte-icons/gi/GiOpenTreasureChest.svelte"; import { auth } from "../store/auth"; import SharingEditor from "./SharingEditor.svelte"; @@ -27,42 +27,49 @@ }); onDestroy(unsubscribeCurrentRoute); - $: { - if ( - $vaultsStore.state === "loaded" && - $auth.state === "initialized" && - vault.name.length === 0 && - currentRoute.split("/").length > 2 - ) { - const split = currentRoute.split("/"); - const vaultOwner = Principal.fromText(split[split.length - 2]); - const vaultName = split[split.length - 1]; - const searchedForVault = $vaultsStore.list.find( - (v) => - v.owner.compareTo(vaultOwner) === "eq" && - v.name === vaultName, - ); - if (searchedForVault) { - vault = searchedForVault; - vaultSummary += summarize(vault); - const me = $auth.client.getIdentity().getPrincipal(); - if (vault.owner.compareTo(me) === "eq") { - accessRights = { ReadWriteManage: null }; - } else { - const foundAccessRights = vault.users.find( - (user) => user[0].compareTo(me) === "eq", - ); - if (foundAccessRights) { - accessRights = foundAccessRights[1]; - } - } + // Parse owner and vault name from the URL once; stored separately so the + // vault lookup below stays reactive to store updates (e.g. from the poller). + let parsedRoute: { owner: Principal; vaultName: string } | null = null; + $: if (currentRoute.split("/").length > 2 && parsedRoute === null) { + const split = currentRoute.split("/"); + parsedRoute = { + owner: Principal.fromText(split[split.length - 2]), + vaultName: decodeURIComponent(split[split.length - 1]), + }; + } + + // Re-runs whenever the store updates so new passwords from the poller appear. + $: if ( + $vaultsStore.state === "loaded" && + $auth.state === "initialized" && + parsedRoute !== null + ) { + const { owner: targetOwner, vaultName: targetVaultName } = parsedRoute; + const searchedForVault = $vaultsStore.list.find( + (v) => + v.owner.compareTo(targetOwner) === "eq" && + v.name === targetVaultName, + ); + if (searchedForVault) { + vault = searchedForVault; + vaultSummary = summarize(vault); + const me = $auth.client.getIdentity().getPrincipal(); + if (vault.owner.compareTo(me) === "eq") { + accessRights = { ReadWriteManage: null }; } else { - vaultSummary = - "could not find vault " + - vaultName + - " owned by " + - vaultOwner.toText(); + const foundAccessRights = vault.users.find( + (user) => user[0].compareTo(me) === "eq", + ); + if (foundAccessRights) { + accessRights = foundAccessRights[1]; + } } + } else { + vaultSummary = + "could not find vault " + + targetVaultName + + " owned by " + + targetOwner.toText(); } } diff --git a/examples/password_manager/frontend/src/lib/encrypted_maps.ts b/examples/password_manager/frontend/src/lib/encrypted_maps.ts index 2b2c7e07..a2399eab 100644 --- a/examples/password_manager/frontend/src/lib/encrypted_maps.ts +++ b/examples/password_manager/frontend/src/lib/encrypted_maps.ts @@ -1,43 +1,35 @@ import "./init.ts"; -import { HttpAgent, type HttpAgentOptions } from "@dfinity/agent"; +import { HttpAgent, type HttpAgentOptions } from "@icp-sdk/core/agent"; import { DefaultEncryptedMapsClient, EncryptedMaps, } from "@dfinity/vetkeys/encrypted_maps"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; + +const canisterEnv = safeGetCanisterEnv<{ + "PUBLIC_CANISTER_ID:ic_vetkeys_encrypted_maps_canister": string; +}>(); export async function createEncryptedMaps( agentOptions?: HttpAgentOptions, ): Promise { - const host = - process.env.DFX_NETWORK === "ic" - ? `https://${process.env.CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER}.ic0.app` - : "http://localhost:4943"; - const hostOptions = { host }; - - if (!agentOptions) { - agentOptions = hostOptions; - } else { - agentOptions.host = hostOptions.host; + const canisterId = + canisterEnv?.[ + "PUBLIC_CANISTER_ID:ic_vetkeys_encrypted_maps_canister" + ]; + if (!canisterId) { + throw new Error( + "Canister ID for ic_vetkeys_encrypted_maps_canister is not set", + ); } - const agent = await HttpAgent.create({ ...agentOptions }); - // Fetch root key for certificate validation during development - if (process.env.NODE_ENV !== "production") { - console.log(`Dev environment - fetching root key...`); - - agent.fetchRootKey().catch((err) => { - console.warn( - "Unable to fetch root key. Check to ensure that your local replica is running", - ); - console.error(err); - }); - } + const agent = await HttpAgent.create({ + ...agentOptions, + host: window.location.origin, + ...(canisterEnv?.IC_ROOT_KEY + ? { rootKey: canisterEnv.IC_ROOT_KEY } + : {}), + }); - // Creates an actor with using the candid interface and the HttpAgent - return new EncryptedMaps( - new DefaultEncryptedMapsClient( - agent, - process.env.CANISTER_ID_IC_VETKEYS_ENCRYPTED_MAPS_CANISTER, - ), - ); + return new EncryptedMaps(new DefaultEncryptedMapsClient(agent, canisterId)); } diff --git a/examples/password_manager/frontend/src/lib/password.ts b/examples/password_manager/frontend/src/lib/password.ts index e37c4620..1bd7c6ba 100644 --- a/examples/password_manager/frontend/src/lib/password.ts +++ b/examples/password_manager/frontend/src/lib/password.ts @@ -1,4 +1,4 @@ -import type { Principal } from "@dfinity/principal"; +import type { Principal } from "@icp-sdk/core/principal"; export interface PasswordModel { owner: Principal; diff --git a/examples/password_manager/frontend/src/lib/vault.ts b/examples/password_manager/frontend/src/lib/vault.ts index 02dc5b71..642569b6 100644 --- a/examples/password_manager/frontend/src/lib/vault.ts +++ b/examples/password_manager/frontend/src/lib/vault.ts @@ -1,4 +1,4 @@ -import type { Principal } from "@dfinity/principal"; +import type { Principal } from "@icp-sdk/core/principal"; import type { PasswordModel } from "./password"; import type { AccessRights } from "@dfinity/vetkeys/encrypted_maps"; diff --git a/examples/password_manager/frontend/src/store/auth.ts b/examples/password_manager/frontend/src/store/auth.ts index ec6547c8..6b3ed3c0 100644 --- a/examples/password_manager/frontend/src/store/auth.ts +++ b/examples/password_manager/frontend/src/store/auth.ts @@ -1,7 +1,7 @@ import "../lib/init.ts"; import { get, writable } from "svelte/store"; -import { AuthClient } from "@dfinity/auth-client"; -import type { JsonnableDelegationChain } from "@dfinity/identity/lib/cjs/identity/delegation"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { DelegationIdentity } from "@icp-sdk/core/identity"; import { replace } from "svelte-spa-router"; import { createEncryptedMaps } from "../lib/encrypted_maps.js"; import { EncryptedMaps } from "@dfinity/vetkeys/encrypted_maps"; @@ -49,9 +49,10 @@ export function login() { void currentAuth.client.login({ maxTimeToLive: BigInt(1800) * BigInt(1_000_000_000), identityProvider: - process.env.DFX_NETWORK === "ic" - ? "https://identity.ic0.app/#authorize" - : `http://rdmx6-jaaaa-aaaaa-aaadq-cai.localhost:4943/#authorize`, + window.location.hostname === "localhost" || + window.location.hostname.endsWith(".localhost") + ? `http://id.ai.localhost:8000/#authorize` + : "https://identity.ic0.app/#authorize", onSuccess: () => authenticate(currentAuth.client), }); } @@ -71,7 +72,7 @@ export async function logout() { } export async function authenticate(client: AuthClient) { - handleSessionTimeout(); + handleSessionTimeout(client); try { const encryptedMaps = await createEncryptedMaps({ @@ -92,25 +93,19 @@ export async function authenticate(client: AuthClient) { } // set a timer when the II session will expire and log the user out -function handleSessionTimeout() { - // upon login the localstorage items may not be set, wait for next tick - setTimeout(() => { - try { - const delegation = JSON.parse( - window.localStorage.getItem("ic-delegation") || "{}", - ) as JsonnableDelegationChain; +function handleSessionTimeout(client: AuthClient) { + try { + const identity = client.getIdentity(); + if (!(identity instanceof DelegationIdentity)) return; - const expirationTimeMs = - Number.parseInt( - delegation.delegations[0].delegation.expiration, - 16, - ) / 1000000; + const chain = identity.getDelegation(); + // expiration is a BigInt of nanoseconds since epoch + const expirationMs = Number(chain.delegations[0].delegation.expiration) / 1_000_000; - setTimeout(() => { - void logout(); - }, expirationTimeMs - Date.now()); - } catch { - console.error("Could not handle delegation expiry."); - } - }); + setTimeout(() => { + void logout(); + }, expirationMs - Date.now()); + } catch { + console.error("Could not handle delegation expiry."); + } } diff --git a/examples/password_manager/frontend/src/store/vaults.ts b/examples/password_manager/frontend/src/store/vaults.ts index 0abfadf6..371712e7 100644 --- a/examples/password_manager/frontend/src/store/vaults.ts +++ b/examples/password_manager/frontend/src/store/vaults.ts @@ -7,7 +7,7 @@ import { type AccessRights, EncryptedMaps, } from "@dfinity/vetkeys/encrypted_maps"; -import type { Principal } from "@dfinity/principal"; +import type { Principal } from "@icp-sdk/core/principal"; export const vaultsStore = writable< | { @@ -148,7 +148,7 @@ auth.subscribe((auth) => { (e: Error) => showError(e, "Could not poll vaults."), ); - }); + })(); }, 3000); } catch { vaultsStore.set({ diff --git a/examples/password_manager_with_metadata/frontend/src/components/EditPassword.svelte b/examples/password_manager_with_metadata/frontend/src/components/EditPassword.svelte index b99631a3..07c13480 100644 --- a/examples/password_manager_with_metadata/frontend/src/components/EditPassword.svelte +++ b/examples/password_manager_with_metadata/frontend/src/components/EditPassword.svelte @@ -11,7 +11,7 @@ import { auth } from "../store/auth"; import Spinner from "./Spinner.svelte"; import { onDestroy } from "svelte"; - import { Principal } from "@dfinity/principal"; + import { Principal } from "@icp-sdk/core/principal"; import type { AccessRights } from "@dfinity/vetkeys/encrypted_maps"; export let currentRoute = ""; diff --git a/examples/password_manager_with_metadata/frontend/src/components/EditVault.svelte b/examples/password_manager_with_metadata/frontend/src/components/EditVault.svelte index 7a369566..53d164f7 100644 --- a/examples/password_manager_with_metadata/frontend/src/components/EditVault.svelte +++ b/examples/password_manager_with_metadata/frontend/src/components/EditVault.svelte @@ -6,8 +6,15 @@ import Trash from "svelte-icons/fa/FaTrash.svelte"; import { auth } from "../store/auth"; import Spinner from "./Spinner.svelte"; + import { location } from "svelte-spa-router"; + import { Principal } from "@icp-sdk/core/principal"; + import { onDestroy } from "svelte"; - export let currentRoute = ""; + let currentRoute = ""; + const unsubscribeCurrentRoute = location.subscribe((value) => { + currentRoute = decodeURI(value); + }); + onDestroy(unsubscribeCurrentRoute); let editedVault: VaultModel; let updating = false; @@ -20,10 +27,16 @@ if ( $auth.state === "initialized" && $vaultsStore.state === "loaded" && - !editedVault + !editedVault && + currentRoute.split("/").length > 2 ) { + const split = currentRoute.split("/"); + const vaultOwner = Principal.fromText(split[split.length - 2]); + const vaultName = split[split.length - 1]; const vault = $vaultsStore.list.find( - (vault) => vault.name === currentRoute, + (v) => + v.owner.compareTo(vaultOwner) === "eq" && + v.name === vaultName, ); if (vault) { diff --git a/examples/password_manager_with_metadata/frontend/src/components/NewPassword.svelte b/examples/password_manager_with_metadata/frontend/src/components/NewPassword.svelte index 998df9cf..d288e2a8 100644 --- a/examples/password_manager_with_metadata/frontend/src/components/NewPassword.svelte +++ b/examples/password_manager_with_metadata/frontend/src/components/NewPassword.svelte @@ -7,7 +7,7 @@ import { addNotification, showError } from "../store/notifications"; import Header from "./Header.svelte"; import PasswordEditor from "./PasswordEditor.svelte"; - import { Principal } from "@dfinity/principal"; + import { Principal } from "@icp-sdk/core/principal"; let creating = false; let vaultOwner = @@ -45,6 +45,14 @@ return; } + if (vaultName.trim() === "" || passwordName.trim() === "") { + addNotification({ + type: "error", + message: "Vault name and password name must not be empty.", + }); + return; + } + creating = true; await setPassword( @@ -131,7 +139,9 @@ diff --git a/examples/password_manager_with_metadata/frontend/src/components/Password.svelte b/examples/password_manager_with_metadata/frontend/src/components/Password.svelte index 1631811d..0bfe5733 100644 --- a/examples/password_manager_with_metadata/frontend/src/components/Password.svelte +++ b/examples/password_manager_with_metadata/frontend/src/components/Password.svelte @@ -2,7 +2,7 @@ import { type PasswordModel, summarize } from "../lib/password"; import { link, location } from "svelte-spa-router"; import { vaultsStore } from "../store/vaults"; - import { Principal } from "@dfinity/principal"; + import { Principal } from "@icp-sdk/core/principal"; import { onDestroy } from "svelte"; import Spinner from "./Spinner.svelte"; import Header from "./Header.svelte"; diff --git a/examples/password_manager_with_metadata/frontend/src/components/SharingEditor.svelte b/examples/password_manager_with_metadata/frontend/src/components/SharingEditor.svelte index 6e7f0b2a..4b846162 100644 --- a/examples/password_manager_with_metadata/frontend/src/components/SharingEditor.svelte +++ b/examples/password_manager_with_metadata/frontend/src/components/SharingEditor.svelte @@ -8,7 +8,7 @@ vaultsStore, } from "../store/vaults"; import { addNotification, showError } from "../store/notifications"; - import { Principal } from "@dfinity/principal"; + import { Principal } from "@icp-sdk/core/principal"; import type { AccessRights } from "@dfinity/vetkeys/encrypted_maps"; export let editedVault: VaultModel; diff --git a/examples/password_manager_with_metadata/frontend/src/components/SidebarLayout.svelte b/examples/password_manager_with_metadata/frontend/src/components/SidebarLayout.svelte index 439db77a..4b6df071 100644 --- a/examples/password_manager_with_metadata/frontend/src/components/SidebarLayout.svelte +++ b/examples/password_manager_with_metadata/frontend/src/components/SidebarLayout.svelte @@ -7,7 +7,7 @@ // @ts-expect-error: svelte-icons have some problems with ts declarations import FaDoorOpen from "svelte-icons/fa/FaDoorOpen.svelte"; import Disclaimer from "./Disclaimer.svelte"; - import { Principal } from "@dfinity/principal"; + import { Principal } from "@icp-sdk/core/principal"; import { link } from "svelte-spa-router"; diff --git a/examples/password_manager_with_metadata/frontend/src/components/Vault.svelte b/examples/password_manager_with_metadata/frontend/src/components/Vault.svelte index 4ce52a0d..495a7510 100644 --- a/examples/password_manager_with_metadata/frontend/src/components/Vault.svelte +++ b/examples/password_manager_with_metadata/frontend/src/components/Vault.svelte @@ -3,7 +3,7 @@ import { link, location } from "svelte-spa-router"; import { onDestroy } from "svelte"; import { vaultsStore } from "../store/vaults"; - import { Principal } from "@dfinity/principal"; + import { Principal } from "@icp-sdk/core/principal"; import Header from "./Header.svelte"; import Spinner from "./Spinner.svelte"; // @ts-expect-error: svelte-icons have some problems with ts declarations @@ -27,42 +27,46 @@ }); onDestroy(unsubscribeCurrentRoute); - $: { - if ( - $vaultsStore.state === "loaded" && - $auth.state === "initialized" && - vault.name.length === 0 && - currentRoute.split("/").length > 2 - ) { - const split = currentRoute.split("/"); - const vaultName = split[split.length - 1]; - const vaultOwner = Principal.fromText(split[split.length - 2]); - const searchedForVault = $vaultsStore.list.find( - (v) => - v.owner.compareTo(vaultOwner) === "eq" && - v.name === vaultName, - ); - if (!searchedForVault) { - vaultSummary = - "could not find vault " + - vaultName + - " owned by " + - vaultOwner.toText(); - } else { - vault = searchedForVault; - vaultSummary += summarize(vault); - const me = $auth.client.getIdentity().getPrincipal(); + // Parse owner and vault name from the URL once; stored separately so the + // vault lookup below stays reactive to store updates (e.g. from the poller). + let parsedRoute: { owner: Principal; vaultName: string } | null = null; + $: if (currentRoute.split("/").length > 2 && parsedRoute === null) { + const split = currentRoute.split("/"); + parsedRoute = { + owner: Principal.fromText(split[split.length - 2]), + vaultName: split[split.length - 1], // already decoded via decodeURI on subscribe + }; + } - if (vault.owner.compareTo(me) === "eq") { - accessRights = { ReadWriteManage: null }; - } else { - const foundRights = vault.users.find( - (user) => user[0].compareTo(me) === "eq", - ); - accessRights = foundRights - ? foundRights[1] - : { Read: null }; - } + // Re-runs whenever the store updates so new passwords from the poller appear. + $: if ( + $vaultsStore.state === "loaded" && + $auth.state === "initialized" && + parsedRoute !== null + ) { + const { owner: targetOwner, vaultName: targetVaultName } = parsedRoute; + const searchedForVault = $vaultsStore.list.find( + (v) => + v.owner.compareTo(targetOwner) === "eq" && + v.name === targetVaultName, + ); + if (!searchedForVault) { + vaultSummary = + "could not find vault " + + targetVaultName + + " owned by " + + targetOwner.toText(); + } else { + vault = searchedForVault; + vaultSummary = summarize(vault); + const me = $auth.client.getIdentity().getPrincipal(); + if (vault.owner.compareTo(me) === "eq") { + accessRights = { ReadWriteManage: null }; + } else { + const foundRights = vault.users.find( + (user) => user[0].compareTo(me) === "eq", + ); + accessRights = foundRights ? foundRights[1] : { Read: null }; } } } diff --git a/examples/password_manager_with_metadata/frontend/src/lib/encrypted_maps.ts b/examples/password_manager_with_metadata/frontend/src/lib/encrypted_maps.ts index 543f05f1..93a6079a 100644 --- a/examples/password_manager_with_metadata/frontend/src/lib/encrypted_maps.ts +++ b/examples/password_manager_with_metadata/frontend/src/lib/encrypted_maps.ts @@ -1,31 +1,23 @@ import "./init.ts"; -import { HttpAgent, type HttpAgentOptions } from "@dfinity/agent"; +import { HttpAgent } from "@icp-sdk/core/agent"; import { DefaultEncryptedMapsClient, EncryptedMaps, } from "@dfinity/vetkeys/encrypted_maps"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; -export async function createEncryptedMaps( - agentOptions: HttpAgentOptions, -): Promise { - const agent = await HttpAgent.create({ ...agentOptions }); - // Fetch root key for certificate validation during development - if (process.env.NODE_ENV !== "production") { - console.log(`Dev environment - fetching root key...`); +const canisterEnv = safeGetCanisterEnv<{ + "PUBLIC_CANISTER_ID:password_manager_with_metadata": string; +}>(); - agent.fetchRootKey().catch((err) => { - console.warn( - "Unable to fetch root key. Check to ensure that your local replica is running", - ); - console.error(err); - }); +export function createEncryptedMaps(agent: HttpAgent): EncryptedMaps { + const canisterId = + canisterEnv?.["PUBLIC_CANISTER_ID:password_manager_with_metadata"]; + if (!canisterId) { + throw new Error( + "Canister ID for password_manager_with_metadata is not set", + ); } - // Creates an actor with using the candid interface and the HttpAgent - return new EncryptedMaps( - new DefaultEncryptedMapsClient( - agent, - process.env.CANISTER_ID_PASSWORD_MANAGER_WITH_METADATA as string, - ), - ); + return new EncryptedMaps(new DefaultEncryptedMapsClient(agent, canisterId)); } diff --git a/examples/password_manager_with_metadata/frontend/src/lib/password.ts b/examples/password_manager_with_metadata/frontend/src/lib/password.ts index 88620bd1..ff7d7828 100644 --- a/examples/password_manager_with_metadata/frontend/src/lib/password.ts +++ b/examples/password_manager_with_metadata/frontend/src/lib/password.ts @@ -1,5 +1,5 @@ -import type { Principal } from "@dfinity/principal"; -import type { PasswordMetadata } from "../declarations/password_manager_with_metadata/password_manager_with_metadata.did"; +import type { Principal } from "@icp-sdk/core/principal"; +import type { PasswordMetadata } from "../declarations/password_manager_with_metadata/backend.did"; export interface PasswordModel { owner: Principal; diff --git a/examples/password_manager_with_metadata/frontend/src/lib/password_manager.ts b/examples/password_manager_with_metadata/frontend/src/lib/password_manager.ts index 232f1873..8b0443d4 100644 --- a/examples/password_manager_with_metadata/frontend/src/lib/password_manager.ts +++ b/examples/password_manager_with_metadata/frontend/src/lib/password_manager.ts @@ -1,13 +1,20 @@ import "./init.ts"; -import { type ActorSubclass, type HttpAgentOptions } from "@dfinity/agent"; +import { Actor, HttpAgent, type ActorSubclass } from "@icp-sdk/core/agent"; +import { safeGetCanisterEnv } from "@icp-sdk/core/agent/canister-env"; +import type { Principal } from "@icp-sdk/core/principal"; import { EncryptedMaps } from "@dfinity/vetkeys/encrypted_maps"; +import { + idlFactory, + type _SERVICE, +} from "../declarations/password_manager_with_metadata/backend.did"; import { createEncryptedMaps } from "./encrypted_maps"; -import type { Principal } from "@dfinity/principal"; -import { createActor } from "../declarations/password_manager_with_metadata"; -import type { _SERVICE } from "../declarations/password_manager_with_metadata/password_manager_with_metadata.did"; import { passwordFromContent, type PasswordModel } from "../lib/password"; import { vaultFromContent, type VaultModel } from "../lib/vault"; +const canisterEnv = safeGetCanisterEnv<{ + "PUBLIC_CANISTER_ID:password_manager_with_metadata": string; +}>(); + export class PasswordManager { /// The actor class representing the full interface of the canister. private readonly canisterClient: ActorSubclass<_SERVICE>; @@ -145,35 +152,30 @@ export class PasswordManager { } } -export async function createPasswordManager( - agentOptions?: HttpAgentOptions, -): Promise { - if (!process.env.CANISTER_ID_PASSWORD_MANAGER_WITH_METADATA) { - console.error( - "CANISTER_ID_PASSWORD_MANAGER_WITH_METADATA is not defined", - ); +export async function createPasswordManager(agentOptions?: { + identity?: HttpAgent["config"]["identity"]; +}): Promise { + const canisterId = + canisterEnv?.["PUBLIC_CANISTER_ID:password_manager_with_metadata"]; + if (!canisterId) { throw new Error( - "CANISTER_ID_PASSWORD_MANAGER_WITH_METADATA is not defined", + "Canister ID for password_manager_with_metadata is not defined", ); } - const host = - process.env.DFX_NETWORK === "ic" - ? `https://${process.env.CANISTER_ID_PASSWORD_MANAGER_WITH_METADATA}.ic0.app` - : "http://localhost:8000"; - const hostOptions = { host }; - - if (!agentOptions) { - agentOptions = hostOptions; - } else { - agentOptions.host = hostOptions.host; - } - - const encryptedMaps = await createEncryptedMaps({ ...agentOptions }); - const canisterClient = createActor( - process.env.CANISTER_ID_PASSWORD_MANAGER_WITH_METADATA, - { agentOptions }, - ); + const agent = await HttpAgent.create({ + ...agentOptions, + host: window.location.origin, + ...(canisterEnv?.IC_ROOT_KEY + ? { rootKey: canisterEnv.IC_ROOT_KEY } + : {}), + }); + + const encryptedMaps = createEncryptedMaps(agent); + const canisterClient = Actor.createActor<_SERVICE>(idlFactory, { + agent, + canisterId, + }); return new PasswordManager(canisterClient, encryptedMaps); } diff --git a/examples/password_manager_with_metadata/frontend/src/lib/vault.ts b/examples/password_manager_with_metadata/frontend/src/lib/vault.ts index 717fc476..f14404a3 100644 --- a/examples/password_manager_with_metadata/frontend/src/lib/vault.ts +++ b/examples/password_manager_with_metadata/frontend/src/lib/vault.ts @@ -1,4 +1,4 @@ -import type { Principal } from "@dfinity/principal"; +import type { Principal } from "@icp-sdk/core/principal"; import type { PasswordModel } from "./password"; import type { AccessRights } from "@dfinity/vetkeys/encrypted_maps"; diff --git a/examples/password_manager_with_metadata/frontend/src/store/auth.ts b/examples/password_manager_with_metadata/frontend/src/store/auth.ts index aa05921c..58d661e1 100644 --- a/examples/password_manager_with_metadata/frontend/src/store/auth.ts +++ b/examples/password_manager_with_metadata/frontend/src/store/auth.ts @@ -1,7 +1,7 @@ import "../lib/init.ts"; import { get, writable } from "svelte/store"; -import { AuthClient } from "@dfinity/auth-client"; -import type { JsonnableDelegationChain } from "@dfinity/identity/lib/cjs/identity/delegation"; +import { AuthClient } from "@icp-sdk/auth/client"; +import { DelegationIdentity } from "@icp-sdk/core/identity"; import { replace } from "svelte-spa-router"; import { PasswordManager, @@ -51,9 +51,10 @@ export async function login() { await currentAuth.client.login({ maxTimeToLive: BigInt(1800) * BigInt(1_000_000_000), identityProvider: - process.env.DFX_NETWORK === "ic" - ? "https://identity.ic0.app/#authorize" - : `http://rdmx6-jaaaa-aaaaa-aaadq-cai.localhost:8000/#authorize`, + window.location.hostname === "localhost" || + window.location.hostname.endsWith(".localhost") + ? `http://id.ai.localhost:8000/#authorize` + : "https://identity.ic0.app/#authorize", onSuccess: async () => { await authenticate(currentAuth.client); }, @@ -79,7 +80,7 @@ export async function logout() { } export async function authenticate(client: AuthClient) { - handleSessionTimeout(); + handleSessionTimeout(client); try { const passwordManager = await createPasswordManager({ @@ -100,31 +101,20 @@ export async function authenticate(client: AuthClient) { } // set a timer when the II session will expire and log the user out -function handleSessionTimeout() { - // upon login the localstorage items may not be set, wait for next tick - setTimeout(() => { - try { - const rawDelegation = window.localStorage.getItem("ic-delegation"); - if (!rawDelegation) { - throw new Error("No delegation found"); - } - const delegation = JSON.parse( - rawDelegation, - ) as JsonnableDelegationChain; +function handleSessionTimeout(client: AuthClient) { + try { + const identity = client.getIdentity(); + if (!(identity instanceof DelegationIdentity)) return; - const expirationTimeMs = - Number.parseInt( - delegation.delegations[0].delegation.expiration, - 16, - ) / 1000000; + const chain = identity.getDelegation(); + // expiration is a BigInt of nanoseconds since epoch + const expirationMs = + Number(chain.delegations[0].delegation.expiration) / 1_000_000; - setTimeout(() => { - void logout(); - }, expirationTimeMs - Date.now()); - } catch (e) { - console.error( - "Could not handle delegation expiry: " + (e as Error).message, - ); - } - }); + setTimeout(() => { + void logout(); + }, expirationMs - Date.now()); + } catch { + console.error("Could not handle delegation expiry."); + } } diff --git a/examples/password_manager_with_metadata/frontend/src/store/vaults.ts b/examples/password_manager_with_metadata/frontend/src/store/vaults.ts index a236a955..b39f687c 100644 --- a/examples/password_manager_with_metadata/frontend/src/store/vaults.ts +++ b/examples/password_manager_with_metadata/frontend/src/store/vaults.ts @@ -4,7 +4,7 @@ import { type VaultModel } from "../lib/vault"; import { auth } from "./auth"; import { showError } from "./notifications"; import { type AccessRights } from "@dfinity/vetkeys/encrypted_maps"; -import type { Principal } from "@dfinity/principal"; +import type { Principal } from "@icp-sdk/core/principal"; import type { PasswordManager } from "../lib/password_manager"; export const vaultsStore = writable< From e4a35dae8e4e6b37518d00ce59e3180e65f25bd5 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:18:23 +0200 Subject: [PATCH 16/24] fix(ci): update CI workflows to use icp-cli instead of dfx Replace dfx start/deploy with icp network start / icp deploy, remove DFX_VERSION env var, add Node.js 22 setup step, and update provisioning scripts to install icp-cli rather than dfx. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/backend-motoko.yml | 18 +++---------- .../workflows/examples-basic-bls-signing.yml | 22 +++++++++++----- .github/workflows/examples-basic-ibe.yml | 24 ++++++++++++------ .../workflows/examples-basic-timelock-ibe.yml | 12 ++++++--- .github/workflows/examples-encrypted-chat.yml | 6 +++++ .../examples-encrypted-notes-dapp.yml | 22 +++++++++++----- ...xamples-password-manager-with-metadata.yml | 22 +++++++++++----- .../workflows/examples-password-manager.yml | 22 +++++++++++----- .github/workflows/frontend.yml | 8 +++--- .github/workflows/provision-darwin.sh | 25 ++----------------- .../workflows/provision-frontend-darwin.sh | 17 ------------- .github/workflows/provision-frontend-linux.sh | 21 ---------------- .github/workflows/provision-linux.sh | 24 ++---------------- 13 files changed, 108 insertions(+), 135 deletions(-) delete mode 100644 .github/workflows/provision-frontend-darwin.sh delete mode 100644 .github/workflows/provision-frontend-linux.sh diff --git a/.github/workflows/backend-motoko.yml b/.github/workflows/backend-motoko.yml index 04fa8705..8ba91d76 100644 --- a/.github/workflows/backend-motoko.yml +++ b/.github/workflows/backend-motoko.yml @@ -13,8 +13,8 @@ on: - backend/rs/canisters/** - Cargo.toml - Cargo.lock - - .github/workflows/provision-frontend-linux.sh - - .github/workflows/provision-frontend-darwin.sh + - .github/workflows/provision-linux.sh + - .github/workflows/provision-darwin.sh - .github/workflows/backend-motoko.yml jobs: @@ -24,17 +24,12 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: '22' - uses: ZenVoich/setup-mops@3e94e453352269b34137b5ce49f09a8df81bed7d # v1.4.1 with: mops-version: 1 - name: Provision Linux - run: bash .github/workflows/provision-frontend-linux.sh + run: bash .github/workflows/provision-linux.sh - name: Run MOPS Test Linux - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd backend/mo/ic_vetkeys @@ -50,17 +45,12 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false - - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 - with: - node-version: '22' - uses: ZenVoich/setup-mops@3e94e453352269b34137b5ce49f09a8df81bed7d # v1.4.1 with: mops-version: 1 - name: Provision Darwin - run: bash .github/workflows/provision-frontend-darwin.sh + run: bash .github/workflows/provision-darwin.sh - name: Run MOPS Test Darwin - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd backend/mo/ic_vetkeys diff --git a/.github/workflows/examples-basic-bls-signing.yml b/.github/workflows/examples-basic-bls-signing.yml index 50dcf7f2..db48ea7c 100644 --- a/.github/workflows/examples-basic-bls-signing.yml +++ b/.github/workflows/examples-basic-bls-signing.yml @@ -15,8 +15,6 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - DFX_VERSION: 0.29.1 jobs: examples-basic-bls-signing-rust-darwin: runs-on: macos-15 @@ -24,6 +22,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -32,7 +33,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_bls_signing/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-basic-bls-signing-rust-linux: @@ -41,6 +42,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic BLS Signing Rust Linux @@ -48,7 +52,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_bls_signing/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-basic-bls-signing-motoko-darwin: @@ -57,6 +61,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -65,7 +72,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_bls_signing/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-basic-bls-signing-motoko-linux: @@ -74,6 +81,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic BLS Signing Motoko Linux @@ -81,6 +91,6 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_bls_signing/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint diff --git a/.github/workflows/examples-basic-ibe.yml b/.github/workflows/examples-basic-ibe.yml index c153c61c..1b81d972 100644 --- a/.github/workflows/examples-basic-ibe.yml +++ b/.github/workflows/examples-basic-ibe.yml @@ -14,8 +14,6 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - DFX_VERSION: 0.29.1 jobs: examples-basic-ibe-rust-darwin: runs-on: macos-15 @@ -23,6 +21,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -31,7 +32,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_ibe/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-basic-ibe-rust-linux: @@ -40,6 +41,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic IBE Rust Linux @@ -47,7 +51,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_ibe/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-basic-ibe-motoko-darwin: @@ -56,6 +60,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -64,7 +71,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_ibe/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-basic-ibe-motoko-linux: @@ -73,6 +80,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic IBE Motoko Linux @@ -80,6 +90,6 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_ibe/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend - npm run lint + npm run lint diff --git a/.github/workflows/examples-basic-timelock-ibe.yml b/.github/workflows/examples-basic-timelock-ibe.yml index 15c26f28..c009a3bf 100644 --- a/.github/workflows/examples-basic-timelock-ibe.yml +++ b/.github/workflows/examples-basic-timelock-ibe.yml @@ -22,6 +22,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -30,7 +33,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_timelock_ibe - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-basic-timelock-ibe-rust-linux: @@ -39,6 +42,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic Timelock IBE Linux @@ -46,6 +52,6 @@ jobs: set -eExuo pipefail cargo install candid-extractor pushd examples/basic_timelock_ibe - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend - npm run lint + npm run lint diff --git a/.github/workflows/examples-encrypted-chat.yml b/.github/workflows/examples-encrypted-chat.yml index 206a93fc..76e7d521 100644 --- a/.github/workflows/examples-encrypted-chat.yml +++ b/.github/workflows/examples-encrypted-chat.yml @@ -20,6 +20,9 @@ jobs: runs-on: macos-15 steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -32,6 +35,9 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Backend Tests Encrypted Chat Rust Linux diff --git a/.github/workflows/examples-encrypted-notes-dapp.yml b/.github/workflows/examples-encrypted-notes-dapp.yml index 6310b026..7afa73c9 100644 --- a/.github/workflows/examples-encrypted-notes-dapp.yml +++ b/.github/workflows/examples-encrypted-notes-dapp.yml @@ -14,8 +14,6 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - DFX_VERSION: 0.29.1 jobs: examples-encrypted-notes-dapp-rust-darwin: runs-on: macos-15 @@ -23,6 +21,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -30,26 +31,32 @@ jobs: run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy examples-encrypted-notes-dapp-rust-linux: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Encrypted Notes Dapp VetKD Linux run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy examples-encrypted-notes-dapp-motoko-darwin: runs-on: macos-15 steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -57,17 +64,20 @@ jobs: run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy examples-encrypted-notes-dapp-motoko-linux: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Encrypted Notes Dapp VetKD Linux run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy diff --git a/.github/workflows/examples-password-manager-with-metadata.yml b/.github/workflows/examples-password-manager-with-metadata.yml index e85003ee..a6a6f7d4 100644 --- a/.github/workflows/examples-password-manager-with-metadata.yml +++ b/.github/workflows/examples-password-manager-with-metadata.yml @@ -16,8 +16,6 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - DFX_VERSION: 0.29.1 jobs: examples-password-manager-with-metadata-rust-darwin: runs-on: macos-15 @@ -25,6 +23,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -33,7 +34,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor cd examples/password_manager_with_metadata/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-password-manager-with-metadata-rust-linux: @@ -42,6 +43,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager With Metadata Linux @@ -49,7 +53,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor cd examples/password_manager_with_metadata/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-password-manager-with-metadata-motoko-darwin: @@ -58,6 +62,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -66,7 +73,7 @@ jobs: set -eExuo pipefail cargo install candid-extractor cd examples/password_manager_with_metadata/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-password-manager-with-metadata-motoko-linux: @@ -75,6 +82,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager With Metadata Linux @@ -82,6 +92,6 @@ jobs: set -eExuo pipefail cargo install candid-extractor cd examples/password_manager_with_metadata/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint diff --git a/.github/workflows/examples-password-manager.yml b/.github/workflows/examples-password-manager.yml index a61fdad9..411ede76 100644 --- a/.github/workflows/examples-password-manager.yml +++ b/.github/workflows/examples-password-manager.yml @@ -16,8 +16,6 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true -env: - DFX_VERSION: 0.29.1 jobs: examples-password-manager-rust-darwin: runs-on: macos-15 @@ -25,6 +23,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -32,7 +33,7 @@ jobs: run: | set -eExuo pipefail cd examples/password_manager/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-password-manager-rust-linux: @@ -41,13 +42,16 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager Linux run: | set -eExuo pipefail cd examples/password_manager/rust - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-password-manager-motoko-darwin: @@ -56,6 +60,9 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh @@ -63,7 +70,7 @@ jobs: run: | set -eExuo pipefail cd examples/password_manager/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint examples-password-manager-motoko-linux: @@ -72,12 +79,15 @@ jobs: - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 with: persist-credentials: false + - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager Linux run: | set -eExuo pipefail cd examples/password_manager/motoko - dfx start --background && dfx deploy + icp network start -d && icp deploy cd frontend npm run lint diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index c270fdac..b09268c7 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -12,8 +12,8 @@ on: - package.json - package-lock.json - .github/workflows/frontend.yml - - .github/workflows/provision-frontend-darwin.sh - - .github/workflows/provision-frontend-linux.sh + - .github/workflows/provision-darwin.sh + - .github/workflows/provision-linux.sh concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -28,7 +28,7 @@ jobs: with: node-version: '22' - name: Provision Linux - run: bash .github/workflows/provision-frontend-linux.sh + run: bash .github/workflows/provision-linux.sh - name: Frontend Tests and Lint env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -50,7 +50,7 @@ jobs: node-version: '22' - name: Provision Darwin run: | - bash .github/workflows/provision-frontend-darwin.sh + bash .github/workflows/provision-darwin.sh - name: Frontend Tests and Lint env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/provision-darwin.sh b/.github/workflows/provision-darwin.sh index 5e18c9f9..495c1d7d 100644 --- a/.github/workflows/provision-darwin.sh +++ b/.github/workflows/provision-darwin.sh @@ -5,29 +5,8 @@ set -ex # Enter temporary directory. pushd /tmp -# Install Node. -brew install nodejs - -# Install DFINITY SDK. -curl --location --output install-dfx.sh "https://raw.githubusercontent.com/dfinity/sdk/master/public/install-dfxvm.sh" -DFX_VERSION=${DFX_VERSION:=0.26.1} DFXVM_INIT_YES=true bash install-dfx.sh -rm install-dfx.sh -echo "$HOME/Library/Application Support/org.dfinity.dfx/bin" >> $GITHUB_PATH -source "$HOME/Library/Application Support/org.dfinity.dfx/env" -dfx cache install - -# check the current ic-commit found in the main branch, check if it differs from the one in this PR branch -# if so, update the dfx cache with the latest ic artifacts -if [ -f "${GITHUB_WORKSPACE}/.ic-commit" ]; then - stable_sha=$(curl https://raw.githubusercontent.com/dfinity/examples/master/.ic-commit) - current_sha=$(sed <"$GITHUB_WORKSPACE/.ic-commit" 's/#.*$//' | sed '/^$/d') - arch="x86_64-darwin" - if [ "$current_sha" != "$stable_sha" ]; then - export current_sha - export arch - sh "$GITHUB_WORKSPACE/.github/workflows/update-dfx-cache.sh" - fi -fi +# Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). +npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm # Install rust curl --location --output install-rustup.sh "https://sh.rustup.rs" diff --git a/.github/workflows/provision-frontend-darwin.sh b/.github/workflows/provision-frontend-darwin.sh deleted file mode 100644 index 495c1d7d..00000000 --- a/.github/workflows/provision-frontend-darwin.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -set -ex - -# Enter temporary directory. -pushd /tmp - -# Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm - -# Install rust -curl --location --output install-rustup.sh "https://sh.rustup.rs" -bash install-rustup.sh -y -rustup target add wasm32-unknown-unknown - -# Exit temporary directory. -popd diff --git a/.github/workflows/provision-frontend-linux.sh b/.github/workflows/provision-frontend-linux.sh deleted file mode 100644 index 9b0ca393..00000000 --- a/.github/workflows/provision-frontend-linux.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash - -set -ex - -# Enter temporary directory. -pushd /tmp - -# Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm - -# Install rust -wget --output-document install-rustup.sh "https://sh.rustup.rs" -bash install-rustup.sh -y -rustup target add wasm32-unknown-unknown - -# Set environment variables. -echo "$HOME/bin" >>$GITHUB_PATH -echo "$HOME/.cargo/bin" >>$GITHUB_PATH - -# Exit temporary directory. -popd diff --git a/.github/workflows/provision-linux.sh b/.github/workflows/provision-linux.sh index 071a9423..210b1b50 100644 --- a/.github/workflows/provision-linux.sh +++ b/.github/workflows/provision-linux.sh @@ -5,28 +5,8 @@ set -ex # Enter temporary directory. pushd /tmp -# Install Node. -sudo apt-get install nodejs - -# Install DFINITY SDK. -wget --output-document install-dfx.sh "https://raw.githubusercontent.com/dfinity/sdk/master/public/install-dfxvm.sh" -DFX_VERSION=${DFX_VERSION:=0.26.1} DFXVM_INIT_YES=true bash install-dfx.sh -rm install-dfx.sh -echo "$HOME/.local/share/dfx/bin" >>$GITHUB_PATH -source "$HOME/.local/share/dfx/env" -dfx cache install -# check the current ic-commit found in the main branch, check if it differs from the one in this PR branch -# if so, update the dfx cache with the latest ic artifacts -if [ -f "${GITHUB_WORKSPACE}/.ic-commit" ]; then - stable_sha=$(curl https://raw.githubusercontent.com/dfinity/examples/master/.ic-commit) - current_sha=$(sed <"$GITHUB_WORKSPACE/.ic-commit" 's/#.*$//' | sed '/^$/d') - arch="x86_64-linux" - if [ "$current_sha" != "$stable_sha" ]; then - export current_sha - export arch - sh "$GITHUB_WORKSPACE/.github/workflows/update-dfx-cache.sh" - fi -fi +# Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). +npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm # Install rust wget --output-document install-rustup.sh "https://sh.rustup.rs" From 0118583bbac1fe0b2b83c101c20fcd0a81fab634 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:18:29 +0200 Subject: [PATCH 17/24] docs(examples): update documentation links and ICP CLI references MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update all internetcomputer.org/docs/ links to docs.internetcomputer.org/ - Replace IC SDK install links with ICP CLI (cli.internetcomputer.org) references - Add `icp network stop` instructions to local deployment sections in all READMEs - Comment out icp.ninja badges (icp.ninja currently requires dfx; will re-enable once icp.ninja supports icp-cli) - Fix broken SPEC.md anchor (#state-cache → #encrypted-symmetric-ratchet-state-cache) Co-Authored-By: Claude Sonnet 4.6 --- README.md | 2 +- examples/basic_bls_signing/README.md | 28 ++++++---- examples/basic_ibe/README.md | 28 ++++++---- examples/basic_timelock_ibe/README.md | 28 ++++++---- examples/encrypted_chat/README.md | 4 +- examples/encrypted_chat/SPEC.md | 56 +++++++++---------- examples/encrypted_notes_dapp_vetkd/README.md | 28 ++++++---- examples/password_manager/README.md | 29 ++++++---- examples/password_manager/frontend/README.md | 4 +- .../password_manager_with_metadata/README.md | 28 ++++++---- 10 files changed, 134 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 59ad0d2a..322b296b 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ vetkd_public_key : (vetkd_public_key_args) -> (vetkd_public_key_result); vetkd_derive_key : (vetkd_derive_key_args) -> (vetkd_derive_key_result); ``` -For more documentation on vetKeys and the management canister API, see the [vetKeys documentation](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction). +For more documentation on vetKeys and the management canister API, see the [vetKeys documentation](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction). Please share your feedback on the [developer forum](https://forum.dfinity.org/t/threshold-key-derivation-privacy-on-the-ic/16560/179). diff --git a/examples/basic_bls_signing/README.md b/examples/basic_bls_signing/README.md index 4d0231fb..5bf0cd57 100644 --- a/examples/basic_bls_signing/README.md +++ b/examples/basic_bls_signing/README.md @@ -1,10 +1,12 @@ # Threshold BLS Signatures + -The **Basic BLS signing** example demonstrates how to use **[vetKeys](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction)** to implement a threshold BLS signing service on the **Internet Computer (IC)**, where every authenticated user can ask the canister (IC smart contract) to produce signatures, where the **Internet Identity Principal** identifies the signer. This canister ensures that users can only produce signature for their own principal and not for someone else's principal. Furthermore, the vetKeys in this dapp can only be produced upon a user request, as specified in the canister code, meaning that the canister cannot produce signatures for arbitrary users or messages. +The **Basic BLS signing** example demonstrates how to use **[vetKeys](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction)** to implement a threshold BLS signing service on the **Internet Computer (IC)**, where every authenticated user can ask the canister (IC smart contract) to produce signatures, where the **Internet Identity Principal** identifies the signer. This canister ensures that users can only produce signature for their own principal and not for someone else's principal. Furthermore, the vetKeys in this dapp can only be produced upon a user request, as specified in the canister code, meaning that the canister cannot produce signatures for arbitrary users or messages. For confirming that the canister can only produce signatures in the intended way, users need to inspect the code installed in the canister. For this, it is crucial that canisters using VetKeys have their code public. @@ -19,23 +21,33 @@ For confirming that the canister can only produce signatures in the intended way ### Prerequisites -- [Internet Computer software development kit](https://internetcomputer.org/docs/building-apps/getting-started/install) +- [ICP CLI](https://cli.internetcomputer.org) - [npm](https://www.npmjs.com/package/npm) ### (Optionally) Choose a Different Master Key -This example uses `test_key_1` by default. To use a different [available master key](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api#available-master-keys), change the `"init_arg": "(\"test_key_1\")"` line in `dfx.json` to the desired key before running `dfx deploy` in the next step. +This example uses `test_key_1` by default. To use a different [available master key](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api#available-master-keys), change the `init_args` value in `icp.yaml` to the desired key before running `icp deploy` in the next step. ### Deploy the Canisters Locally If you want to deploy this project locally with a Motoko backend, then run: ```bash -dfx start --background && dfx deploy +icp network start -d && icp deploy ``` from the `motoko` folder. To use the Rust backend instead of Motoko, run the same command in the `rust` folder. +To run the frontend in development mode with hot reloading (after running `icp deploy`): +```bash +npm run dev +``` + +When you are done testing, stop the local network to free up resources and unblock the default port for other projects: +```bash +icp network stop +``` + ## Example Components ### Backend @@ -49,12 +61,6 @@ The backend consists of a canister that: The frontend is a vanilla typescript application providing a simple interface for signing, showing the signatures stored in the canister, and publishing a signature. -To run the frontend in development mode with hot reloading (after running `dfx deploy`): - -```bash -npm run dev -``` - ## Additional Resources -- **[What are VetKeys](https://internetcomputer.org/docs/building-apps/network-features/encryption/vetkeys)** - For more information about VetKeys and VetKD. +- **[What are VetKeys](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction)** - For more information about VetKeys and VetKD. diff --git a/examples/basic_ibe/README.md b/examples/basic_ibe/README.md index 33a4c2bf..47979ac7 100644 --- a/examples/basic_ibe/README.md +++ b/examples/basic_ibe/README.md @@ -1,10 +1,12 @@ # Identity-Based Encryption + -The **Basic IBE** example demonstrates how to use **[VetKeys](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction)** to implement secure messaging between users by means of Identity-Based Encryption (IBE) on the **Internet Computer (IC)**. This application allows users to send encrypted messages to other users using their **Internet Identity Principal** as the encryption key identifier. This canister (IC smart contract) ensures that only the authorized user can access their private decryption key, meaning that even if someone else knows your principal, they cannot decrypt messages intended for you because neither other users nor this canister can access your private key. +The **Basic IBE** example demonstrates how to use **[VetKeys](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction)** to implement secure messaging between users by means of Identity-Based Encryption (IBE) on the **Internet Computer (IC)**. This application allows users to send encrypted messages to other users using their **Internet Identity Principal** as the encryption key identifier. This canister (IC smart contract) ensures that only the authorized user can access their private decryption key, meaning that even if someone else knows your principal, they cannot decrypt messages intended for you because neither other users nor this canister can access your private key. Note that generally it is possible for a canister to request a decryption key to decrypt secrets as part of its code. However, doing so requires the canister to provide its own transport key instead of requesting a user's transport key and this inherently makes secrets public. @@ -22,23 +24,33 @@ A canister functionality for decrypting secrets can be detected by inspecting th ### Prerequisites -- [Internet Computer software development kit](https://internetcomputer.org/docs/building-apps/getting-started/install) +- [ICP CLI](https://cli.internetcomputer.org) - [npm](https://www.npmjs.com/package/npm) ### (Optionally) Choose a Different Master Key -This example uses `test_key_1` by default. To use a different [available master key](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api#available-master-keys), change the `"init_arg": "(\"test_key_1\")"` line in `dfx.json` to the desired key before running `dfx deploy` in the next step. +This example uses `test_key_1` by default. To use a different [available master key](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api#available-master-keys), change the `init_args` value in `icp.yaml` to the desired key before running `icp deploy` in the next step. ### Deploy the Canisters Locally If you want to deploy this project locally with a Motoko backend, then run: ```bash -dfx start --background && dfx deploy +icp network start -d && icp deploy ``` from the `motoko` folder. To use the Rust backend instead of Motoko, run the same command in the `rust` folder. +To run the frontend in development mode with hot reloading (after running `icp deploy`): +```bash +npm run dev +``` + +When you are done testing, stop the local network to free up resources and unblock the default port for other projects: +```bash +icp network stop +``` + ## Example Components ### Backend @@ -52,16 +64,10 @@ The backend consists of a canister that: The frontend is a vanilla typescript application providing a simple interface for sending, receiving, and deleting encrypted messages. -To run the frontend in development mode with hot reloading (after running `dfx deploy`): - -```bash -npm run dev -``` - ## Limitations This example dapp does not implement key rotation, which is strongly recommended in a production dapp to limit the impact of potential key compromise if a malicious party gains access to the user's decryption key. ## Additional Resources -- **[What are VetKeys](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction)** - For more information about VetKeys and VetKD. +- **[What are VetKeys](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction)** - For more information about VetKeys and VetKD. diff --git a/examples/basic_timelock_ibe/README.md b/examples/basic_timelock_ibe/README.md index 39a6b18b..b8b5d56f 100644 --- a/examples/basic_timelock_ibe/README.md +++ b/examples/basic_timelock_ibe/README.md @@ -1,8 +1,10 @@ # Timelock Encryption + -The **Basic Timelock IBE** example demonstrates how to use **[VetKeys](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction)** to implement a secret-bid auction using timelock encryption on the **Internet Computer (IC)**. This application allows users authenticated with their **Internet Identity Principal** to create auction lots with a description and deadline, and other users to place a secret bid for the lot. The bids in this example are just dummy integer values, contrary to real-world use cases where users would place bids holding some value. +The **Basic Timelock IBE** example demonstrates how to use **[VetKeys](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction)** to implement a secret-bid auction using timelock encryption on the **Internet Computer (IC)**. This application allows users authenticated with their **Internet Identity Principal** to create auction lots with a description and deadline, and other users to place a secret bid for the lot. The bids in this example are just dummy integer values, contrary to real-world use cases where users would place bids holding some value. This canister (IC smart contract) ensures that: 1. Only authorized users can create auction lots and place secret bids until the lot is closed. @@ -31,17 +33,27 @@ A canister functionality for decrypting secrets can be detected by inspecting th ### Prerequisites -- [Internet Computer software development kit](https://internetcomputer.org/docs/building-apps/getting-started/install) +- [ICP CLI](https://cli.internetcomputer.org) - [npm](https://www.npmjs.com/package/npm) ### (Optionally) Choose a Different Master Key -This example uses `test_key_1` by default. To use a different [available master key](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api#available-master-keys), change the `"init_arg": "(\"test_key_1\")"` line in `dfx.json` to the desired key before running `dfx deploy` in the next step. +This example uses `test_key_1` by default. To use a different [available master key](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api#available-master-keys), change the `init_args` value in `icp.yaml` to the desired key before running `icp deploy` in the next step. ### Deploy the Canisters Locally ```bash -dfx start --background && dfx deploy +icp network start -d && icp deploy +``` + +To run the frontend in development mode with hot reloading (after running `icp deploy`): +```bash +npm run dev +``` + +When you are done testing, stop the local network to free up resources and unblock the default port for other projects: +```bash +icp network stop ``` ## Example Components @@ -61,13 +73,7 @@ The frontend is a vanilla typescript application providing a simple interface fo * Viewing open and closed lots including winners and bidders * Placing a secret bid for open lots created by other users -To run the frontend in development mode with hot reloading (after running `dfx deploy`): - -```bash -npm run dev -``` - ## Additional Resources - **[Basic IBE Example](../basic_ibe/)** - If you are interested in using IBE with users decrypting secrets. -- **[What are VetKeys](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction)** - For more information about VetKeys and VetKD. \ No newline at end of file +- **[What are VetKeys](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction)** - For more information about VetKeys and VetKD. \ No newline at end of file diff --git a/examples/encrypted_chat/README.md b/examples/encrypted_chat/README.md index c66424a1..a4c9b5d7 100644 --- a/examples/encrypted_chat/README.md +++ b/examples/encrypted_chat/README.md @@ -2,4 +2,6 @@ > > DO NOT USE IN PRODUCTION!! -[![](https://icp.ninja/assets/open.svg)](https://icp.ninja/editor?g=https://github.com/dfinity/vetkeys/tree/main/examples/encrypted_chat/rust) \ No newline at end of file + \ No newline at end of file diff --git a/examples/encrypted_chat/SPEC.md b/examples/encrypted_chat/SPEC.md index 7351b8b4..d20ab3a0 100644 --- a/examples/encrypted_chat/SPEC.md +++ b/examples/encrypted_chat/SPEC.md @@ -4,7 +4,7 @@ vetKey Encrypted Chat has two main components: the canister backend and user fro * End-to-end encrypted messaging. -* High security through symmetric ratchet and key rotation via [vetKeys](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/introduction). +* High security through symmetric ratchet and key rotation via [vetKeys](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/introduction). * Disappearing messages, enforced by the canister (ICP smart contract) logic. Messages are automatically removed from the frontend and encrypted messages are purged from the backend once they expire. @@ -15,7 +15,7 @@ vetKey Encrypted Chat has two main components: the canister backend and user fro ### Key Hierarchy vetKey encrypted chat uses three layers of cryptographic keys: -* **vetKeys**: shared keys established thorough the [vetKD protocol](https://internetcomputer.org/docs/references/vetkeys-overview). +* **vetKeys**: shared keys established thorough the [vetKD protocol](https://docs.internetcomputer.org/references/vetkeys-overview). They rotate periodically, e.g. upon group configuration changes, to ensure both forward security and post-compromise security. This means that an adversary who obtains the key material for one vetKey epoch gains no information about past or future epochs. Deriving new vetKeys incurs some cost, as it requires interaction with the backend canister, which triggers a vetKey-derivation protocol on the ICP. @@ -128,7 +128,7 @@ The frontend's responsibilities are: * User data per chat and vetKey epoch - * [User-uploaded optional encrypted symmetric ratchet state cache](#state-cache) + * [User-uploaded optional encrypted symmetric ratchet state cache](#encrypted-symmetric-ratchet-state-cache) * Optional optimization: [IBE-encrypted vetKey reshared by another user](#ibe-encrypted-vetkey-resharing) @@ -355,7 +355,7 @@ Then, the canister checks that: * The user did not upload an encrypted cache for his symmetric ratchet state for the vetKey epoch in question (see [State Recovery](#state-recovery)). -If the checks pass, the canister calls the [`vetkd_derive_key`](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api) API of the management canister with: +If the checks pass, the canister calls the [`vetkd_derive_key`](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api) API of the management canister with: * `context` being computed by invoking the `ratchet_context` function defined below. @@ -625,28 +625,27 @@ Types: * `type ChatIdAsString = string` * `interface Message { - nonce: bigint; - chatId: ChatId; - senderId: Principal; + messageId: string; + chatId: ChatIdAsString; + senderId: string; content: string; timestamp: Date; - vetkeyEpoch: bigint; - symmetricRatchetEpoch: bigint; + vetkeyEpoch: number; + symmetricRatchetEpoch: number; + decryptionFailed?: boolean; } ` + When `decryptionFailed` is `true` the message content is empty and the UI should render a placeholder indicating the message could not be decrypted. Such messages are not persisted to local storage so that the next session can retry decryption. + The EMS exposes the following APIs: * `enqueueSendMessage(chatId: ChatId, content: Uint8Array)`: adds the message `content` to be encrypted for and sent to the chat with ID `chatId`. This API does not give any guarantees that the message will actually be added to the chat but it makes attempts to recover from recoverable errors (see [Encrypting and Sending Messages in the EMS](#encrypting-and-sending-messages)). -* `takeReceivedMessages(): Map`: returns latest chat messages that were received and decrypted by the EMS and were not yet taken by the user from the EMS (see [Fetching and Decrypting Messages in the EMS](#fetching-and-decrypting-messages)). - -* `start()`: starts the EMS service. Before the service is started, calling any other APIs should throw an error. Once it is started, the APIs start to return their intended values, and the EMS starts background tasks to continuously update the relevant chat information from the canister. +* `start(onMessagesDecrypted: (chatIdStr: ChatIdAsString, messages: Message[]) => void, onNewChatDiscovered: (chatId: ChatId) => void)`: starts the EMS service and registers push-based delivery callbacks. Once started, the EMS runs background tasks that continuously fetch and decrypt messages. Newly decrypted messages (including decryption-failed placeholders) are delivered immediately to the caller via `onMessagesDecrypted` rather than buffered in a pull queue. When a chat is first observed that has no local key state, `onNewChatDiscovered` is called so the UI can refresh its chat list. The `firstPollComplete` promise resolves as soon as the first fetch cycle finishes (before decryption completes), which the UI can await to determine when the initial chat list is available. * `skipMessagesAvailableLocally(chatId: ChatId, lastKnownChatMessageId: bigint)`: tells the EMS what chat message ID should be the first one to be fetched. This is relevant if some of the messages are available from another source such as [browser storage](#local-cache-in-indexeddb). -* `getCurrentChatIds(): ChatId[]`: returns the chat IDs that are currently accessible to the user. This particular API is mostly an efficiency optimization, since the message retrieval in the EMS anyways requires fetching the information about the currently accessible chats. - * `getCurrentUsersInChat(chatId: ChatId): Principal[]`: takes in a chat ID and returns the current users in the chat. If the EMS does not have data about the chat with `chatId` because either the user does not have access to the chat, or if `chatId` does not exist, or the frontend did not yet manage to synchronize with the backend, this function throws an error. #### Encrypting and Sending Messages @@ -680,33 +679,28 @@ For message [retrieval](#encrypted-message-retrieval) and [decryption](#ratchet- * Further canister APIs required for [Ratchet Initialization](#ratchet-initialization). -The frontend stores the following related data related in its state: +The frontend stores the following related state: * The chat IDs accessible to the user. -* The first accessible message ID for the user for each chat +* The number of messages already fetched for each chat (used to request only new messages on the next poll cycle). -* The last fetched message for the chat. +* A per-chat queue of fetched-but-not-yet-decrypted encrypted messages. -* The total number of messages in the chat. +Periodically, the EMS background worker runs a combined fetch-then-decrypt cycle: -Let's call this information frontend chat metadata. +**Fetch phase**: The EMS calls `get_my_chats_and_time` to learn which chats exist and how many messages each has. For each chat it fetches only the messages it has not yet seen (starting from the locally tracked fetch offset). If a chat is seen for the first time, `onNewChatDiscovered` is called. If an error occurs because a batch of messages is too large for a single response, the fetch is retried with a limit of one message. After all chats have been processed, the `firstPollComplete` promise is resolved — this allows the UI to clear its loading screen even if some messages later fail to decrypt. -Periodically, the EMS queries the `get_my_chats_and_time` backend canister API. -Its result is compared to the frontend chat metadata in the state. -The existing chat metadata is updated if required. -If there is a new chat in the result that is not yet in the state, the EMS adds it to the state along with the information that no messages were obtained for this chat yet. -If one of the chats in the state does not appear in the result of `get_my_chats_and_time` anymore, then this chat is deleted from the state including from the queues containing received and decrypted messages. +**Decrypt phase**: For each chat that has messages in the pending queue: -Also periodically, two separate routines run. +1. The EMS checks if it already has the symmetric ratchet state required to decrypt the message (identified by the vetKey epoch in the message metadata). If the state is not yet initialized, the EMS [initializes](#ratchet-initialization) it. A failure to initialize is treated as unrecoverable for that message. -1. Check if there are new messages to be fetched from the canister: if the largest received message ID for the chat plus one is smaller than the total number of messages in the chat. If it is, then `get_messages` is invoked with the first message ID to be fetched that is equal to the largest received message ID for the chat plus one, or if no messages were received so far for a chat, message ID 0 is used. If an error occurs due to too large messages that don't fit into the canister's response due to the query response limits on the ICP, the query to `get_messages` is retried with a limit of e.g. one. A successful result appended to the received messages queue. +2. The EMS [decrypts](#ratchet-message-decryption) the message using the ratchet state. If decryption succeeds, the plaintext `Message` is added to the batch. If decryption fails, a placeholder `Message` with `decryptionFailed: true` is added instead so the user can see that a message exists but could not be read. Note that receiver-side decryption errors cannot be fully prevented, since the canister cannot verify that the stored ciphertext is valid. -2. Try to take a message from the received messages queue and decrypt it. +3. After processing all messages for a chat, the entire batch (successes and placeholders) is delivered immediately to the UI via the `onMessagesDecrypted` callback registered in `start()`. There is no pull-based queue; messages appear in the UI as soon as they are processed. - a. The EMS checks if it already has the symmetric ratchet state in its state that is required to decrypt the message, whose metadata specifies the required vetKey epoch and symmetric ratchet epoch. If the symmetric ratchet state is not yet initialized, the EMS [initializes](#ratchet-initialization) it. An error to do so is unrecoverable. - - b. The EMS [decrypts](#ratchet-message-decryption) the message using the symmetric ratchet state and the vetKey epoch ID stored in the message metadata. A successfully decrypted message is put into the decrypted message queue that is exposed to the chat UI component via the [`takeReceivedMessages` API](#encrypted-messaging-service) of the EMS. If the decryption returns an error, such an error is unrecoverable and instead of a decrypted message, a message of special form is put into the decrypted message queue that indicated that this message could not be decrypted. Note that user-side errors cannot be avoided, since the canister cannot check if the encryption is valid. +> [!NOTE] +> **Implementation deviation — ratchet evolution during decryption**: The spec states that symmetric ratchet evolution should be performed in a dedicated background task separate from decryption. In the current implementation, evolution happens inline inside `decryptAtEpochAndEvolveIfNeeded` during the decrypt phase. This is a known deviation; see [Ratchet Evolution](#ratchet-evolution) for the intended design. #### Symmetric Ratchet @@ -742,7 +736,7 @@ The ratchet state is initialized from a vetKey as follows: b. Initialize the symmetric ratchet state as `rootKey` and symmetric ratchet epoch that is equal to zero. -More details about the retrieval and decryption of vetKeys can be found in the [developer docs](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api) of the ICP. +More details about the retrieval and decryption of vetKeys can be found in the [developer docs](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api) of the ICP. After initializing the ratchet state, the user uploads encrypted cache of the state to the backend canister which is further described in [Encrypted Ratchet State Cache](#encrypted-symmetric-ratchet-state-cache). diff --git a/examples/encrypted_notes_dapp_vetkd/README.md b/examples/encrypted_notes_dapp_vetkd/README.md index a61966de..278bed30 100644 --- a/examples/encrypted_notes_dapp_vetkd/README.md +++ b/examples/encrypted_notes_dapp_vetkd/README.md @@ -1,8 +1,10 @@ # Encrypted notes: vetKD + Encrypted notes is an example dapp for authoring and storing confidential information on the Internet Computer (ICP) in the form of short pieces of text. Users can create and access their notes via any number of automatically synchronized devices authenticated via Internet Identity (II). Notes are stored confidentially using vetKeys. The end-to-end encryption is performed by the dapp’s frontend. @@ -14,39 +16,43 @@ The vetKey used to encrypt and decrypt a note is note-ID-specific (and not, for This example requires an installation of: -- [x] Install the [IC SDK](https://internetcomputer.org/docs/current/developer-docs/setup/install/index.mdx). +- [x] Install the [ICP CLI](https://cli.internetcomputer.org). - [x] Install [npm](https://www.npmjs.com/package/npm). ### (Optionally) Choose a Different Master Key -This example uses `test_key_1` by default. To use a different [available master key](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api#available-master-keys), change the `"init_arg": "(\"test_key_1\")"` line in `dfx.json` to the desired key before running `dfx deploy` in the next step. +This example uses `test_key_1` by default. To use a different [available master key](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api#available-master-keys), change the `init_args` value in `icp.yaml` to the desired key before running `icp deploy` in the next step. ## Deploy the Canisters Locally If you want to deploy this project locally with a Motoko backend, then run: ```bash -dfx start --background && dfx deploy +icp network start -d && icp deploy ``` from the `motoko` folder. -To use the Rust backend instead of Motoko, run the same command in the rust folder. +To use the Rust backend instead of Motoko, run the same command in the `rust` folder. + +To run the frontend in development mode with hot reloading (after running `icp deploy`): +```bash +npm run dev +``` + +When you are done testing, stop the local network to free up resources and unblock the default port for other projects: +```bash +icp network stop +``` ## Example Components ### Backend -The backend consists of a canister that stores encrypted notes. It is automatically deployed with `dfx deploy`. +The backend consists of a canister that stores encrypted notes. ### Frontend The frontend is a **Svelte** application providing a user-friendly interface for managing encrypted notes. -To run the frontend in development mode with hot reloading (after running `dfx deploy`): - -```bash -npm run dev -``` - ## Limitations This example dapp does not implement key rotation, which is strongly recommended in a production environment. diff --git a/examples/password_manager/README.md b/examples/password_manager/README.md index ed5bd30c..4a7f122b 100644 --- a/examples/password_manager/README.md +++ b/examples/password_manager/README.md @@ -1,8 +1,10 @@ # VetKey Password Manager + The **VetKey Password Manager** is an example application demonstrating how to use **VetKeys** and **Encrypted Maps** to build a secure, decentralized password manager on the **Internet Computer (IC)**. This application allows users to create password vaults, store encrypted passwords, and share vaults with other users via their **Internet Identity Principal**. @@ -16,38 +18,43 @@ The **VetKey Password Manager** is an example application demonstrating how to u ### Prerequisites -- [Local Internet Computer dev environment](https://internetcomputer.org/docs/building-apps/getting-started/install) +- [ICP CLI](https://cli.internetcomputer.org) - [npm](https://www.npmjs.com/package/npm) ### (Optionally) Choose a Different Master Key -This example uses `test_key_1` by default. To use a different [available master key](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api#available-master-keys), change the `"init_arg": "(\"test_key_1\")"` line in `dfx.json` to the desired key before running `dfx deploy` in the next step. +This example uses `test_key_1` by default. To use a different [available master key](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api#available-master-keys), change the `init_args` value in `icp.yaml` to the desired key before running `icp deploy` in the next step. ### Deploy the Canisters Locally + If you want to deploy this project locally with a Motoko backend, then run: ```bash -dfx start --background && dfx deploy +icp network start -d && icp deploy ``` from the `motoko` folder. To use the Rust backend instead of Motoko, run the same command in the `rust` folder. -## Running the Project +To run the frontend in development mode with hot reloading (after running `icp deploy`): +```bash +npm run dev +``` + +When you are done testing, stop the local network to free up resources and unblock the default port for other projects: +```bash +icp network stop +``` + +## Example Components ### Backend -The backend consists of an **Encrypted Maps**-enabled canister that securely stores passwords. It is automatically deployed with `dfx deploy`. +The backend consists of an **Encrypted Maps**-enabled canister that securely stores passwords. ### Frontend The frontend is a **Svelte** application providing a user-friendly interface for managing vaults and passwords. -To run the frontend in development mode with hot reloading: - -```bash -npm run dev -``` - ## Limitations This example dapp does not implement key rotation, which is strongly recommended in a production environment. diff --git a/examples/password_manager/frontend/README.md b/examples/password_manager/frontend/README.md index 134a1abb..9774cfc0 100644 --- a/examples/password_manager/frontend/README.md +++ b/examples/password_manager/frontend/README.md @@ -11,7 +11,7 @@ frontend implementation that uses all defaults from the SDK. ## Step 3: Deploy frontend. This returns a link that can be used to access the frontend from the asset canister. ```shell -dfx deploy www +icp deploy www ``` -Note: if this returns a URL with the IP `0.0.0.0` and the fronetned does not +Note: if this returns a URL with the IP `0.0.0.0` and the frontend does not work, a potential fix is to replace it with `localhost`. \ No newline at end of file diff --git a/examples/password_manager_with_metadata/README.md b/examples/password_manager_with_metadata/README.md index c7290f7a..8983243f 100644 --- a/examples/password_manager_with_metadata/README.md +++ b/examples/password_manager_with_metadata/README.md @@ -1,8 +1,10 @@ # VetKey Password Manager with Metadata + The **VetKey Password Manager** is an example application demonstrating how to use **VetKeys** and **Encrypted Maps** to build a secure, decentralized password manager on the **Internet Computer (IC)**. This application allows users to create password vaults, store encrypted passwords, and share vaults with other users via their **Internet Identity Principal**. @@ -19,39 +21,43 @@ This version of the application extends the basic password manager by supporting ### Prerequisites -- [Local Internet Computer dev environment](https://internetcomputer.org/docs/building-apps/getting-started/install) +- [ICP CLI](https://cli.internetcomputer.org) - [npm](https://www.npmjs.com/package/npm) ### (Optionally) Choose a Different Master Key -This example uses `test_key_1` by default. To use a different [available master key](https://internetcomputer.org/docs/building-apps/network-features/vetkeys/api#available-master-keys), change the `"init_arg": "(\"test_key_1\")"` line in `dfx.json` to the desired key before running `dfx deploy` in the next step. +This example uses `test_key_1` by default. To use a different [available master key](https://docs.internetcomputer.org/building-apps/network-features/vetkeys/api#available-master-keys), change the `init_args` value in `icp.yaml` to the desired key before running `icp deploy` in the next step. ### Deploy the Canisters Locally If you want to deploy this project locally with a Motoko backend, then run: ```bash -dfx start --background && dfx deploy +icp network start -d && icp deploy ``` from the `motoko` folder. To use the Rust backend instead of Motoko, run the same command in the `rust` folder. -## Running the Project +To run the frontend in development mode with hot reloading (after running `icp deploy`): +```bash +npm run dev +``` + +When you are done testing, stop the local network to free up resources and unblock the default port for other projects: +```bash +icp network stop +``` + +## Example Components ### Backend -The backend consists of an **Encrypted Maps**-enabled canister that securely stores passwords. It is automatically deployed with `dfx deploy`. +The backend consists of an **Encrypted Maps**-enabled canister that securely stores passwords. ### Frontend The frontend is a **Svelte** application providing a user-friendly interface for managing vaults and passwords. -To run the frontend in development mode with hot reloading: - -```bash -npm run dev -``` - ## Limitations This example dapp does not implement key rotation, which is strongly recommended in a production environment. From d3b7b95ba5be28344666e8a9b62918f28f94d909 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:19:50 +0200 Subject: [PATCH 18/24] chore(examples): add missed new files from icp-cli and frontend migrations - encrypted_chat/rust/icp.yaml: missing Rust backend icp.yaml - encrypted_notes_dapp_vetkd/frontend/index.html: new Vite entry point (replaces rollup-based public/index.html) - encrypted_notes_dapp_vetkd/frontend/svelte.config.js: Svelte preprocessor config for Vite - encrypted_notes_dapp_vetkd/rust/backend/Makefile: helper targets for Rust backend - password_manager/frontend/scripts/gen_bindings.sh: binding generation script - password_manager*/frontend/tailwind.config.mjs: renamed from .cjs to .mjs (package.json has "type":"module") Co-Authored-By: Claude Sonnet 4.6 --- examples/encrypted_chat/rust/icp.yaml | 23 +++++++++++++++++++ .../frontend/index.html | 15 ++++++++++++ .../frontend/svelte.config.js | 5 ++++ .../rust/backend/Makefile | 14 +++++++++++ .../frontend/scripts/gen_bindings.sh | 15 ++++++++++++ .../frontend/tailwind.config.mjs | 6 +++++ .../frontend/tailwind.config.mjs | 9 ++++++++ 7 files changed, 87 insertions(+) create mode 100644 examples/encrypted_chat/rust/icp.yaml create mode 100644 examples/encrypted_notes_dapp_vetkd/frontend/index.html create mode 100644 examples/encrypted_notes_dapp_vetkd/frontend/svelte.config.js create mode 100644 examples/encrypted_notes_dapp_vetkd/rust/backend/Makefile create mode 100755 examples/password_manager/frontend/scripts/gen_bindings.sh create mode 100644 examples/password_manager/frontend/tailwind.config.mjs create mode 100644 examples/password_manager_with_metadata/frontend/tailwind.config.mjs diff --git a/examples/encrypted_chat/rust/icp.yaml b/examples/encrypted_chat/rust/icp.yaml new file mode 100644 index 00000000..60139058 --- /dev/null +++ b/examples/encrypted_chat/rust/icp.yaml @@ -0,0 +1,23 @@ +canisters: + - name: encrypted_chat + recipe: + type: "@dfinity/rust@v3.2.0" + configuration: + package: ic-vetkeys-example-encrypted-chat-backend + candid: backend/backend.did + init_args: + type: text + value: "(\"test_key_1\")" + + - name: www + recipe: + type: "@dfinity/asset-canister@v2.1.0" + configuration: + dir: dist + build: + - cd frontend && npm i --include=dev && npm run build && cd - && rm -rf dist; mv frontend/dist ./ + +networks: + - name: local + mode: managed + ii: true diff --git a/examples/encrypted_notes_dapp_vetkd/frontend/index.html b/examples/encrypted_notes_dapp_vetkd/frontend/index.html new file mode 100644 index 00000000..12cb0fea --- /dev/null +++ b/examples/encrypted_notes_dapp_vetkd/frontend/index.html @@ -0,0 +1,15 @@ + + + + + + + Encrypted Notes + + + + + + + + diff --git a/examples/encrypted_notes_dapp_vetkd/frontend/svelte.config.js b/examples/encrypted_notes_dapp_vetkd/frontend/svelte.config.js new file mode 100644 index 00000000..8abe4369 --- /dev/null +++ b/examples/encrypted_notes_dapp_vetkd/frontend/svelte.config.js @@ -0,0 +1,5 @@ +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte' + +export default { + preprocess: vitePreprocess(), +} diff --git a/examples/encrypted_notes_dapp_vetkd/rust/backend/Makefile b/examples/encrypted_notes_dapp_vetkd/rust/backend/Makefile new file mode 100644 index 00000000..b58ca8b7 --- /dev/null +++ b/examples/encrypted_notes_dapp_vetkd/rust/backend/Makefile @@ -0,0 +1,14 @@ +.PHONY: compile-wasm +.SILENT: compile-wasm +compile-wasm: + cargo build --release --target wasm32-unknown-unknown + +.PHONY: extract-candid +.SILENT: extract-candid +extract-candid: compile-wasm + candid-extractor ../target/wasm32-unknown-unknown/release/encrypted_notes_backend.wasm > src/encrypted_notes_rust.did + +.PHONY: clean +.SILENT: clean +clean: + cargo clean diff --git a/examples/password_manager/frontend/scripts/gen_bindings.sh b/examples/password_manager/frontend/scripts/gen_bindings.sh new file mode 100755 index 00000000..39f54edf --- /dev/null +++ b/examples/password_manager/frontend/scripts/gen_bindings.sh @@ -0,0 +1,15 @@ +#!/bin/bash +# Bindings are always generated from the Rust backend since both backends +# expose the same Candid interface. + +# Resolve the physical path of this script so that navigating up works +# correctly even when frontend/ is reached via a symlink (e.g. motoko/frontend). +SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd -P) +cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid + +cd "$SCRIPT_DIR/../.." +rm -rf frontend/src/declarations/ic_vetkeys_encrypted_maps_canister +mkdir -p frontend/src/declarations/ic_vetkeys_encrypted_maps_canister +npx @icp-sdk/bindgen --did-file rust/backend/ic_vetkeys_encrypted_maps_canister.did \ + --out-dir frontend/src/declarations/ic_vetkeys_encrypted_maps_canister \ + --declarations-flat --force diff --git a/examples/password_manager/frontend/tailwind.config.mjs b/examples/password_manager/frontend/tailwind.config.mjs new file mode 100644 index 00000000..4bcec256 --- /dev/null +++ b/examples/password_manager/frontend/tailwind.config.mjs @@ -0,0 +1,6 @@ +import daisyui from "daisyui"; + +export default { + content: ["./index.html", "./src/**/*.{svelte,js,ts,jsx,tsx}"], + plugins: [daisyui], +}; diff --git a/examples/password_manager_with_metadata/frontend/tailwind.config.mjs b/examples/password_manager_with_metadata/frontend/tailwind.config.mjs new file mode 100644 index 00000000..18a39dbc --- /dev/null +++ b/examples/password_manager_with_metadata/frontend/tailwind.config.mjs @@ -0,0 +1,9 @@ +import daisyui from "daisyui"; + +export default { + content: ["./index.html", "./src/**/*.{svelte,js,ts,jsx,tsx}"], + theme: { + extend: {}, + }, + plugins: [daisyui], +}; From 4378ea1e655c608b3096fee17995ae1a93609170 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:27:16 +0200 Subject: [PATCH 19/24] fix(ci): add GITHUB_TOKEN to icp network start steps in example workflows icp fetches the network launcher version from the GitHub API; without GITHUB_TOKEN the unauthenticated rate limit causes 403 errors in CI. Mirrors the pattern already applied in frontend.yml and backend-motoko.yml in the base branch. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/examples-basic-bls-signing.yml | 8 ++++++++ .github/workflows/examples-basic-ibe.yml | 8 ++++++++ .github/workflows/examples-basic-timelock-ibe.yml | 4 ++++ .github/workflows/examples-encrypted-notes-dapp.yml | 8 ++++++++ .../workflows/examples-password-manager-with-metadata.yml | 8 ++++++++ .github/workflows/examples-password-manager.yml | 8 ++++++++ 6 files changed, 44 insertions(+) diff --git a/.github/workflows/examples-basic-bls-signing.yml b/.github/workflows/examples-basic-bls-signing.yml index db48ea7c..291132b2 100644 --- a/.github/workflows/examples-basic-bls-signing.yml +++ b/.github/workflows/examples-basic-bls-signing.yml @@ -29,6 +29,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Basic BLS Signing Rust Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -48,6 +50,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic BLS Signing Rust Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -68,6 +72,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Basic BLS Signing Motoko Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -87,6 +93,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic BLS Signing Motoko Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-basic-ibe.yml b/.github/workflows/examples-basic-ibe.yml index 1b81d972..94be5c17 100644 --- a/.github/workflows/examples-basic-ibe.yml +++ b/.github/workflows/examples-basic-ibe.yml @@ -28,6 +28,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Basic IBE Rust Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -47,6 +49,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic IBE Rust Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -67,6 +71,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Basic IBE Motoko Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -86,6 +92,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic IBE Motoko Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-basic-timelock-ibe.yml b/.github/workflows/examples-basic-timelock-ibe.yml index c009a3bf..1dfee0b2 100644 --- a/.github/workflows/examples-basic-timelock-ibe.yml +++ b/.github/workflows/examples-basic-timelock-ibe.yml @@ -29,6 +29,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Basic Timelock IBE Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -48,6 +50,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Basic Timelock IBE Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-encrypted-notes-dapp.yml b/.github/workflows/examples-encrypted-notes-dapp.yml index 7afa73c9..5c0ac4bc 100644 --- a/.github/workflows/examples-encrypted-notes-dapp.yml +++ b/.github/workflows/examples-encrypted-notes-dapp.yml @@ -28,6 +28,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Encrypted Notes Dapp VetKD Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/rust @@ -44,6 +46,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Encrypted Notes Dapp VetKD Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/rust @@ -61,6 +65,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Encrypted Notes Dapp VetKD Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/motoko @@ -77,6 +83,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Encrypted Notes Dapp VetKD Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/motoko diff --git a/.github/workflows/examples-password-manager-with-metadata.yml b/.github/workflows/examples-password-manager-with-metadata.yml index a6a6f7d4..97b814c6 100644 --- a/.github/workflows/examples-password-manager-with-metadata.yml +++ b/.github/workflows/examples-password-manager-with-metadata.yml @@ -30,6 +30,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager With Metadata Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -49,6 +51,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager With Metadata Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -69,6 +73,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager With Metadata Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -88,6 +94,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager With Metadata Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-password-manager.yml b/.github/workflows/examples-password-manager.yml index 411ede76..a1f5870b 100644 --- a/.github/workflows/examples-password-manager.yml +++ b/.github/workflows/examples-password-manager.yml @@ -30,6 +30,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/rust @@ -48,6 +50,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/rust @@ -67,6 +71,8 @@ jobs: run: | bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager Darwin + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/motoko @@ -85,6 +91,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager Linux + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/motoko From 0c4616c34301e366e898cd68a084d9a10bdcaf35 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:28:28 +0200 Subject: [PATCH 20/24] fix(ci): restore [toolchain] moc = "1.5.0" in backend/mo/ic_vetkeys/mops.toml The toolchain section was added in the base branch (2c7813b) to allow mops test to resolve the Motoko compiler without falling back to `dfx cache show` (dfx is not installed). Our patch overwrote the file with the version from all-changes which was missing this section, causing backend-motoko CI jobs to fail with "dfx: not found". Co-Authored-By: Claude Sonnet 4.6 --- backend/mo/ic_vetkeys/mops.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/mo/ic_vetkeys/mops.toml b/backend/mo/ic_vetkeys/mops.toml index 10ef53ed..6e8b1c85 100644 --- a/backend/mo/ic_vetkeys/mops.toml +++ b/backend/mo/ic_vetkeys/mops.toml @@ -1,3 +1,6 @@ +[toolchain] +moc = "1.5.0" + [package] name = "ic-vetkeys" version = "0.4.0" From 5177e71c3aa9d9ba0d4f1269ba506ef5c56bdb07 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:41:55 +0200 Subject: [PATCH 21/24] fix(ci): use ICP_CLI_GITHUB_TOKEN instead of GITHUB_TOKEN for icp rate limiting icp-cli reads ICP_CLI_GITHUB_TOKEN (not GITHUB_TOKEN) when fetching the network launcher version from the GitHub API. Using the wrong variable name caused 403 Forbidden errors even with the token set. Also restores ICP_CLI_GITHUB_TOKEN on the frontend.yml and backend-motoko.yml test steps, which were lost when our diff overwrote the base branch's 2c7813b fix. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/backend-motoko.yml | 4 ++++ .github/workflows/examples-basic-bls-signing.yml | 8 ++++---- .github/workflows/examples-basic-ibe.yml | 8 ++++---- .github/workflows/examples-basic-timelock-ibe.yml | 4 ++-- .github/workflows/examples-encrypted-notes-dapp.yml | 8 ++++---- .../workflows/examples-password-manager-with-metadata.yml | 8 ++++---- .github/workflows/examples-password-manager.yml | 8 ++++---- 7 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.github/workflows/backend-motoko.yml b/.github/workflows/backend-motoko.yml index 8ba91d76..00153b50 100644 --- a/.github/workflows/backend-motoko.yml +++ b/.github/workflows/backend-motoko.yml @@ -30,6 +30,8 @@ jobs: - name: Provision Linux run: bash .github/workflows/provision-linux.sh - name: Run MOPS Test Linux + env: + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd backend/mo/ic_vetkeys @@ -51,6 +53,8 @@ jobs: - name: Provision Darwin run: bash .github/workflows/provision-darwin.sh - name: Run MOPS Test Darwin + env: + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd backend/mo/ic_vetkeys diff --git a/.github/workflows/examples-basic-bls-signing.yml b/.github/workflows/examples-basic-bls-signing.yml index 291132b2..ffda97fc 100644 --- a/.github/workflows/examples-basic-bls-signing.yml +++ b/.github/workflows/examples-basic-bls-signing.yml @@ -30,7 +30,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Basic BLS Signing Rust Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -51,7 +51,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Basic BLS Signing Rust Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -73,7 +73,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Basic BLS Signing Motoko Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -94,7 +94,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Basic BLS Signing Motoko Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-basic-ibe.yml b/.github/workflows/examples-basic-ibe.yml index 94be5c17..0f103210 100644 --- a/.github/workflows/examples-basic-ibe.yml +++ b/.github/workflows/examples-basic-ibe.yml @@ -29,7 +29,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Basic IBE Rust Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -50,7 +50,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Basic IBE Rust Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -72,7 +72,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Basic IBE Motoko Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -93,7 +93,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Basic IBE Motoko Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-basic-timelock-ibe.yml b/.github/workflows/examples-basic-timelock-ibe.yml index 1dfee0b2..1ee80940 100644 --- a/.github/workflows/examples-basic-timelock-ibe.yml +++ b/.github/workflows/examples-basic-timelock-ibe.yml @@ -30,7 +30,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Basic Timelock IBE Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -51,7 +51,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Basic Timelock IBE Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-encrypted-notes-dapp.yml b/.github/workflows/examples-encrypted-notes-dapp.yml index 5c0ac4bc..eb6d1eb6 100644 --- a/.github/workflows/examples-encrypted-notes-dapp.yml +++ b/.github/workflows/examples-encrypted-notes-dapp.yml @@ -29,7 +29,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Encrypted Notes Dapp VetKD Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/rust @@ -47,7 +47,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Encrypted Notes Dapp VetKD Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/rust @@ -66,7 +66,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Encrypted Notes Dapp VetKD Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/motoko @@ -84,7 +84,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Encrypted Notes Dapp VetKD Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/encrypted_notes_dapp_vetkd/motoko diff --git a/.github/workflows/examples-password-manager-with-metadata.yml b/.github/workflows/examples-password-manager-with-metadata.yml index 97b814c6..efd73d69 100644 --- a/.github/workflows/examples-password-manager-with-metadata.yml +++ b/.github/workflows/examples-password-manager-with-metadata.yml @@ -31,7 +31,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager With Metadata Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -52,7 +52,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager With Metadata Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -74,7 +74,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager With Metadata Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor @@ -95,7 +95,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager With Metadata Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cargo install candid-extractor diff --git a/.github/workflows/examples-password-manager.yml b/.github/workflows/examples-password-manager.yml index a1f5870b..7dc17ef9 100644 --- a/.github/workflows/examples-password-manager.yml +++ b/.github/workflows/examples-password-manager.yml @@ -31,7 +31,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/rust @@ -51,7 +51,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/rust @@ -72,7 +72,7 @@ jobs: bash .github/workflows/provision-darwin.sh - name: Deploy Password Manager Darwin env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/motoko @@ -92,7 +92,7 @@ jobs: run: bash .github/workflows/provision-linux.sh - name: Deploy Password Manager Linux env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | set -eExuo pipefail cd examples/password_manager/motoko From a236968b494633242fda33f57d71ff9c002f94e7 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 21:53:51 +0200 Subject: [PATCH 22/24] fix(ci): install ic-mops and build workspace before icp deploy in examples Two issues caused all example CI jobs to fail: 1. mops not installed: the motoko canister recipe checks for `mops` on PATH, but the provision scripts only installed icp-cli and ic-wasm. Add ic-mops to the global npm install in provision-linux.sh and provision-darwin.sh. 2. frontend/ic_vetkeys prepare script fails during npm i: the example frontends reference @dfinity/vetkeys as a file: dependency. When npm installs it, it runs the package's `prepare` script (npm run build = tsc && vite build), but the library's own node_modules are missing in a clean CI environment. Fix: add an "Install workspace dependencies" step (npm install at repo root) before each icp deploy step in all example workflows. This pre-builds the workspace so the prepare script succeeds. Note: both issues are invisible locally because developers typically have already run `npm install` at the repo root and have ic-mops installed. Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/examples-basic-bls-signing.yml | 8 ++++++++ .github/workflows/examples-basic-ibe.yml | 8 ++++++++ .github/workflows/examples-basic-timelock-ibe.yml | 4 ++++ .github/workflows/examples-encrypted-notes-dapp.yml | 8 ++++++++ .../workflows/examples-password-manager-with-metadata.yml | 8 ++++++++ .github/workflows/examples-password-manager.yml | 8 ++++++++ .github/workflows/provision-darwin.sh | 2 +- .github/workflows/provision-linux.sh | 2 +- 8 files changed, 46 insertions(+), 2 deletions(-) diff --git a/.github/workflows/examples-basic-bls-signing.yml b/.github/workflows/examples-basic-bls-signing.yml index ffda97fc..fdb1e6bd 100644 --- a/.github/workflows/examples-basic-bls-signing.yml +++ b/.github/workflows/examples-basic-bls-signing.yml @@ -28,6 +28,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic BLS Signing Rust Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -49,6 +51,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic BLS Signing Rust Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -71,6 +75,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic BLS Signing Motoko Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -92,6 +98,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic BLS Signing Motoko Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/examples-basic-ibe.yml b/.github/workflows/examples-basic-ibe.yml index 0f103210..479f50ba 100644 --- a/.github/workflows/examples-basic-ibe.yml +++ b/.github/workflows/examples-basic-ibe.yml @@ -27,6 +27,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic IBE Rust Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -48,6 +50,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic IBE Rust Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -70,6 +74,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic IBE Motoko Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -91,6 +97,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic IBE Motoko Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/examples-basic-timelock-ibe.yml b/.github/workflows/examples-basic-timelock-ibe.yml index 1ee80940..a654feeb 100644 --- a/.github/workflows/examples-basic-timelock-ibe.yml +++ b/.github/workflows/examples-basic-timelock-ibe.yml @@ -28,6 +28,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic Timelock IBE Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -49,6 +51,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Basic Timelock IBE Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/examples-encrypted-notes-dapp.yml b/.github/workflows/examples-encrypted-notes-dapp.yml index eb6d1eb6..31661da6 100644 --- a/.github/workflows/examples-encrypted-notes-dapp.yml +++ b/.github/workflows/examples-encrypted-notes-dapp.yml @@ -27,6 +27,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Encrypted Notes Dapp VetKD Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -45,6 +47,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Encrypted Notes Dapp VetKD Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -64,6 +68,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Encrypted Notes Dapp VetKD Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -82,6 +88,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Encrypted Notes Dapp VetKD Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/examples-password-manager-with-metadata.yml b/.github/workflows/examples-password-manager-with-metadata.yml index efd73d69..9468e02c 100644 --- a/.github/workflows/examples-password-manager-with-metadata.yml +++ b/.github/workflows/examples-password-manager-with-metadata.yml @@ -29,6 +29,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager With Metadata Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -50,6 +52,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager With Metadata Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -72,6 +76,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager With Metadata Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -93,6 +99,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager With Metadata Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/examples-password-manager.yml b/.github/workflows/examples-password-manager.yml index 7dc17ef9..38704e00 100644 --- a/.github/workflows/examples-password-manager.yml +++ b/.github/workflows/examples-password-manager.yml @@ -29,6 +29,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -49,6 +51,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -70,6 +74,8 @@ jobs: - name: Provision Darwin run: | bash .github/workflows/provision-darwin.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager Darwin env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} @@ -90,6 +96,8 @@ jobs: node-version: '22' - name: Provision Linux run: bash .github/workflows/provision-linux.sh + - name: Install workspace dependencies + run: npm install - name: Deploy Password Manager Linux env: ICP_CLI_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/provision-darwin.sh b/.github/workflows/provision-darwin.sh index 495c1d7d..c9ee22b1 100644 --- a/.github/workflows/provision-darwin.sh +++ b/.github/workflows/provision-darwin.sh @@ -6,7 +6,7 @@ set -ex pushd /tmp # Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm +npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm ic-mops # Install rust curl --location --output install-rustup.sh "https://sh.rustup.rs" diff --git a/.github/workflows/provision-linux.sh b/.github/workflows/provision-linux.sh index 210b1b50..46108954 100644 --- a/.github/workflows/provision-linux.sh +++ b/.github/workflows/provision-linux.sh @@ -6,7 +6,7 @@ set -ex pushd /tmp # Install icp-cli (requires Node.js >=22, set up via actions/setup-node in the workflow). -npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm +npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm ic-mops # Install rust wget --output-document install-rustup.sh "https://sh.rustup.rs" From cfaf2cac68f0c1e15d88ed928268a2126335a060 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 22:40:15 +0200 Subject: [PATCH 23/24] fix(ci): remove sudo from provision-linux.sh, guard candid-extractor, fix lint - Remove sudo from provision-linux.sh rustup install so cargo lands in the runner user's PATH (same fix already applied to provision-frontend-linux.sh) - Guard all gen_bindings.sh scripts behind `command -v candid-extractor` to prevent bash from truncating the static .did file via shell redirection when candid-extractor is absent but the WASM build cache is present - Fix 4 prettier/eslint violations in password_manager frontend: - NewPassword.svelte: break long disabled attribute across lines - Vault.svelte: remove unnecessary @ts-ignore (svelte-icons types resolve fine) - encrypted_maps.ts: inline canisterEnv lookup onto one line - auth.ts: wrap long expirationMs expression Co-Authored-By: Claude Sonnet 4.6 --- .github/workflows/provision-linux.sh | 2 +- .../basic_bls_signing/frontend/scripts/gen_bindings.sh | 9 ++++++--- examples/basic_ibe/frontend/scripts/gen_bindings.sh | 9 ++++++--- .../basic_timelock_ibe/frontend/scripts/gen_bindings.sh | 9 ++++++--- examples/encrypted_chat/frontend/scripts/gen_bindings.sh | 4 +++- .../frontend/scripts/gen_bindings.sh | 4 +++- .../password_manager/frontend/scripts/gen_bindings.sh | 4 +++- .../frontend/src/components/NewPassword.svelte | 4 +++- .../frontend/src/components/Vault.svelte | 1 - .../password_manager/frontend/src/lib/encrypted_maps.ts | 4 +--- examples/password_manager/frontend/src/store/auth.ts | 3 ++- .../frontend/scripts/gen_bindings.sh | 4 +++- 12 files changed, 37 insertions(+), 20 deletions(-) diff --git a/.github/workflows/provision-linux.sh b/.github/workflows/provision-linux.sh index 46108954..43100398 100644 --- a/.github/workflows/provision-linux.sh +++ b/.github/workflows/provision-linux.sh @@ -10,7 +10,7 @@ npm install -g @icp-sdk/icp-cli @icp-sdk/ic-wasm ic-mops # Install rust wget --output-document install-rustup.sh "https://sh.rustup.rs" -sudo bash install-rustup.sh -y +bash install-rustup.sh -y rustup target add wasm32-unknown-unknown # Set environment variables. diff --git a/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh b/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh index e15c3899..003e82d1 100755 --- a/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh +++ b/examples/basic_bls_signing/frontend/scripts/gen_bindings.sh @@ -2,9 +2,12 @@ # Bindings are always generated from the Rust backend since both backends # expose the same Candid interface. -cd ../../rust/backend && make extract-candid - -cd ../.. +if command -v candid-extractor >/dev/null 2>&1; then + cd ../../rust/backend && make extract-candid + cd ../.. +else + cd ../.. +fi rm -rf frontend/src/declarations/basic_bls_signing diff --git a/examples/basic_ibe/frontend/scripts/gen_bindings.sh b/examples/basic_ibe/frontend/scripts/gen_bindings.sh index 487c8be0..9c4993ab 100755 --- a/examples/basic_ibe/frontend/scripts/gen_bindings.sh +++ b/examples/basic_ibe/frontend/scripts/gen_bindings.sh @@ -1,8 +1,11 @@ #!/bin/bash -cd ../../rust/backend && make extract-candid - -cd ../.. +if command -v candid-extractor >/dev/null 2>&1; then + cd ../../rust/backend && make extract-candid + cd ../.. +else + cd ../.. +fi rm -rf frontend/src/declarations/basic_ibe diff --git a/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh b/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh index 5a978e29..361111b6 100755 --- a/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh +++ b/examples/basic_timelock_ibe/frontend/scripts/gen_bindings.sh @@ -1,8 +1,11 @@ #!/bin/bash -cd ../../backend && make extract-candid - -cd .. +if command -v candid-extractor >/dev/null 2>&1; then + cd ../../backend && make extract-candid + cd .. +else + cd .. +fi rm -rf frontend/src/declarations/basic_timelock_ibe diff --git a/examples/encrypted_chat/frontend/scripts/gen_bindings.sh b/examples/encrypted_chat/frontend/scripts/gen_bindings.sh index b600743c..4a2aecd3 100755 --- a/examples/encrypted_chat/frontend/scripts/gen_bindings.sh +++ b/examples/encrypted_chat/frontend/scripts/gen_bindings.sh @@ -5,7 +5,9 @@ # Resolve the physical path of this script so that navigating up works # correctly even when frontend/ is reached via a symlink (e.g. motoko/frontend). SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd -P) -cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +if command -v candid-extractor >/dev/null 2>&1; then + cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +fi cd "$SCRIPT_DIR/../.." rm -rf frontend/src/declarations/encrypted_chat diff --git a/examples/encrypted_notes_dapp_vetkd/frontend/scripts/gen_bindings.sh b/examples/encrypted_notes_dapp_vetkd/frontend/scripts/gen_bindings.sh index 1d6d3fed..ade3c9d3 100755 --- a/examples/encrypted_notes_dapp_vetkd/frontend/scripts/gen_bindings.sh +++ b/examples/encrypted_notes_dapp_vetkd/frontend/scripts/gen_bindings.sh @@ -6,7 +6,9 @@ # Resolve the physical path of this script so that navigating up works # correctly even when frontend/ is reached via a symlink (e.g. motoko/frontend). SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd -P) -cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +if command -v candid-extractor >/dev/null 2>&1; then + cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +fi cd "$SCRIPT_DIR/../.." diff --git a/examples/password_manager/frontend/scripts/gen_bindings.sh b/examples/password_manager/frontend/scripts/gen_bindings.sh index 39f54edf..4ba00ab6 100755 --- a/examples/password_manager/frontend/scripts/gen_bindings.sh +++ b/examples/password_manager/frontend/scripts/gen_bindings.sh @@ -5,7 +5,9 @@ # Resolve the physical path of this script so that navigating up works # correctly even when frontend/ is reached via a symlink (e.g. motoko/frontend). SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd -P) -cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +if command -v candid-extractor >/dev/null 2>&1; then + cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +fi cd "$SCRIPT_DIR/../.." rm -rf frontend/src/declarations/ic_vetkeys_encrypted_maps_canister diff --git a/examples/password_manager/frontend/src/components/NewPassword.svelte b/examples/password_manager/frontend/src/components/NewPassword.svelte index 3dc424e2..0e70b9ba 100644 --- a/examples/password_manager/frontend/src/components/NewPassword.svelte +++ b/examples/password_manager/frontend/src/components/NewPassword.svelte @@ -110,7 +110,9 @@ diff --git a/examples/password_manager/frontend/src/components/Vault.svelte b/examples/password_manager/frontend/src/components/Vault.svelte index c539f188..914978e7 100644 --- a/examples/password_manager/frontend/src/components/Vault.svelte +++ b/examples/password_manager/frontend/src/components/Vault.svelte @@ -6,7 +6,6 @@ import { Principal } from "@icp-sdk/core/principal"; import Header from "./Header.svelte"; import Spinner from "./Spinner.svelte"; - // @ts-ignore: svelte-icons have no type declarations import GiOpenTreasureChest from "svelte-icons/gi/GiOpenTreasureChest.svelte"; import { auth } from "../store/auth"; import SharingEditor from "./SharingEditor.svelte"; diff --git a/examples/password_manager/frontend/src/lib/encrypted_maps.ts b/examples/password_manager/frontend/src/lib/encrypted_maps.ts index a2399eab..ab5b90e3 100644 --- a/examples/password_manager/frontend/src/lib/encrypted_maps.ts +++ b/examples/password_manager/frontend/src/lib/encrypted_maps.ts @@ -14,9 +14,7 @@ export async function createEncryptedMaps( agentOptions?: HttpAgentOptions, ): Promise { const canisterId = - canisterEnv?.[ - "PUBLIC_CANISTER_ID:ic_vetkeys_encrypted_maps_canister" - ]; + canisterEnv?.["PUBLIC_CANISTER_ID:ic_vetkeys_encrypted_maps_canister"]; if (!canisterId) { throw new Error( "Canister ID for ic_vetkeys_encrypted_maps_canister is not set", diff --git a/examples/password_manager/frontend/src/store/auth.ts b/examples/password_manager/frontend/src/store/auth.ts index 6b3ed3c0..6b899080 100644 --- a/examples/password_manager/frontend/src/store/auth.ts +++ b/examples/password_manager/frontend/src/store/auth.ts @@ -100,7 +100,8 @@ function handleSessionTimeout(client: AuthClient) { const chain = identity.getDelegation(); // expiration is a BigInt of nanoseconds since epoch - const expirationMs = Number(chain.delegations[0].delegation.expiration) / 1_000_000; + const expirationMs = + Number(chain.delegations[0].delegation.expiration) / 1_000_000; setTimeout(() => { void logout(); diff --git a/examples/password_manager_with_metadata/frontend/scripts/gen_bindings.sh b/examples/password_manager_with_metadata/frontend/scripts/gen_bindings.sh index 47e7cc2b..4c66807c 100755 --- a/examples/password_manager_with_metadata/frontend/scripts/gen_bindings.sh +++ b/examples/password_manager_with_metadata/frontend/scripts/gen_bindings.sh @@ -5,7 +5,9 @@ # Resolve the physical path of this script so that navigating up works # correctly even when frontend/ is reached via a symlink (e.g. motoko/frontend). SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd -P) -cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +if command -v candid-extractor >/dev/null 2>&1; then + cd "$SCRIPT_DIR/../../rust/backend" && make extract-candid +fi cd "$SCRIPT_DIR/../.." rm -rf frontend/src/declarations/password_manager_with_metadata From 0c7eed4bf6e4e3d9a8e408afa4ca1391624b8343 Mon Sep 17 00:00:00 2001 From: Marco Walz Date: Tue, 14 Apr 2026 23:41:32 +0200 Subject: [PATCH 24/24] chore(examples): use test_key_1 instead of dfx_test_key in encrypted_chat tests Consistent with the same change made to the backend canister tests in #365. Co-Authored-By: Claude Sonnet 4.6 --- examples/encrypted_chat/rust/backend/tests/common/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/encrypted_chat/rust/backend/tests/common/mod.rs b/examples/encrypted_chat/rust/backend/tests/common/mod.rs index 3ae1e89f..acdcde2c 100644 --- a/examples/encrypted_chat/rust/backend/tests/common/mod.rs +++ b/examples/encrypted_chat/rust/backend/tests/common/mod.rs @@ -53,7 +53,7 @@ impl TestEnvironment { pic.install_canister( canister_id, wasm_bytes, - encode_one("dfx_test_key").unwrap(), + encode_one("test_key_1").unwrap(), None, );