Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 70 additions & 1 deletion .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,74 @@ permissions:
contents: read

jobs:
cdn:
if: github.event_name == 'release' || github.ref_type == 'tag'
runs-on: ubuntu-latest
timeout-minutes: 15
environment: cdn
permissions:
contents: read
env:
VERSION: ${{ github.event.release.tag_name || github.ref_name }}

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Use Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: '24.14.1'

- name: Validate version
run: |
if [[ ! "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
echo "::error::$VERSION is not a semantic version"
exit 1
fi
PACKAGE_VERSION=$(node -p "require('./package.json').version")
if [[ "$VERSION" != "$PACKAGE_VERSION" ]]; then
echo "::error::$VERSION does not match package.json version $PACKAGE_VERSION"
exit 1
fi

- name: Install dependencies, audit, and build
run: |
npm ci
npm audit --audit-level=high --omit=dev
npm run build:cdn

- name: Write integrity hashes
run: |
node --input-type=module <<'EOF'
import { createHash } from 'node:crypto';
import { readdirSync, readFileSync, writeFileSync } from 'node:fs';

const root = 'dist/cdn';
const integrity = Object.fromEntries(
readdirSync(root, { recursive: true })
.filter((path) => path.endsWith('.js'))
.sort()
.map((path) => [path, 'sha384-' + createHash('sha384').update(readFileSync(`${root}/${path}`)).digest('base64')]),
);
writeFileSync(`${root}/integrity.json`, JSON.stringify(integrity, null, 2) + '\n');
EOF

- name: Upload to the CDN
uses: docker://rclone/rclone@sha256:45401ad7410db1d67ffdb58e19059ad20b0d8e0285a60e38bbec55cc1019c7a5 # 1.75.1
with:
args: 'copy dist/cdn r2:appwrite-sdk/console/${{ env.VERSION }} --immutable --checksum --header-upload "Cache-Control: public, max-age=31536000, immutable"'
env:
RCLONE_CONFIG_R2_TYPE: s3
RCLONE_CONFIG_R2_PROVIDER: Cloudflare
RCLONE_CONFIG_R2_ENDPOINT: ${{ vars.R2_ENDPOINT }}
RCLONE_CONFIG_R2_REGION: auto
RCLONE_CONFIG_R2_NO_CHECK_BUCKET: 'true'
RCLONE_CONFIG_R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
RCLONE_CONFIG_R2_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }}

publish:
needs: cdn
if: ${{ !failure() && !cancelled() }}
runs-on: ubuntu-latest

steps:
Expand All @@ -27,8 +94,10 @@ jobs:

- name: Determine release tag
id: release_tag
env:
REF: ${{ github.ref }}
run: |
if [[ "${{ github.ref }}" == *"-rc"* ]] || [[ "${{ github.ref }}" == *"-RC"* ]]; then
if [[ "$REF" == *"-rc"* ]] || [[ "$REF" == *"-RC"* ]]; then
echo "tag=next" >> "$GITHUB_OUTPUT"
else
echo "tag=latest" >> "$GITHUB_OUTPUT"
Expand Down
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Change Log

## 20.0.0

* Breaking: requests send `X-Appwrite-Response-Format: 2.5.0`; responses follow the 2.5 shapes
* Breaking: nullable model fields are typed `T | null`, such as `Account.emailCanonical` and `Execution.scheduledAt`
* Breaking: removed `Topic.any()`, `Topic.all()` and `ResolvedTopic`; topic levels reject `+` and `#`
* Breaking: requires Node.js 20 or later to build
* Added: `proxy.createSMTPRule` and the `ProxyRuleProtocol` enum, with `ProxyRule.protocol`
* Added: `promoteRestoration` on `mysql`, `postgresql` and `mongo`
* Added: optional `description` on databases, collections, tables, columns, indexes, buckets, functions, sites, keys, topics, variables and webhooks
* Added: `Query` aggregates, `groupBy`, `having`, `distinct`, joins, `relationship`, `covers`, `spatialEquals` and `page`
* Added: `Query.builder()` to chain queries; `build()` returns the `string[]` list methods take, and realtime subscriptions accept a builder directly
* Added: `ExecutionTrigger.Email`, `Function.emailEnabled` and `ConsoleVariables._APP_DOMAIN_EMAIL`
* Added: per-service ES modules and a minified script on `sdk.appwrite.io/console/<version>/`
* Updated: nullable request params accept `null`
* Fixed: list and object defaults filled into a response are copied per model

## 19.0.0

* Breaking: removed the `Assistant` service (`assistant.chat`) and `_APP_ASSISTANT_ENABLED` from `ConsoleVariables`
Expand Down
30 changes: 29 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,43 @@ import { Client, Account } from '@appwrite.io/console';

### CDN

Every release is published to `https://sdk.appwrite.io/console/20.0.0/`.

#### ES modules

Each service, helper and enum is its own module, so the browser downloads only what you import. A service is served under its name in kebab case, such as `TablesDB` from `tables-db.js`, and enums under `enums/`, such as `OAuthProvider` from `enums/o-auth-provider.js`. `index.js` re-exports everything, so importing it loads every service:

```html
<script type="module">
import { Client } from 'https://sdk.appwrite.io/console/20.0.0/client.js';
import { Account } from 'https://sdk.appwrite.io/console/20.0.0/account.js';
import { OAuthProvider } from 'https://sdk.appwrite.io/console/20.0.0/enums/o-auth-provider.js';
</script>
```

#### Script tag

Add the script before any code that uses the SDK. It exposes every export on the global `Appwrite` object:

