From 100a297b886dba96f5fa427c46929af5444dd650 Mon Sep 17 00:00:00 2001
From: Jordan Last This chapter is a work in progress. You can access the management canister like this: See the management canister reference section for more information. This chapter is a work in progress. This chapter is a work in progress.Management Canister
import { blob, Result, $update } from 'azle';
+
import { blob, Canister, ic, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
-$update;
-export async function randomBytes(): Promise<Result<blob, string>> {
- return await managementCanister.raw_rand().call();
-}
+export default Canister({
+ randomBytes: update([], blob, async () => {
+ return await ic.call(managementCanister.raw_rand);
+ })
+});
Canister Lifecycle
import { $init, $postUpgrade, $preUpgrade } from 'azle';
-
-$init;
-export function init(): void {
- console.log('runs on first canister install');
-}
+
import { Canister, init, postUpgrade, preUpgrade } from 'azle';
-$preUpgrade;
-export function preUpgrade(): void {
- console.log('runs before canister upgrade');
-}
-
-$postUpgrade;
-export function postUpgrade(): void {
- console.log('runs after canister upgrade');
-}
+export default Canister({
+ init: init([], () => {
+ console.log('runs on first canister install');
+ }),
+ preUpgrade: preUpgrade(() => {
+ console.log('runs before canister upgrade');
+ }),
+ postUpgrade: postUpgrade([], () => {
+ console.log('runs after canister upgrade');
+ })
+});
Timers
import {
blob,
+ bool,
+ Canister,
Duration,
ic,
int8,
- match,
- $query,
+ query,
Record,
+ text,
TimerId,
- $update
+ update,
+ Void
} from 'azle';
import { managementCanister } from 'azle/canisters/management';
-type StatusReport = Record<{
- single: boolean;
- inline: int8;
- capture: string;
- repeat: int8;
- singleCrossCanister: blob;
- repeatCrossCanister: blob;
-}>;
+const StatusReport = Record({
+ single: bool,
+ inline: int8,
+ capture: text,
+ repeat: int8,
+ singleCrossCanister: blob,
+ repeatCrossCanister: blob
+});
-type TimerIds = Record<{
- single: TimerId;
- inline: TimerId;
- capture: TimerId;
- repeat: TimerId;
- singleCrossCanister: TimerId;
- repeatCrossCanister: TimerId;
-}>;
+const TimerIds = Record({
+ single: TimerId,
+ inline: TimerId,
+ capture: TimerId,
+ repeat: TimerId,
+ singleCrossCanister: TimerId,
+ repeatCrossCanister: TimerId
+});
-let status: StatusReport = {
+let statusReport: typeof StatusReport = {
single: false,
inline: 0,
capture: '',
@@ -1806,90 +1807,75 @@
Cycles
@@ -1903,17 +1889,15 @@ Maybe here we just show the basic concept of cycles, link to the main cycles cost page, and show a few examples of how to break down these costs or estimate these costs.
Azle is a beta project using an experimental JS engine. See the disclaimer for more information.
-Azle canisters will generally use more Wasm instructions and thus cycles than Motoko or Rust canisters. A good rule of thumb for now would be 2-4x the cycles. Azle's efficiency should increase dramatically with the upcoming JS engine swapout.
-You may encounter various missing JavaScript syntax or features. Azle generally has better conformance than that of its underlying JS engine.
+Azle is a beta project. See the disclaimer for more information.
Some npm packages will work and some will not work. It is our long-term goal to support as many npm packages as possible. There are many reasons why an npm package may not currently work, including the small Wasm binary limit of the IC, bugs in Azle's JS engine Boa, or unimplemented web or Node.js APIs. Feel free to open issues if your npm package does not work in Azle.
+Some npm packages will work and some will not work. It is our long-term goal to support as many npm packages as possible. There are various reasons why an npm package may not currently work, including the small Wasm binary limit of the IC and unimplemented web or Node.js APIs. Feel free to open issues if your npm package does not work in Azle.
+You may encounter various missing JavaScript environment APIs, such as those you would expect in the web or Node.js environments.
+Candid encoding/decoding is currently very unoptimized. This will most likely lead to a ~1-2 million instruction extra fixed cost for all calls, plus more if you use StableBTreeMap
or any other API or data structure that engages in Candid encoding/decoding.
Though promises are implemented, the underlying queue that handles asynchronous operations is very simple. This queue will not behave exactly as queues from the major JS engines. The queue can be thought of as a simple queue that executes tasks sequentially without reporting errors.
-You should treat Azle types essentially as unique keywords, not creating types of the same name elsewhere in your codebase or in other libraries. Any types exported from this file should be treated thusly.
+Though promises are implemented, the underlying queue that handles asynchronous operations is very simple. This queue will not behave exactly as queues from the major JS engines.
This chapter is a work in progress.
import {
blob,
+ bool,
+ Canister,
Duration,
ic,
int8,
- match,
- $query,
+ query,
Record,
+ text,
TimerId,
- $update
+ update,
+ Void
} from 'azle';
import { managementCanister } from 'azle/canisters/management';
-type StatusReport = Record<{
- single: boolean;
- inline: int8;
- capture: string;
- repeat: int8;
- singleCrossCanister: blob;
- repeatCrossCanister: blob;
-}>;
-
-type TimerIds = Record<{
- single: TimerId;
- inline: TimerId;
- capture: TimerId;
- repeat: TimerId;
- singleCrossCanister: TimerId;
- repeatCrossCanister: TimerId;
-}>;
-
-let status: StatusReport = {
+const StatusReport = Record({
+ single: bool,
+ inline: int8,
+ capture: text,
+ repeat: int8,
+ singleCrossCanister: blob,
+ repeatCrossCanister: blob
+});
+
+const TimerIds = Record({
+ single: TimerId,
+ inline: TimerId,
+ capture: TimerId,
+ repeat: TimerId,
+ singleCrossCanister: TimerId,
+ repeatCrossCanister: TimerId
+});
+
+let statusReport: typeof StatusReport = {
single: false,
inline: 0,
capture: '',
@@ -186,90 +189,75 @@ Timers
repeatCrossCanister: Uint8Array.from([])
};
-$update;
-export function clearTimer(timerId: TimerId): void {
- ic.clearTimer(timerId);
- console.log(`timer ${timerId} cancelled`);
-}
-
-$update;
-export function setTimers(delay: Duration, interval: Duration): TimerIds {
- const capturedValue = '๐ฉ';
-
- const singleId = ic.setTimer(delay, oneTimeTimerCallback);
-
- const inlineId = ic.setTimer(delay, () => {
- status.inline = 1;
- console.log('Inline timer called');
- });
-
- const captureId = ic.setTimer(delay, () => {
- status.capture = capturedValue;
- console.log(`Timer captured value ${capturedValue}`);
- });
-
- const repeatId = ic.setTimerInterval(interval, () => {
- status.repeat++;
- console.log(`Repeating timer. Call ${status.repeat}`);
- });
-
- const singleCrossCanisterId = ic.setTimer(
- delay,
- singleCrossCanisterTimerCallback
- );
-
- const repeatCrossCanisterId = ic.setTimerInterval(
- interval,
- repeatCrossCanisterTimerCallback
- );
-
- return {
- single: singleId,
- inline: inlineId,
- capture: captureId,
- repeat: repeatId,
- singleCrossCanister: singleCrossCanisterId,
- repeatCrossCanister: repeatCrossCanisterId
- };
-}
-
-$query;
-export function statusReport(): StatusReport {
- return status;
-}
-
-function oneTimeTimerCallback(): void {
- status.single = true;
+export default Canister({
+ clearTimer: update([TimerId], Void, (timerId) => {
+ ic.clearTimer(timerId);
+ console.log(`timer ${timerId} cancelled`);
+ }),
+ setTimers: update([Duration, Duration], TimerIds, (delay, interval) => {
+ const capturedValue = '๐ฉ';
+
+ const singleId = ic.setTimer(delay, oneTimeTimerCallback);
+
+ const inlineId = ic.setTimer(delay, () => {
+ statusReport.inline = 1;
+ console.log('Inline timer called');
+ });
+
+ const captureId = ic.setTimer(delay, () => {
+ statusReport.capture = capturedValue;
+ console.log(`Timer captured value ${capturedValue}`);
+ });
+
+ const repeatId = ic.setTimerInterval(interval, () => {
+ statusReport.repeat++;
+ console.log(`Repeating timer. Call ${statusReport.repeat}`);
+ });
+
+ const singleCrossCanisterId = ic.setTimer(
+ delay,
+ singleCrossCanisterTimerCallback
+ );
+
+ const repeatCrossCanisterId = ic.setTimerInterval(
+ interval,
+ repeatCrossCanisterTimerCallback
+ );
+
+ return {
+ single: singleId,
+ inline: inlineId,
+ capture: captureId,
+ repeat: repeatId,
+ singleCrossCanister: singleCrossCanisterId,
+ repeatCrossCanister: repeatCrossCanisterId
+ };
+ }),
+ statusReport: query([], StatusReport, () => {
+ return statusReport;
+ })
+});
+
+function oneTimeTimerCallback() {
+ statusReport.single = true;
console.log('oneTimeTimerCallback called');
}
-async function singleCrossCanisterTimerCallback(): Promise<void> {
+async function singleCrossCanisterTimerCallback() {
console.log('singleCrossCanisterTimerCallback');
- const result = await managementCanister.raw_rand().call();
-
- match(result, {
- Ok: (ok) => {
- status.singleCrossCanister = ok;
- },
- Err: (err) => ic.trap(err)
- });
+ statusReport.singleCrossCanister = await ic.call(
+ managementCanister.raw_rand
+ );
}
-async function repeatCrossCanisterTimerCallback(): Promise<void> {
+async function repeatCrossCanisterTimerCallback() {
console.log('repeatCrossCanisterTimerCallback');
- const result = await managementCanister.raw_rand().call();
-
- match(result, {
- Ok: (ok) => {
- status.repeatCrossCanister = Uint8Array.from([
- ...status.repeatCrossCanister,
- ...ok
- ]);
- },
- Err: (err) => ic.trap(err)
- });
+ statusReport.repeatCrossCanister = Uint8Array.from([
+ ...statusReport.repeatCrossCanister,
+ ...(await ic.call(managementCanister.raw_rand))
+ ]);
}
diff --git a/the_azle_book/src/canister_lifecycle.md b/the_azle_book/src/canister_lifecycle.md
index 799b5367ba..033e575975 100644
--- a/the_azle_book/src/canister_lifecycle.md
+++ b/the_azle_book/src/canister_lifecycle.md
@@ -3,20 +3,17 @@
This chapter is a work in progress.
```typescript
-import { $init, $postUpgrade, $preUpgrade } from 'azle';
+import { Canister, init, postUpgrade, preUpgrade } from 'azle';
-$init;
-export function init(): void {
- console.log('runs on first canister install');
-}
-
-$preUpgrade;
-export function preUpgrade(): void {
- console.log('runs before canister upgrade');
-}
-
-$postUpgrade;
-export function postUpgrade(): void {
- console.log('runs after canister upgrade');
-}
+export default Canister({
+ init: init([], () => {
+ console.log('runs on first canister install');
+ }),
+ preUpgrade: preUpgrade(() => {
+ console.log('runs before canister upgrade');
+ }),
+ postUpgrade: postUpgrade([], () => {
+ console.log('runs after canister upgrade');
+ })
+});
```
diff --git a/the_azle_book/src/caveats.md b/the_azle_book/src/caveats.md
index 8ca8c50a8b..ed8de60190 100644
--- a/the_azle_book/src/caveats.md
+++ b/the_azle_book/src/caveats.md
@@ -2,24 +2,20 @@
## Unknown security vulnerabilities
-Azle is a beta project using an experimental JS engine. See [the disclaimer](/azle.md#disclaimer) for more information.
+Azle is a beta project. See [the disclaimer](/azle.md#disclaimer) for more information.
-## High instruction/cycle count
+## npm packages
-Azle canisters will generally use more Wasm instructions and thus cycles than Motoko or Rust canisters. A good rule of thumb for now would be 2-4x the cycles. Azle's efficiency should increase dramatically with the upcoming JS engine swapout.
+Some npm packages will work and some will not work. It is our long-term goal to support as many npm packages as possible. There are various reasons why an npm package may not currently work, including the small Wasm binary limit of the IC and unimplemented web or Node.js APIs. Feel free to open issues if your npm package does not work in Azle.
-## JavaScript syntax and features
+## JavaScript environment APIs
-You may encounter various missing JavaScript syntax or features. Azle generally has better conformance than that of its [underlying JS engine](https://boajs.dev/boa/test262/).
+You may encounter various missing JavaScript environment APIs, such as those you would expect in the web or Node.js environments.
-## npm packages
+## High Candid encoding/decoding costs
-Some npm packages will work and some will not work. It is our long-term goal to support as many npm packages as possible. There are many reasons why an npm package may not currently work, including the small Wasm binary limit of the IC, bugs in Azle's JS engine [Boa](https://github.com/boa-dev/boa), or unimplemented web or Node.js APIs. Feel free to open issues if your npm package does not work in Azle.
+Candid encoding/decoding is currently very unoptimized. This will most likely lead to a ~1-2 million instruction extra fixed cost for all calls, plus more if you use `StableBTreeMap` or any other API or data structure that engages in Candid encoding/decoding.
## Promises
-Though promises are implemented, the underlying queue that handles asynchronous operations is very simple. This queue will not behave exactly as queues from the major JS engines. The queue can be thought of as a simple queue that executes tasks sequentially without reporting errors.
-
-## Treat Azle types as unique keywords
-
-You should treat Azle types essentially as unique keywords, not creating types of the same name elsewhere in your codebase or in other libraries. Any types exported from [this file](https://github.com/demergent-labs/azle/blob/main/index.ts) should be treated thusly.
+Though promises are implemented, the underlying queue that handles asynchronous operations is very simple. This queue will not behave exactly as queues from the major JS engines.
diff --git a/the_azle_book/src/management_canister.md b/the_azle_book/src/management_canister.md
index 788afd98a2..e848f737d1 100644
--- a/the_azle_book/src/management_canister.md
+++ b/the_azle_book/src/management_canister.md
@@ -5,13 +5,14 @@ This chapter is a work in progress.
You can access the management canister like this:
```typescript
-import { blob, Result, $update } from 'azle';
+import { blob, Canister, ic, update } from 'azle';
import { managementCanister } from 'azle/canisters/management';
-$update;
-export async function randomBytes(): Promise