Skip to content

Releases: demergent-labs/azle

0.15.0

16 Apr 00:18
dc3160e
Compare
Choose a tag to compare

This release focuses on updating many of Azle's under-the-hood dependencies, most notably the underlying JS engine (Boa) and stable structures.

Breaking changes

StableBTreeMap.insert no longer returns a result, instead it returns an Opt of the inserted value's type.

What's Changed

  • Fixed name collisions by @dansteren in #995
  • Update dfx to 0.13.1, Rust to 1.68.2, ic-cdk-macros to 0.6.10, ic-cdk-timers to 0.1.2, Boa to latest, ic-stable-structures to 0.5.2 by @lastmjs in #994
  • Prefixed user defined functions by @dansteren in #996
  • Reorganized JS Files by @dansteren in #969
  • Documentation 0.15.0 by @lastmjs in #1003

Full Changelog: 0.14.0...0.15.0

0.14.0

10 Apr 14:52
9813fbe
Compare
Choose a tag to compare

The main focus of this release is further syntax changes that we hope improve the developer experience and solve various issues. If you run into problems while upgrading, please refer to these release notes and The Azle Book carefully.

Breaking Changes

Camel case

Generally speaking all Azle APIs have been converted from snake case to camel case. Methods or types from cross-canister calls, like from the management canister, have not changed.

The following are just a few examples.

management_canister to managementCanister:

Old

import { blob, match, $update } from 'azle';
import { management_canister } from 'azle/canisters/management';

$update;
export async function getRandomnessDirectly(): Promise<blob> {
    const randomnessResult = await management_canister.raw_rand().call();

    return match(randomnessResult, {
        Ok: (randomness) => randomness,
        Err: () => Uint8Array.from([])
    });
}

New

import { blob, match, $update } from 'azle';
import { managementCanister } from 'azle/canisters/management';

$update;
export async function getRandomnessDirectly(): Promise<blob> {
    const randomnessResult = await managementCanister.raw_rand().call();

    return match(randomnessResult, {
        Ok: (randomness) => randomness,
        Err: () => Uint8Array.from([])
    });
}

ic.canister_balance to ic.canisterBalance:

Old

import { ic, nat64, $query } from 'azle';

$query;
export function canisterBalance(): nat64 {
    return ic.canister_balance();
}

New

import { ic, nat64, $query } from 'azle';

$query;
export function canisterBalance(): nat64 {
    return ic.canisterBalance();
}

Alias

Type aliases must now explicitly use the Alias type:

Old

import { nat64, $query } from 'azle';

type Tokens = nat64;

$query;
export numTokens(): Tokens {
  return 100n;
}

New

import { Alias, nat64, $query } from 'azle';

type Tokens = Alias<nat64>;

$query;
export numTokens(): Tokens {
  return 100n;
}

ExternalCanister, @method, and CanisterResult

The ExternalCanister class has been changed to Service, the @method decorator has been changed to either @serviceQuery for query methods or @serviceUpdate for update methods, and CanisterResult has been changed to CallResult The service Candid type is now fully implemented:

Old

import { CanisterResult, ExternalCanister, method } from 'azle';

class SomeExternalCanister extends ExternalCanister {
    @method
    query1: () => CanisterResult<boolean>;

    @method
    update1: () => CanisterResult<string>;
}

New

import { CallResult, Service, serviceQuery, serviceUpdate } from 'azle';

class SomeService extends Service {
    @serviceQuery
    query1: () => CallResult<boolean>;

    @serviceUpdate
    update1: () => CallResult<string>;
}

[] -> Vec

For array types, the [] TypeScript array syntax can no longer be used. You must now use the Vec type:

Old

import { $query } from 'azle';

$query;
export function listOfStringOne(param: string[]): string[] {
    return param;
}

$query;
export function listOfStringTwo(params: string[][]): string[][] {
    return params;
}

New

import { $query, Vec } from 'azle';

$query;
export function listOfStringOne(param: Vec<string>): Vec<string> {
    return param;
}

$query;
export function listOfStringTwo(params: Vec<Vec<string>>): Vec<Vec<string>> {
    return params;
}

void for system methods

The void type must be explicitly used as the return type on all system methods:

Old

import { $init, $post_upgrade, $pre_upgrade } from 'azle';

$init;
export function init() {
    console.log('runs on first canister install');
}

$pre_upgrade;
export function preUpgrade() {
    console.log('runs before canister upgrade');
}

