What we are asking for
Document that the frontend client is swappable, and show it in the two
custom-canister examples this repo already ships. No API change —
EncryptedMapsClient already makes it possible, and nothing points at it.
Why
This repo ships two custom-canister examples —
backend/mo/canisters/ic_vetkeys_encrypted_maps_custom_canister/src/Main.mo
and its Rust twin — and both define insert_encrypted_value_custom /
get_encrypted_value_custom. Neither has a frontend counterpart. An
adopter who follows either example produces a canister the stock client cannot
talk to, with nothing telling them the fix is a six-line subclass.
The seam exists and is fully public: EncryptedMapsClient is an exported
interface, EncryptedMaps takes it as its constructor argument,
DefaultEncryptedMapsClient.actor is public, and the derived-key cache is a
swappable exported abstraction. One method override is enough to route an
operation anywhere:
class VaultMapsClient extends DefaultEncryptedMapsClient {
constructor(agent, canisterId, private own: ActorSubclass<Backend>) { super(agent, canisterId); }
insert_encrypted_value(owner, mapName, mapKey, data) {
return this.own.save_item(owner, mapName, mapKey, data);
}
}
Fifteen methods in the interface, fourteen inherited, crypto and cache kept.
The endpoint names are fixed in the convenience implementation, not in the
library.
The reason we are filing this is that we got it wrong ourselves. We
concluded the case was unsupported — that the frontend pinned the endpoint
names, so an adopter could reimplement an endpoint but never rename or drop
one — while the package sat in our own node_modules. If an adopter who reads
the source reaches the wrong conclusion, the examples are the place to fix it.
Scope
- A frontend counterpart for both custom-canister examples, subclassing
DefaultEncryptedMapsClient to reach the *_custom endpoints.
- A short note in the frontend docs that the client is an interface and the
default implementation is one of possibly many.
- One sentence on the sharp edge: when an adopter drops an endpoint the stock
IDL factory still declares, their Candid and the client's declared service
disagree. Harmless — Candid resolves per method — but it reads like a bug
the first time.
Split out of #443, where this was ask 3. It needs no decision from anyone and
does not depend on how that issue's boundary question is answered.
What we are asking for
Document that the frontend client is swappable, and show it in the two
custom-canister examples this repo already ships. No API change —
EncryptedMapsClientalready makes it possible, and nothing points at it.Why
This repo ships two custom-canister examples —
backend/mo/canisters/ic_vetkeys_encrypted_maps_custom_canister/src/Main.moand its Rust twin — and both define
insert_encrypted_value_custom/get_encrypted_value_custom. Neither has a frontend counterpart. Anadopter who follows either example produces a canister the stock client cannot
talk to, with nothing telling them the fix is a six-line subclass.
The seam exists and is fully public:
EncryptedMapsClientis an exportedinterface,
EncryptedMapstakes it as its constructor argument,DefaultEncryptedMapsClient.actoris public, and the derived-key cache is aswappable exported abstraction. One method override is enough to route an
operation anywhere:
Fifteen methods in the interface, fourteen inherited, crypto and cache kept.
The endpoint names are fixed in the convenience implementation, not in the
library.
The reason we are filing this is that we got it wrong ourselves. We
concluded the case was unsupported — that the frontend pinned the endpoint
names, so an adopter could reimplement an endpoint but never rename or drop
one — while the package sat in our own
node_modules. If an adopter who readsthe source reaches the wrong conclusion, the examples are the place to fix it.
Scope
DefaultEncryptedMapsClientto reach the*_customendpoints.default implementation is one of possibly many.
IDL factory still declares, their Candid and the client's declared service
disagree. Harmless — Candid resolves per method — but it reads like a bug
the first time.
Split out of #443, where this was ask 3. It needs no decision from anyone and
does not depend on how that issue's boundary question is answered.