```html
<script src="https://cdn.jsdelivr.net/npm/@appwrite.io/console@19.0.0"></script>
<script src="https://sdk.appwrite.io/console/20.0.0/sdk.min.js"></script>
<script>
const { Client, Account } = Appwrite;
</script>
```

#### Subresource integrity

`integrity.json` in the same directory maps each `.js` file to its `sha384-` hash. An `integrity` attribute checks only the file it is set on. `sdk.min.js` is a single file, so its hash as the `integrity` attribute, together with `crossorigin="anonymous"`, covers the whole SDK. ES modules import other modules and shared chunks, so supply their hashes through the `integrity` field of an import map to cover those too.

#### jsDelivr

The script tag build is also available from jsDelivr:

```html
<script src="https://cdn.jsdelivr.net/npm/@appwrite.io/console@20.0.0"></script>
```

## Getting started

### Add a Web platform
Expand Down
2 changes: 2 additions & 0 deletions docs/examples/account/create-push-target.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const result = await account.createPushTarget({
targetId: '<TARGET_ID>',
identifier: '<IDENTIFIER>',
providerId: '<PROVIDER_ID>', // optional
bundleId: '<BUNDLE_ID>', // optional
environment: 'sandbox', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/account/list-billing-addresses.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const account = new Account(client);

const result = await account.listBillingAddresses({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/account/list-invoices.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const account = new Account(client);

const result = await account.listInvoices({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/account/list-payment-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const account = new Account(client);

const result = await account.listPaymentMethods({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
2 changes: 2 additions & 0 deletions docs/examples/account/update-push-target.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const account = new Account(client);
const result = await account.updatePushTarget({
targetId: '<TARGET_ID>',
identifier: '<IDENTIFIER>',
bundleId: '<BUNDLE_ID>', // optional
environment: 'sandbox', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/activities/list-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const activities = new Activities(client);

const result = await activities.listEvents({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
16 changes: 16 additions & 0 deletions docs/examples/admin/update-user-admin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
```javascript
import { Client, Admin } from '@appwrite.io/console';

const client = new Client()
.setEndpoint('https://<REGION>.cloud.appwrite.io/v1') // Your API Endpoint
.setProject('<YOUR_PROJECT_ID>'); // Your project ID

const admin = new Admin(client);

const result = await admin.updateUserAdmin({
userId: '<USER_ID>',
admin: false,
});

console.log(result);
```
1 change: 1 addition & 0 deletions docs/examples/affiliates/list-links.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const affiliates = new Affiliates(client);

const result = await affiliates.listLinks({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/affiliates/list-referrals.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const affiliates = new Affiliates(client);

const result = await affiliates.listReferrals({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/affiliates/list-rewards.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const affiliates = new Affiliates(client);

const result = await affiliates.listRewards({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/analytics/create-event.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const result = await analytics.createEvent({
url: 'https://example.com',
domain: '<DOMAIN>', // optional
referrer: '<REFERRER>', // optional
screenWidth: null, // optional
screenWidth: 0, // optional
sessionHash: '<SESSION_HASH>', // optional
scrollDepth: 0, // optional
engagementTime: 0, // optional
Expand Down
1 change: 1 addition & 0 deletions docs/examples/analytics/list-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ const result = await analytics.listMetrics({
startAt: '2020-10-15T06:38:00.000+00:00', // optional
endAt: '2020-10-15T06:38:00.000+00:00', // optional
limit: 1, // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/backups/list-archives.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const backups = new Backups(client);

const result = await backups.listArchives({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/backups/list-policies.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const backups = new Backups(client);

const result = await backups.listPolicies({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/backups/list-restorations.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const backups = new Backups(client);

const result = await backups.listRestorations({
queries: [], // optional
total: false, // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-big-int-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const result = await databases.createBigIntAttribute({
max: 1000000, // optional
xdefault: 0, // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-boolean-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const result = await databases.createBooleanAttribute({
required: false,
xdefault: false, // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-collection.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const result = await databases.createCollection({
enabled: false, // optional
attributes: [], // optional
indexes: [], // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-datetime-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const result = await databases.createDatetimeAttribute({
required: false,
xdefault: '2020-10-15T06:38:00.000+00:00', // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-email-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const result = await databases.createEmailAttribute({
required: false,
xdefault: 'email@example.com', // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-enum-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const result = await databases.createEnumAttribute({
required: false,
xdefault: 'active', // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-float-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const result = await databases.createFloatAttribute({
max: 100, // optional
xdefault: 10.5, // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-index.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const result = await databases.createIndex({
attributes: ['username'],
orders: [OrderBy.Asc], // optional
lengths: [], // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-integer-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const result = await databases.createIntegerAttribute({
max: 100, // optional
xdefault: 10, // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-ip-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const result = await databases.createIpAttribute({
required: false,
xdefault: '192.0.2.0', // optional
array: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-line-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const result = await databases.createLineAttribute({
[3, 4],
[5, 6],
], // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-longtext-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const result = await databases.createLongtextAttribute({
xdefault: 'Hello World', // optional
array: false, // optional
encrypt: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-mediumtext-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const result = await databases.createMediumtextAttribute({
xdefault: 'Hello World', // optional
array: false, // optional
encrypt: false, // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
1 change: 1 addition & 0 deletions docs/examples/databases/create-point-attribute.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const result = await databases.createPointAttribute({
key: '<KEY>',
required: false,
xdefault: [1, 2], // optional
description: '<DESCRIPTION>', // optional
});

console.log(result);
Expand Down
Loading