$post_upgrade;
export function postUpgrade() {
    console.log('runs after canister upgrade');
}

New

import { $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');
}

New Features

We have implemented some powerful new features with this release:

Generics

Before it was not possible to use generics with Variants, Records, or anywhere else. Generics are now supported in various locations, allowing you to do things like generics Results:

import { blob, Result } from 'azle';
import { managementCanister } from 'azle/canisters/management';

async function getRandomness(): Promise<Result<blob, string>> {
    return await managementCanister.raw_rand().call();
}

Guard functions

You now have the ability to protect canister methods with guard functions. The guard function will be executed before the annotated function. If the guard function returns an error, the annotated function will not proceed.

Example

import { GuardResult, ic, $query } from 'azle';

function simpleWhitelist(): GuardResult {
    if (ic.caller().toText() === 'aaaaa-aa') {
        return { Ok: null };
    } else {
        return { Err: 'Access denied' };
    }
}

$query({ guard: simpleWhitelist });
export function myCanisterMethod(): boolean {
    return true;
}

See the guard functions example for more information.

text is now an alias to Candid string

If you so desire, you can use the Azle text type as an alias to Candid string:

import { $query, test } from 'azle';

$query;
export textQueryMethod(): text {
    return 'This works great';
}

number is now an alias to Candid float64

If you so desire, you can use the TypeScript number type as an alias to Candid float64. We generally don't recommend doing this, it is designed to allow beginners to quickly get started without having to learn about the Candid number types:

import { $query } from 'azle';

$query;
export numberQueryMethod(): number {
  return 1111;
}

match

We've introduced a powerful new match function that attempts to emulate the behavior of Rust's match function. Combined with the new generic Result variants, we have a more capable algebraic data type-like typing situation:

import {
    ic,
    InsertError,
    match,
    nat64,
    Principal,
    Record,
    Result,
    StableBTreeMap,
    $update,
    Vec
} from 'azle';

type User = Record<{
    id: Principal;
    createdAt: nat64;
    recordingIds: Vec<Principal>;
    username: string;
}>;

let users = new StableBTreeMap<Principal, User>(0, 38, 100_000);

$update;
export function createUser(username: string): Result<User, InsertError> {
    const id = generateId();
    const user: User = {
        id,
        createdAt: ic.time(),
        recordingIds: [],
        username
    };

    const result = users.insert(user.id, user);

    return match(result, {
        Ok: () => ({ Ok: user }),
        Err: (err) => ({ Err: err })
    });
}

What's Changed

Read more

0.13.2

22 Feb 15:05
4a7556d
Compare
Choose a tag to compare

This release improves error handling around external canister definitions.

What's Changed

Full Changelog: 0.13.1...0.13.2

0.13.1

22 Feb 11:58
3fe8ee1
Compare
Choose a tag to compare

This release fixes a couple bugs and typos with explicit void.

What's Changed

  • getting close on cross-canister calls chapter and adding some tempora… by @lastmjs in #906
  • polishing intial chapters by @lastmjs in #907

Full Changelog: 0.13.0...0.13.1

0.13.0

20 Feb 19:21
4d4bd92
Compare
Choose a tag to compare

This release has introduced a number of syntax changes that we hope improve the developer experience and solve various issues.

Breaking Changes

Query and Update methods

We have introduced the following new annotations:

  • $heartbeat
  • $init
  • $inspect_message
  • $post_upgrade
  • $pre_upgrade
  • $query
  • $update

These annotations replace the wrapper return types previously used to mark canister methods:

  • Heartbeat
  • Init
  • InspectMessage
  • PostUpgrade
  • PreUpgrade
  • Query
  • Update

Here's an example of the old vs the new syntax for query methods. The other annotations are used similarly.

Old:

import { Query } from 'azle';

export function simple_query(): Query<string> {
    return `This is a query method`;
}

New:

import { $query } from 'azle';

$query;
export function simple_query(): string {
    return `This is a query method`;
}

Record

Record types must now be wrapped with the Record type, similar to how variants currently work. Inline records also need to be wrapped in the Record type:

Old:

type User = {
    id: string;
    username: string;
};

New:

import { Record } from 'azle';

type User = Record<{
    id: string;
    username: string;
}>;

Func

The function portion of Func types now need to be wrapped in the Query, Update, or Oneway types.

Old:

type BasicFunc = Func<(param1: string) => Query<string>>;

New:

type BasicFunc = Func<Query<(param1: string) => string>>;

External canister

External canisters are now defined as classes that extend from ExternalCanister. Each method must be marked with either the @query or @update decorators.

Old:

import { Canister, CanisterResult, ic, nat64, Opt } from 'azle';

type Canister2 = Canister<{
    transfer(from: string, to: string, amount: nat64): CanisterResult<nat64>;
    balance(id: string): CanisterResult<nat64>;
    account(accountArgs: AccountArgs): CanisterResult<Opt<Account>>;
    accounts(): CanisterResult<Account[]>;
    trap(): CanisterResult<string>;
    receive_notification(message: string): CanisterResult<void>;
}>;

let canister2 = ic.canisters.Canister2<Canister2>(
    Principal.fromText('ryjl3-tyaaa-aaaaa-aaaba-cai')
);

New:

import { CanisterResult, ExternalCanister, nat64, Opt, query, update } from 'azle';

class Canister2 extends ExternalCanister {
    @update
    transfer: (
        from: string,
        to: string,
        amount: nat64
    ) => CanisterResult<nat64>;

    @query
    balance: (id: string) => CanisterResult<nat64>;

    @query
    account: (accountArgs: AccountArgs) => CanisterResult<Opt<Account>>;

    @query
    accounts: () => CanisterResult<Account[]>;

    @query
    trap: () => CanisterResult<string>;

    @update
    receive_notification: (message: string) => CanisterResult<void>;
}

const canister2 = new Canister2(
    Principal.fromText('ryjl3-tyaaa-aaaaa-aaaba-cai')
);

What's Changed

Full Changelog: 0.12.0...0.13.0

0.12.0

27 Jan 17:03
3ec573a
Compare
Choose a tag to compare

TLDR

Cross-canister calls within timers are now supported. Randomness is now automatically seeeded after init and post upgrade, giving better randomness to Math.random and any other APIs that rely on the under-the-hood Rust random number generation. Some issues were fixed with inline types.

What's Changed

Full Changelog: 0.11.0...0.12.0

0.11.0

24 Jan 23:22
5753227
Compare
Choose a tag to compare

TLDR

There is no more need to manually install Rust on your machine. Azle will now install an encapsulated Rust environment inside of ~/.config/azle per version of Azle. Composite queries are now supported for use in the local replica, and the Manual return type was introduced.

Breaking Changes

  1. QueryManual and UpdateManual have been removed. If you want to create a manual query you must now use the Manual return type
  2. Please delete your local .dfx, target, and node_modules directories before installing and deploying with the new version of Azle
  3. You should add .azle to your .gitignore file

What's Changed

Full Changelog: 0.10.0...0.11.0

0.10.0

13 Jan 23:13
a2064ef
Compare
Choose a tag to compare

If you run into issues after an upgrade:

  1. Ensure all versions of dfx, Rust, and Node.js are exactly as described in the README
  2. Completely delete the .dfx, target and node_modules directories and deploy again
  3. Run rustup update

TLDR

This release is all about introducing StableBTreeMap.

What's Changed

Full Changelog: 0.9.0...0.10.0

0.9.0

21 Dec 02:56
169207a
Compare
Choose a tag to compare

If you run into issues after an upgrade, the safest thing to do is ensure that all versions of dfx, rust, and node are exactly as described in the README. Also try completely deleting the .dfx, target, and node_modules directories and then reinstalling and deploying again.

TLDR

  • async/await has replaced generators for cross-canister calls
  • timers API now implemented
  • Major Bug in Boa JS engine has been fixed
  • Increased ECMAScript support and support for async/await and promises
  • Principal.selfAuthenticating now works
  • Reduced compilation times
  • Candid metadata and CDK info metadata
  • lists of lists now generally supported

Breaking Changes

  • ManagementCanister from azle/canisters/management has been renamed to management_canister
  • All generators syntax (yield and *) has been replaced with await and async
  • with_cycles and with_cycles128 in the cross-canister calls API have been changed to cycles and cycles128
  • To execute a cross-canister call you must now explicitly invoke .call, similar to .notify
  • You must update to at least rustc 1.66, use rustup update

What's Changed

Full Changelog: 0.8.0...0.9.0

0.8.0

28 Nov 14:48
e435926
Compare
Choose a tag to compare

This release updates Azle to work with dfx 0.12.0, contains a large rewrite of the Azle compiler in Rust, the creation of a CDK Framework, and includes greatly improved compiler errors for the end user developer.

What's Changed

Full Changelog: 0.7.0...0.8.0