mirror of
https://github.com/LukeHagar/website.git
synced 2025-12-10 21:07:46 +00:00
Merge branch 'main' of https://github.com/appwrite/website
This commit is contained in:
@@ -5,6 +5,7 @@ PUBLIC_APPWRITE_FN_TLDR_ID=
|
||||
PUBLIC_APPWRITE_ENDPOINT=
|
||||
PUBLIC_APPWRITE_PROJECT_ID=
|
||||
PUBLIC_APPWRITE_PROJECT_INIT_ID=
|
||||
PUBLIC_GROWTH_ENDPOINT=
|
||||
APPWRITE_DB_INIT_ID=
|
||||
APPWRITE_COL_INIT_ID=
|
||||
APPWRITE_API_KEY_INIT=
|
||||
|
||||
1
.github/workflows/production.yml
vendored
1
.github/workflows/production.yml
vendored
@@ -37,6 +37,7 @@ jobs:
|
||||
"PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_ID }}"
|
||||
"PUBLIC_APPWRITE_FN_TLDR_ID=${{ vars.PUBLIC_APPWRITE_FN_TLDR_ID }}"
|
||||
"PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}"
|
||||
"PUBLIC_GROWTH_ENDPOINT=${{ vars.PUBLIC_GROWTH_ENDPOINT }}"
|
||||
"APPWRITE_DB_INIT_ID=${{ secrets.APPWRITE_DB_INIT_ID }}"
|
||||
"APPWRITE_COL_INIT_ID=${{ secrets.APPWRITE_COL_INIT_ID }}"
|
||||
"APPWRITE_API_KEY_INIT=${{ secrets.APPWRITE_API_KEY_INIT }}"
|
||||
|
||||
1
.github/workflows/staging.yml
vendored
1
.github/workflows/staging.yml
vendored
@@ -38,6 +38,7 @@ jobs:
|
||||
"PUBLIC_APPWRITE_COL_MESSAGES_ID=${{ vars.PUBLIC_APPWRITE_COL_MESSAGES_ID }}"
|
||||
"PUBLIC_APPWRITE_FN_TLDR_ID=${{ vars.PUBLIC_APPWRITE_FN_TLDR_ID }}"
|
||||
"PUBLIC_APPWRITE_PROJECT_INIT_ID=${{ vars.PUBLIC_APPWRITE_PROJECT_INIT_ID }}"
|
||||
"PUBLIC_GROWTH_ENDPOINT=${{ vars.PUBLIC_GROWTH_ENDPOINT }}"
|
||||
"APPWRITE_DB_INIT_ID=${{ secrets.APPWRITE_DB_INIT_ID }}"
|
||||
"APPWRITE_COL_INIT_ID=${{ secrets.APPWRITE_COL_INIT_ID }}"
|
||||
"APPWRITE_API_KEY_INIT=${{ secrets.APPWRITE_API_KEY_INIT }}"
|
||||
|
||||
1
.github/workflows/tests.yml
vendored
1
.github/workflows/tests.yml
vendored
@@ -43,6 +43,7 @@ jobs:
|
||||
PUBLIC_APPWRITE_COL_MESSAGES_ID: ${{ secrets.PUBLIC_APPWRITE_COL_MESSAGES_ID }}
|
||||
PUBLIC_APPWRITE_FN_TLDR_ID: ${{ secrets.PUBLIC_APPWRITE_FN_TLDR_ID }}
|
||||
PUBLIC_APPWRITE_PROJECT_INIT_ID: ${{ secrets.PUBLIC_APPWRITE_PROJECT_INIT_ID }}
|
||||
PUBLIC_GROWTH_ENDPOINT: ${{ secrets.PUBLIC_GROWTH_ENDPOINT }}
|
||||
APPWRITE_DB_INIT_ID: ${{ secrets.APPWRITE_DB_INIT_ID }}
|
||||
APPWRITE_COL_INIT_ID: ${{ secrets.APPWRITE_COL_INIT_ID }}
|
||||
APPWRITE_API_KEY_INIT: ${{ secrets.APPWRITE_API_KEY_INIT }}
|
||||
|
||||
11
CONTENT.md
11
CONTENT.md
@@ -228,3 +228,14 @@ Get started with Appwrite and Nuxt
|
||||
Get started with Appwrite and SvelteKit
|
||||
{% /cards_item %}
|
||||
{% /cards %}
|
||||
|
||||
#### Accordions
|
||||
|
||||
{% accordion %}
|
||||
{% accordion_item title="Team ID" %}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Bundle ID" %}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% /accordion %}
|
||||
|
||||
@@ -19,6 +19,9 @@ ENV PUBLIC_APPWRITE_PROJECT_ID ${PUBLIC_APPWRITE_PROJECT_ID}
|
||||
ARG PUBLIC_APPWRITE_PROJECT_INIT_ID
|
||||
ENV PUBLIC_APPWRITE_PROJECT_INIT_ID ${PUBLIC_APPWRITE_PROJECT_INIT_ID}
|
||||
|
||||
ARG PUBLIC_GROWTH_ENDPOINT
|
||||
ENV PUBLIC_GROWTH_ENDPOINT ${PUBLIC_GROWTH_ENDPOINT}
|
||||
|
||||
ARG APPWRITE_DB_INIT_ID
|
||||
ENV APPWRITE_DB_INIT_ID ${APPWRITE_DB_INIT_ID}
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ For security issues, kindly email us at [security@appwrite.io](mailto:security@a
|
||||
|
||||
## Follow Us
|
||||
|
||||
Join our growing community around the world! See our official [Blog](https://medium.com/appwrite-io). Follow us on [Twitter](https://twitter.com/appwrite), [Facebook Page](https://www.facebook.com/appwrite.io), [Facebook Group](https://www.facebook.com/groups/appwrite.developers/), and [Dev Community](https://dev.to/appwrite) or join our live [Discord server](https://appwrite.io/discord) for more help, ideas, and discussions.
|
||||
Join our growing community around the world! See our official [Blog](https://appwrite.io/blog). Follow us on [X](https://twitter.com/appwrite), [Facebook Page](https://www.facebook.com/appwrite.io), [Facebook Group](https://www.facebook.com/groups/appwrite.developers/), and [Dev Community](https://dev.to/appwrite) or join our live [Discord server](https://appwrite.io/discord) for more help, ideas, and discussions.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -20,14 +20,15 @@
|
||||
"test:integration": "playwright test",
|
||||
"test:unit": "vitest"
|
||||
},
|
||||
"packageManager": "pnpm@8.15.6",
|
||||
"dependencies": {
|
||||
"compression": "^1.7.4",
|
||||
"express": "^4.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@appwrite.io/console": "^0.4.2",
|
||||
"@appwrite.io/pink": "0.1.0-next.9",
|
||||
"@appwrite.io/pink-icons": "0.1.0-next.9",
|
||||
"@appwrite.io/pink": "0.9.0",
|
||||
"@appwrite.io/pink-icons": "0.9.0",
|
||||
"@appwrite.io/repo": "github:appwrite/appwrite#main",
|
||||
"@melt-ui/pp": "^0.3.0",
|
||||
"@melt-ui/svelte": "^0.74.3",
|
||||
|
||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -17,11 +17,11 @@ devDependencies:
|
||||
specifier: ^0.4.2
|
||||
version: 0.4.2
|
||||
'@appwrite.io/pink':
|
||||
specifier: 0.1.0-next.9
|
||||
version: 0.1.0-next.9
|
||||
specifier: 0.9.0
|
||||
version: 0.9.0
|
||||
'@appwrite.io/pink-icons':
|
||||
specifier: 0.1.0-next.9
|
||||
version: 0.1.0-next.9
|
||||
specifier: 0.9.0
|
||||
version: 0.9.0
|
||||
'@appwrite.io/repo':
|
||||
specifier: github:appwrite/appwrite#main
|
||||
version: github.com/appwrite/appwrite/e868ae60c6db9d0dcbc5ce27a0ca609a7ceada7f
|
||||
@@ -167,14 +167,14 @@ packages:
|
||||
- encoding
|
||||
dev: true
|
||||
|
||||
/@appwrite.io/pink-icons@0.1.0-next.9:
|
||||
resolution: {integrity: sha512-6t4Pqt/xugjpJQyaMx1u/7Gt9CkW5iItDAgUKcIMm84E4NbDJq8ZdAhhvctGQQppKUgHDPi+6x1XveUUd7tdbg==}
|
||||
/@appwrite.io/pink-icons@0.9.0:
|
||||
resolution: {integrity: sha512-Y088XXzm08pHh8NKIhaZfQyZr+XkgVWUlQqmu8r1eeK4hKcQXqohGOm61gYwoDI8XA7ysi4s5FeVQVLRnZAcEw==}
|
||||
dev: true
|
||||
|
||||
/@appwrite.io/pink@0.1.0-next.9:
|
||||
resolution: {integrity: sha512-W5xVm2ZXlEqbbKv0GkpnM5saunDKdSfuhWouLnORsonENGFsG529PxRjqeClz4zrlkt2x1DiwN175wpgV3GoEQ==}
|
||||
/@appwrite.io/pink@0.9.0:
|
||||
resolution: {integrity: sha512-koit0ZuUINO5YlAbxA+QzDY7Tp3/YUiOVLOl/lEalhW6CQk8jMkFxO73pzIHf7nuBG/F1rFCLSG9qI8K5Qs1+g==}
|
||||
dependencies:
|
||||
'@appwrite.io/pink-icons': 0.1.0-next.9
|
||||
'@appwrite.io/pink-icons': 0.9.0
|
||||
normalize.css: 8.0.1
|
||||
the-new-css-reset: 1.11.2
|
||||
dev: true
|
||||
|
||||
@@ -15,14 +15,18 @@
|
||||
const links: Record<string, { label: string; href: string; target?: string; rel?: string }[]> =
|
||||
{
|
||||
'Quick starts': [
|
||||
{ label: 'Flutter', href: '/docs/quick-starts/flutter' },
|
||||
{ label: 'Web', href: '/docs/quick-starts/web' },
|
||||
{ label: 'Next.js', href: '/docs/quick-starts/nextjs' },
|
||||
{ label: 'React', href: '/docs/quick-starts/react' },
|
||||
{ label: 'Vue.js', href: '/docs/quick-starts/vue' },
|
||||
{ label: 'Nuxt', href: '/docs/quick-starts/nuxt' },
|
||||
{ label: 'SvelteKit', href: '/docs/quick-starts/sveltekit' },
|
||||
{ label: 'Refine', href: '/docs/quick-starts/refine' },
|
||||
{ label: 'Angular', href: '/docs/quick-starts/angular' },
|
||||
{ label: 'React Native', href: '/docs/quick-starts/react-native' },
|
||||
{ label: 'Flutter', href: '/docs/quick-starts/flutter' },
|
||||
{ label: 'Apple', href: '/docs/quick-starts/apple' },
|
||||
{ label: 'Android', href: '/docs/quick-starts/android' },
|
||||
{ label: 'Nuxt', href: '/docs/quick-starts/nuxt' },
|
||||
{ label: 'Angular', href: '/docs/quick-starts/angular' },
|
||||
{ label: 'Qwik', href: '/docs/quick-starts/qwik' },
|
||||
{ label: 'Astro', href: '/docs/quick-starts/astro' }
|
||||
],
|
||||
@@ -30,8 +34,9 @@
|
||||
{ label: 'Auth', href: '/docs/products/auth' },
|
||||
{ label: 'Databases', href: '/docs/products/databases' },
|
||||
{ label: 'Functions', href: '/docs/products/functions' },
|
||||
{ label: 'Messaging', href: '/docs/products/messaging' },
|
||||
{ label: 'Storage', href: '/docs/products/storage' },
|
||||
{ label: 'Realtime', href: '/docs/apis/realtime' },
|
||||
{ label: 'Realtime', href: '/docs/apis/realtime' }
|
||||
],
|
||||
Learn: [
|
||||
{ label: 'Docs', href: '/docs' },
|
||||
@@ -52,6 +57,10 @@
|
||||
rel: 'noopener noreferrer'
|
||||
}
|
||||
],
|
||||
Program: [
|
||||
{ label: 'Heroes', href: '/heroes' },
|
||||
{ label: 'Startups', href: '/startups' }
|
||||
],
|
||||
About: [
|
||||
{ label: 'Company', href: '/company' },
|
||||
{ label: 'Pricing', href: '/pricing' },
|
||||
@@ -61,7 +70,6 @@
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer'
|
||||
},
|
||||
{ label: 'Heroes', href: '/heroes' },
|
||||
{
|
||||
label: 'Store',
|
||||
href: 'https://appwrite.store',
|
||||
@@ -69,12 +77,7 @@
|
||||
rel: 'noopener noreferrer'
|
||||
},
|
||||
{ label: 'Contact us', href: '/contact-us' },
|
||||
{ label: 'Assets', href: '/assets' },
|
||||
],
|
||||
Policies: [
|
||||
{ label: 'Terms', href: '/terms' },
|
||||
{ label: 'Privacy', href: '/privacy' },
|
||||
{ label: 'Cookies', href: '/cookies' }
|
||||
{ label: 'Assets', href: '/assets' }
|
||||
]
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -24,7 +24,14 @@
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
<div>Copyright © {year} Appwrite</div>
|
||||
<div class="u-flex u-gap-16">
|
||||
<ul class="u-flex u-gap-8">
|
||||
<li><a class="web-link" href="/terms">Terms</a></li>
|
||||
<li><a class="web-link" href="/privacy">Privacy</a></li>
|
||||
<li><a class="web-link" href="/cookies">Cookies</a></li>
|
||||
</ul>
|
||||
<div>Copyright © {year} Appwrite</div>
|
||||
</div>
|
||||
</footer>
|
||||
{:else if variant === 'docs'}
|
||||
<footer
|
||||
|
||||
@@ -53,6 +53,11 @@
|
||||
href: '/docs/quick-starts/android',
|
||||
image: `/images/platforms/${$themeInUse}/android.svg`
|
||||
},
|
||||
{
|
||||
name: 'React Native',
|
||||
href: '/docs/quick-starts/react-native',
|
||||
image: `/images/platforms/${$themeInUse}/react-native.svg`
|
||||
},
|
||||
|
||||
] as Array<{
|
||||
name: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export const GITHUB_STARS = '39.5K';
|
||||
export const GITHUB_STARS = '40K';
|
||||
export const BANNER_KEY = 'discord-banner-01'; // Change key to force banner to show again
|
||||
|
||||
/**
|
||||
|
||||
@@ -73,7 +73,6 @@
|
||||
{#each toc as parent (parent.href)}
|
||||
<li
|
||||
class="web-references-menu-item"
|
||||
class:article-scroll-indicator={parent.selected}
|
||||
>
|
||||
<a
|
||||
href={parent.href}
|
||||
@@ -119,18 +118,3 @@
|
||||
</aside>
|
||||
</article>
|
||||
</main>
|
||||
|
||||
<style lang="scss">
|
||||
.article-scroll-indicator {
|
||||
position: relative;
|
||||
&::before {
|
||||
position: absolute;
|
||||
content: '';
|
||||
top: 0;
|
||||
left: -1.8rem;
|
||||
height: 100%;
|
||||
width: 2px;
|
||||
background-color: hsl(var(--p-references-menu-link-color-text));
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export const formatDate = (date: string): string => {
|
||||
const dt = new Date(date);
|
||||
const month = dt.toLocaleString('default', { month: 'short' });
|
||||
const day = dt.getDate();
|
||||
const year = dt.getFullYear();
|
||||
return `${month} ${day}, ${year}`;
|
||||
export const formatDate = (date: string | Date | number): string => {
|
||||
const dt = new Date(date);
|
||||
const month = dt.toLocaleString('en-US', { month: 'short' });
|
||||
const day = dt.getDate();
|
||||
const year = dt.getFullYear();
|
||||
return `${month} ${day}, ${year}`;
|
||||
};
|
||||
|
||||
@@ -31,16 +31,16 @@ export enum Platform {
|
||||
ClientAndroidJava = 'client-android-java',
|
||||
ClientGraphql = 'client-graphql',
|
||||
ClientRest = 'client-rest',
|
||||
ServerNodeJs = 'server-nodejs',
|
||||
ServerPython = 'server-python',
|
||||
ServerDart = 'server-dart',
|
||||
ServerDeno = 'server-deno',
|
||||
ServerDotNet = 'server-dotnet',
|
||||
ServerNodeJs = 'server-nodejs',
|
||||
ServerPhp = 'server-php',
|
||||
ServerPython = 'server-python',
|
||||
ServerRuby = 'server-ruby',
|
||||
ServerSwift = 'server-swift',
|
||||
ServerKotlin = 'server-kotlin',
|
||||
ServerJava = 'server-java',
|
||||
ServerDotNet = 'server-dotnet',
|
||||
ServerGraphql = 'server-graphql',
|
||||
ServerRest = 'server-rest'
|
||||
}
|
||||
|
||||
@@ -51,6 +51,19 @@ export type AppwriteSchemaObject = OpenAPIV3.SchemaObject & {
|
||||
'x-example': string;
|
||||
};
|
||||
|
||||
export interface Property {
|
||||
name: string;
|
||||
items?: {
|
||||
type?: string;
|
||||
oneOf?: OpenAPIV3.ReferenceObject[];
|
||||
} & OpenAPIV3.ReferenceObject;
|
||||
}
|
||||
|
||||
export enum ModelType {
|
||||
REST = 'REST',
|
||||
GRAPHQL = 'GraphQL'
|
||||
}
|
||||
|
||||
function getExamples(version: string) {
|
||||
switch (version) {
|
||||
case '0.15.x':
|
||||
@@ -169,8 +182,7 @@ export function getSchema(id: string, api: OpenAPIV3.Document): OpenAPIV3.Schema
|
||||
if (schema) {
|
||||
return schema;
|
||||
}
|
||||
throw new Error("Schema doesn't exist");
|
||||
}
|
||||
throw new Error(`Schema doesn't exist for id: ${id}`);}
|
||||
|
||||
const specs = import.meta.glob(
|
||||
'$appwrite/app/config/specs/open-api3*-(client|server|console).json',
|
||||
@@ -191,6 +203,7 @@ async function getSpec(version: string, platform: string) {
|
||||
export async function getApi(version: string, platform: string): Promise<OpenAPIV3.Document> {
|
||||
const raw = await getSpec(version, platform);
|
||||
const api = JSON.parse(raw);
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
@@ -208,7 +221,10 @@ export async function getDescription(service: string): Promise<string> {
|
||||
if (!(target in descriptions)) {
|
||||
throw new Error('Missing service description');
|
||||
}
|
||||
return descriptions[target]();
|
||||
|
||||
const description = descriptions[target]();
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
export async function getService(
|
||||
@@ -296,6 +312,7 @@ export async function getService(
|
||||
if (!(path in examples)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
data.methods.push({
|
||||
id: operation['x-appwrite'].method,
|
||||
demo: await examples[path](),
|
||||
@@ -336,3 +353,85 @@ export function resolveReference(
|
||||
}
|
||||
throw new Error("Schema doesn't exist");
|
||||
}
|
||||
|
||||
export const generateExample = (schema: OpenAPIV3.SchemaObject, api: OpenAPIV3.Document<{}>, modelType: ModelType = ModelType.REST): Object => {
|
||||
|
||||
const properties = Object.keys(schema.properties ?? {}).map((key) =>{
|
||||
const name = key;
|
||||
const fields = schema.properties?.[key];
|
||||
return {
|
||||
name,
|
||||
...fields
|
||||
}
|
||||
});
|
||||
|
||||
const example = properties.reduce((carry, currentValue) => {
|
||||
const property = currentValue as AppwriteSchemaObject & Property;
|
||||
let propertyName;
|
||||
switch (modelType) {
|
||||
case ModelType.REST:
|
||||
propertyName = property.name;
|
||||
break;
|
||||
case ModelType.GRAPHQL:
|
||||
propertyName = property.name.replace('$', '_');
|
||||
break;
|
||||
default:
|
||||
propertyName = property.name;
|
||||
break;
|
||||
}
|
||||
|
||||
if (property.type === 'array') {
|
||||
// If it's an array type containing primatives
|
||||
if (property.items?.type){
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: property['x-example']
|
||||
}
|
||||
}
|
||||
|
||||
if (property.items && 'anyOf' in property.items) {
|
||||
// default to first child type if multiple available
|
||||
const firstSchema = (property.items as unknown as AppwriteSchemaObject)?.anyOf?.[0];
|
||||
const schema = getSchema(getIdFromReference(firstSchema as OpenAPIV3.ReferenceObject), api)
|
||||
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: [generateExample(schema, api, modelType)]
|
||||
};
|
||||
}
|
||||
|
||||
// if an array of objects without child types
|
||||
const schema = getSchema(getIdFromReference(property.items as OpenAPIV3.ReferenceObject), api);
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: [generateExample(schema, api, modelType)]
|
||||
}
|
||||
}
|
||||
|
||||
// If it's an object type, but not in an array.
|
||||
if (property.type === 'object') {
|
||||
if (property.items?.oneOf){
|
||||
// default to first child type if multiple available
|
||||
const schema = getSchema(getIdFromReference(property.items.oneOf[0] as OpenAPIV3.ReferenceObject), api);
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: generateExample(schema, api, modelType)
|
||||
}
|
||||
}
|
||||
|
||||
if (property.items){
|
||||
const schema = getSchema(getIdFromReference(property.items), api);
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: generateExample(schema, api, modelType)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
...carry,
|
||||
[propertyName]: property['x-example']
|
||||
}
|
||||
}, {});
|
||||
return example;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
export type Tutorial = {
|
||||
title: string;
|
||||
framework?: string;
|
||||
category?: string;
|
||||
step: number;
|
||||
href: string;
|
||||
draft?: boolean;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
<div style:margin-block="1.5rem">
|
||||
<div>
|
||||
<ul class="web-grid-row-2">
|
||||
<slot />
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
margin-block-start: 1rem;
|
||||
margin-block-end: 2rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
23
src/markdoc/tags/Cards_Image_Item.svelte
Normal file
23
src/markdoc/tags/Cards_Image_Item.svelte
Normal file
@@ -0,0 +1,23 @@
|
||||
<script lang="ts">
|
||||
import { setContext } from 'svelte';
|
||||
|
||||
export let href: string;
|
||||
export let light = '';
|
||||
export let dark = '';
|
||||
export let title: string;
|
||||
|
||||
setContext('no-paragraph', true);
|
||||
</script>
|
||||
|
||||
<li>
|
||||
<a {href} class="web-card is-normal" style:margin-block-end="0">
|
||||
<img src={dark} alt="" class="u-only-dark" width="32" height="32" />
|
||||
<img src={light} alt="" class="u-only-light" width="32" height="32" />
|
||||
<h4 class="web-sub-body-500 web-u-color-text-primary u-margin-block-start-8">
|
||||
{title}
|
||||
</h4>
|
||||
<p class="web-sub-body-400 u-margin-block-start-4">
|
||||
<slot />
|
||||
</p>
|
||||
</a>
|
||||
</li>
|
||||
@@ -1,83 +1,83 @@
|
||||
<script context="module" lang="ts">
|
||||
import type { Writable } from 'svelte/store';
|
||||
export type CodeContext = {
|
||||
selected: Writable<string | null>;
|
||||
snippets: Writable<Set<Language>>;
|
||||
content: Writable<string>;
|
||||
};
|
||||
import type { Writable } from 'svelte/store';
|
||||
export type CodeContext = {
|
||||
selected: Writable<string | null>;
|
||||
snippets: Writable<Set<Language>>;
|
||||
content: Writable<string>;
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
import { platformMap } from '$lib/utils/references';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import type { Language } from '$lib/utils/code';
|
||||
import { copy } from '$lib/utils/copy';
|
||||
import { Tooltip } from '$lib/components';
|
||||
import { platformMap } from '$lib/utils/references';
|
||||
import { getContext, setContext } from 'svelte';
|
||||
import { writable } from 'svelte/store';
|
||||
import type { Language } from '$lib/utils/code';
|
||||
import { copy } from '$lib/utils/copy';
|
||||
import { Select, Tooltip } from '$lib/components';
|
||||
|
||||
setContext<CodeContext>('multi-code', {
|
||||
selected: writable(null),
|
||||
snippets: writable(new Set()),
|
||||
content: writable('')
|
||||
});
|
||||
setContext<CodeContext>('multi-code', {
|
||||
selected: writable(null),
|
||||
snippets: writable(new Set()),
|
||||
content: writable('')
|
||||
});
|
||||
|
||||
const { snippets, selected, content } = getContext<CodeContext>('multi-code');
|
||||
const { snippets, selected, content } = getContext<CodeContext>('multi-code');
|
||||
|
||||
snippets.subscribe((n) => {
|
||||
if ($selected === null && n.size > 0) {
|
||||
$selected = Array.from(n)[0];
|
||||
}
|
||||
});
|
||||
snippets.subscribe((n) => {
|
||||
if ($selected === null && n.size > 0) {
|
||||
$selected = Array.from(n)[0];
|
||||
}
|
||||
});
|
||||
|
||||
enum CopyStatus {
|
||||
Copy = 'Copy',
|
||||
Copied = 'Copied!'
|
||||
}
|
||||
let copyText = CopyStatus.Copy;
|
||||
async function handleCopy() {
|
||||
await copy($content);
|
||||
enum CopyStatus {
|
||||
Copy = 'Copy',
|
||||
Copied = 'Copied!'
|
||||
}
|
||||
let copyText = CopyStatus.Copy;
|
||||
async function handleCopy() {
|
||||
await copy($content);
|
||||
|
||||
copyText = CopyStatus.Copied;
|
||||
setTimeout(() => {
|
||||
copyText = CopyStatus.Copy;
|
||||
}, 1000);
|
||||
}
|
||||
copyText = CopyStatus.Copied;
|
||||
setTimeout(() => {
|
||||
copyText = CopyStatus.Copy;
|
||||
}, 1000);
|
||||
}
|
||||
</script>
|
||||
|
||||
<section class="theme-dark web-code-snippet" aria-label="code-snippet panel">
|
||||
<header class="web-code-snippet-header">
|
||||
<div class="web-code-snippet-header-start">
|
||||
<div class="u-flex u-gap-16">
|
||||
<!-- <div class="web-tag"><span class="text">Default</span></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="web-code-snippet-header-end">
|
||||
<ul class="buttons-list u-flex u-gap-8">
|
||||
<li class="buttons-list-item u-flex u-cross-child-scenter">
|
||||
<div class="web-select">
|
||||
<select bind:value={$selected}>
|
||||
{#each Array.from($snippets) as language}
|
||||
<option value={language}>{platformMap[language]}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<span class="icon-cheveron-down" aria-hidden="true" />
|
||||
</div>
|
||||
</li>
|
||||
<li class="buttons-list-item web-u-padding-inline-start-20">
|
||||
<Tooltip>
|
||||
<button
|
||||
on:click={handleCopy}
|
||||
class="web-icon-button"
|
||||
aria-label="copy code from code-snippet"
|
||||
><span class="web-icon-copy" aria-hidden="true" /></button
|
||||
>
|
||||
<svelte:fragment slot="tooltip">
|
||||
{copyText}
|
||||
</svelte:fragment>
|
||||
</Tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
<div class="web-code-snippet-content"><slot /></div>
|
||||
<header class="web-code-snippet-header">
|
||||
<div class="web-code-snippet-header-start">
|
||||
<div class="u-flex u-gap-16">
|
||||
<!-- <div class="web-tag"><span class="text">Default</span></div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="web-code-snippet-header-end">
|
||||
<ul class="buttons-list u-flex u-gap-12">
|
||||
<li class="buttons-list-item u-flex u-cross-child-scenter">
|
||||
<Select
|
||||
bind:value={$selected}
|
||||
options={Array.from($snippets).map((language) => ({
|
||||
value: language,
|
||||
label: platformMap[language]
|
||||
}))}
|
||||
/>
|
||||
</li>
|
||||
|
||||
<li class="buttons-list-item" style="padding-inline-start: 13px">
|
||||
<Tooltip>
|
||||
<button
|
||||
on:click={handleCopy}
|
||||
class="web-icon-button"
|
||||
aria-label="copy code from code-snippet"
|
||||
><span class="web-icon-copy" aria-hidden="true" /></button
|
||||
>
|
||||
<svelte:fragment slot="tooltip">
|
||||
{copyText}
|
||||
</svelte:fragment>
|
||||
</Tooltip>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
<div class="web-code-snippet-content"><slot /></div>
|
||||
</section>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
export { default as Icon_Image } from './Icon_Image.svelte';
|
||||
export { default as Cards } from './Cards.svelte';
|
||||
export { default as Cards_Item } from './Cards_Item.svelte';
|
||||
export { default as Cards_Image_Item } from './Cards_Image_Item.svelte';
|
||||
export { default as Only_Light } from './Only_Light.svelte';
|
||||
export { default as Only_Dark } from './Only_Dark.svelte';
|
||||
export { default as Video } from './Video.svelte';
|
||||
|
||||
@@ -1,32 +1,144 @@
|
||||
## Authentication events {% #authentication-events %}
|
||||
|
||||
| Name | Payload | Description |
|
||||
|----------------------------------------|------------------------------------|-----------------------------------------------------|
|
||||
| `teams.*` | [Team Object](/docs/references/cloud/models/team) | This event triggers on any teams event. |
|
||||
| `teams.*.create` | [Team Object](/docs/references/cloud/models/team) | This event triggers when a team is created. |
|
||||
| `teams.*.delete` | [Team Object](/docs/references/cloud/models/team) | This event triggers when a team is deleted. |
|
||||
| `teams.*.memberships.*` | [Membership Object](/docs/references/cloud/models/membership) | This event triggers on any team memberships event. |
|
||||
| `teams.*.memberships.*.create` | [Membership Object](/docs/references/cloud/models/membership) | This event triggers when a membership is created. |
|
||||
| `teams.*.memberships.*.delete` | [Membership Object](/docs/references/cloud/models/membership) | This event triggers when a membership is deleted. |
|
||||
| `teams.*.memberships.*.update` | [Membership Object](/docs/references/cloud/models/membership) | This event triggers when a membership is updated. |
|
||||
| `teams.*.memberships.*.update.status` | [Membership Object](/docs/references/cloud/models/membership) | This event triggers when a team memberships status is updated. |
|
||||
| `teams.*.update` | [Team Object](/docs/references/cloud/models/team) | This event triggers when a team is updated. |
|
||||
| `teams.*.update.prefs` | [Team Object](/docs/references/cloud/models/team) | This event triggers when a team's preferences are updated. |
|
||||
| `users.*` | [User Object](/docs/references/cloud/models/user) | This event triggers on any user's event. |
|
||||
| `users.*.create` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user is created. |
|
||||
| `users.*.delete` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user is deleted. |
|
||||
| `users.*.recovery.*` | [Token Object](/docs/references/cloud/models/token) | This event triggers on any user's recovery token event. |
|
||||
| `users.*.recovery.*.create` | [Token Object](/docs/references/cloud/models/token) | This event triggers when a recovery token for a user is created. |
|
||||
| `users.*.recovery.*.update` | [Token Object](/docs/references/cloud/models/token) | This event triggers when a recovery token for a user is validated. |
|
||||
| `users.*.sessions.*` | [Session Object](/docs/references/cloud/models/session) | This event triggers on any user's sessions event. |
|
||||
| `users.*.sessions.*.create` | [Session Object](/docs/references/cloud/models/session) | This event triggers when a session for a user is created. |
|
||||
| `users.*.sessions.*.delete` | [Session Object](/docs/references/cloud/models/session) | This event triggers when a session for a user is deleted. |
|
||||
| `users.*.update` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user is updated. |
|
||||
| `users.*.update.email` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user's email address is updated. |
|
||||
| `users.*.update.name` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user's name is updated. |
|
||||
| `users.*.update.password` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user's password is updated. |
|
||||
| `users.*.update.prefs` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user's preferences is updated. |
|
||||
| `users.*.update.status` | [User Object](/docs/references/cloud/models/user) | This event triggers when a user's status is updated. |
|
||||
| `users.*.verification.*` | [Token Object](/docs/references/cloud/models/token) | This event triggers on any user's verification token event. |
|
||||
| `users.*.verification.*.create` | [Token Object](/docs/references/cloud/models/token) | This event triggers when a verification token for a user is created. |
|
||||
| `users.*.verification.*.update` | [Token Object](/docs/references/cloud/models/token) | This event triggers when a verification token for a user is validated. |
|
||||
{% table %}
|
||||
* Name
|
||||
* Description
|
||||
---
|
||||
* `teams.*`
|
||||
*
|
||||
This event triggers on any teams event.
|
||||
Returns [Team Object](/docs/references/cloud/models/team)
|
||||
---
|
||||
* `teams.*.create`
|
||||
*
|
||||
This event triggers when a team is created.
|
||||
Returns [Team Object](/docs/references/cloud/models/team)
|
||||
---
|
||||
* `teams.*.delete`
|
||||
*
|
||||
This event triggers when a team is deleted.
|
||||
Returns [Team Object](/docs/references/cloud/models/team)
|
||||
---
|
||||
* `teams.*.memberships.*`
|
||||
*
|
||||
This event triggers on any team memberships event.
|
||||
Returns [Membership Object](/docs/references/cloud/models/membership)
|
||||
---
|
||||
* `teams.*.memberships.*.create`
|
||||
*
|
||||
This event triggers when a membership is created.
|
||||
Returns [Membership Object](/docs/references/cloud/models/membership)
|
||||
---
|
||||
* `teams.*.memberships.*.delete`
|
||||
*
|
||||
This event triggers when a membership is deleted.
|
||||
Returns [Membership Object](/docs/references/cloud/models/membership)
|
||||
---
|
||||
* `teams.*.memberships.*.update`
|
||||
*
|
||||
This event triggers when a membership is updated.
|
||||
Returns [Membership Object](/docs/references/cloud/models/membership)
|
||||
---
|
||||
* `teams.*.memberships.*.update.status`
|
||||
*
|
||||
This event triggers when a team memberships status is updated.
|
||||
Returns [Membership Object](/docs/references/cloud/models/membership)
|
||||
---
|
||||
* `teams.*.update`
|
||||
*
|
||||
This event triggers when a team is updated.
|
||||
Returns [Team Object](/docs/references/cloud/models/team)
|
||||
---
|
||||
* `teams.*.update.prefs`
|
||||
*
|
||||
This event triggers when a team's preferences are updated.
|
||||
Returns [Team Object](/docs/references/cloud/models/team)
|
||||
---
|
||||
* `users.*`
|
||||
*
|
||||
This event triggers on any user's event.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.create`
|
||||
*
|
||||
This event triggers when a user is created.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.delete`
|
||||
*
|
||||
This event triggers when a user is deleted.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.recovery.*`
|
||||
*
|
||||
This event triggers on any user's recovery token event.
|
||||
Returns [Token Object](/docs/references/cloud/models/token)
|
||||
---
|
||||
* `users.*.recovery.*.create`
|
||||
*
|
||||
This event triggers when a recovery token for a user is created.
|
||||
Returns [Token Object](/docs/references/cloud/models/token)
|
||||
---
|
||||
* `users.*.recovery.*.update`
|
||||
*
|
||||
This event triggers when a recovery token for a user is validated.
|
||||
Returns [Token Object](/docs/references/cloud/models/token)
|
||||
---
|
||||
* `users.*.sessions.*`
|
||||
*
|
||||
This event triggers on any user's sessions event.
|
||||
Returns [Session Object](/docs/references/cloud/models/session)
|
||||
---
|
||||
* `users.*.sessions.*.create`
|
||||
*
|
||||
This event triggers when a session for a user is created.
|
||||
Returns [Session Object](/docs/references/cloud/models/session)
|
||||
---
|
||||
* `users.*.sessions.*.delete`
|
||||
*
|
||||
This event triggers when a session for a user is deleted.
|
||||
Returns [Session Object](/docs/references/cloud/models/session)
|
||||
---
|
||||
* `users.*.update`
|
||||
*
|
||||
This event triggers when a user is updated.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.update.email`
|
||||
*
|
||||
This event triggers when a user's email address is updated.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.update.name`
|
||||
*
|
||||
This event triggers when a user's name is updated.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.update.password`
|
||||
*
|
||||
This event triggers when a user's password is updated.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.update.prefs`
|
||||
*
|
||||
This event triggers when a user's preferences is updated.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.update.status`
|
||||
*
|
||||
This event triggers when a user's status is updated.
|
||||
Returns [User Object](/docs/references/cloud/models/user)
|
||||
---
|
||||
* `users.*.verification.*`
|
||||
*
|
||||
This event triggers on any user's verification token event.
|
||||
Returns [Token Object](/docs/references/cloud/models/token)
|
||||
---
|
||||
* `users.*.verification.*.create`
|
||||
*
|
||||
This event triggers when a verification token for a user is created.
|
||||
Returns [Token Object](/docs/references/cloud/models/token)
|
||||
---
|
||||
* `users.*.verification.*.update`
|
||||
*
|
||||
This event triggers when a verification token for a user is validated.
|
||||
Returns [Token Object](/docs/references/cloud/models/token)
|
||||
{% /table %}
|
||||
@@ -1,22 +1,93 @@
|
||||
## Databases events {% #databases-events %}
|
||||
|
||||
| Name | Payload | Description |
|
||||
| ----------------------------------------- | ------------------------------ | --------------------------------------- |
|
||||
| `databases.*` | [Database Object](/docs/references/cloud/models/database) | This event triggers on any database event. |
|
||||
| `databases.*.collections.*` | [Collection Object](/docs/references/cloud/models/collection) | This event triggers on any collection event. |
|
||||
| `databases.*.collections.*.attributes.*` | [Attribute Object](/docs/references/cloud/models/attributeList) | This event triggers on any attributes event. |
|
||||
| `databases.*.collections.*.attributes.*.create` | [Attribute Object](/docs/references/cloud/models/attributeList) | This event triggers when an attribute is created. |
|
||||
| `databases.*.collections.*.attributes.*.delete` | [Attribute Object](/docs/references/cloud/models/attributeList) | This event triggers when an attribute is deleted. |
|
||||
| `databases.*.collections.*.create` | [Collection Object](/docs/references/cloud/models/collection) | This event triggers when a collection is created. |
|
||||
| `databases.*.collections.*.delete` | [Collection Object](/docs/references/cloud/models/collection) | This event triggers when a collection is deleted. |
|
||||
| `databases.*.collections.*.documents.*` | [Document Object](/docs/references/cloud/models/document) | This event triggers on any documents event. |
|
||||
| `databases.*.collections.*.documents.*.create` | [Document Object](/docs/references/cloud/models/document) | This event triggers when a document is created. |
|
||||
| `databases.*.collections.*.documents.*.delete` | [Document Object](/docs/references/cloud/models/document) | This event triggers when a document is deleted. |
|
||||
| `databases.*.collections.*.documents.*.update` | [Document Object](/docs/references/cloud/models/document) | This event triggers when a document is updated. |
|
||||
| `databases.*.collections.*.indexes.*` | [Index Object](/docs/references/cloud/models/index) | This event triggers on any indexes event. |
|
||||
| `databases.*.collections.*.indexes.*.create` | [Index Object](/docs/references/cloud/models/index) | This event triggers when an index is created. |
|
||||
| `databases.*.collections.*.indexes.*.delete` | [Index Object](/docs/references/cloud/models/index) | This event triggers when an index is deleted. |
|
||||
| `databases.*.collections.*.update` | [Collection Object](/docs/references/cloud/models/collection) | This event triggers when a collection is updated. |
|
||||
| `databases.*.create` | [Database Object](/docs/references/cloud/models/database) | This event triggers when a database is created. |
|
||||
| `databases.*.delete` | [Database Object](/docs/references/cloud/models/database) | This event triggers when a database is deleted. |
|
||||
| `databases.*.update` | [Database Object](/docs/references/cloud/models/database) | This event triggers when a database is updated. |
|
||||
{% table %}
|
||||
* Name
|
||||
* Description
|
||||
---
|
||||
* `databases.*`
|
||||
*
|
||||
This event triggers on any database event.
|
||||
Returns [Database Object](/docs/references/cloud/models/database)
|
||||
---
|
||||
* `databases.*.collections.*`
|
||||
*
|
||||
This event triggers on any collection event.
|
||||
Returns [Collection Object](/docs/references/cloud/models/collection)
|
||||
---
|
||||
* `databases.*.collections.*.attributes.*`
|
||||
*
|
||||
This event triggers on any attributes event.
|
||||
Returns [Attribute Object](/docs/references/cloud/models/attributeList)
|
||||
---
|
||||
* `databases.*.collections.*.attributes.*.create`
|
||||
*
|
||||
This event triggers when an attribute is created.
|
||||
Returns [Attribute Object](/docs/references/cloud/models/attributeList)
|
||||
---
|
||||
* `databases.*.collections.*.attributes.*.delete`
|
||||
*
|
||||
This event triggers when an attribute is deleted.
|
||||
Returns [Attribute Object](/docs/references/cloud/models/attributeList)
|
||||
---
|
||||
* `databases.*.collections.*.create`
|
||||
*
|
||||
This event triggers when a collection is created.
|
||||
Returns [Collection Object](/docs/references/cloud/models/collection)
|
||||
---
|
||||
* `databases.*.collections.*.delete`
|
||||
*
|
||||
This event triggers when a collection is deleted.
|
||||
Returns [Collection Object](/docs/references/cloud/models/collection)
|
||||
---
|
||||
* `databases.*.collections.*.documents.*`
|
||||
*
|
||||
This event triggers on any documents event.
|
||||
Returns [Document Object](/docs/references/cloud/models/document)
|
||||
---
|
||||
* `databases.*.collections.*.documents.*.create`
|
||||
*
|
||||
This event triggers when a document is created.
|
||||
Returns [Document Object](/docs/references/cloud/models/document)
|
||||
---
|
||||
* `databases.*.collections.*.documents.*.delete`
|
||||
*
|
||||
This event triggers when a document is deleted.
|
||||
Returns [Document Object](/docs/references/cloud/models/document)
|
||||
---
|
||||
* `databases.*.collections.*.documents.*.update`
|
||||
*
|
||||
This event triggers when a document is updated.
|
||||
Returns [Document Object](/docs/references/cloud/models/document)
|
||||
---
|
||||
* `databases.*.collections.*.indexes.*`
|
||||
*
|
||||
This event triggers on any indexes event.
|
||||
Returns [Index Object](/docs/references/cloud/models/index)
|
||||
---
|
||||
* `databases.*.collections.*.indexes.*.create`
|
||||
*
|
||||
This event triggers when an index is created.
|
||||
Returns [Index Object](/docs/references/cloud/models/index)
|
||||
---
|
||||
* `databases.*.collections.*.indexes.*.delete`
|
||||
*
|
||||
This event triggers when an index is deleted.
|
||||
Returns [Index Object](/docs/references/cloud/models/index)
|
||||
---
|
||||
* `databases.*.collections.*.update`
|
||||
*
|
||||
This event triggers when a collection is updated.
|
||||
Returns [Collection Object](/docs/references/cloud/models/collection)
|
||||
---
|
||||
* `databases.*.create`
|
||||
*
|
||||
This event triggers when a database is created.
|
||||
Returns [Database Object](/docs/references/cloud/models/database)
|
||||
---
|
||||
* `databases.*.delete`
|
||||
*
|
||||
This event triggers when a database is deleted.
|
||||
Returns [Database Object](/docs/references/cloud/models/database)
|
||||
---
|
||||
* `databases.*.update`
|
||||
*
|
||||
This event triggers when a database is updated.
|
||||
Returns [Database Object](/docs/references/cloud/models/database){% /table %}
|
||||
@@ -1,16 +1,64 @@
|
||||
## Functions events {% #functions-events %}
|
||||
|
||||
| Name | Payload | Description |
|
||||
| ------------------------------------------- | --------------------------------- | ----------------------------------------- |
|
||||
| `functions.*` | [Function Object](/docs/references/cloud/models/function) | This event triggers on any functions event. |
|
||||
| `functions.*.create` | [Function Object](/docs/references/cloud/models/function) | This event triggers when a function is created. |
|
||||
| `functions.*.delete` | [Function Object](/docs/references/cloud/models/function) | This event triggers when a function is deleted. |
|
||||
| `functions.*.deployments.*` | [Deployment Object](/docs/references/cloud/models/deployment) | This event triggers on any deployments event. |
|
||||
| `functions.*.deployments.*.create` | [Deployment Object](/docs/references/cloud/models/deployment) | This event triggers when a deployment is created. |
|
||||
| `functions.*.deployments.*.delete` | [Deployment Object](/docs/references/cloud/models/deployment) | This event triggers when a deployment is deleted. |
|
||||
| `functions.*.deployments.*.update` | [Deployment Object](/docs/references/cloud/models/deployment) | This event triggers when a deployment is updated. |
|
||||
| `functions.*.executions.*` | [Execution Object](/docs/references/cloud/models/execution) | This event triggers on any executions event. |
|
||||
| `functions.*.executions.*.create` | [Execution Object](/docs/references/cloud/models/execution) | This event triggers when an execution is created. |
|
||||
| `functions.*.executions.*.delete` | [Execution Object](/docs/references/cloud/models/execution) | This event triggers when an execution is deleted. |
|
||||
| `functions.*.executions.*.update` | [Execution Object](/docs/references/cloud/models/execution) | This event triggers when an execution is updated. |
|
||||
| `functions.*.update` | [Function Object](/docs/references/cloud/models/function) | This event triggers when a function is updated. |
|
||||
{% table %}
|
||||
* Name
|
||||
* Description
|
||||
---
|
||||
* `functions.*`
|
||||
*
|
||||
This event triggers on any functions event.
|
||||
Returns [Function Object](/docs/references/cloud/models/function)
|
||||
---
|
||||
* `functions.*.create`
|
||||
*
|
||||
This event triggers when a function is created.
|
||||
Returns [Function Object](/docs/references/cloud/models/function)
|
||||
---
|
||||
* `functions.*.delete`
|
||||
*
|
||||
This event triggers when a function is deleted.
|
||||
Returns [Function Object](/docs/references/cloud/models/function)
|
||||
---
|
||||
* `functions.*.deployments.*`
|
||||
*
|
||||
This event triggers on any deployments event.
|
||||
Returns [Deployment Object](/docs/references/cloud/models/deployment)
|
||||
---
|
||||
* `functions.*.deployments.*.create`
|
||||
*
|
||||
This event triggers when a deployment is created.
|
||||
Returns [Deployment Object](/docs/references/cloud/models/deployment)
|
||||
---
|
||||
* `functions.*.deployments.*.delete`
|
||||
*
|
||||
This event triggers when a deployment is deleted.
|
||||
Returns [Deployment Object](/docs/references/cloud/models/deployment)
|
||||
---
|
||||
* `functions.*.deployments.*.update`
|
||||
*
|
||||
This event triggers when a deployment is updated.
|
||||
Returns [Deployment Object](/docs/references/cloud/models/deployment)
|
||||
---
|
||||
* `functions.*.executions.*`
|
||||
*
|
||||
This event triggers on any executions event.
|
||||
Returns [Execution Object](/docs/references/cloud/models/execution)
|
||||
---
|
||||
* `functions.*.executions.*.create`
|
||||
*
|
||||
This event triggers when an execution is created.
|
||||
Returns [Execution Object](/docs/references/cloud/models/execution)
|
||||
---
|
||||
* `functions.*.executions.*.delete`
|
||||
*
|
||||
This event triggers when an execution is deleted.
|
||||
Returns [Execution Object](/docs/references/cloud/models/execution)
|
||||
---
|
||||
* `functions.*.executions.*.update`
|
||||
*
|
||||
This event triggers when an execution is updated.
|
||||
Returns [Execution Object](/docs/references/cloud/models/execution)
|
||||
---
|
||||
* `functions.*.update`
|
||||
*
|
||||
This event triggers when a function is updated.
|
||||
Returns [Function Object](/docs/references/cloud/models/function)
|
||||
{% /table %}
|
||||
@@ -1,18 +1,74 @@
|
||||
## Messaging events {% #messaging-events %}
|
||||
|
||||
| Name | Payload | Description |
|
||||
| ------------------------------- | --------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| `providers.*` | [Provider Object](/docs/references/1.5.x/models/provider) | This event triggers on any providers event. |
|
||||
| `providers.*.create` | [Provider Object](/docs/references/1.5.x/models/provider) | This event triggers when a provider is created. |
|
||||
| `providers.*.delete` | [Provider Object](/docs/references/1.5.x/models/provider) | This event triggers when a provider is deleted. |
|
||||
| `providers.*.update` | [Provider Object](/docs/references/1.5.x/models/provider) | This event triggers when a provider is updated. |
|
||||
| `topics.*` | [Topic Object](/docs/references/1.5.x/models/topic) | This event triggers on any topic event. |
|
||||
| `topics.*.create` | [Topic Object](/docs/references/1.5.x/models/topic) | This event triggers when a topic is created. |
|
||||
| `topics.*.delete` | [Topic Object](/docs/references/1.5.x/models/topic) | This event triggers when a topic is deleted. |
|
||||
| `topics.*.update` | [Topic Object](/docs/references/1.5.x/models/topic) | This event triggers when a topic is updated. |
|
||||
| `topics.*.subscribers.*.create` | [Topic Object](/docs/references/1.5.x/models/topic) | This event triggers when a subscriber to a topic is created. |
|
||||
| `topics.*.subscribers.*.delete` | [Topic Object](/docs/references/1.5.x/models/topic) | This event triggers when a subscriber to a topic is deleted. |
|
||||
| `messages.*` | [Message Object](/docs/references/1.5.x/models/message) | This event triggers on any message event. |
|
||||
| `messages.*.create` | [Message Object](/docs/references/1.5.x/models/message) | This event triggers when a message is created. |
|
||||
| `messages.*.delete` | [Message Object](/docs/references/1.5.x/models/message) | This event triggers when a message is deleted. |
|
||||
| `messages.*.update` | [Message Object](/docs/references/1.5.x/models/message) | This event triggers when a message is updated. |
|
||||
{% table %}
|
||||
* Name
|
||||
* Description
|
||||
---
|
||||
* `providers.*`
|
||||
*
|
||||
This event triggers on any providers event.
|
||||
Returns [Provider Object](/docs/references/1.5.x/models/provider)
|
||||
---
|
||||
* `providers.*.create`
|
||||
*
|
||||
This event triggers when a provider is created.
|
||||
Returns [Provider Object](/docs/references/1.5.x/models/provider)
|
||||
---
|
||||
* `providers.*.delete`
|
||||
*
|
||||
This event triggers when a provider is deleted.
|
||||
Returns [Provider Object](/docs/references/1.5.x/models/provider)
|
||||
---
|
||||
* `providers.*.update`
|
||||
*
|
||||
This event triggers when a provider is updated.
|
||||
Returns [Provider Object](/docs/references/1.5.x/models/provider)
|
||||
---
|
||||
* `topics.*`
|
||||
*
|
||||
This event triggers on any topic event.
|
||||
Returns [Topic Object](/docs/references/1.5.x/models/topic)
|
||||
---
|
||||
* `topics.*.create`
|
||||
*
|
||||
This event triggers when a topic is created.
|
||||
Returns [Topic Object](/docs/references/1.5.x/models/topic)
|
||||
---
|
||||
* `topics.*.delete`
|
||||
*
|
||||
This event triggers when a topic is deleted.
|
||||
Returns [Topic Object](/docs/references/1.5.x/models/topic)
|
||||
---
|
||||
* `topics.*.update`
|
||||
*
|
||||
This event triggers when a topic is updated.
|
||||
Returns [Topic Object](/docs/references/1.5.x/models/topic)
|
||||
---
|
||||
* `topics.*.subscribers.*.create`
|
||||
*
|
||||
This event triggers when a subscriber to a topic is created.
|
||||
Returns [Topic Object](/docs/references/1.5.x/models/topic)
|
||||
---
|
||||
* `topics.*.subscribers.*.delete`
|
||||
*
|
||||
This event triggers when a subscriber to a topic is deleted.
|
||||
Returns [Topic Object](/docs/references/1.5.x/models/topic)
|
||||
---
|
||||
* `messages.*`
|
||||
*
|
||||
This event triggers on any message event.
|
||||
Returns [Message Object](/docs/references/1.5.x/models/message)
|
||||
---
|
||||
* `messages.*.create`
|
||||
*
|
||||
This event triggers when a message is created.
|
||||
Returns [Message Object](/docs/references/1.5.x/models/message)
|
||||
---
|
||||
* `messages.*.delete`
|
||||
*
|
||||
This event triggers when a message is deleted.
|
||||
Returns [Message Object](/docs/references/1.5.x/models/message)
|
||||
---
|
||||
* `messages.*.update`
|
||||
*
|
||||
This event triggers when a message is updated.
|
||||
Returns [Message Object](/docs/references/1.5.x/models/message)
|
||||
{% /table %}
|
||||
@@ -1,12 +1,44 @@
|
||||
## Storage events {% ##storage-events %}
|
||||
|
||||
| Name | Payload | Description |
|
||||
|---------------------------------|-------------------------------------------------|----------------------------------------------|
|
||||
| `buckets.*` | [Bucket Object](/docs/references/cloud/models/bucket) | This event triggers on any buckets event. |
|
||||
| `buckets.*.create` | [Bucket Object](/docs/references/cloud/models/bucket) | This event triggers when a bucket is created.|
|
||||
| `buckets.*.delete` | [Bucket Object](/docs/references/cloud/models/bucket) | This event triggers when a bucket is deleted.|
|
||||
| `buckets.*.files.*` | [File Object](/docs/references/cloud/models/file) | This event triggers on any files event. |
|
||||
| `buckets.*.files.*.create` | [File Object](/docs/references/cloud/models/file) | This event triggers when a file is created. |
|
||||
| `buckets.*.files.*.delete` | [File Object](/docs/references/cloud/models/file) | This event triggers when a file is deleted. |
|
||||
| `buckets.*.files.*.update` | [File Object](/docs/references/cloud/models/file) | This event triggers when a file is updated. |
|
||||
| `buckets.*.update` | [Bucket Object](/docs/references/cloud/models/bucket) | This event triggers when a bucket is updated.|
|
||||
{% table %}
|
||||
* Name
|
||||
* Description
|
||||
---
|
||||
* `buckets.*`
|
||||
*
|
||||
This event triggers on any buckets event.
|
||||
Returns [Bucket Object](/docs/references/cloud/models/bucket)
|
||||
---
|
||||
* `buckets.*.create`
|
||||
*
|
||||
This event triggers when a bucket is created.
|
||||
Returns [Bucket Object](/docs/references/cloud/models/bucket)
|
||||
---
|
||||
* `buckets.*.delete`
|
||||
*
|
||||
This event triggers when a bucket is deleted.
|
||||
Returns [Bucket Object](/docs/references/cloud/models/bucket)
|
||||
---
|
||||
* `buckets.*.files.*`
|
||||
*
|
||||
This event triggers on any files event.
|
||||
Returns [File Object](/docs/references/cloud/models/file)
|
||||
---
|
||||
* `buckets.*.files.*.create`
|
||||
*
|
||||
This event triggers when a file is created.
|
||||
Returns [File Object](/docs/references/cloud/models/file)
|
||||
---
|
||||
* `buckets.*.files.*.delete`
|
||||
*
|
||||
This event triggers when a file is deleted.
|
||||
Returns [File Object](/docs/references/cloud/models/file)
|
||||
---
|
||||
* `buckets.*.files.*.update`
|
||||
*
|
||||
This event triggers when a file is updated.
|
||||
Returns [File Object](/docs/references/cloud/models/file)
|
||||
---
|
||||
* `buckets.*.update`
|
||||
*
|
||||
This event triggers when a bucket is updated.
|
||||
Returns [Bucket Object](/docs/references/cloud/models/bucket)
|
||||
{% /table %}
|
||||
@@ -151,17 +151,29 @@
|
||||
"link": "/docs/authentication-security",
|
||||
"redirect": "/docs/products/auth/security"
|
||||
},
|
||||
{
|
||||
"link": "/docs/products/functions/development",
|
||||
"redirect": "/docs/products/functions/develop"
|
||||
},
|
||||
{
|
||||
"link": "/docs/products/functions/deployment",
|
||||
"redirect": "/docs/products/functions/deploy-from-git"
|
||||
},
|
||||
{
|
||||
"link": "/docs/products/functions/execution",
|
||||
"redirect": "/docs/products/functions/execute"
|
||||
},
|
||||
{
|
||||
"link": "/docs/functions-develop",
|
||||
"redirect": "/docs/products/functions/development"
|
||||
"redirect": "/docs/products/functions/develop"
|
||||
},
|
||||
{
|
||||
"link": "/docs/functions-deploy",
|
||||
"redirect": "/docs/products/functions/deployment"
|
||||
"redirect": "/docs/products/functions/deploy-from-git"
|
||||
},
|
||||
{
|
||||
"link": "/docs/functions-execute",
|
||||
"redirect": "/docs/products/functions/execution"
|
||||
"redirect": "/docs/products/functions/execute"
|
||||
},
|
||||
{
|
||||
"link": "/docs/functions-runtimes",
|
||||
@@ -169,7 +181,7 @@
|
||||
},
|
||||
{
|
||||
"link": "/docs/functions-examples",
|
||||
"redirect": "/docs/products/functions/examples"
|
||||
"redirect": "/docs/products/functions"
|
||||
},
|
||||
{
|
||||
"link": "/docs/migrations",
|
||||
|
||||
@@ -76,13 +76,13 @@
|
||||
<div class="web-big-padding-section-level-2">
|
||||
<section class="web-container web-u-padding-block-end-0">
|
||||
<a
|
||||
href="/blog/post/announcing-init"
|
||||
href="/blog/post/introducing-appwrite-react-native-sdk"
|
||||
class="web-hero-banner-button web-u-margin-block-end-24"
|
||||
>
|
||||
<span class="web-icon-star" aria-hidden="true" />
|
||||
<span class="web-caption-500">New</span>
|
||||
<div class="web-hero-banner-button-sep" />
|
||||
<span class="web-caption-400">Announcing Init</span>
|
||||
<span class="web-caption-400 web-u-trim-1">Introducing Appwrite's React Native SDK</span>
|
||||
<span class="web-icon-arrow-right" aria-hidden="true" />
|
||||
</a>
|
||||
<div class="web-hero is-horizontal">
|
||||
@@ -95,9 +95,10 @@
|
||||
</h1>
|
||||
<div class="u-cross-child-end">
|
||||
<p class="web-description">
|
||||
Appwrite's open-source platform lets you add Auth, DBs, Functions
|
||||
and Storage to your product and build any application at any scale,
|
||||
own your data, and use your preferred coding languages and tools.
|
||||
Build your entire backend within minutes and scale effortlessly
|
||||
using Appwrite's open-source platform. Add Authentication,
|
||||
Databases, Functions, Storage, and Messaging to your projects
|
||||
using the frameworks and languages of your choice.
|
||||
</p>
|
||||
<a
|
||||
href="https://cloud.appwrite.io"
|
||||
@@ -349,7 +350,6 @@
|
||||
/>
|
||||
<h3 class="web-info-boxes-title">
|
||||
<span>HIPAA</span>
|
||||
<span class="web-inline-tag is-pink">Coming Soon</span>
|
||||
</h3>
|
||||
<p class="web-info-boxes-content">
|
||||
Protect sensitive user health data.
|
||||
|
||||
@@ -132,30 +132,6 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="u-flex u-gap-8 u-margin-inline-start-auto u-hide">
|
||||
<li>
|
||||
<a
|
||||
href="https://twitter.com/appwrite"
|
||||
class="web-icon-button"
|
||||
aria-label="Author twitter"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<span class="web-icon-x" aria-hidden="true" />
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
href="https://twitter.com/appwrite"
|
||||
class="web-icon-button"
|
||||
aria-label="Author LinkedIn"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<span class="web-icon-linkedin" aria-hidden="true" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<a
|
||||
href={featured.href}
|
||||
@@ -180,7 +156,7 @@
|
||||
{@const author = data.authors.find(
|
||||
(author) => author.slug === post.author
|
||||
)}
|
||||
{#if author}
|
||||
{#if author && !post.draft}
|
||||
<Article
|
||||
title={post.title}
|
||||
href={post.href}
|
||||
|
||||
@@ -27,7 +27,8 @@ export function load() {
|
||||
timeToRead: frontmatter.timeToRead,
|
||||
author: frontmatter.author,
|
||||
category: frontmatter.category,
|
||||
href: `${base}/blog/post/${postName}`
|
||||
href: `${base}/blog/post/${postName}`,
|
||||
draft: frontmatter.draft
|
||||
};
|
||||
})
|
||||
.sort((a, b) => {
|
||||
|
||||
11
src/routes/blog/author/bradley-schofield/+page.markdoc
Normal file
11
src/routes/blog/author/bradley-schofield/+page.markdoc
Normal file
@@ -0,0 +1,11 @@
|
||||
---
|
||||
layout: author
|
||||
slug: bradley-schofield
|
||||
name: Bradley Schofield
|
||||
role: Software Engineer
|
||||
bio: Integrating platforms and managing data in Appwrite.
|
||||
avatar: /images/avatars/bradley.png
|
||||
twitter: https://x.com/ionicisere
|
||||
github: https://github.com/PineappleIOnic
|
||||
linkedin: https://www.linkedin.com/in/bradley-schofield-7512b7188/
|
||||
---
|
||||
5
src/routes/blog/category/company/+page.markdoc
Normal file
5
src/routes/blog/category/company/+page.markdoc
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
layout: category
|
||||
name: Company
|
||||
description: Get the latest insights and updates about Appwrite.
|
||||
---
|
||||
5
src/routes/blog/category/devrel/+page.markdoc
Normal file
5
src/routes/blog/category/devrel/+page.markdoc
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
layout: category
|
||||
name: DevRel
|
||||
description: Read about developer relations and gain tips and insights on building community and collaboration.
|
||||
---
|
||||
5
src/routes/blog/category/init/+page.markdoc
Normal file
5
src/routes/blog/category/init/+page.markdoc
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
layout: category
|
||||
name: Init
|
||||
description: Read about Init, during which we celebrate and demonstrate new products, features, and functionality for you to build with.
|
||||
---
|
||||
5
src/routes/blog/category/integrations/+page.markdoc
Normal file
5
src/routes/blog/category/integrations/+page.markdoc
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
layout: category
|
||||
name: Integrations
|
||||
description: Learn how to integrate various tools with Appwrite.
|
||||
---
|
||||
5
src/routes/blog/category/security/+page.markdoc
Normal file
5
src/routes/blog/category/security/+page.markdoc
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
layout: category
|
||||
name: Security
|
||||
description: Learn security best practices and trends with our insights.
|
||||
---
|
||||
5
src/routes/blog/category/tutorial/+page.markdoc
Normal file
5
src/routes/blog/category/tutorial/+page.markdoc
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
layout: category
|
||||
name: Tutorial
|
||||
description: Learn how to implement Appwrite into your projects.
|
||||
---
|
||||
@@ -16,6 +16,7 @@ export type AuthorData = {
|
||||
href: string;
|
||||
};
|
||||
export type PostsData = {
|
||||
draft: boolean;
|
||||
title: string;
|
||||
description: string;
|
||||
date: Date;
|
||||
|
||||
@@ -7,6 +7,7 @@ cover: /images/blog/a-recap-of-init/the-recap.png
|
||||
timeToRead: 12
|
||||
author: laura-du-ry
|
||||
category: OSS
|
||||
featured: true
|
||||
---
|
||||
|
||||
Init has come to an end, and we’re happy how all of you showed up and made it an amazing week filled with product announcements, events, content, celebrations, a release, and most of all, community fun!
|
||||
|
||||
@@ -47,7 +47,7 @@ It is possible to enhance accessibility through development as well. In collabor
|
||||
|
||||
Browsers have a default font size that users can change via the browser setting. A pixel is an absolute unit for fixed sizes and spaces that ignores browser settings. This means that if we are using pixels and a user (with or without vision impairment) changes the font size in their browser settings, their setting won't affect our product. That being said, pixels should not cause any problems if the user zooms in, but we make no assumptions about users' preferences. This is why we decided to define the font size in REM, which is a relative unit.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Account } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
|
||||
@@ -44,7 +44,7 @@ Visit the **Domains** tab on the function page and copy the domain URL to test
|
||||
|
||||
Go to the function URL in your web browser, and you'll see a short url like the one shown below.
|
||||
|
||||
# Next Steps
|
||||
# Next steps
|
||||
|
||||
URL shorteners often offer additional features such as tracking click-through rates, providing analytics on link usage, and allowing users to customize the shortened URL to some extent.This Function Template can be extended to perform a lot of functionalities. Some examples are:
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ category: GDPR
|
||||
|
||||
We have always kept strict internal policies with regard to personal data and privacy. But to be GDPR compliant, one must undertake the necessary steps and show proof. We have done this and are pleased that we are now certified with the European General Data Protection Regulation (GDPR) standards.
|
||||
|
||||
Appwrite developers will no longer have to navigate the complex waters of GDPR compliance – we've got you covered. We have undertaken the necessary measures to protect personal information. Our policies, procedures, and infrastructure have been updated, and we are committed to a continuous improvement cycle as time goes by.
|
||||
Appwrite developers will no longer have to navigate the complex waters of GDPR compliance, we've got you covered. We have undertaken the necessary measures to protect personal information. Our policies, procedures, and infrastructure have been updated, and we are committed to a continuous improvement cycle as time goes by.
|
||||
|
||||
If you are interested in having a data processing agreement with Appwrite, you can now find our DPA download button in our console. Click and sign it, and the agreement will be implemented.
|
||||
|
||||
@@ -26,6 +26,6 @@ Here are some technical insights into how we enhance data security:
|
||||
|
||||
As always, with Appwrite, developers can continue creating with peace of mind. Your personal data will not be mistreated.
|
||||
|
||||
Appwrite is also actively working towards compliance with SOC 2 standards and HIPPA, which will be announced at a later date.
|
||||
Appwrite is also HIPAA compliant while actively working towards compliance with SOC 2 standards which will be announced at a later date.
|
||||
|
||||
Further resources: [Documentation](https://appwrite.io/docs/advanced/security/gdpr), [Privacy policy](https://appwrite.io/privacy) , [Cookie policy](https://appwrite.io/cookies)
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
---
|
||||
layout: post
|
||||
title: Appwrite is now HIPAA compliant
|
||||
description: This is another step towards building a platform for developers from all industries.
|
||||
date: 2024-04-11
|
||||
cover: /images/blog/hipaa.png
|
||||
timeToRead: 4
|
||||
author: may-ender
|
||||
category: security
|
||||
---
|
||||
|
||||
We’re happy to announce that Appwrite fully complies with the Health Insurance Portability and Accountability Act (HIPAA), allowing developers who handle sensitive health data to trust Appwrite as their backend.
|
||||
|
||||
## Commitment to data security
|
||||
|
||||
If you’re familiar with Appwrite, you will know that data security is a top priority. We offer out-of-the-box solutions to protect your applications, making your life much easier and your users safer. Announcing our HIPAA compliance is a step to make Appwrite accessible to even more industries.
|
||||
|
||||
## Measures taken to comply
|
||||
|
||||
To attain HIPAA compliance, we’ve undergone audits and implemented measures to safeguard personal information, updating our policies, procedures, and infrastructure to meet the strict requirements of HIPAA regulations.
|
||||
|
||||
So what did we do to comply? We’ve set measures and controls to maintain security, availability, processing integrity, and confidentiality, including:
|
||||
|
||||
- A strict data backup schedule.
|
||||
- An extended business continuity plan.
|
||||
- Data retention rights for individuals as outlined in our Privacy Policy.
|
||||
- Intrusion detection and penetration testing.
|
||||
- Encryption of data transmitted between Appwrite and users using transport layer security (TLS) and HTTP strict Transport Security, ensuring confidentiality both at rest and during transmission.
|
||||
- Access to environments containing customer data is strictly controlled, requiring authentication and authorization through multi-factor authentication (MFA).
|
||||
|
||||
Appwrite safeguards personal information to the same extent it protects its own, complying with relevant privacy laws and regulations in the jurisdictions where its services are offered.
|
||||
|
||||
Please note that while Appwrite Cloud serves as a HIPAA-compliant platform to handle data,
|
||||
it is the responsibility of developers to ensure that their application is also compliant with HIPAA regulations.
|
||||
|
||||
Looking for a HIPAA compliant backend provider? Or looking to replace Firebase? Appwrite can be your solution. Take a look at our [documentation](https://appwrite.io/docs/advanced/security) to learn more about our security.
|
||||
@@ -7,7 +7,7 @@ cover: /images/blog/init-announcement.png
|
||||
timeToRead: 4
|
||||
author: eldad-fux
|
||||
category: open-source
|
||||
featured: true
|
||||
featured: false
|
||||
---
|
||||
|
||||
We are very excited to announce Init.
|
||||
|
||||
@@ -39,7 +39,7 @@ One great aspect of Appwrite 2FA is that it can be used in conjunction with any
|
||||
|
||||
To use 2FA, it needs to be enabled on a user’s account. This can be achieved by calling `account.updateMFA()`.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Account } from "appwrite";
|
||||
|
||||
// Init SDK
|
||||
|
||||
181
src/routes/blog/post/appwrite-compared-to-supabase/+page.markdoc
Normal file
181
src/routes/blog/post/appwrite-compared-to-supabase/+page.markdoc
Normal file
@@ -0,0 +1,181 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Appwrite vs Supabase: a comparison of Backend-as-a-Service platforms"
|
||||
description: Get a comprehensive comparison between Appwrite and Supabase to decide what platform to use for your project's backend.
|
||||
date: 2024-03-01
|
||||
cover: /images/blog/appwrite-compared-to-supabase/cover.png
|
||||
timeToRead: 7
|
||||
author: aditya-oberai
|
||||
category: product
|
||||
---
|
||||
|
||||
If you are looking to build a mobile app, website, tool, or any other application that needs a backend, then you also know the daunting tasks that await. This is probably what brought you to this blog in the first place: looking for a solution to take care of your backend. One of these solutions is a Backend-as-a-Service (BaaS). It provides pre-built backend infrastructure and services to simplify app development, handling server-side tasks like data storage, user management, APIs, server maintenance, security, database management, and more. Two of these solutions are Appwrite and Supabase, and although both are solid options for your BaaS, they’re somewhat different.
|
||||
|
||||
This article will give you a rundown of Appwrite and Supabase to understand the feature sets. Then, we’ll provide a quick Appwrite vs Supabase comparison so you can understand how each provider will fit your specific needs.
|
||||
|
||||
# Appwrite
|
||||
|
||||
In 2019, [Appwrite](https://appwrite.io/) started as an open-source project to make software development more accessible and enjoyable. It is a Backend as a Service platform with a vibrant developer community. You can self-host Appwrite on your server or utilize [Appwrite Cloud](https://cloud.appwrite.io/). Appwrite provides a wide range of features, including user authentication, databases, storage, real-time features, and functions. It is known for its flexibility, security, and extensibility, enabling you to implement custom backend logic and build applications tailored to your needs. You can view Appwrite’s source code on [GitHub](https://github.com/appwrite/appwrite).
|
||||
|
||||
# Supabase
|
||||
|
||||
Supabase positions itself as an alternative to Firebase, which offers a range of tools and services for developing and deploying web and mobile apps. It was founded in 2020 and aims to be a user-friendly, scalable, and secure platform for creating modern applications. Supabase provides features for user authentication, app analytics, databases, real-time, and functions. It supports various platforms like web, Android, and iOS and can easily integrate with other tools and services. You can use their Cloud platform or self-host. You can view Supabase’s source code on [GitHub](https://github.com/supabase/supabase).
|
||||
|
||||
# Features compared
|
||||
|
||||
When looking into a BaaS solution, it is good to understand how the products and features can serve your project’s needs. We compiled a list of similarities and differences between Appwrite and Supabase for you to understand both offerings better.
|
||||
|
||||
## Authentication
|
||||
|
||||
Authentication is the process of verifying a user's identity to ensure that only the appropriate individuals have access to their private data. Different authentication methods include email and passwords, passwordless login via emails and phone numbers, or applications that offer single sign-on (SSO) capabilities. It is usually the initial step in application development for developers. BaaS platforms simplify this process by offering SDKs and APIs.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both offer robust authentication capabilities, including user registration, login, and passwordless login options.
|
||||
- They both support various authentication methods, such as email and password, social logins (Google, Facebook, etc.), and device authentication.
|
||||
- Role-based access control (RBAC) is available to manage user permissions and restrict access to resources.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite's authentication system allows developers to integrate with any existing external authentication systems through [custom token login](https://appwrite.io/docs/products/auth/custom-token).
|
||||
- Appwrite provides two user grouping and categorization features: teams and labels, for simpler permissions management.
|
||||
- Supabase offers integration with SAML for enterprise SSO.
|
||||
|
||||
## Databases
|
||||
|
||||
A database is an organized collection of information stored in a way that allows for easy access, retrieval, management, and updating. Databases store and manage large volumes of structured data, supporting activities such as data storage, analysis, and management. They are integral to any application.
|
||||
|
||||
Both Appwrite and Supbase provide databases that can be used depending on the needs of your project.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both provide a user-friendly database interface for creating and managing tables, indexes, and relationships.
|
||||
- They both support relational databases.
|
||||
- Schema migrations are available to manage database changes in a structured manner.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite offers an abstraction layer above MariaDB as part of its API, offering a simpler developer experience for data consumption and user permissions management.
|
||||
- Appwrite offers offset and cursor pagination out-of-the-box to developers, which will have to be manually developed with Supabase.
|
||||
- Supabase's PostgreSQL database provides more flexibility by giving developers direct access to the database but substantially increases the learning curve.
|
||||
|
||||
## Storage
|
||||
|
||||
Storage allows you to manage files in your project. It can store images, videos, documents, and other project files. Storage can be a crucial requirement for any application that operates on binary data (e.g., social media platforms), and here's what Appwrite and Supbase have to offer:
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both provide object storage for storing and managing files, images, and other binary data.
|
||||
- Access control is available to manage files and restrict access.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite offers file previews and thumbnails to enhance user experience.
|
||||
- Appwrite offers an image manipulation API, including functionalities such as manipulating resolution, image reformatting, caching, and compression, in the free tier. Supabase offers image manipulation only in their paid tiers.
|
||||
- Supabase offers a CDN to serve assets via an edge network in their paid tiers.
|
||||
|
||||
## Functions
|
||||
|
||||
Functions are "self-contained" modules of code that accomplish a specific task. BaaS platforms make it easier for you to extend the services by using functions with code snippets.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both Appwrite and Supabase provide serverless functions for executing code on demand.
|
||||
- They both offer triggers to execute functions on events, such as file uploads or database changes.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite supports [functions runtimes across over 10 programming languages](https://appwrite.io/docs/products/functions/runtimes), including JavaScript, Python, PHP, and Dart, whereas Supabase officially supports only one programming language, TypeScript.
|
||||
- Appwrite’s functions runtimes have been developed in-house, enabling a more curated developer experience and the ability to develop runtimes more quickly, whereas Supabase uses a 3rd party offering, limiting the pace of development and control over experience.
|
||||
- Appwrite offers a marketplace of function templates that are ready to deploy with a few button clicks, which Supabase does not offer.
|
||||
|
||||
## Realtime
|
||||
|
||||
Real-time, by definition, means "without significant delay.” You can use it to get constant updates on any activities that occur within the application you are building. This can be applied in various ways, such as a chat application. While real-time features can be complex to build, you can use Appwrite and Supabase to achieve them quickly.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Appwrite and Supabase provide real-time data synchronization using WebSockets.
|
||||
- Both of them support broadcasting changes to large audiences.
|
||||
- They both offer client libraries for various programming languages.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite also supports real-time updates across every product (e.g., function executions, file uploads, account creation) whereas Supabase supports real-time updates for database changes only.
|
||||
- Supabase offers state tracking and synchronization across users out of the box.
|
||||
|
||||
## Messaging
|
||||
|
||||
Messaging allows you to implement communications in your application. You can use this to send information and updates directly to users through various methods, such as push notifications, SMS, and email. Currently, Supabase has no direct messaging features, whereas Appwrite does.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- You can use real-time features along with databases in both Appwrite and Supabase to create a chat application.
|
||||
- You can use functions in both Appwrite and Supabase to use external providers for SMS and email.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite Messaging features ten different providers to leverage major communications providers for SMS, email, and push notifications. It offers user segregation, message scheduling, and message previews as well. Supabase offers none of these.
|
||||
|
||||
## Self-hosting
|
||||
|
||||
Self-hosting support essentially means a developer can deploy the application on their infrastructure rather than use a managed solution. This allows the developer complete control over their data and more flexibility to tweak how the application works and pick their own hosting solution. Being open-source, both Appwrite and Supabase allow developers to self-host them.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both Appwrite and Supabase are self-hosted using Docker. They both offer Docker Compose files to deploy different components of the platforms and can be built directly from their GitHub repositories.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite offers a [single installation command](https://appwrite.io/docs/advanced/self-hosting#install-with-docker) with a pre-built configuration to simplify the self-hosting process, making it more straightforward and cohesive. Supabase, on the other hand, expects the developer to manually configure each component during the setup process.
|
||||
- Appwrite offers one-click setups for DigitalOcean, Gitpod, and Akamai Compute. Supabase offers the same for DigitalOcean and AWS.
|
||||
- Supabase features community-maintained helm charts to self-host using Kubernetes.
|
||||
|
||||
## Support
|
||||
|
||||
Any developer-first product, regardless of how good and simple it may be, will need a system for support in case its consumers face any issues. Both Appwrite and Supabase have developed support offerings to ensure their consumers can share feedback and get the necessary help.
|
||||
|
||||
*Similarities*:
|
||||
|
||||
- Both Appwrite and Supabase offer comprehensive documentation and community forums for self-help.
|
||||
- They both provide paid support plans for priority email assistance.
|
||||
- They both have active open-source communities where users can collaborate and share knowledge.
|
||||
|
||||
*Differences*:
|
||||
|
||||
- The Appwrite community is very active and provides fast and comprehensive support.
|
||||
- Supabase provides a higher tier of support for a higher price.
|
||||
|
||||
# Conclusion
|
||||
|
||||
While Appwrite and Supabase are great Backend-as-a-Service (BaaS) offerings that support numerous SDKs, they differ in engineering approaches. The choice between Appwrite and Supabase hinges on your needs and preferences.
|
||||
|
||||
Here’s a table that compares both Appwrite and Supabase:
|
||||
|
||||
| Feature | Appwrite | Supabase |
|
||||
| --- | --- | --- |
|
||||
| Database | Relational (MariaDB) | Relational (PostgreSQL) |
|
||||
| Serverless functions runtimes | 10+ languages supported | Only 1 language officially supported |
|
||||
| Self-hosting / Cloud | Self-hosting and Cloud available | Self-hosting and Cloud available |
|
||||
| Supported programming languages | Supports https://appwrite.io/docs/sdks in 10 languages JavaScript, Python, PHP, Kotlin, Dart | Supports SDKs in 6 languages |
|
||||
| Pausing of projects | Free projects are not paused ever | Free projects are paused after 1 week of inactivity |
|
||||
| Functions marketplace | Has a marketplace featuring a variety of function templates and integrations such as Discord bots, payments with Stripe, ChatGPT API, etc. | No functions marketplace |
|
||||
| Permissions | A simple-to-use permissions system that is consistent across all Appwrite products | Complex permissions system that needs knowledge of SQL to get started |
|
||||
| Messaging providers | 10 providers covering SMSes, emails, and push notifications | Zero |
|
||||
|
||||
Here's a price comparison between Appwrite and Supabase to help you choose the one that best suits your needs:
|
||||
|
||||
| Feature | Appwrite | Supabase |
|
||||
| --- | --- | --- |
|
||||
| Pricing Model | Tiered pricing | Tiered pricing |
|
||||
| Paid Plan | Starts at $15 per month | Starts at $25 per month |
|
||||
|
||||
# Resources
|
||||
|
||||
If you want to learn more about Appwrite, you can find more resources below.
|
||||
|
||||
- [Appwrite documentation](https://appwrite.io/docs) - Visit Appwrite’s docs to learn how to get started and more about Appwrite’s functionality.
|
||||
- [Appwrite Migration API](https://appwrite.io/docs/advanced/migrations/supabase) - Find out how to transfer your applications from Supabase to Appwrite in just a few steps.
|
||||
- [Appwrite GitHub repo](https://github.com/appwrite/appwrite/stargazers) - Explore Appwrite’s code and architecture and see how you can contribute to Appwrite.
|
||||
- [Appwrite Discord](https://appwrite.io/discord) - Join Appwrite’s Discord server and be part of a vibrant community.
|
||||
- [Appwrite YouTube](https://www.youtube.com/@Appwrite) - Visit Appwrite YouTube for hands-on tutorials to help you learn.
|
||||
193
src/routes/blog/post/appwrite-decoded-dennis-ivy/+page.markdoc
Normal file
193
src/routes/blog/post/appwrite-decoded-dennis-ivy/+page.markdoc
Normal file
@@ -0,0 +1,193 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Appwrite Decoded: Dennis Ivy"
|
||||
description: In this blog, we put Dennis Ivy in the spotlight and share his side of the story.
|
||||
cover: /images/blog/appwrite-decoded-dennis/dennis-cover.png
|
||||
timeToRead: 12
|
||||
date: 2024-04-22
|
||||
author: laura-du-ry
|
||||
category: culture
|
||||
---
|
||||
|
||||
The team behind Appwrite is situated worldwide and works together daily from different time zones. We’re proud of the remote and open source culture the team has built so far. In Appwrite Decoded, we introduce the people behind the code and celebrate them.
|
||||
|
||||
In this blog, we'll walk you through the career journey of Dennis Ivy, one of our Developer Advocates. You'll discover how his passion for technology, commitment to community engagement, and practical career insights make a real difference in the tech world, from his early days as a skeptic of backend as a service (BaaS) tools to his current role leading developer education. Dennis’s story is all about growth, learning, and the impact of staying true to what excites you in your work.
|
||||
|
||||
# From self taught to teaching others
|
||||
|
||||
Dennis, fueled by his passion for technology, turned his self-taught coding skills into a dynamic career, all without the formal education you might expect. His journey kicked off not in a classroom but from a deep curiosity. Dennis dove headfirst into the coding world, motivated by the goal of launching his own online businesses. It wasn't just about building for companies; it was about mastering the process of creation and then sharing that knowledge with anybody who needs it.
|
||||
|
||||
> "I started coding out of pure curiosity, and before I knew it, I was hooked. Building projects was exciting, but sharing what I learned was the real game changer.”
|
||||
>
|
||||
|
||||
He took this passion to [YouTube](https://www.youtube.com/@DennisIvy), creating a space where he could pass on his experiences, turning every tutorial into a collaborative learning journey.
|
||||
|
||||

|
||||
|
||||
Dennis's path was anything but traditional. Drawn to the endless possibilities of digital spaces, he saw a chance to break free from the traditional physical business model and reach people on a global scale.
|
||||
|
||||
> "The digital world was like a vast ocean, and I just had to learn how to sail it. The potential to scale and connect was limitless.”
|
||||
>
|
||||
|
||||
This insight led him to explore digital marketing and web development, eventually founding a digital marketing and web development agency. While operating his agency for several years, he gained experience managing and growing a business.
|
||||
|
||||
Now, as a developer advocate, Dennis continues to share, connect, and inspire. What he values most about his job is the balance it offers.
|
||||
|
||||
> "It's like being in a sandbox, but the castles I build now can reach and teach others.”
|
||||
>
|
||||
|
||||
This blend of independence and the opportunity to work remotely allows him to control his routine while still engaging deeply with the community. The joy of his work comes not just from the projects he completes but from the lightbulb moments he witnesses in others as they grasp the once challenging concepts of coding.
|
||||
|
||||
> "It's being able to actually see people take a concept that was difficult to understand and then have that 'aha' moment of 'wow, I finally understand what I'm trying to learn.'"
|
||||
>
|
||||
|
||||
# Choosing passion over routine
|
||||
|
||||
Before Dennis switched to Appwrite, in his old gig, things were okay on paper—nice paycheck, stable job—but it was like walking down the same road every day, never really getting satisfied. It wasn't about the money for him; it was about finding work that made him actually want to get out of bed in the morning, something that sparked a bit of fire in his eyes. That's exactly what he found at Appwrite.
|
||||
|
||||
> "Landing at Appwrite was like catching the perfect wave. I saw this product, and I just knew it was going to make some serious noise in the industry.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
For Dennis, Appwrite boils down to three big ideas: open source, community, and, yeah, excitement. Open source is the heartbeat of Appwrite—it's about doing things together, out in the open, making something cool that everyone can be a part of.
|
||||
|
||||
> "It's teamwork, through and through.”
|
||||
>
|
||||
|
||||
At Appwrite, it's never just another day at work; it's another chance to dive into something that really matters with a team that's all about pushing boundaries.
|
||||
|
||||
Appwrite's focus on [community](https://appwrite.io/community) stands out, from the active engagement on the Discord server to the support of educational meetups.
|
||||
|
||||
> "I've never been part of a company this dedicated to its community.”
|
||||
>
|
||||
|
||||
This commitment to building a supportive environment was recognized when Appwrite received the Best DevRel Team award in 2023, a clear nod to our exceptional community engagement.
|
||||
|
||||

|
||||
|
||||
Dennis is excited about Appwrite’s future, especially considering the competitive field with some big names in the industry. It's not just about being in the ring with the giants; it’s the excitement of innovation and the commitment to introducing bold and ambitious products that drive him.
|
||||
|
||||
> “Tackling projects that might look a bit intimidating or complex, but have the potential to leave a mark? That's what fires me up. Imagining all the cool stuff we can achieve looking forward—now that's a vision I get behind.”
|
||||
>
|
||||
|
||||
# Finding a new perspective on development
|
||||
|
||||
Before teaming up with Appwrite, Dennis rarely had [back-end as a service](https://appwrite.io/blog/post/leveraging-baas-tools-to-scale-faster) (BaaS) tools on his radar. As a die-hard back-end engineer, he was a bit skeptical. He questioned how these tools would fit into his skill set and workflow. Appwrite turned those doubts into a definitive yes, proving that such tools could boost efficiency and speed, complementing his skills rather than constraining them.
|
||||
|
||||
> "Initially, I was all about refining and expanding back-ends on my own. Appwrite shifted my focus, encouraging a broader, product-centric perspective over mere code perfection."
|
||||
>
|
||||
|
||||
In terms of teamwork, Dennis views it through a pragmatic lens. It's not about keeping everyone occupied with tasks; it’s about strategic synergy, aligning tasks with individual strengths to optimize the team's output. This approach not only boosts efficiency but also fosters an atmosphere where each member gets to be the star in their domain.
|
||||
|
||||
> "We lean into our strengths—everyone brings their A-game, making us unstoppable as a unit."
|
||||
>
|
||||
|
||||

|
||||
|
||||
One of Dennis's standout abilities is his knack for spotting areas within projects that need fine-tuning. Being both a user and an advocate of Appwrite gives him a dual perspective; he sees things from a user’s angle, which means he’s on the front line for catching glitches or figuring out what could be better. This skill comes in handy, especially when it’s time to level up content. Whether it’s filling in the blanks in a guide or adding the missing piece to a video, Dennis has an eye for what’s needed. He’s all about creating content that doesn’t just talk at users but really speaks to them, breaking down Appwrite's ins and outs into something everyone can grasp. His goal? To ensure everyone understands what Appwrite can do and how to make the most of it.
|
||||
|
||||
> “I’m here to make sure our content not only covers everything Appwrite is capable of but also actually helps you use it.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
Finding his place at Appwrite has been a game-changer for Dennis. No more feeling stuck in a box or like he’s just going through the motions. Here, he’s found the space to shine, contributing big ways to content and how the product shapes up. It’s the kind of work that motivates him to get up in the morning, knowing he’s part of a team that truly values his contributions.
|
||||
|
||||
> “I’m all in on what we’re building here, dedicating hours because it matters—to me, to the team, and to our users.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
What Dennis has achieved so far at Appwrite is a strong indicator of what he is up to in the future. What's at the top of his list? The revival of Appwrite's [YouTube channel](https://www.youtube.com/appwrite) and deeper engagement with its tools led to a significant uptick in audience growth—almost doubling since he began contributing to video content. This initiative not only raised awareness about the platform's educational resources but also marked a personal milestone in his career.
|
||||
|
||||
> “I’m definitely proud of the fact that I've brought awareness there, and seeing the community grow is incredibly rewarding."
|
||||
>
|
||||
|
||||
Another highlight for him was taking the stage in New York, representing Appwrite at a conference—a moment where he got to share the essence of Appwrite with a broader audience, feeling a deep sense of accomplishment.
|
||||
|
||||

|
||||
|
||||
His vision for Appwrite is ambitious yet clear: positioning it as the foremost choice for back-end services.
|
||||
|
||||
> "I'm all in on making Appwrite the top pick for anyone needing back-end services."
|
||||
>
|
||||
|
||||
His game plan involves not just showcasing its solid features but also ensuring it’s known for top-notch developer education and an unbeatable user experience. His dedication is all about shining a spotlight on Appwrite, ensuring it's recognized as an essential player in the tech arena.
|
||||
|
||||

|
||||
|
||||
On the personal front, Dennis is entering into exciting new territory. A publishing house has expressed interest in his expertise on various topics, presenting him with an opportunity to broaden his influence. He has already started working on the preliminary content, dedicating his energy to this new project, which has the potential to share his insights and experiences on a wider scale.
|
||||
|
||||
> “I’m excited to develop content that resonates and educates.”
|
||||
>
|
||||
|
||||
# Work from home, don’t live at work
|
||||
|
||||
Dennis has a keen perspective on remote work life. It’s certainly a mixed bag. The absence of face-to-face communication is deeply felt, as it removes the nuanced understanding and connection from physically sharing space with colleagues.
|
||||
|
||||
However, the advantages of remote work shine through, especially in how it enables organizations to scale rapidly and tap into talent beyond geographical boundaries. Appwrite, by embracing remote work, spans multiple time zones, enhances operational efficiency and offers team members the flexibility to tailor their work schedules.
|
||||
|
||||
> "Discovering talent from the comfort of your own living room? That's invaluable. It's how we manage to be everywhere, all at once."
|
||||
>
|
||||
|
||||

|
||||
|
||||
For Dennis, flexibility isn’t just about geographic freedom; it's about redefining productivity on one's own terms and escaping the 9-to-5 mold. Appwrite's culture supports this vision with daily check-ins that ensure accountability. Dennis appreciates how these practices reinforce team focus and cohesion.
|
||||
|
||||
Maintaining personal discipline and a distinct separation between work and home life is essential, Dennis advises. For those balancing family responsibilities, setting clear boundaries ensures that work concerns don’t encroach on personal time and vice versa.
|
||||
|
||||
> “Keeping my home free from work stress is important. I separate professional discussions from my personal life until the workday ends.”
|
||||
>
|
||||
|
||||
It’s also about creating a dedicated workspace that’s all business during work hours. For Dennis, this means rituals like dressing for work, even if the commute is just across the hallway.
|
||||
|
||||
> Respecting the work you do, no matter the location, is crucial. Even for minor calls, I make sure to look presentable. It's about blending the professional feel of an office with the comfort of home—the best of both worlds.”
|
||||
>
|
||||
|
||||
This approach not only boosts his productivity but also preserves a healthy balance between work obligations and personal life.
|
||||
|
||||
# From insight to impact, advocating to the community
|
||||
|
||||
Dennis is genuinely proud to represent Appwrite, cherishing the chance to engage directly with users and watch their journey from confusion to clarity. Witnessing users reach that "aha" moment, where everything clicks and they see the full potential of what they can do with the product, is a highlight for him.
|
||||
|
||||
> "It's incredible to see users evolve from a place of uncertainty about what we offer to a point where they grasp the potential of what they can create with us. That’s a big win in my book."
|
||||
>
|
||||
|
||||
This aspect of community engagement doesn't just show him the direct impact of his work; it’s a major source of joy.
|
||||
|
||||
In his interactions with the community, Dennis treasures the mosaic of experiences and backgrounds he comes across. From industry veterans with years of wisdom to eager beginners just starting their journey, and resilient individuals navigating career changes, each interaction is a chance to connect, share insights, and offer support, enriching his understanding of the tech community’s diverse landscape.
|
||||
|
||||
> "Getting to really connect, learn who they are, share stories, and sometimes offer a piece of advice—there’s excitement in that. The tech community is a vast, vibrant mix of people from every possible background. Engaging with such a broad spectrum is genuinely uplifting.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
Stepping into Appwrite isn’t for those who shy away from a challenge, as Dennis points out:
|
||||
|
||||
> “If you’re coming on board, be ready to hit the ground running.”
|
||||
>
|
||||
|
||||
This isn’t just any routine job; Appwrite is built on a culture of proactive engagement and meaningful contribution. For those eyeing a spot in this dynamic crew, Dennis advises preparing themselves for an immersive experience. At Appwrite, every opinion matters, and ideas are not just acknowledged—they're brought to life. This approach stands in sharp contrast to environments where feedback might silently disappear into the void. The ethos here champions meaningful involvement, where each team member plays a crucial role in driving the product forward.
|
||||
|
||||
> “So, yes, gear up for some real work, expect to get your hands dirty, but also know that your ideas will pave the path.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
For developers, professionals, or anyone stepping into new territory, Dennis’s advice is straightforward yet profound:
|
||||
|
||||
> “Waiting for the stars to align? Don’t. Just dive in.”
|
||||
>
|
||||
|
||||
Whether it's launching into a project, gearing up for an interview, or mastering a new skill, the notion of being fully prepared is a myth, and hesitancy can be a barrier to progress. Procrastination often masquerades as preparation.
|
||||
|
||||
> “This isn’t just about coding but applies to many walks of life; whatever you're doing, go for it.”
|
||||
>
|
||||
|
||||
If you’re looking to learn more about Dennis or connect with him, visit his social profiles:
|
||||
|
||||
- [LinkedIn](https://www.linkedin.com/in/dennis-ivanov/)
|
||||
- [Twitter](https://twitter.com/dennisivy11)
|
||||
- [GitHub](https://github.com/divanov11)
|
||||
- [Instagram](https://www.instagram.com/dennisivy11/)
|
||||
@@ -0,0 +1,186 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Appwrite Decoded: Khushboo Verma"
|
||||
description: In this blog, we put Khushboo Verma in the spotlight and share her side of the story.
|
||||
cover: /images/blog/appwrite-decoded-khushboo/khushboo-cover.png
|
||||
timeToRead: 10
|
||||
date: 2024-03-21
|
||||
author: laura-du-ry
|
||||
category: culture
|
||||
---
|
||||
|
||||
The team behind Appwrite is situated worldwide and works together daily from different time zones. We’re proud of the remote and open source culture the team has built so far. In Appwrite Decoded, we introduce the people behind the code and celebrate them.
|
||||
|
||||
In this episode we will take you through Khushboo Verma’s career journey, a software engineer at Appwrite who embodies the power of community engagement and leadership in tech.
|
||||
|
||||
# On and off campus advocate
|
||||
|
||||
Khushboo earned her degree in computer science engineering from one of the largest all-women's universities in Asia. However, her university life was about more than just hitting the books. It was about fostering a sense of community.
|
||||
|
||||
> "I led numerous workshops on campus and worked to build communities not just within our university but also at a state level.”
|
||||
>
|
||||
|
||||
She recognized the potential among women and was instrumental in proving that software engineering wasn't just a man's world.
|
||||
|
||||
> "In our university, women were very hardworking and had access to the right opportunities, something that wasn't quite the same in other universities. So, through communities, I tried to bridge that gap as much as possible and always advocated for diversity and inclusion.”
|
||||
>
|
||||
|
||||
Khushboo didn't stop there. She actively engaged in several community programs, like the Microsoft Student Ambassador and Google Machine Learning programs. These experiences expanded her horizon beyond the university walls, keeping her in the loop with the latest tech trends and what everyone was exploring in their spare time. Landing internships at big names like Microsoft and Adobe as a software engineer and product intern, respectively, was just the icing on the cake. These opportunities didn't just add to her resume, but they advanced her career forward, offering valuable experience in the dynamic tech landscape.
|
||||
|
||||

|
||||
|
||||
> "All of this motivated me to contribute more to the software engineering space, a field I truly love."
|
||||
>
|
||||
|
||||
After graduating, she joined Microsoft full-time as a software engineer and explored the cloud computing space working with the Azure storage team. But despite her new role, she still was eager to be involved with the community. During this period, she also got the opportunity to speak publicly. From international stages at Microsoft Ignite and Microsoft Build to Pycon India, she was there, sharing her knowledge, leading hands-on coding workshops, and everything in between.
|
||||
|
||||

|
||||
|
||||
> "I also got involved with GitHub Campus Experts, which was about being a part of this global network of student leaders who are all about pushing for open source and making tech communities more inclusive."
|
||||
>
|
||||
|
||||

|
||||
|
||||
So, why does she pour so much into community work? It's about giving back to the place that gave her so much.
|
||||
|
||||
> “I believe communities have this amazing power to lift people up, to help them become the best version of themselves. That's been true for me, so I see it as my responsibility to give it back."
|
||||
>
|
||||
|
||||
This connection to her community isn't just a side project, it's a core part of who Khushboo is.
|
||||
|
||||
> "It's more than just work. It's a passion that's really close to my heart.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
# Joining Appwrite through community
|
||||
|
||||
Her journey to Appwrite is nothing short of inspirational. Back when she was hosting a podcast called "Tech Interviews Simplified" for GitHub Education, she had the chance to invite Aditya, a Developer Advocate from Appwrite, to discuss DevRel roles. Eldad, the CEO of Appwrite, also joined the live stream to support Aditya, setting the stage for what was to come.
|
||||
|
||||
> "After the show wrapped up, Aditya and I had a great conversation about Appwrite, his reasons for joining, and where I could dive deeper into learning about it.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
When the time came for a new challenge post-Microsoft, she remembered that conversation and reached out to Eldad. Everything clicked into place from there, as if it was meant to be.
|
||||
|
||||

|
||||
|
||||
Her favorite part about working at Appwrite? It's the opportunity to shoulder a lot of responsibility. This keeps her learning journey continuously active.
|
||||
|
||||
> "What's more, the people here are incredibly supportive and approachable, making the learning process not just easy, but fun and exciting too."
|
||||
>
|
||||
|
||||
For Khushboo, it's all about the win-win: tackling high-impact projects with a swift and efficient process. This setup not only supports her learning but also ensures she's always surrounded by a team ready to lend a hand.
|
||||
|
||||
> "Software engineering is very complex and filled with challenges. Often, we find ourselves diving into unknown waters, tackling problems that no one has solved before.”
|
||||
>
|
||||
|
||||
This is precisely why she values being part of a team so highly. When you hit a snag or find your motivation lacking, it's the team that comes to your rescue. You're surrounded by a mix of people who've been in your shoes or who can help you overcome obstacles and encourage you to excel. For her, it's more than just collaboration, it's about cultivating a supportive environment.
|
||||
|
||||
> "It's a place where newcomers are nurtured, and the more experienced offer guidance and mentorship."
|
||||
>
|
||||
|
||||
In Khushboo's eyes, being part of a team means you're in a constant state of growth, always learning, and always helping others advance along with you.
|
||||
|
||||

|
||||
|
||||
When asked to describe Appwrite in three words, Khushboo immediately says "ambition."
|
||||
|
||||
> "We're always pushing the envelope, striving to achieve more and do our best.”
|
||||
>
|
||||
|
||||
“Collaboration” comes next on her list.
|
||||
|
||||
> "It's incredible to see how the design, product, engineering, and growth team work together. The level of collaboration is amazing, allowing us to see the product's journey from start to finish."
|
||||
>
|
||||
|
||||
But what really sealed the deal for her was the “culture.”
|
||||
|
||||
> "The culture here was a major deciding factor for me. It's refreshing to be part of a workspace that's not only supportive and friendly but also acknowledges and celebrates each employee's efforts. This makes Appwrite a fantastic place to work."
|
||||
>
|
||||
|
||||
# Thriving in her role
|
||||
|
||||
At Appwrite, there's real trust in Khushboo's abilities. When she faces a new task, even if it's something she hasn't tackled before, the support from her team is clear. They make it a point to ensure she's working on projects that genuinely excite her. It’s a way to keep her engaged and focused on what she loves doing most.
|
||||
|
||||
> "They'll lay out a bunch of important projects and ask me, 'What excites you the most?'"
|
||||
>
|
||||
|
||||

|
||||
|
||||
> "And, really, everyone at Appwrite is just so smart."
|
||||
>
|
||||
|
||||
Being surrounded by such talented individuals is a daily motivation, constantly inspiring her to aim higher in her professional and personal life.
|
||||
|
||||

|
||||
|
||||
But it's not all about the work. Appwrite values her holistic growth. Despite being a software engineer, she's encouraged to explore her passions beyond coding. Whether it's public speaking or content creation, there's always support for her to engage in activities beyond her core responsibilities.
|
||||
|
||||
> "It's an amazing setup that's enhanced my growth more than I ever imagined.”
|
||||
>
|
||||
|
||||

|
||||
|
||||
With Appwrite, she stepped into an environment where openness and transparency were more than just ideals—they were practiced daily. Getting a grip on the company’s bigger picture wasn’t just encouraged. It was essential. Seeing the direct line between her work in engineering and the company's achievements was a breath of fresh air.
|
||||
|
||||
> “I found myself collaborating more closely with other teams in a way that was both new and exciting. It’s one thing to work on a project, but it’s another to see your piece fit into the puzzle, contributing to something that we all have a hand in.”
|
||||
>
|
||||
|
||||
This approach didn’t just widen her view on how businesses operate, it also reshaped her entire mindset toward working together and solving problems. The impact of these experiences has been profound, leaving a lasting impression on her professional path.
|
||||
|
||||

|
||||
|
||||
# Past and future through Appwrite
|
||||
|
||||
Working on [Appwrite Functions](https://appwrite.io/docs/products/functions) was a real journey of discovery for Khushboo. Starting from square one, she was prepared to tackle every detail from the ground up. The initial steps of drafting a detailed design document and steering it through the approval stages were just the prologue. The real excitement kicked in as she began building the feature from zero, witnessing its progression to a live environment. But for Khushboo, the project didn’t end with deployment. She was keen on hearing the community's voice, eagerly welcoming their feedback to enhance the feature further. Integrating this feedback, she fine-tuned the function to better meet user expectations. The community’s positive response was incredibly affirming, fueling her drive to innovate and keep exceeding what’s possible.
|
||||
|
||||
> "At Appwrite, I see tremendous room for personal and professional development, especially as the product evolves.”
|
||||
>
|
||||
|
||||
Every day is a chance for her to polish her system design abilities and advance as a self-reliant software engineer. As she looks to the future, she's eager to embrace a leadership position, whether it be technical or people-oriented, guided by a mindset of openness to new challenges. Yet, at the core of her ambition lies a genuine desire to contribute meaningfully and witness the impact of her work on users. This sentiment resonates with both her friendly nature and professional approach.
|
||||
|
||||
# Keeping it real with remote work
|
||||
|
||||
Switching from the structured environment of an office to the flexibility of remote work initially presented a few challenges for Khushboo. Adjusting to Appwrite's remote nature didn't happen overnight. However, she quickly appreciated the benefits of asynchronous communication, which was crucial in maintaining transparency and fostering teamwork despite the team being spread across the globe. Navigating the challenges of interacting effectively with teammates in various time zones and cultural contexts was a learning curve.
|
||||
|
||||
> "Appwrite really supports us by providing options like co-working spaces. I've taken to working from one, and it’s a game-changer. It brings a bit of the office vibe back, allowing me to hang out with professionals from other fields and partake in the communal energy and events typical of an office setting."
|
||||
>
|
||||
|
||||
She's all about taking regular breaks, whether for a quick walk in the park or chatting with a coworker. It's one of the perks of remote work—being able to set your own schedule and work when you're feeling most productive. Remote work has its challenges, but Khushboo is a shining example that with the right mindset and a handful of clever strategies, not only can you navigate these challenges, but also fully tap into the wealth of benefits remote work offers.
|
||||
|
||||

|
||||
|
||||
# Career tips
|
||||
|
||||
If you have your eyes on a software engineering career, Khushboo has some golden advice: get your hands dirty with code, lots of it. But don’t stop there. Once you've built up your confidence in coding, dive into the world of system design.
|
||||
|
||||
> "Software engineering can sometimes be daunting. You might feel overwhelmed by everything there is to learn, worrying you’re falling behind or getting left out. But here’s the thing, every engineer has been there. The key? Commit to learning something new every day."
|
||||
>
|
||||
|
||||
She believes in the power of sticking to a path of constant learning and finding joy in small discoveries. Linking up with mentors who've faced similar hurdles and surrounding yourself with driven peers can be transformative, making those big challenges much more manageable.
|
||||
|
||||
> "Finding your way through the job market's competitive terrain can feel like a tough climb, especially with how things are today.”
|
||||
>
|
||||
|
||||
She's convinced that those who dive into open source projects, share their achievements on social media, and [connect with the wider community](https://appwrite.io/heroes) by writing blogs, making videos, or speaking at conferences stand out. She points out that in a world where opportunities know no borders, making yourself seen and heard on the global stage is crucial.
|
||||
|
||||
Take, for example, Appwrite—a globally remote company constantly [scouting for talent](https://www.appwrite.careers) worldwide. Khushboo’s guidance is clear-cut: develop a passion for building and exploring new things, but don’t forget to let the [commnunity](https://appwrite.io/community) see what you’re capable of. Rather than solely relying on traditional job applications, she advocates for proactively sharing one's projects and expertise, enabling potential employers to discover them. Khushboo also highlights the significance of empathy and cultural fit in addition to technical proficiency. Being empathetic and understanding others' perspectives fosters strong teamwork and collaboration, qualities that are highly valued in today's workplace.
|
||||
|
||||
Khushboo wraps up her journey's story with a quote that resonates deeply with her:
|
||||
|
||||
> “As long as you have faith and are willing to work hard, you can achieve anything you want.”
|
||||
>
|
||||
|
||||
Her dedication to spreading knowledge doesn't stop; whether it's workshops, meetups, or conferences, she's there, eager to share what she knows with anyone willing to learn.
|
||||
|
||||

|
||||
|
||||
If you’re looking to learn more about Khushboo or to connect with her, visit her social profiles:
|
||||
|
||||
- [LinkedIn](https://www.linkedin.com/in/verma-khushboo/)
|
||||
- [Twitter](https://twitter.com/khushbooverma_)
|
||||
- [GitHub](https://github.com/vermakhushboo)
|
||||
- [Instagram](https://www.instagram.com/hey.khushboo/)
|
||||
|
||||
@@ -75,7 +75,7 @@ docker run -it --rm \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:1.4.3
|
||||
appwrite/appwrite:1.5.4
|
||||
```
|
||||
|
||||
For one-click setups, check out the [installation docs](https://appwrite.io/docs/self-hosting).
|
||||
|
||||
208
src/routes/blog/post/bun-function-resume/+page.markdoc
Normal file
208
src/routes/blog/post/bun-function-resume/+page.markdoc
Normal file
@@ -0,0 +1,208 @@
|
||||
---
|
||||
layout: post
|
||||
title: Share your resume using Appwrite Functions
|
||||
description: How you can create a resume using HTML and use a Bun Appwrite Function to share it with the world.
|
||||
date: 2024-03-07
|
||||
cover: /images/blog/bun-function-resume/cover.png
|
||||
timeToRead: 7
|
||||
author: aditya-oberai
|
||||
category: functions
|
||||
---
|
||||
|
||||
One of the coolest things about Appwrite Functions is that you can now consume them as REST APIs. This means you can send HTTP requests to any path, using common HTTP methods such as `GET` and `POST` to any path on the function and get a response in JSON or any other text-based formats (such as plain text, HTML, and CSV). This has opened up a lot of potential use-cases, one of which is how you can host and share your online resume through an Appwrite Function when applying for a new job.
|
||||
|
||||
Therefore, in this blog, we will leverage one of Appwrite’s newest functions runtimes, Bun, to create a function that delivers an HTML-based resume.
|
||||
|
||||
# Pre-requisites
|
||||
|
||||
To create the Appwrite Function, you must go to [Appwrite Cloud](https://cloud.appwrite.io) and create a new project. Once a new project is created, you must visit the **Functions** page. Once you click on the **Create a new function** button, you will discover a number of starter templates, of which you must select **Bun**. Once you have created a starter function with Bun and connected your GitHub account, we are ready to begin developing our resume function.
|
||||
|
||||

|
||||
|
||||
# Building the Appwrite Function
|
||||
|
||||
Once your function’s GitHub repository is ready, clone it to your local device and enter the directory. You will notice a directory structure as follows:
|
||||
|
||||
```md
|
||||
.
|
||||
├── src/
|
||||
│ └── main.ts
|
||||
├── README.md
|
||||
├── bun.locklb
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Creating the HTML resume
|
||||
|
||||
First things first, let’s create an HTML resume. We will create a folder `static` at the root level of our project directory and add a file `resume.html`. We will then add the following HTML to this file:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Resume</title>
|
||||
<style>
|
||||
body {
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
div {
|
||||
margin: auto;
|
||||
max-width: 50%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
hr {
|
||||
width: 70%;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>John Doe</h1>
|
||||
<h2>Software Engineer</h2>
|
||||
</header>
|
||||
<hr>
|
||||
<div>
|
||||
<h2>Work Experience</h2>
|
||||
<h3>Software Engineer, ABC Company (Jan 2019 - Present)</h3>
|
||||
<ul>
|
||||
<li>Developed APIs for aggregation and analysis of automotive sales data using .NET 5</li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<h2>Education</h2>
|
||||
<h3>Master of Science in Computer Science, XYZ University (2017 - 2019)</h3>
|
||||
<ul>
|
||||
<li>CGPA: 9.0</li>
|
||||
</ul>
|
||||
<h3>Bachelor of Engineering in Computer Science, XYZ University (2013 - 2017)</h3>
|
||||
<ul>
|
||||
<li>CGPA: 8.5</li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<h2>Skills</h2>
|
||||
<ul>
|
||||
<li>Programming Languages: JS, TS, C#, Java, Python</li>
|
||||
<li>Frameworks: .NET, Spring Boot</li>
|
||||
<li>Database: MySQL, MongoDB</li>
|
||||
<li>Cloud: AWS, Azure</li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<h2>Projects</h2>
|
||||
<h3>Project 1</h3>
|
||||
<ul>
|
||||
<li>Developed a web application for online shopping using Spring Boot</li>
|
||||
</ul>
|
||||
<h3>Project 2</h3>
|
||||
<ul>
|
||||
<li>Developed a web application for calendar management using ASP.NET</li>
|
||||
</ul>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<h2>Contact Me</h2>
|
||||
<ul>
|
||||
<li>Email: john.doe@test.com</li>
|
||||
<li>Phone: 1234567890</li>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
> Note: You can customize this file in any way you want. The only thing I recommend, however, is to keep the styles within the same file, as the function will only deliver the content of this particular file at a time.
|
||||
## Preparing our utility function to get the HTML content
|
||||
|
||||
To simplify the function logic, we create an additional utility function to help easily read the content from our HTML resume and return it as a `string`. This is necessary to deliver the content as a response from our function.
|
||||
|
||||
For that, we shall enter the `src` folder and create a file `utils.ts` with the following code:
|
||||
|
||||
```ts
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import fs from 'fs';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const staticFolder = path.join(__dirname, '../static');
|
||||
|
||||
export function getStaticFile(fileName: string): string {
|
||||
return fs.readFileSync(path.join(staticFolder, fileName)).toString();
|
||||
}
|
||||
```
|
||||
|
||||
## Developing the function logic
|
||||
|
||||
Now that our HTML resume and utility function are ready, we can develop our final function logic. For that, we shall enter the `main.ts` file in the `src` folder and replace it with the following code:
|
||||
|
||||
```ts
|
||||
import { getStaticFile } from './utils.js';
|
||||
|
||||
export default async ({ req, res }) => {
|
||||
|
||||
if (req.method === 'GET' && req.path === '/') {
|
||||
return res.send(getStaticFile('resume.html'), 200, {
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
This function will return our HTML resume content with the appropriate content type when we send a `GET` request to the default path of our function domain.
|
||||
|
||||
At this point, our project directory structure should look as follows:
|
||||
|
||||
```md
|
||||
.
|
||||
├── src/
|
||||
│ ├── main.ts
|
||||
│ └── utils.ts
|
||||
├── static/
|
||||
│ └── resume.html
|
||||
├── README.md
|
||||
├── bun.locklb
|
||||
└── package.json
|
||||
```
|
||||
|
||||
## Testing the function
|
||||
|
||||
Once you’ve completed all the aforementioned steps, you can push the code to our GitHub repository, at which point Appwrite Cloud will automatically deploy the changes to your function.
|
||||
|
||||

|
||||
|
||||
You can then go ahead and test your function by opening the function domain in your browser.
|
||||
|
||||
Here is what an example of this looks like: [apwr.dev/bun-functions-resume-demo](https://apwr.dev/bun-functions-resume-demo)
|
||||
|
||||
# Next steps
|
||||
|
||||
And with that, you have successfully deployed your resume using Appwrite Functions. If you liked this project or want to investigate the full project code, visit our [GitHub repository](https://github.com/adityaoberai/resume-appwrite).
|
||||
|
||||
Additionally, if you would like to learn more about Appwrite Functions, here are some resources:
|
||||
|
||||
- [Appwrite Functions docs](https://appwrite.io/docs/functions): These documents provide more information on how to use Appwrite Functions.
|
||||
- [Bun functions announcements](https://appwrite.io/blog/post/why-you-need-to-try-the-new-bun-runtime): Read the full announcement about our Bun functions runtime.
|
||||
- [Appwrite Discord](https://discord.com/invite/appwrite): Connect with other developers and the Appwrite team for discussion, questions, and collaboration.
|
||||
50
src/routes/blog/post/case-study-open-mind/+page.markdoc
Normal file
50
src/routes/blog/post/case-study-open-mind/+page.markdoc
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Data dilemma and cost efficiency solved: Open Mind's journey to scalable education"
|
||||
description: Learn how App Innovators used Appwrite Cloud to decrease costs and deliver education about psychoactive substances to over 12,500 consumers via the Open Mind app.
|
||||
date: 2024-04-12
|
||||
cover: /images/blog/case-study-open-mind/cover.png
|
||||
timeToRead: 5
|
||||
author: aditya-oberai
|
||||
category: case-studies
|
||||
---
|
||||
|
||||
While still at school, David Forster noticed a substantial increase in the usage of narcotic substances by his peers. He saw that the consumption of narcotic substances led to a decline in the mental and physical health of these folks. However, at that time, the only educational forums on this topic that were accessible to people were Wiki pages with information that was too complex to understand. A lack of simple educational tools prevented David from helping his peers break out of a substance habit.
|
||||
|
||||
Therefore, as Germany closes in toward the legalization of cannabis, David and his software development agency, [App Innovators](https://app-innovators.de/), developed an app that helps people understand the different psychoactive substances available in the market, track their consumption, deal with emergencies, and more. With this, the Open Mind application was born!
|
||||
|
||||
# What is Open Mind?
|
||||
|
||||
Open Mind is an application that helps create better awareness of psychoactive substances and helps teach people how they can consume substances responsibly. It was developed in collaboration with a **prominent German YouTuber,** [OpenMind3000](https://www.youtube.com/@OpenMind3000), who regularly caters content on how different drugs work and mix, and how people can decrease risks to life when consuming such substances to an audience of **over 540,000 subscribers**.
|
||||
|
||||
The [Open Mind app](https://openmindapp.de/) offers the following features:
|
||||
|
||||
- **Information about psychoactive substances**: Descriptive information on a vast range of substances, including what they are, safe quantities to consume, and how long they remain effective.
|
||||
- **Substance combination checker**: A tool that verifies how risky a combination of different substances can be to a person's health and any possible side-effects of consuming such a cocktail.
|
||||
- **Trip games**: Two games (a reaction test and a memory cards game) that allow a user to evaluate their sobriety after consuming any substance(s).
|
||||
- **Emergency instructions**: A set of instructions for different harmful (or risky) situations a user might experience after consuming any substance(s).
|
||||
- **Consumption history log**: A self-logging tool that lets users track their consumption history, including the type of drug, quantity of intake, method of consumption, start and end of the effect, and any additional notes.
|
||||
|
||||
# Developing the application
|
||||
|
||||
The first iteration of Open Mind was designed as a mobile application. The team at App Innovators chose to use Flutter to allow them to build Android and iOS applications simultaneously at a rapid pace. While most user data is retained on each user's local device, they decided to host all data related to substances on an external platform, allowing them easier access to maintain, update, and distribute the information. They decided it was simplest to achieve the same by maintaining JSON files (one file per language they support, including German and English) with all this data that would be hosted at an external storage service.
|
||||
|
||||
Initially, due to their past experience, the team explored Firebase to host these files. However, Firebase's high storage and bandwidth costs forced them to explore other backend-as-a-service solutions. At this point, the team at Open Mind discovered Appwrite. The availability of **Appwrite's Flutter SDK** meant that the team could quickly adopt **Appwrite Storage**, with features such as chunked downloads and file compression available out of the box. The **plug-and-play architecture** of Appwrite's SDK would allow them to use their existing application architecture without much change. Additionally, Appwrite Cloud's more **economical pricing** allowed them to serve thousands of users regularly without breaking the bank.
|
||||
|
||||
In David's own words,
|
||||
|
||||
> We really loved working with Appwrite for launching our bootstrapped "Open Mind" App. It was saving us a lot of money in comparison to Firebase since the amount of users grew quite fast and we needed a quick switch. I am still surprised how easy the implementation into Flutter was.
|
||||
|
||||
# The journey so far
|
||||
|
||||
The App Innovators team made the Open Mind app available publicly on the [Google Play Store](https://play.google.com/store/apps/details?id=de.app.innovators.open_mind&hl=en&gl=US) and through Testflight for beta users on the Apple App Store.
|
||||
|
||||
Although localized to regions within Europe, the Android app has amassed:
|
||||
|
||||
- Over 11,500 downloads
|
||||
- 3600+ monthly active users
|
||||
- 350-500 daily active users, with the majority coming from Germany, Austria, and Switzerland
|
||||
|
||||
In Testflight, the Apple app amassed over 1000 beta users; however, changes in the App Store policies prevented them from further updating and promoting the Apple app. In recent times, however, the team has taken a new direction and is converting the Open Mind mobile app into a web app using Flutter Web. The current version of the web application is available at [openmindapp.de](https://openmindapp.de/) and is quickly gaining traction and users.
|
||||
|
||||
As the Open Mind application grows, we wish David and the App Innovators team the best of luck and look forward to their future ventures. You can learn more about them by visiting their [website](https://app-innovators.de/).
|
||||
@@ -55,7 +55,7 @@ The next step is extend the template to show real invoice data. Here’s a high-
|
||||
3. If necessary, use the order document to ensure the user has permission to see the order. For example, compare the `x-appwrite-user-id` header with the document user ID.
|
||||
4. Change the function to populate the PDF template with the real order document.
|
||||
|
||||
# Next Steps
|
||||
# Next steps
|
||||
|
||||
We’ve covered the basics, and now it’s your time to shine! With a few changes, you can extend this template to fit your application. Be sure to check out the other available Function Templates. We’ve created many that could be of use in your projects. You can find the [templates GitHub repository here](https://github.com/appwrite/templates).
|
||||
|
||||
|
||||
203
src/routes/blog/post/email-otp-auth-sveltekit/+page.markdoc
Normal file
203
src/routes/blog/post/email-otp-auth-sveltekit/+page.markdoc
Normal file
@@ -0,0 +1,203 @@
|
||||
---
|
||||
layout: post
|
||||
title: Improving user security in your web apps with email OTP auth
|
||||
description: Understand how email OTP authentication works and how you can implement it in a SvelteKit application.
|
||||
date: 2024-04-05
|
||||
cover: /images/blog/email-otp-auth-sveltekit/cover.png
|
||||
timeToRead: 6
|
||||
author: aditya-oberai
|
||||
category: authentication
|
||||
---
|
||||
|
||||
To discover a balance between security and user convenience, one growing trend we have seen recently is the implementation of passwordless authentication. Today, both small and large companies are transitioning to using passwordless authentication methods over traditional password-based ones, such as Expensify (whose transition was also covered in a Forbes [article](https://www.forbes.com/sites/quickerbettertech/2023/05/29/on-technology-expensify-forces-passwordless-on-its-users-and-good-for-them/?sh=397a7b017cac) in 2023). Appwrite has always maintained support for both types of authentication, featuring phone-based OTPs (one-time passwords) and magic URLs in our list of authentication methods.
|
||||
|
||||
With the recent Appwrite 1.5 release, we added a new passwordless authentication method: email OTPs. In this blog, you’ll learn how email OTP authentication works and how you can implement it in a SvelteKit application.
|
||||
|
||||
# What is email OTP authentication?
|
||||
|
||||
[Email OTP authentication](https://appwrite.io/docs/products/auth/email-otp) lets users create accounts using their email address and sign in using a 6-digit code delivered to their email inbox. This method is similar to [Magic URL login](https://appwrite.io/docs/products/auth/magic-url) but can provide a better user experience in some scenarios.
|
||||
|
||||
## Email OTP vs magic URL
|
||||
|
||||
Email OTP authentication sends an email with a 6-digit code that a user needs to enter into the app, while magic URL authentication delivers a clickable button or link to the user's inbox. Both allow passwordless login flows with different advantages.
|
||||
|
||||
| Benefits of email OTP | Downsides of email OTP |
|
||||
| --- | --- |
|
||||
| Doesn't require the user to be signed into their email inbox on the device | Expires quicker |
|
||||
| Doesn't disturb the application flow with a redirect | Requires more inputs from the user |
|
||||
| Doesn't require deep linking on mobile apps | |
|
||||
|
||||
# Implementing email OTP in a SvelteKit app
|
||||
|
||||
Now that we have a basic understanding of email OTP authentication, let’s learn how we can implement it in a SvelteKit application.
|
||||
|
||||
## Set up Appwrite 1.5
|
||||
|
||||
Email OTP authentication is not yet released on Cloud, which is on `Appwrite 1.4.x`. This is a feature available in `Appwrite 1.5.x` and will be available on Appwrite Cloud later. In the meantime, you can use it by [self-hosting Appwrite](https://appwrite.io/docs/advanced/self-hosting) on your system or an external VM/VPS.
|
||||
|
||||
You can self-host Appwrite using the following Docker command:
|
||||
|
||||
```bash
|
||||
docker run -it --rm \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:1.5.4
|
||||
```
|
||||
|
||||
Once that is done, [set up email delivery](https://appwrite.io/docs/advanced/self-hosting/email) on your self-hosted Appwrite instance. This can be done by visiting your `appwrite` directory and updating the `.env` file in a similar manner as follows:
|
||||
|
||||
```
|
||||
_APP_SMTP_HOST=smtp.sendgrid.net
|
||||
_APP_SMTP_PORT=587
|
||||
_APP_SMTP_SECURE=tls
|
||||
_APP_SMTP_USERNAME=YOUR-SMTP-USERNAME
|
||||
_APP_SMTP_PASSWORD=YOUR-SMTP-PASSWORD
|
||||
_APP_SYSTEM_EMAIL_ADDRESS=YOUR-SENDER-EMAIL
|
||||
```
|
||||
|
||||
Don’t forget to run `docker compose up -d` after you update the environment variables to ensure the changes are implemented in your instance.
|
||||
|
||||
Once your Appwrite instance is set up, create a project and copy both the Appwrite API endpoint and project ID.
|
||||
|
||||
## Create your SvelteKit web app
|
||||
|
||||
In order to create your SvelteKit application, open your terminal and enter the command `npm create svelte@latest` to create a project.
|
||||
|
||||
```bash
|
||||
npm create svelte@latest
|
||||
|
||||
create-svelte version 6.0.10
|
||||
|
||||
┌ Welcome to SvelteKit!
|
||||
│
|
||||
◇ Where should we create your project?
|
||||
│ appwrite-email-otp
|
||||
│
|
||||
◇ Which Svelte app template?
|
||||
│ Skeleton project
|
||||
│
|
||||
◇ Add type checking with TypeScript?
|
||||
│ No
|
||||
│
|
||||
◇ Select additional options (use arrow keys/space bar)
|
||||
│ Add ESLint for code linting, Add Prettier for code formatting
|
||||
│
|
||||
└ Your project is ready!
|
||||
```
|
||||
|
||||
Once that is done, enter the directory and install any existing dependencies.
|
||||
|
||||
```bash
|
||||
cd appwrite-email-otp
|
||||
npm i
|
||||
```
|
||||
|
||||
Also, create a file `.env` in the root directory and add your Appwrite API endpoint and project ID.
|
||||
|
||||
```
|
||||
PUBLIC_APPWRITE_ENDPOINT=
|
||||
PUBLIC_APPWRITE_PROJECT_ID=
|
||||
```
|
||||
|
||||
## Install the Appwrite Web SDK and prepare the app logic
|
||||
|
||||
Once your project is ready, install the Appwrite Web SDK using NPM:
|
||||
|
||||
```bash
|
||||
npm i appwrite
|
||||
```
|
||||
|
||||
As soon as that’s done, we can start preparing our application logic. For that, visit the `src/lib` directory and create a file `appwrite.js`. Add the following code to the same.
|
||||
|
||||
```js
|
||||
import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_ID } from "$env/static/public";
|
||||
import { Client, Account } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint(PUBLIC_APPWRITE_ENDPOINT)
|
||||
.setProject(PUBLIC_APPWRITE_PROJECT_ID);
|
||||
|
||||
export const account = new Account(client);
|
||||
```
|
||||
|
||||
In the same directory, create a file `user.js` and add the following code.
|
||||
|
||||
```js
|
||||
import { account } from "./appwrite";
|
||||
import { ID } from "appwrite";
|
||||
|
||||
export const user = {
|
||||
createOtp: async (email) => {
|
||||
return await account.createEmailToken(ID.unique(), email, true);
|
||||
},
|
||||
|
||||
verifyOtp: async (userId, secret) => {
|
||||
return await account.createSession(userId, secret);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Update the application UI
|
||||
|
||||
Once the authentication logic is ready, we can create the web app’s user interface. To prioritize ease of understanding and simplicity, the example will not feature any styling-related code.
|
||||
|
||||
In the `src/routes` directory, visit the file `+page.svelte` and replace it with the following code.
|
||||
|
||||
```html
|
||||
<script>
|
||||
import { user } from "$lib/user.js";
|
||||
|
||||
var token;
|
||||
var securityPhrase = "Create OTP first to get the security phrase.";
|
||||
|
||||
async function createOtp(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
token = await user.createOtp(formData.get('email'));
|
||||
securityPhrase = `Security phrase: ${token.phrase}`;
|
||||
alert("OTP sent to email");
|
||||
}
|
||||
|
||||
async function verifyOtp(e) {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(e.target);
|
||||
const response = await user.verifyOtp(token.userId, formData.get('otp'));
|
||||
alert("OTP verified");
|
||||
}
|
||||
</script>
|
||||
|
||||
<section>
|
||||
<div class="container">
|
||||
<div id="email">
|
||||
<h2>Enter Email</h2>
|
||||
<form on:submit={createOtp}>
|
||||
<input type="email" name="email" id="email" placeholder="team@appwrite.io" required>
|
||||
<button class="button" type="submit">Submit</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div id="otp">
|
||||
<h2>Enter OTP</h2>
|
||||
<form on:submit={verifyOtp}>
|
||||
<input type="text" name="otp" id="otp" placeholder="012345" required>
|
||||
<button class="button" type="submit">Submit</button>
|
||||
</form>
|
||||
<p>{securityPhrase}</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
```
|
||||
|
||||
This UI features both steps of the email OTP flow, entering the email to send an OTP followed by entering the OTP to login. It also features the security phrase sent on the email along with the OTP so that the user can verify that a third party didn’t initiate the authentication flow.
|
||||
|
||||
Once this is done, you can test the application by running the command `npm run dev` and opening the app URL in your browser.
|
||||
|
||||
# Next steps
|
||||
|
||||
And with that, our demo application is ready. If you liked this project or want to investigate the full codebase, visit the [GitHub repository](https://github.com/adityaoberai/appwrite-email-otp-demo).
|
||||
|
||||
For more information about Appwrite Authentication, visit the following resources:
|
||||
|
||||
- [Appwrite Authentication Docs](https://appwrite.io/docs/products/auth): These docs provide more information on how to use the different methods offered under Appwrite Authentication.
|
||||
- [Appwrite Discord](https://discord.com/invite/appwrite): Connect with other developers and the Appwrite team for discussion, questions, and collaboration.
|
||||
@@ -65,7 +65,7 @@ Code maintainability is extremely important for any piece of software, which is
|
||||
|
||||
With the latest release of Appwrite, we have taken steps to improve type safety within our SDKs by leveraging enums. We have replaced all magic literals, such as constants needed for OAuth adapters, with enums to simplify the developer experience for all those who are building with Appwrite.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Account, OAuthProvider } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
---
|
||||
layout: post
|
||||
title: Ensuring security amidst the XZ Utils backdoor concern
|
||||
description: Learn about Appwrite's response to XZ Utils backdoor concerns and how to safeguard your Appwrite projects.
|
||||
date: 2024-04-02
|
||||
cover: /images/blog/ensuring-security-amidst-xz-concern/cover.png
|
||||
timeToRead: 7
|
||||
author: jake-barnby
|
||||
category: engineering
|
||||
featured: false
|
||||
---
|
||||
|
||||
In the light of recent unsettling revelations regarding a backdoor discovered in the widely-used XZ Utils,
|
||||
a compression tool used in Linux environments, including Red Hat and Debian systems, the cyber-security landscape has been abuzz with concern.
|
||||
This discovery had a large potential impact on encrypted SSH connections, a backbone of secure communications in the tech world.
|
||||
|
||||
At Appwrite, ensuring the security and trust of our developers and users is paramount.
|
||||
We understand the concerns that arise from such vulnerabilities and their potential implications.
|
||||
|
||||
It's crucial for the Appwrite community to know that Appwrite's services **remain unaffected** by the XZ Utils backdoor.
|
||||
This issue affected beta and test versions of Red Hat and Debian distributions, which Appwrite **does not use**.
|
||||
|
||||
# What does this mean for self-hosting Appwrite?
|
||||
|
||||
For our valued users who prefer the self-hosted route, leveraging Appwrite on affected operating systems (OS),
|
||||
we understand your concerns. Here are our recommendations to ensure your self-hosted Appwrite instances remain secure:
|
||||
|
||||
- Immediate Update/Removal: The first and foremost step is to check if you have the affect versions (`5.6.0`,` 5.6.1`) of the XZ Utils installed. If so, downgrade to a safe version or remove the utility altogether.
|
||||
- Enhanced Monitoring: Keep a keen eye on network traffic and system logs for any unusual activity.
|
||||
- Employ Firewalls: Employ stringent firewall rules to limit inbound and outbound connections to the bare minimum required for your operations. This reduces the attack surface significantly.
|
||||
- Regular System Audits: Conduct thorough audits of your systems to ensure no unauthorized modifications have been made to the OS or installed utilities.
|
||||
- Stay Informed: Follow updates from your OS's security advisory to apply security patches as soon as they are released.
|
||||
|
||||
# Does this affect Appwrite Cloud developers?
|
||||
|
||||
Appwrite Cloud users can rest assured that our cloud infrastructure is secure and unaffected by the XZ Utils backdoor.
|
||||
The Appwrite team has taken necessary measures to ensure that containers in our cloud environment do not have the affected versions of the XZ Utils installed.
|
||||
We also took further steps to restrict SSH access to our cloud infrastructure to reduce attack surfaces further.
|
||||
No actions are required from Appwrite Cloud developers at this time.
|
||||
|
||||
In a world where cyber threats are evolving at an alarming pace,
|
||||
the Appwrite team is committed to ensuring the security and reliability of Appwrite Cloud's infrastructure,
|
||||
so you can build applications with peace of mind.
|
||||
The team will continue to monitor the situation closely, take necessary actions to mitigate any potential risks,
|
||||
and communicate any updates transparently to the community.
|
||||
|
||||
For any further questions or concerns, please reach out through [email](https://appwrite.io/contact-us) or on [Discord](https://appwrite.io/discord).
|
||||
We're here to support you every step of the way.
|
||||
@@ -74,7 +74,7 @@ By being aware of these pitfalls and employing strategies to avoid them, you can
|
||||
|
||||
With the latest release of Appwrite, we have taken steps to improve type safety within our SDKs by leveraging enums. We have replaced all magic literals, such as constants needed for OAuth adapters, with enums to simplify the developer experience and make it less error-prone for all those who are building with Appwrite. This change exemplifies our commitment to robust and user-friendly API design.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Account, OAuthProvider } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
---
|
||||
layout: post
|
||||
title: Chat with your favorite fictional character using OpenAI and Appwrite Functions
|
||||
description: Learn how you can use Appwrite Functions and OpenAI to chat with popular characters such as Batman.
|
||||
date: 2024-04-04
|
||||
cover: /images/blog/function-chat-fictional-character/cover.png
|
||||
timeToRead: 6
|
||||
author: aditya-oberai
|
||||
category: functions
|
||||
---
|
||||
|
||||
Have you ever wondered what it would feel like to interact with your favorite fictional characters, such as Superman, Hermione Granger, Gandalf, or Snow White? As a part of an internal hackathon at Appwrite recently, my team developed an Appwrite Function that you can use to chat with any popular fictional character you like (we really wanted to talk to Batman!)
|
||||
|
||||
In this blog, let’s learn how you can build this Appwrite Function using OpenAI’s GPT-4 API.
|
||||
|
||||

|
||||
|
||||
# Setting up the OpenAI platform
|
||||
|
||||
To develop this project, you first need an OpenAI API Key, for which you must create an account on the [OpenAI platform](https://platform.openai.com/). Once your account is set up, visit their [API keys](https://platform.openai.com/account/api-keys) page and create an API Key. Ensure you copy and save this key in a safe place, as the OpenAI platform will not let you view the key after it is created.
|
||||
|
||||

|
||||
|
||||
> Note: To use the GPT-4 API, your account must be upgraded to the Usage tier 1. To learn more, visit their [Usage tiers documentation](https://platform.openai.com/docs/guides/rate-limits/usage-tiers?context=tier-one).
|
||||
|
||||
# Initializing the Appwrite Function
|
||||
|
||||
Now that we have our OpenAI API Key, let us get the function ready on [Appwrite](https://cloud.appwrite.io/). Head over to your Appwrite project and visit the Functions page. From there, we will use the Node.js starter template and create a function.
|
||||
|
||||

|
||||
|
||||
Once the function is ready, we must visit the Settings tab on the Function page and add the following environment variables:
|
||||
|
||||
- `OPENAI_API_KEY`: API Key from our OpenAI account
|
||||
- `OPENAI_MAX_TOKENS`: Maximum number of tokens that the OpenAI response should contain (we’ll set this as `512`)
|
||||
|
||||
Once that is done, visit the function’s GitHub repository and clone the project.
|
||||
|
||||
# Developing the function logic
|
||||
|
||||
To develop the function, we must first install the `openai` npm package. Open your terminal in the project directory and run the following command:
|
||||
|
||||
```bash
|
||||
npm i openai
|
||||
```
|
||||
|
||||
Once that is done, visit the `src/main.js` file and replace the entire code with the following:
|
||||
|
||||
```js
|
||||
import { OpenAI } from 'openai';
|
||||
|
||||
export default async ({ req, res, log, error }) => {
|
||||
try {
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
var prompt = `You are ${req.body.character}.\nRespond to the following question in first-person: ${req.body.question}\n${req.body.additionalPrompt}`
|
||||
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-4',
|
||||
max_tokens: parseInt(process.env.OPENAI_MAX_TOKENS ?? '512'),
|
||||
messages: [{ role: 'user', content: prompt }],
|
||||
});
|
||||
const completion = response.choices[0].message?.content;
|
||||
log(completion);
|
||||
return res.json({ ok: true, answer: completion }, 200);
|
||||
} catch (err) {
|
||||
error(err.message);
|
||||
return res.json({ ok: false, error: err.message }, 500);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
This function will accept the name of a character, the question from a user, and any additional prompt you might optionally like to give. For example, in our hackathon project, we wanted to interact with Bruce Wayne and ensure that his Batman alter-ego was not directly given away, so here’s what our inputs looked like:
|
||||
|
||||
| Character name | Question | Additional prompt |
|
||||
| --- | --- | --- |
|
||||
| Bruce Wayne | Are you Batman? | Ensure that you don't reveal your Batman alter-ego but you can tip-toe around it. |
|
||||
|
||||
# Testing the function
|
||||
|
||||
Once you’ve completed all the aforementioned steps, you can push the code to the generated GitHub repository, at which point Appwrite Cloud will automatically deploy the changes to your function.
|
||||
|
||||
You can test the function by sending it a cURL request from your terminal or any other API testing client.
|
||||
|
||||
```bash
|
||||
curl --location '<YOUR_FUNCTION_URL>' \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data '{
|
||||
"character": "Bruce Wayne",
|
||||
"question": "Are you Batman?",
|
||||
"additionalPrompt": "Ensure that you don'\''t reveal your Batman alter-ego but you can tip-toe around it."
|
||||
}'
|
||||
```
|
||||
|
||||

|
||||
|
||||
# Next steps
|
||||
|
||||
And with that, our fictional character chat function is ready! If you liked this project and/or want to investigate the function code, visit the [GitHub repository](https://github.com/adityaoberai/CharacterChat).
|
||||
|
||||
For more information about Appwrite Functions, visit the following resources:
|
||||
|
||||
- [Appwrite Function Docs](https://appwrite.io/docs/functions): These documents provide more information on how to use Appwrite Functions.
|
||||
- [Appwrite Discord](https://discord.com/invite/appwrite): Connect with other developers and the Appwrite team for discussion, questions, and collaboration.
|
||||
@@ -60,7 +60,7 @@ Here’s a screenshot of a test prompt that was sent to the function using Postm
|
||||
|
||||

|
||||
|
||||
## Next Steps
|
||||
## Next steps
|
||||
|
||||
We’ve covered the basics, and now it’s your time to shine! With a few changes, you should be able to extend this template to fit your app. Be sure to check out the other available Function Templates. We’ve created many that could be of use in your projects. You can find the [templates GitHub repository here](https://github.com/appwrite/templates).
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ Open the WhatsApp app on your phone, join the Vonage WhatsApp Channel (via the s
|
||||
|
||||

|
||||
|
||||
## Next Steps
|
||||
## Next steps
|
||||
|
||||
We’ve covered the basics, and now it’s your time to shine! With a few changes, you should be able to extend this template to fit your app. Be sure to check out the other available Function Templates. We’ve created many that could be of use in your projects. You can find the [templates GitHub repository here](https://github.com/appwrite/templates).
|
||||
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Rethinking password security: say goodbye to plaintext passwords"
|
||||
description: Understanding what passwordless authentication is and how it is a game-changer for both user experience and security.
|
||||
date: 2024-03-22
|
||||
cover: /images/blog/goodbye-plaintext-passwords/cover.png
|
||||
timeToRead: 6
|
||||
author: aditya-oberai
|
||||
category: authentication
|
||||
---
|
||||
|
||||
Recently, we came across a report by [BleepingComputer](https://www.bleepingcomputer.com/news/security/misconfigured-firebase-instances-leaked-19-million-plaintext-passwords/), which shared how misconfigured Firebase projects led to the leakage of 19 million plaintext passwords on the public internet. This was primarily caused by missing or incorrectly configured security rules on Firebase instances that consequently permitted read access to databases, resulting in a massive data leak that exposed:
|
||||
|
||||
- Names: 84,221,169
|
||||
- Emails: 106,266,766
|
||||
- Phone numbers: 33,559,863
|
||||
- Passwords: 20,185,831
|
||||
- Billing info (bank details, invoices, etc.): 27,487,924
|
||||
|
||||
For passwords, the problem was a lot worse because 98% of them, or 19,867,627 to be exact, were in plaintext. While this problem is not inherently a Firebase bug, it does signify a massive lack of understanding around authentication tooling and password security. Therefore, this blog will discuss why plaintext passwords are bad for your security and alternative solutions.
|
||||
|
||||
# The dangers of plain text passwords
|
||||
|
||||
Storing passwords in plaintext presents significant security risks and vulnerabilities for both users and organizations. Here are several vital points illustrating why plaintext passwords are bad:
|
||||
|
||||
- **An easy target for hackers**: Plaintext passwords can be easily read and exploited by anyone who gains unauthorized access to the storage database, making them prime targets for hackers.
|
||||
- **Lack of confidentiality**: Storing passwords in plaintext fails to protect the confidentiality of user information. If a security breach occurs, users’ passwords are exposed without any layer of protection.
|
||||
- **Non-compliance with security standards**: Many industry standards and regulations, such as GDPR, PCI DSS, and HIPAA, require that personal data, including passwords, be adequately protected, and storing passwords in plaintext can result in non-compliance.
|
||||
- **Increased risk of insider threats**: Plaintext passwords are vulnerable to external threats and insider threats. Employees with access to the database can view and potentially misuse this information, leading to internal security breaches.
|
||||
- **Higher impact of data breaches**: When passwords are stored in plaintext, the impact of a data breach is magnified. Attackers can access the compromised system and use the same credentials to attempt access to other services, exploiting the common habit of password reuse.
|
||||
- **No defense against brute force attacks**: Plaintext passwords offer no defense against brute force attacks. While hashed passwords can also be vulnerable, hashing makes decoding user passwords a lot more difficult.
|
||||
- **Damage to reputation**: A company found to be storing passwords in plaintext can suffer significant damage to its reputation. Users and clients lose trust in a business that doesn’t prioritize their information’s security.
|
||||
|
||||
# Alternatives to plaintext passwords
|
||||
|
||||
Fortunately, modern authentication systems are built with the drawbacks of plaintext passwords kept in mind. Two major solutions that have been developed to solve this problem are as follows:
|
||||
|
||||
## Password hashing
|
||||
|
||||
Password hashing is a security technique that converts a plaintext password into a fixed-size string of characters, which is virtually impossible to reverse. This process uses a hash function to transform the original password, ensuring that even if the data storage is compromised, the actual passwords are not easily deciphered.
|
||||
|
||||
Benefits of password hashing compared to storing passwords in plaintext include:
|
||||
|
||||
- **Enhanced security**: Hashed passwords are extremely difficult to reverse-engineer, providing a higher level of security against data theft.
|
||||
- **Data breach protection**: In the event of a breach, hashed passwords significantly reduce the risk of passwords being used for unauthorized access.
|
||||
- **Compliance with standards**: Hashing passwords helps organizations comply with data protection and privacy regulations.
|
||||
- **User trust**: By securing passwords effectively, businesses can maintain and even boost user trust by demonstrating a commitment to privacy and security.
|
||||
- **Mitigation of reuse attacks**: Hashed passwords make it harder for attackers to use stolen credentials on other sites, reducing the impact of credential reuse attacks.
|
||||
- **Scalability and future-proofing**: Hashing algorithms can be updated and strengthened over time, providing flexibility as security standards evolve.
|
||||
|
||||
You can read our [blog on password hashing algorithms](https://appwrite.io/blog/post/password-hashing-algorithms) to learn more.
|
||||
|
||||
## Passwordless authentication
|
||||
|
||||
Passwordless authentication eliminates the need for users to create and remember passwords, aiming to enhance both security and user experience. Instead of relying on a traditional password, passwordless methods verify identity through alternative means. This approach can significantly reduce the risk of phishing attacks and password theft, as there’s no password to steal or guess.
|
||||
|
||||
Some common passwordless authentication methods are:
|
||||
|
||||
- **Biometric verification**: Uses unique biological characteristics, such as fingerprints or facial recognition, for identification.
|
||||
- **Magic links**: Sends a one-time use URL to the user’s registered email address for login.
|
||||
- **One-time passwords (OTPs)**: Generates a single-use code sent via SMS or email.
|
||||
- **Authentication apps**: Generates time-based codes or push notifications for user approval.
|
||||
- **Smart cards and security tokens**: Physical devices that the user must possess to gain access.
|
||||
|
||||
You can read our [blog on passwordless authentication](https://appwrite.io/blog/post/improve-ux-passwordless-auth) to learn more.
|
||||
|
||||
# How Appwrite solves this problem
|
||||
|
||||
[Appwrite Authentication](https://appwrite.io/docs/products/auth) makes building secure and robust authentication easy and supports many authentication methods. Currently, the following authentication methods are available on Appwrite to combat plaintext passwords:
|
||||
|
||||
- Email and password login with `Argon2id` password hashing
|
||||
- OTP-based login via SMS and email
|
||||
- Magic URL login via email
|
||||
- 30+ external OAuth2 providers, including Google, Facebook, GitHub, LinkedIn, and Apple
|
||||
- JSON Web Token ([JWT](https://jwt.io/)) creation to extend user authentication to server-side functions
|
||||
- Custom token login to allow integration with any external authentication solution of your choice
|
||||
- Two-factor authentication to add an additional layer of security to user accounts
|
||||
|
||||
Additionally, to prevent unauthorized data access, Appwrite features a [robust permissions system](https://appwrite.io/docs/advanced/platform/permissions) that is thoroughly coupled with Appwrite Authentication. The most significant benefit of Appwrite’s permissions system is that any developer needs to offer read or write access to any user intentionally. No default rule provides open access to your application’s client, and the process of setting permissions is simplified by using Appwrite’s console UI.
|
||||
|
||||
Appwrite also enforces the setting of authorized clients to communicate with an Appwrite project for all supported client platforms (web, Android, Apple, and Flutter). This way, no unauthorized clients can access data, adding an extra layer of protection.
|
||||
|
||||
# Moving forward
|
||||
|
||||
No matter what rules and systems any platform provides, combating plaintext passwords is a responsibility shared by all application developers. If you, as a developer, care about the security and privacy of your user accounts and data, you must take the necessary actions to safeguard their authentication information. Appwrite takes this problem very seriously and will continue to add new tools and improve our existing ones to make user authentication simpler and safer for all developers and their users.
|
||||
|
||||
Learn more about Appwrite Authentication through our [docs](https://appwrite.io/docs/products/auth) and join our [Discord server](https://appwrite.io/discord).
|
||||
@@ -151,7 +151,7 @@ import { redirect } from '@sveltejs/kit';
|
||||
export const load = async () => {
|
||||
const loggedIn = await isLoggedIn();
|
||||
if (!loggedIn) {
|
||||
throw redirect(307, '/init/ticket');
|
||||
redirect(307, '/init/ticket');
|
||||
}
|
||||
|
||||
const user = await getUser();
|
||||
|
||||
168
src/routes/blog/post/improve-ux-passwordless-auth/+page.markdoc
Normal file
168
src/routes/blog/post/improve-ux-passwordless-auth/+page.markdoc
Normal file
@@ -0,0 +1,168 @@
|
||||
---
|
||||
layout: post
|
||||
title: Improving user experience with passwordless authentication
|
||||
description: Understanding what passwordless authentication is and how it is a game-changer for both user experience and security.
|
||||
date: 2024-03-18
|
||||
cover: /images/blog/improve-ux-passwordless-auth/cover.png
|
||||
timeToRead: 6
|
||||
author: aditya-oberai
|
||||
category: authentication
|
||||
---
|
||||
|
||||
Today, as concerns about security and user convenience only grow with digital activity, traditional password-based authentication systems are becoming a relic of the past. In recent times, we have seen a rise in passwordless systems, which are increasingly seeing adoption in both small and big companies alike, such as Expensify (whose transition was also covered in a Forbes [article](https://www.forbes.com/sites/quickerbettertech/2023/05/29/on-technology-expensify-forces-passwordless-on-its-users-and-good-for-them/?sh=397a7b017cac) in 2023. A [survey from Enterprise Strategy Group](https://research.esg-global.com/reportaction/SecuringTheIdentityPerimeterReport/Toc), a division of TechTarget, in 2022 also revealed that:
|
||||
|
||||
- 31% of respondents picked passwordless authentication as their top identity-related activity
|
||||
- 34% of respondents chose passwordless authentication among their top three identity-related activities
|
||||
- 54% of respondents have started to transition to passwordless authentication
|
||||
- Of organizations transitioning to passwordless strategies, more than 50% experienced a significant positive impact on risk reduction and improved UX
|
||||
- Almost two-thirds reported increased efficiency for IT and security teams
|
||||
|
||||
Therefore, in this blog, we'll explore what passwordless authentication is, the drawbacks of conventional methods, and how embracing passwordless solutions can be a game-changer.
|
||||
|
||||
# The drawbacks of traditional password-based systems
|
||||
|
||||
As per an [article](https://blog.lastpass.com/2023/07/pervasive-password-less-protection-the-solution-to-the-compromised-credentials-crisis) by Lastpass, passwords need to be treated like a user experience today because repeated login attempts, forgotten passwords, mandatory password changes, and looking up passwords in a document or notebook only slow employees down and create friction in their workflow. Traditional password systems, despite their ubiquity, come with significant drawbacks, including:
|
||||
|
||||
- **Password fatigue**: Users struggle with remembering numerous passwords for different accounts.
|
||||
- **Security risks**: Weak or reused passwords increase vulnerability to hacking and data breaches.
|
||||
- **User inconvenience**: Managing complex passwords is often cumbersome and frustrating and only causes more fatigue.
|
||||
- **Time-consuming**: Resetting forgotten passwords and managing accounts adds unnecessary steps.
|
||||
- **Phishing vulnerabilities**: Traditional passwords are susceptible to phishing attacks and can open up new attack vectors for a product.
|
||||
- **Limited physical security**: Passwords can be easily observed or stolen, especially in public or shared spaces.
|
||||
|
||||
# What is passwordless authentication?
|
||||
|
||||
Passwordless authentication is exactly what it sounds like – a way to authenticate users without the need for passwords. This paradigm shift in user verification employs methods like *passkeys* (fingerprint, facial scans, or screen lock), *magic links* (one-time clickable links sent via email or SMS), and *one-time passcodes* (OTPs) sent to a user's device. These methods are not only innovative but also align with the natural human tendency to seek convenience and simplicity.
|
||||
|
||||
## Benefits of passwordless authentication for user experience
|
||||
|
||||
The transition to passwordless authentication brings a myriad of benefits:
|
||||
|
||||
- **Enhanced security**: By eliminating passwords, we inherently reduce the risk of password-related breaches.
|
||||
- **Improved ease of use**: Users no longer need to remember or manage a plethora of passwords. This simplifies the login process, leading to a more frictionless user experience.
|
||||
- **Accelerated process**: Authentication becomes quicker, with just a click or a touch, streamlining the user's journey.
|
||||
- **Higher authentication speed**: Users can access services faster, without the delay of typing a password.
|
||||
- **Enhanced user retention**: Easier login processes can lead to lower user drop-off rates.
|
||||
- **Accessibility for all users**: Such methods can be more accessible for users who have difficulty remembering passwords or have physical disabilities that make typing challenging.
|
||||
- **Lower support costs**: A lack of passwords reduces the volume of password reset requests and related support issues, saving an immense amount of IT and support effort and cost.
|
||||
- **Scalability**: Easily adapts to growing user bases without the need for extensive password management systems.
|
||||
- **Reduced risk of internal threats**: Minimizes the risk of password theft or misuse by internal actors within an organization.
|
||||
|
||||
## Tradeoffs of passwordless authentication
|
||||
|
||||
While the benefits are substantial, passwordless authentication isn't without its tradeoffs, such as:
|
||||
|
||||
- **Implementation complexity**: It can be more challenging and resource-intensive to implement than traditional methods.
|
||||
- **Hardware dependencies**: Some methods require specific hardware, like biometric scanners, which add further costs and may not be as readily accessible everywhere.
|
||||
- **Privacy and security concerns**: The collection of biometric data raises privacy issues for individuals as well as opens up newer security challenges in regard to how the data must be stored.
|
||||
- **User adaptation**: Users are often accustomed to well-set systems and may need time to adapt to new authentication methods.
|
||||
- **Potential technical issues**: Some methods rely on the proper functioning of user devices and external systems (like email or SMS services), which the company may not have control of.
|
||||
|
||||
# Implementing passwordless authentication using Appwrite
|
||||
|
||||
Appwrite Authentication also features three commonly used passwordless authentication methods: [**magic links**](https://appwrite.io/docs/products/auth/magic-url), [**email OTPs**](https://appwrite.io/docs/products/auth/email-otp), and [**phone authentication**](https://appwrite.io/docs/products/auth/phone-sms), which can be integrated into applications seamlessly with Appwrite’s client-side SDKs. This approach not only enhances security but also significantly improves the user experience by simplifying and streamlining the login process.
|
||||
|
||||
{% tabs %}
|
||||
{% tabsitem #magicurl title="Magic URLs" %}
|
||||
|
||||
Magic URL authentication is a two-step process in Appwrite.
|
||||
|
||||
First, we initialize the login process by sending an email with the magic URL. If the email has never been used, a new account is also generated.
|
||||
|
||||
```client-web
|
||||
import { Client, Account, ID } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('https://cloud.appwrite.io/v1')
|
||||
.setProject('<PROJECT_ID>');
|
||||
|
||||
const account = new Account(client);
|
||||
|
||||
const user = await account.createMagicURLSession(ID.unique(), 'email@example.com', '<APP_URL>');
|
||||
```
|
||||
|
||||
After receiving the secret from an email, you can create a session for the user.
|
||||
|
||||
```js
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const secret = urlParams.get('secret');
|
||||
const userId = urlParams.get('userId');
|
||||
|
||||
const user = await account.updateMagicURLSession(userId, secret);
|
||||
```
|
||||
|
||||
{% /tabsitem %}
|
||||
|
||||
{% tabsitem #emailotp title="Email OTPs" %}
|
||||
|
||||
Email OTP authentication is a two-step process in Appwrite.
|
||||
|
||||
First, we initialize the login process by sending an email. If the email has never been used, a new account is also generated.
|
||||
|
||||
```client-web
|
||||
import { Client, Account, ID } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('https://cloud.appwrite.io/v1')
|
||||
.setProject('<PROJECT_ID>');
|
||||
|
||||
const account = new Account(client);
|
||||
|
||||
const sessionToken = await account.createEmailToken(
|
||||
ID.unique(),
|
||||
'email@example.com'
|
||||
);
|
||||
|
||||
const userId = sessionToken.userId;
|
||||
|
||||
```
|
||||
|
||||
After receiving the secret (6-digit number) in the email, you can use it along with the returned user ID to confirm the user.
|
||||
|
||||
```js
|
||||
const session = await account.createSession(
|
||||
userId,
|
||||
'[SECRET]'
|
||||
);
|
||||
```
|
||||
|
||||
{% /tabsitem %}
|
||||
|
||||
{% tabsitem #phoneotp title="Phone auth" %}
|
||||
|
||||
Phone authentication is a two-step process in Appwrite.
|
||||
|
||||
First, we initialize the login process by sending an SMS. If the phone number has never been used, a new account is also generated.
|
||||
|
||||
```client-flutter
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
|
||||
final client = Client()
|
||||
.setEndpoint('https://cloud.appwrite.io/v1')
|
||||
.setProject('<PROJECT_ID>');
|
||||
|
||||
final account = Account(client);
|
||||
|
||||
final sessionToken = await account.createPhoneSession(
|
||||
userId: ID.unique(),
|
||||
phone: '+14255550123'
|
||||
);
|
||||
|
||||
final userId = sessionToken.userId;
|
||||
```
|
||||
|
||||
After receiving the secret (6-digit number) in the SMS, you can use it along with the returned user ID to confirm the user.
|
||||
|
||||
```dart
|
||||
final session = await account.updatePhoneSession(
|
||||
userId: userId,
|
||||
secret: '[SECRET]'
|
||||
);
|
||||
```
|
||||
|
||||
{% /tabsitem %}
|
||||
{% /tabs %}
|
||||
|
||||
Passwordless authentication stands at the forefront of a new era in digital security and user experience. My recommendation to all is to embrace the future – say goodbye to passwords and hello to a more secure, convenient digital experience.
|
||||
|
||||
Learn more about Appwrite Authentication from our [docs](https://appwrite.io/docs/products/auth) and join our [Discord community](https://appwrite.io/discord) to interact with fellow developers using the same.
|
||||
@@ -0,0 +1,98 @@
|
||||
---
|
||||
layout: post
|
||||
title: Introducing Appwrite's React Native SDK in open beta
|
||||
description: A new SDK that allows more mobile developers to benefit from Appwrite's powerful tools.
|
||||
date: 2024-04-09
|
||||
cover: /images/blog/introducing-appwrite-react-native-sdk/cover.png
|
||||
timeToRead: 4
|
||||
author: vincent-ge
|
||||
category: product
|
||||
---
|
||||
|
||||
If you’re a mobile developer who doesn’t (want to) use Flutter, we have great news for you. Appwrite now has a React Native SDK in open beta. This will allow more mobile developers to benefit from Appwrite, giving everything you need to build your mobile applications backend, without the hassle of building it yourself.
|
||||
|
||||
## A brief history of React Native
|
||||
|
||||
[React Native](https://reactnative.dev/) has been a game-changer since its inception. Launched by Facebook in 2015, it emerged from the need to unify the development stacks for iOS and Android platforms, enabling a single codebase for both. Its importance to the developer community is monumental, enabling rapid development, offering native capabilities, and using one codebase for both iOS and Android platforms. With over 2,000 contributors on [GitHub](https://github.com/facebook/react-native) and used by thousands of apps worldwide, React Native has significantly contributed to the mobile development landscape by making app development more accessible, efficient, and scalable.
|
||||
|
||||
## Appwrite and React Native
|
||||
|
||||
The addition of the SDK to Appwrite is great news for React Native mobile developers. Appwrite's commitment to providing a secure, scalable backend, combined with React Native's efficiency and native capabilities, creates a strong toolkit for building mobile applications. This integration means developers can now enjoy the best of both worlds: Appwrite's [ready-to-use APIs](https://appwrite.io/docs/references) for Authentication, Database, Storage, Messaging, Realtime, and more, alongside React Native's seamless developer experience and native feel.
|
||||
|
||||
Appwrite already has a Web SDK, so why a dedicated React Native SDK? React Native requires abstractions of device and system APIs to access device permissions, cameras, storage, gyroscope, and more. Appwrite leverages [Expo](https://docs.expo.dev/) to implement APIs such as Appwrite Storage that require access to device and system APIs.
|
||||
|
||||
Why is this good news for the [React Native community](https://www.reddit.com/r/reactnative/)? It simplifies the development process significantly. With Appwrite's React Native SDK, setting up backend services becomes as straightforward as developing the front end. This means less time worrying about backend complexities and more time crafting exceptional user experiences.
|
||||
|
||||
As the SDK is released in open beta, we will be working with the React Native community to improve it. We invite all developers to use the SDK and share feedback to help us make it more stable in the next few months.
|
||||
|
||||
## Building mobile apps
|
||||
|
||||
What can you build with Appwrite and React Native? Basically, anything you can think of from social media platforms and e-commerce apps to productivity tools and interactive games. Appwrite even supports push notifications for your mobile app with [Messaging](https://appwrite.io/docs/products/messaging/send-push-notifications).
|
||||
|
||||
We’ve created a playground on [GitHub](https://github.com/appwrite/playground-for-react-native) where we will add simple ideas for getting started with Appwrite and React Native. You can also find inspiration from other Appwrite projects on [builtwithappwrite.io](http://builtwithappwrite.io) to see how other mobile developers have used Appwrite as their backend.
|
||||
|
||||
If you are used to working with [Firebase and React Native](https://stackshare.io/react-native-firebase/alternatives) but have been looking for an open-source alternative, Appwrite is now a solid choice.
|
||||
|
||||
## Getting started with Appwrite and React Native
|
||||
|
||||
Diving into Appwrite's React Native SDK is easy. Here's how to get started:
|
||||
|
||||
### Step 1: Set up Appwrite
|
||||
|
||||
First thing first, you must set up an Appwrite project. To do so, you must either [create an Appwrite Cloud account](https://cloud.appwrite.io) or [self-host Appwrite](https://appwrite.io/docs/advanced/self-hosting) on your system.
|
||||
|
||||

|
||||
|
||||
Once that is done, under **Add a platform**, add an **Android app** or an **Apple app**. You can skip optional steps.
|
||||
|
||||
- **iOS steps:** Add your app **name** and **Bundle ID**. You can find your **Bundle Identifier** in the **General** tab for your app's primary target in XCode.
|
||||
- **Android steps:** Add your app's **name** and **package name.** Your package name is generally the **applicationId** in your app-level `build.gradle` file.
|
||||
|
||||
## Step 2: Install the React Native SDK
|
||||
|
||||
Once Appwrite is up and running, install the React Native SDK in your project. This will connect your React Native app with Appwrite's suite of backend services. You can install the SDK (and necessary dependencies) using the following command:
|
||||
|
||||
```bash
|
||||
npx expo install react-native-appwrite react-native-url-polyfill
|
||||
```
|
||||
|
||||
### Step 3: Explore the Documentation
|
||||
|
||||
Familiarize yourself with [Appwrite's documentation](https://appwrite.io/docs). It's packed with tutorials, examples, and API references designed to get you up to speed in no time.
|
||||
|
||||
### Step 4: Start Building
|
||||
|
||||
With everything in place, you're ready to start building your app. The React Native SDK is designed to be intuitive, allowing you to implement features like authentication, database operations, and file storage with ease.
|
||||
|
||||
```js
|
||||
import { Client, Account, ID } from 'react-native-appwrite';
|
||||
|
||||
const client = new Client();
|
||||
|
||||
client
|
||||
.setEndpoint('http://cloud.appwrite.io/v1') // Your Appwrite Endpoint
|
||||
.setProject('455x34dfkj') // Your project ID
|
||||
.setPlatform('com.example.myappwriteapp'); // Your application ID or bundle ID
|
||||
|
||||
const account = new Account(client);
|
||||
|
||||
// Register a user
|
||||
account.create(ID.unique(), 'me@example.com', 'password', 'Jane Doe')
|
||||
.then(function (response) {
|
||||
console.log(response);
|
||||
}, function (error) {
|
||||
console.log(error);
|
||||
});
|
||||
```
|
||||
|
||||
Read the [quick start](http://appwrite.io/docs/quick-starts/react-native) to get started or find a [tutorial](http://appwrite.io/docs/tutorials/react-native/step-1) to build an ideas tracker with React Native.
|
||||
|
||||
## Resources
|
||||
|
||||
Visit our documentation to learn more about our SDKs, join us on Discord to be part of the discussion, view our blog and YouTube channel, or visit our GitHub repository to see our source code.
|
||||
|
||||
- [Docs](https://appwrite.io/docs/sdks)
|
||||
- [Discord](https://appwrite.io/discord)
|
||||
- [Blog](https://appwrite.io/blog)
|
||||
- [YouTube](https://www.youtube.com/channel/UCtBJ1v69gm8NgbCju_03Fiw)
|
||||
- [GitHub](https://github.com/appwrite/appwrite)
|
||||
@@ -25,7 +25,7 @@ This new feature, however, ensures you can use more readable and self-documentin
|
||||
|
||||
Bringing along benefits such as massively reducing friction when using routes that have predefined parameters. One of the most common examples of SDK Enums is OAuth providers. To log in with Apple, you must pass the `apple` string as the provider. With enums, you'll be able to pass `OAuthProvider.Apple` instead.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Account, OAuthProvider } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
|
||||
105
src/routes/blog/post/oauth-openid/+page.markdoc
Normal file
105
src/routes/blog/post/oauth-openid/+page.markdoc
Normal file
@@ -0,0 +1,105 @@
|
||||
---
|
||||
layout: post
|
||||
title: Understanding OAuth and OpenID Connect
|
||||
description: How OAuth and OpenID Connect work and why they are beneficial for application security.
|
||||
date: 2024-03-07
|
||||
cover: /images/blog/oauth-openid.png
|
||||
timeToRead: 6
|
||||
author: aditya-oberai
|
||||
category: authentication, security
|
||||
---
|
||||
|
||||
When it comes to web security, **OAuth** and **OpenID Connect (OIDC)** have revolutionized how we manage and secure user authentication and authorization. OAuth, primarily a protocol for authorization, enables third-party access to user data without exposing their credentials. On the other hand, OIDC, built on top of OAuth 2.0, extends this protocol by adding user authentication. These technologies provide a secure, efficient way for users to log in and share information across different services without compromising their privacy or security.
|
||||
|
||||
# What is OAuth?
|
||||
|
||||
OAuth is an open standard for access delegation commonly used as a way for internet users to grant websites or applications access to their information on other websites without giving them the actual user passwords. It's particularly useful for providing controlled access to resources hosted by a third-party service. OAuth 2.0, the latest version, simplifies the earlier protocol, offering improved security and interoperability.
|
||||
|
||||
## The OAuth 2.0 authorization flow
|
||||
|
||||
1. **User authorization request**: The process begins when a user tries to access a resource or service that requires them to log in via a third-party service (like logging into a website using their Google account). The website (client) redirects the user to log in to the third-party service (authorization server).
|
||||
2. **User login**: The user logs in to the third-party service. This step involves user authentication by the third-party service, but this authentication process is not part of OAuth—it's handled entirely by the third-party service.
|
||||
3. **Grant access**: After successful login, the third-party service asks the user if they want to grant the requesting website access to their information. If the user consents, the third-party service (authorization server) redirects the user back to the website with an authorization code.
|
||||
4. **Access token request**: The website (now having the authorization code) makes a separate request to the third-party service, exchanging the authorization code for an access token.
|
||||
5. **Access token response**: The third-party service responds with an access token (and sometimes a refresh token).
|
||||
6. **Resource access**: The website uses this access token to make requests to the third-party service’s resource server to access the user’s information. The resource server validates the access token and returns the requested resource.
|
||||
|
||||
## Use cases of OAuth 2.0
|
||||
|
||||
OAuth 2.0 is widely used for secure, delegated access across various applications. Some of its use cases include:
|
||||
|
||||
- **Social media logins**: Allowing users to log in to websites and apps using their social media accounts.
|
||||
- **Third-party application access**: Enabling apps to access services like email or calendars on behalf of the user.
|
||||
- **Single Sign-On (SSO)**: Facilitating one-login access to multiple enterprise applications.
|
||||
- **Payment gateway access**: Letting third-party vendors access transaction details or initiate payments via services like PayPal.
|
||||
- **Mobile app integrations**: Connecting mobile apps with other services and platforms for enhanced functionality.
|
||||
|
||||
# What is OpenID Connect?
|
||||
|
||||
OpenID Connect is a simple identity layer built on top of OAuth 2.0. It allows clients to verify the user's identity based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the user in an interoperable way.
|
||||
|
||||
OIDC uses OAuth 2.0 as its foundation. While OAuth 2.0 provides a framework for authorization, OIDC extends this to include authentication, delivering a more holistic security solution.
|
||||
|
||||
The core components of OpenID Connect include the ID token (a JWT that contains information about the user's session and authentication information), the User Info endpoint (to fetch user profile data), and the Discovery document (a JSON document listing crucial OIDC endpoints). The authentication process typically involves redirecting the user to an Authorization Server, logging in, and then being redirected back to the application with an ID Token and Access Token.
|
||||
|
||||
# Comparing OAuth and OpenID Connect
|
||||
|
||||
OAuth 2.0 and OpenID Connect are closely related standards used in online identity and access management, but they serve different purposes. Here are some key differences:
|
||||
|
||||
- **Primary focus**:
|
||||
- **OAuth 2.0** is a framework for authorization. It allows applications to obtain limited access to a user's data on another application or service.
|
||||
- **OpenID Connect** is built on top of OAuth 2.0 and is specifically designed for authentication. It allows applications to verify the identity of a user and obtain basic profile information.
|
||||
- **Token usage**:
|
||||
- **OAuth 2.0** provides access tokens, which are used by applications to access APIs on behalf of the user.
|
||||
- **OpenID Connect** provides an ID Token in addition to the access token. The ID Token is a JWT (JSON Web Token) used for identity verification and contains user profile information.
|
||||
- **User information**:
|
||||
- **OAuth 2.0** doesn't standardize (or provide) information about the user. It focuses on the scopes and permissions given to the access token.
|
||||
- **OpenID Connect** standardizes the way applications can receive identity information about the user in a secure and RESTful manner.
|
||||
- **Scenarios**:
|
||||
- **OAuth 2.0** is used when an application needs to perform actions or access resources from another service on behalf of the user without needing to know the user's identity.
|
||||
- **OpenID Connect** is used when an application needs to authenticate the user and potentially access basic profile information.
|
||||
- **Compatibility and extension**:
|
||||
- **OAuth 2.0** serves as a base for various protocols, including OpenID Connect.
|
||||
- **OpenID Connect** is an extension of OAuth 2.0, adding an additional layer specifically for user authentication.
|
||||
|
||||
## Security best practices
|
||||
|
||||
Implementing OAuth and OIDC securely involves using secure channels for all communications, validating all tokens, employing state parameters to mitigate CSRF attacks, and regularly updating and auditing your security configurations. Here are some best practices for ensuring security in OAuth and OIDC implementations:
|
||||
|
||||
- **Use HTTPS**: Always use HTTPS to protect the data in transit against interception and tampering. This is essential for all communications in OAuth and OpenID Connect flows.
|
||||
- **Validate redirect URIs**: Strictly validate redirect URIs to prevent redirection attacks. Ensure that the redirect URI in an authorization request matches the one registered with the authorization server.
|
||||
- **Use 'state' parameter**: Implement the 'state' parameter in OAuth flows to mitigate Cross-Site Request Forgery (CSRF) attacks. This parameter should be a random value that is validated at the beginning and end of the flow.
|
||||
- **Utilize PKCE (Proof Key for Code Exchange)**: Especially in mobile and single-page applications, use PKCE to enhance the security of the authorization code flow.
|
||||
- **Secure client credentials**: Store client credentials securely. Avoid exposing client secrets in client-side code.
|
||||
- **Token security**: Use access tokens and ID tokens securely. Avoid storing tokens in insecure locations. Implement token expiration and refresh token rotation.
|
||||
- **Validate ID tokens**: When using OpenID Connect, properly validate the ID token, especially its signature and the issuer.
|
||||
- **Implement scopes and consent appropriately**: Define scopes clearly and request only the permissions that are necessary. Always get user consent where applicable.
|
||||
|
||||
# Using OAuth and OpenID Connect with Appwrite
|
||||
|
||||
Appwrite Authentication features support for over 30 OAuth 2.0 adapters, including a generic OIDC adapter, out of the box for developers to implement. To set up the generic OIDC adapter, you need the following details:
|
||||
|
||||
- Client ID
|
||||
- Client Secret
|
||||
- Well-Known Endpoint
|
||||
- Authorization Endpoint
|
||||
- Token Endpoint
|
||||
- User Info Endpoint
|
||||
|
||||
Appwrite provides the necessary redirect URL to add to your OIDC app configuration.
|
||||
|
||||
Once that is done, you can use any of the Appwrite client SDKs to implement OAuth 2.0 or OIDC authentication in just a few lines of code.
|
||||
|
||||
```client-web
|
||||
import { Client, Account, OAuthProvider } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
.setEndpoint('https://cloud.appwrite.io/v1')
|
||||
.setProject('<PROJECT_ID>');
|
||||
|
||||
const account = new Account(client);
|
||||
|
||||
account.createOAuth2Session(OAuthProvider.Oidc, '[LINK_ON_SUCCESS]', '[LINK_ON_FAILURE]');
|
||||
```
|
||||
|
||||
To learn more about Appwrite and OAuth 2.0, ensure you visit the [Appwrite documentation](https://appwrite.io/docs/products/auth/oauth2).
|
||||
@@ -0,0 +1,146 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Appwrite vs Firebase: An open source alternative for Firebase"
|
||||
description: Get a comprehensive comparison between Appwrite and Firebase to decide what platform to use for your project's backend. And learn how Appwrite's open source nature allows you total control of your project's data.
|
||||
date: 2024-02-03
|
||||
cover: /images/blog/open-source-firebase-alternative/cover.png
|
||||
timeToRead: 7
|
||||
author: aditya-oberai
|
||||
category: product
|
||||
---
|
||||
|
||||
If you are looking to build a mobile app, website, tool, or any other application that needs a backend, then you also know the daunting tasks that await. This is probably what brought you to this blog in the first place: looking for a solution to take care of your backend. BaaS provides pre-built backend infrastructure and services to simplify app development, handling server-side tasks like data storage, user management, APIs, server maintenance, security, database management, and more. Two of these services are Firebase and Appwrite.
|
||||
|
||||
Appwrite and Firebase are both solid options to choose as the Backend-as-a-Service (BaaS) for your app. However, their feature sets can vary substantially. In this article, we will give you a rundown of Appwrite and Firebase to understand how each provider will fit your specific needs.
|
||||
|
||||
# Appwrite - Open-source backend platform
|
||||
|
||||
In 2019, [Appwrite](https://appwrite.io/) started as an open-source project to make software development more accessible and enjoyable. It is a Backend as a Service platform with a vibrant developer community. You can self-host Appwrite on your server or utilize [Appwrite Cloud](https://cloud.appwrite.io/). Appwrite provides many features, including user authentication, databases, storage, real-time features, and functions. It is known for its flexibility, security, and extensibility, enabling you to customize backend logic and build applications tailored to your needs. You can view Appwrite’s source code on [GitHub](https://github.com/appwrite/appwrite).
|
||||
|
||||
# Firebase - Google-owned BaaS
|
||||
|
||||
Firebase was founded in 2011 as a real-time chat API. It gradually evolved into a real-time database and later pivoted to the backend-as-a-service it is today. It offers various services, including real-time databases, cloud hosting, user authentication, cloud functions, analytics, and more. Firebase has been well-known and widely used in the market as the only BaaS for a long time.
|
||||
|
||||
# Features compared
|
||||
|
||||
When looking into a BaaS solution, it is good to understand how the products and features can serve your project’s needs. We compiled a list of similarities and differences between Appwrite and Firebase for you to understand both offerings better.
|
||||
|
||||
## Authentication
|
||||
|
||||
Authentication is the process of verifying a user's identity. This is typically done by providing agreed-upon credentials, which are pieces of information shared between the user and the system. There are different authentication methods, including email and passwords, phone verification, or applications that offer single sign-on (SSO) capabilities. It is usually the initial step in application development for developers. BaaS platforms simplify this process by offering SDKs and APIs.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both Appwrite and Firebase offer comprehensive user authentication and authorization capabilities.
|
||||
- Both use industry-leading hashing algorithms to protect user passwords.
|
||||
- They provide various authentication methods, including email/password, social login, OTP-based login, and JWTs.
|
||||
- Both platforms support different user roles and permissions for granular access control.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite's authentication system allows developers to integrate with any existing external authentication systems through [custom token login](https://appwrite.io/docs/products/auth/custom-token), which allows for various new use cases such as passkey authentication. It also allows for password [history](https://appwrite.io/docs/products/auth/security#password-history) and [dictionary](https://appwrite.io/docs/products/auth/security#password-dictionary), [session limits](https://appwrite.io/docs/products/auth/security#session-limits), and [personal data](https://appwrite.io/docs/products/auth/security#personal-data) checks on your passwords.
|
||||
- Firebase offers a user-friendly authentication system that seamlessly integrates with other Firebase services, providing developers with a streamlined experience.
|
||||
|
||||
## Database
|
||||
|
||||
A database is an organized collection of information stored in a way that allows for easy access, retrieval, management, and updating. Databases store and manage large volumes of structured and unstructured data, supporting activities such as data storage, analysis, and management. They are integral to any application.
|
||||
|
||||
Both Appwrite and Firebase provide databases that can be used depending on the needs of your project.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both Appwrite and Firebase offer managed databases on their cloud offering.
|
||||
- Both platforms support real-time data updates for reactive applications.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite's database offers an abstraction layer on top of MariaDB, allowing developers to develop custom schema and use queries without any pre-existing SQL knowledge. Also, you can [configure permissions](https://appwrite.io/docs/advanced/platform/permissions#appwrite-resource) in Appwrite within the Console, making this an easy task.
|
||||
- Firebase provides a NoSQL, document-oriented database called Cloud Firestore for storing and managing data in a non-relational manner. To manage permissions, they offer a different product called Security Rules, which allows more flexibility but increases the learning curve.
|
||||
|
||||
## Storage
|
||||
|
||||
Storage allows you to manage files in your project. It can store images, videos, documents, and other project files. Storage is a crucial requirement for every application, and here's what Appwrite and Firebase have to offer:
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both Appwrite and Firebase provide cloud storage for storing files and media content.
|
||||
- They offer both scalable object storage and structured file storage options.
|
||||
- Both platforms provide permissions systems for secure access controls.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Firebase's storage system is a direct extension of Google Cloud Storage and has additional out-of-the-box integrations such as image filtering and video transcoding.
|
||||
- Appwrite Storage offers a dedicated API for [image transformations](https://appwrite.io/docs/products/storage/images), including functionalities such as manipulating resolution, image reformatting, caching, and compression.
|
||||
- Appwrite Storage offers file encryption for increased security as well as gzip and zstd compression for network transfer optimization.
|
||||
|
||||
## Functions
|
||||
|
||||
Functions are "self-contained" modules of code that accomplish a specific task. BaaS platforms make it easier for you to extend the business logic by using functions with code snippets.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Both Appwrite and Firebase provide serverless computing solutions for executing code in the cloud.
|
||||
- Both Appwrite and Firebase provide templates or extensions to build apps easily.
|
||||
- They offer asynchronous, scheduled, and real-time functions.
|
||||
- Functions in both platforms are event-driven, executing in response to specific events, such as HTTP requests, database changes, or authentication events.
|
||||
- Both provide automatic scaling. They handle increasing loads by scaling the functions up or down as required.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite offers easy and quick deployment of [functions using Git](https://appwrite.io/docs/products/functions/deploy-from-git), has ready-to-use templates, and supports a large number of runtimes.
|
||||
- Appwrite supports [function runtimes across over 10 different languages](https://appwrite.io/docs/products/functions/runtimes), including Dart, Bun, Kotlin, and Swift, whereas Firebase only supports JavaScript, TypeScript, and Python.
|
||||
- Firebase offers additional event triggers for different Google Cloud services.
|
||||
|
||||
## Realtime
|
||||
|
||||
Real-time, by definition, means "without significant delay.” You can use it to get constant updates on any activities that occur within the application you are building. This can be applied in various ways, such as a chat application. While real-time features can be complex to build, you can use Appwrite and Firebase to achieve this with much less hassle.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- Appwrite and Firebase provide real-time data updates for applications requiring synchronized data access.
|
||||
- They leverage WebSockets for real-time communication.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite's real-time system is built on top of our internal events system, which means that any new product/features will automatically support real-time.
|
||||
- Firebase only offers real-time updates from its Realtime Database offering, whereas every Appwrite offering supports real-time updates.
|
||||
|
||||
## Messaging
|
||||
|
||||
Messaging allows you to implement communications in your application. You can use this to send information and updates directly to users through various methods, such as push notifications, SMSes, and emails. Both Appwrite and Firebase provide certain features to implement messaging in your applications.
|
||||
|
||||
*Similarities:*
|
||||
|
||||
- You can use real-time features along with databases in both Appwrite and Firebase to create a chat application.
|
||||
- You can use functions in both Appwrite and Firebase to use external providers for SMSes and emails.
|
||||
|
||||
*Differences:*
|
||||
|
||||
- Appwrite Messaging features ten different providers to leverage major communications providers for SMS, email, and push notifications. It offers user segregation, message scheduling, and message previews as well.
|
||||
- Firebase offers the infrastructure to implement push notifications via Firebase Cloud Messaging (FCM). Appwrite doesn’t have its own infrastructure but contains a provider to implement FCM.
|
||||
- Firebase offers In-App Messaging to help you engage your app's active users through targeted, contextual messages inside the app. Appwrite does not offer this feature yet but aims to do so in the future.
|
||||
|
||||
# Conclusion
|
||||
|
||||
While both Appwrite and Firebase are great Backend-as-a-Service offerings that support numerous SDKs and integrations, they differ in terms of capabilities and pricing. The choice between Appwrite and Firebase hinges on the specific needs of a project. Appwrite stands out with its open-source nature, self-hosting capabilities, pricing affordability, and emphasis on privacy. The community is very welcoming and is praised for it. Firebase's strength lies in its comprehensive ecosystem, Google support, and maturity.
|
||||
|
||||
Here’s a table that compares both Appwrite and Firebase:
|
||||
|
||||
| Feature | Appwrite | Firebase |
|
||||
| --- | --- | --- |
|
||||
| Deployment | Self-hosted or cloud-hosted | Cloud-hosted only |
|
||||
| Free plan | Yes, Starter plan | Yes, Spark plan |
|
||||
| Paid plan | Yes, Pro plan - $15 per month per member and addons | Yes, Blaze plan - Pay-as-you-go |
|
||||
| Open source | Yes | No |
|
||||
| Support | Community and email | Community, Support Portal, and help center |
|
||||
| Functions marketplace | Has a marketplace featuring a variety of function templates and integrations such as Discord bots, payments with Stripe, ChatGPT API, etc. | Has an extensions hub featuring pre-built functions ready to deploy. |
|
||||
| Messaging providers | 10 providers covering SMS, email, and push notifications | No external providers, but offers the infrastructure for FCM and In-App Messaging |
|
||||
|
||||
# Resources
|
||||
|
||||
If you want to learn more about Appwrite, you can find more resources below.
|
||||
|
||||
- [Appwrite documentation](https://appwrite.io/docs) - Visit Appwrite’s docs to learn how to get started and more about Appwrite’s functionality.
|
||||
- [Appwrite GitHub repository](https://github.com/appwrite/appwrite/stargazers)Explore the code and architecture and see how you can contribute to Appwrite.
|
||||
- [Appwrite Discord](https://appwrite.io/discord) - Join Appwrite’s Discord server, be part of a vibrant community, and get support.
|
||||
- [Appwrite YouTub](https://www.youtube.com/@Appwrite)
|
||||
@@ -74,7 +74,7 @@ PBKDF2 is a widely-used password hashing algorithm that iteratively applies a ps
|
||||
|
||||
Appwrite Authentication also leverages password hashing algorithms to allow developers to secure their users’ passwords via password hashing algorithms. Appwrite uses the `Argon2id` algorithm to hash the password when a user creates an account from a client-side application. Appwrite’s SDKs offer a simple abstraction for the Appwrite Accounts API to let developers implement this, like the following example:
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Account, ID } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
---
|
||||
layout: post
|
||||
title: How Appwrite Databases can replace your PlanetScale database
|
||||
description: Compare PlanetScale Databases to Appwrite Databases so you can understand whether Appwrite is a viable alternative to PlanetScale's free-tier.
|
||||
date: 2024-03-10
|
||||
cover: /images/blog/planetscale-databases-alternative/cover.png
|
||||
timeToRead: 7
|
||||
author: aditya-oberai
|
||||
category: product
|
||||
---
|
||||
|
||||
On March 6th, 2024, PlanetScale announced their plan to sunset their free tier, impacting developers and their projects worldwide. Many devs are now forced to migrate away and find a new database solution. As an open-source backend-as-a-service platform, Appwrite can be the solution to finding a PlanetScale alternative. In this article, we compare PlanetScale Databases to Appwrite Databases so you can understand whether Appwrite’s free-tier Databases are a feasible option.
|
||||
|
||||
# How Appwrite can help
|
||||
|
||||
When comparing PlanetScale with Appwrite, it's essential to understand that they serve somewhat different purposes. PlanetScale is known to be a highly scalable, MySQL-compatible database service, focusing on providing a robust solution for scaling relational databases horizontally. Appwrite, on the other hand, offers a more comprehensive set of products for your backend, including Databases, Authentication, Functions, Storage, and Messaging. If PlanetScale is a great screwdriver set, Appwrite is a Swiss Army Knife for the developer.
|
||||
|
||||
## An all-in-one package
|
||||
|
||||
Appwrite is a backend-as-a-service platform that offers a variety of products to enable developers to build their applications faster and better. Here are the core products Appwrite offers:
|
||||
|
||||
- **Authentication:** Manage user registration, login, and account functionalities. It supports multiple sign-in methods as well as two-factor authentication.
|
||||
- **Database:** Create and manage databases to store and query your application's data.
|
||||
- **Storage:** Securely store and manage files used within your application. Appwrite also allows for file previews and image manipulations.
|
||||
- **Functions:** Execute custom code within a secure environment to implement specific application logic without managing servers.
|
||||
- **Messaging:** Communicate with your users through push notifications, emails, and SMS text messages.
|
||||
- **Realtime:** Enable real-time updates and synchronization within your application for features like chat or collaborative editing.
|
||||
|
||||
[Signing up for Appwrite Cloud](https://cloud.appwrite.io/register) or self-hosting it on your server doesn't just give you access to one of these, but all of these.
|
||||
|
||||
Let’s delve further into some of our developer experience and more database-oriented benefits.
|
||||
|
||||
## API-first approach
|
||||
|
||||
A major difference that Appwrite has from other database-as-a-service offerings like PlanetScale is that instead of directly querying the underlying database, we offer APIs to interact with the product.
|
||||
|
||||
This approach offers several advantages:
|
||||
|
||||
- **Simpler interactions with data:** Developers can perform CRUD actions easily through straightforward HTTP requests. Knowledge of SQL isn’t mandatory anymore.
|
||||
- **Works with any language**: Any programming language or platform capable of making HTTP requests can consume Appwrite Databases, making it highly versatile.
|
||||
- **Additional security**: Integrated authentication and access control ensure that data is only accessible to authorized users, keeping your application secure.
|
||||
- **Easier education:** Detailed API documentation and SDKs for various languages offer a smooth developer experience, making it easy to get started and efficient to use.
|
||||
|
||||
Leveraging an API-first approach, we have built a lot of abstractions to interact with the underlying MariaDB database in Appwrite and not just to perform CRUD actions on the tables but also to handle the creation and management of databases, tables, columns, indexes, and relationships. This experience extends beyond Appwrite Databases to all other Appwrite products.
|
||||
|
||||
## SDKs and developer tooling
|
||||
|
||||
To decrease the friction in building for all developers and complement our API-first approach, Appwrite offers over 10 SDKs across languages such as JavaScript, Python, Dart, and Kotlin, as well as a CLI that works on Linux, MacOS, and Windows-based systems.
|
||||
|
||||
- **Simplicity:** SDKs eliminate the need for developers to write code from scratch to interact with Appwrite's API, saving them time and effort.
|
||||
- **Consistency and reliability**: SDKs and the CLI ensure that applications use Appwrite’s API correctly and efficiently while retaining type safety, reducing the risk of errors.
|
||||
- **Enhanced productivity:** By automating and simplifying tasks, SDKs and CLI help developers accomplish more in less time, boosting productivity. They make integrating Appwrite’s features, test applications, and deploy updates easier.
|
||||
|
||||
This way, any developer transitioning to Appwrite can get started with our stack quickly and easily.
|
||||
|
||||
## Self-hosting Appwrite
|
||||
|
||||
Since Appwrite is open-source, we have simplified the process to self-host it. This has several benefits:
|
||||
|
||||
- **Control**: You gain complete authority over your server environment and configurations.
|
||||
- **Privacy and security**: You can keep all data in-house for enhanced security and compliance with data protection laws.
|
||||
- **Cost efficiency**: You might potentially lower expenses over time by optimizing resources and avoiding third-party fees.
|
||||
- **Reduced latency:** Hosting closer to your clients may help improve application performance.
|
||||
- **Avoid vendor lock-in**: You're not tied to the services, pricing, and terms of a specific cloud provider.
|
||||
|
||||
Currently, Appwrite uses Docker Compose to deliver all the necessary services and components necessary for the platform. We provide a single installation command to set up an Appwrite instance on any system with Docker.
|
||||
|
||||
```bash
|
||||
docker run -it --rm \
|
||||
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||
--volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \
|
||||
--entrypoint="install" \
|
||||
appwrite/appwrite:1.5.4
|
||||
```
|
||||
|
||||
We have a dedicated [self-hosting guide](https://appwrite.io/docs/advanced/self-hosting) in our docs for more info.
|
||||
|
||||
## Managed databases on Appwrite Cloud
|
||||
|
||||
With Appwrite Cloud, our Database offering is fully managed. This means that our team handles any administrative tasks associated with running the underlying database. This carries several key benefits:
|
||||
|
||||
- **Automated backups**: Regular snapshots of the database are taken automatically to ensure data can be restored in case of loss.
|
||||
- **Scaling**: Resources (CPU, memory, storage) are adjusted by our team according to demand, often with minimal or no downtime.
|
||||
- **Monitoring and alerts**: There is continuous monitoring of database performance and health, with alerts for any issues, which are team takes care of.
|
||||
- **Maintenance and updates**: We handle updates to the database software and operating system, applying patches and security fixes as needed.
|
||||
- **Enhanced security:** We maintain robust security measures to protect your data.
|
||||
|
||||
One of the biggest advantages of Appwrite Cloud is that these benefits are not just restricted to paid customers but also available to consumers of our free tier.
|
||||
|
||||
## Pricing plans
|
||||
|
||||
With Appwrite Cloud, we have mindfully designed our pricing plans to be accessible to most developers. Right now, we offer two [pricing plans on Appwrite Cloud](https://appwrite.io/pricing).
|
||||
|
||||
- **Starter plan**
|
||||
- A free tier for every developer working on a side project or SaaS product that can thrive on our starter plan limits.
|
||||
- Free of cost
|
||||
- **Pro plan**
|
||||
- A plan that supports your ambitions to scale your production project and allows you to grow.
|
||||
- Comes with flexible budget control tools to ensure you never get a surprise bill.
|
||||
- $15, per month, per member.
|
||||
|
||||

|
||||
|
||||
For databases, here are the differences between both plans:
|
||||
|
||||
| Category | Starter plan | Pro plan |
|
||||
| --- | --- | --- |
|
||||
| Databases | 1 per project | Unlimited |
|
||||
| Documents | Unlimited | Unlimited |
|
||||
| Reads & Writes | Unlimited | Unlimited |
|
||||
| Dedicated databases | No | Yes |
|
||||
|
||||
You can also look at PlanetScale [pricing](https://planetscale.com/pricing) to understand how Appwrite compares.
|
||||
|
||||
# Moving forward
|
||||
|
||||
There is no denying that PlanetScale has done a fantastic job developing a scalable and robust database offering. They are a massive inspiration in the database space and the larger developer tooling ecosystem. That being said, there are gaps in the developer community that PlanetScale chooses not to prioritize due to their business growth plans, which we can help with. Free users have formed an influential part of the Appwrite community and have made a difference not just as consumers but also as builders, public speakers, contributors, etc., who have constantly criticized and shared feedback, added ideas and suggestions, and made Appwrite a much better platform. We hope we will see more such developers give us a shot in the days to come.
|
||||
|
||||
Learn more about Appwrite by visiting our [docs](https://appwrite.io/docs) and joining our [Discord community](https://appwrite.io/discord).
|
||||
@@ -0,0 +1,68 @@
|
||||
---
|
||||
layout: post
|
||||
title: "The cost of convenience: preventing password sharing"
|
||||
description: How we as developers can prevent password sharing and make our applications more secure.
|
||||
date: 2024-03-07
|
||||
cover: /images/blog/preventing-password-sharing.png
|
||||
timeToRead: 6
|
||||
author: aditya-oberai
|
||||
category: authentication, security
|
||||
---
|
||||
|
||||
Over the last few years, password sharing has emerged as a notable challenge for developers and companies, intertwining concerns of security, privacy, and revenue. Although seemingly benign, this practice has significant implications, especially for platforms with seat-based pricing models. Netflix made waves in 2023 with its [ban on account sharing](https://www.techradar.com/news/netflix-password-sharing), spotlighting the potential revenue loss businesses face when users circumvent subscription models designed to reflect actual usage. Beyond financial repercussions, the critical importance of addressing password sharing simply cannot go unaddressed today.
|
||||
|
||||
# Understanding the risks of password sharing
|
||||
|
||||
Despite its commonality in both personal and professional contexts, password sharing poses significant risks for businesses across various sectors. This practice can undermine the security infrastructure, compromise sensitive data, and even affect the financial health of an organization. Here are the key risks associated with password sharing for businesses:
|
||||
|
||||
- **Security breaches**: Increases vulnerability to unauthorized access and cyberattacks.
|
||||
- **Data leaks**: Raises the likelihood of unintentional exposure of sensitive information.
|
||||
- **Compliance violations**: Can lead to breaches of regulatory standards (e.g., GDPR, HIPAA), resulting in fines and sanctions.
|
||||
- **Diminished accountability**: Makes it difficult to trace activities and attribute actions back to individual users accurately.
|
||||
- **Operational disruptions**: Causes inefficiencies and potential system lockouts affecting productivity in certain scenario (for instance, if shared accounts are locked out due to suspicious activities).
|
||||
- **Increased IT support costs**: Requires additional resources to manage and resolve access issues.
|
||||
- **Erosion of trust**: Undermines customer and partner confidence if security is compromised.
|
||||
- **Loss of intellectual property**: Enhances the risk of proprietary information theft.
|
||||
|
||||
# Best practices for secure authentication
|
||||
|
||||
To prevent password sharing and enhance security, businesses and software development teams can adopt various authentication best practices. These methods secure access to systems and data and encourage individual accountability and compliance with regulatory standards. Here are some of the most effective authentication best practices:
|
||||
|
||||
- **Enforce multi-factor authentication:** Use MFA to require multiple verification factors, making unauthorized access more difficult.
|
||||
- **Passkeys and passwordless authentication:** Adopt passkeys or passwordless methods that rely on cryptographic keys or biometrics, eliminating the need for passwords and reducing phishing risks.
|
||||
- **Time-based One-Time Passwords (TOTP):** Deploy TOTPs that expire quickly to minimize the risk of password theft.
|
||||
- **Enable role or policy-based access control:** Apply RBAC or PBAC to ensure users access only what they need for their roles, minimizing unnecessary access and reducing the incentive for password sharing.
|
||||
- **Password policies:** Enforce regular password changes and complexity requirements judiciously to discourage password sharing without burdening users.
|
||||
- **Education and awareness:** Foster security awareness through education on the importance of secure authentication practices and the risks of password sharing.
|
||||
|
||||
# Technological solutions to prevent password sharing
|
||||
|
||||
To prevent password sharing and enhance security, several tools and technologies are available that help organizations control access and monitor usage. These include:
|
||||
|
||||
## 1. Authentication systems
|
||||
|
||||
- **Multi-factor authentication (MFA)**: Tools like Duo Security, Authy, and Google Authenticator add an extra layer of security by requiring additional verification beyond just a password. We at Appwrite have also recently announced our own 2FA solution for consumers of our Authentication product, which you can read about in our [product announcement](https://appwrite.io/blog/post/announcing-two-factor-authentication).
|
||||
- **Single Sign-On (SSO) providers**: Solutions like Okta, Azure Active Directory, and OneLogin allow users to access multiple applications with a single set of credentials, reducing the temptation to share passwords.
|
||||
|
||||
## 2. Passwordless authentication technologies
|
||||
|
||||
- **Biometric authentication systems**: These systems use fingerprints, facial recognition, or iris scans for secure access, available through smartphones and specialized hardware.
|
||||
- **FIDO2 security keys**: Devices such as YubiKey or Titan Security Key support passwordless login, offering a physical hardware-based second factor.
|
||||
|
||||
## 3. Access management tools
|
||||
|
||||
- **Privileged Access Management (PAM) solutions**: CyberArk, BeyondTrust, and Thycotic secure, control, and monitor access to critical assets and infrastructure, limiting the need for shared passwords.
|
||||
- **Role-Based Access Control (RBAC) Systems**: Built into many cloud platforms (AWS IAM, Azure Role-Based Access Control) and enterprise systems to ensure users have access only to what they need based on their role.
|
||||
|
||||
## 4. User and entity behavior analytics
|
||||
|
||||
- **Behavioral analytics tools**: Solutions like Exabeam and Splunk use analytics to detect abnormal behavior that might indicate shared passwords or other security risks.
|
||||
|
||||
## 5. Educational and policy management tools
|
||||
|
||||
- **Security awareness training platforms**: KnowBe4, Proofpoint, and Mimecast offer training to educate employees about the risks of password sharing and promote secure practices.
|
||||
- **Policy management software**: Tools for creating, managing, and enforcing security policies can help organizations maintain standards that discourage password sharing.
|
||||
|
||||
# Developing a culture of security among developers
|
||||
|
||||
Cultivating a culture of security within software development teams is crucial today. This entails a collective commitment to upholding security protocols, including the prevention of password sharing. By embedding security as a core value, organizations can foster an environment where best practices are not only understood but embraced. This cultural shift is instrumental in ensuring that security considerations are integrated into every aspect of the development process, thereby safeguarding against potential vulnerabilities. As the software development community moves forward, the collective effort to combat password sharing will undoubtedly contribute to a more secure environment for all.
|
||||
@@ -53,7 +53,7 @@ The content of the messages plays a crucial role. Here are some best practices t
|
||||
|
||||
The newly released Appwrite Messaging substantially simplifies your process of sending out push notifications to your application’s users. We have added simple-to-use adapters for Firebase Cloud Messaging (FCM) and Apple Push Notification Service (APNS) to let you send push notifications to let you send push notifications to both Android and iOS users.
|
||||
|
||||
```js
|
||||
```server-nodejs
|
||||
const sdk = require('node-appwrite');
|
||||
|
||||
// Init SDK
|
||||
|
||||
@@ -70,7 +70,7 @@ Here's an overview of the Twilio Programmable Messaging:
|
||||
|
||||
As a part of our latest release, Appwrite 1.5, we have launched a new product, Messaging, that helps developers implement communication services within their applications. As a part of the SMS offering within Messaging, we have added an adapter to integrate Twilio Programmable Messaging with Appwrite. Once you have access to your account SID, auth token, and phone number from Twilio, you will be able to send messages to your users with just a few lines of code.
|
||||
|
||||
```js
|
||||
```server-nodejs
|
||||
const sdk = require('node-appwrite');
|
||||
|
||||
// Init SDK
|
||||
|
||||
55
src/routes/blog/post/social-media-auth/+page.markdoc
Normal file
55
src/routes/blog/post/social-media-auth/+page.markdoc
Normal file
@@ -0,0 +1,55 @@
|
||||
---
|
||||
layout: post
|
||||
title: "Social media authentication: convenience vs privacy"
|
||||
description: Let's discuss the pros and cons of social media authentication and the delicate balance of convenience and privacy surrounding it.
|
||||
date: 2024-03-18
|
||||
cover: /images/blog/social-media-auth/cover.png
|
||||
timeToRead: 5
|
||||
author: aditya-oberai
|
||||
category: authentication
|
||||
---
|
||||
|
||||
Social media authentication has become an integral part of our digital lives, offering a streamlined way to access various online services. We may not even realize it at times; however, logging in with Facebook, X, Linkedin, and other such providers are common authentication methods we come across in most major applications today. There are challenges to using social media providers as authentication methods, though. A [massive Facebook incident in 2021](https://abcnews.go.com/International/facebook-outage-highlights-risks-overdependence-single-tech-giant/story?id=80413709) rendered over a billion people helpless as they lost access to a major part of the internet. Such dependence on major social media providers for essential internet activity can have major drawbacks, too. Therefore, in this blog, let us discuss the pros and cons of social media authentication and the delicate balance of convenience and privacy surrounding it.
|
||||
|
||||
# The benefits of social media authentication
|
||||
|
||||
Social media authentication has a number of benefits for developers and consumers of their products:
|
||||
|
||||
- **Simplified login process**: Social media authentication streamlines the login process. Users can access multiple services without the need to create and remember different usernames and passwords. This ease of access reduces friction and enhances user experience significantly.
|
||||
- **Increased registration and conversion rates**: For websites and apps, offering social media authentication can lead to higher registration rates. Users are more likely to sign up for a service if they can do it with just a few clicks rather than filling out a lengthy registration form.
|
||||
- **Reduced password fatigue**: With the overwhelming number of online accounts today, password fatigue is a real issue. Social media authentication helps mitigate this by reducing the number of passwords a user has to remember.
|
||||
- **Faster account recovery**: Recovering accounts is generally more straightforward with social media authentication, as it often involves fewer steps than traditional email/password recovery processes.
|
||||
- **Social proof and trust**: Users often trust social media platforms they frequently use. By offering authentication through these platforms, services can leverage this trust, making users feel more secure about signing up or logging in.
|
||||
- **Improved security**: Often, social media platforms have robust security measures in place. Using their authentication systems can, in some cases, offer better security than relying on traditional username-password systems, especially if users tend to create weak passwords.
|
||||
- **Access to social data**: For businesses, social media authentication can provide access to certain user data from their social media profiles (with user consent). This data can be used to personalize and enhance the user experience.
|
||||
|
||||
# The drawbacks of social media authentication
|
||||
|
||||
While the list of benefits that social media authentication brings is not small, the drawbacks are not insignificant. Here are some of the cons to keep in mind:
|
||||
|
||||
- **Privacy concerns**: Social media authentication often requires sharing personal information from social media accounts with third-party services. Users may unintentionally grant access to more data than they realize, raising serious privacy concerns.
|
||||
- **Data security risks**: Linking multiple accounts through social media authentication can create a single point of failure. If a user's social media account is compromised, it could potentially jeopardize the security of all connected accounts.
|
||||
- **Limited control over data**: Users typically have less control over what data is shared when using social media login options. They might be sharing personal information like email addresses, friend lists, or even browsing habits without explicit knowledge.
|
||||
- **Dependency on social media platforms**: This authentication method creates a dependency on social media platforms. If a social media service experiences downtime or decides to change its policy or authentication process, it can directly impact all linked services. Additionally, if a user loses access to their social media account, it also means losing access to all relying services.
|
||||
- **Loss of anonymity**: Users may prefer to keep their social media profiles private and separate from other online activities. Social media authentication can erode this separation, leading to a loss of anonymity online.
|
||||
- **Potential for data breaches**: The interconnectedness of accounts through social media authentication can escalate the impact of data breaches. A breach in one service could potentially expose information across multiple platforms.
|
||||
- **Legal and compliance issues**: Relying on social media authentication can complicate compliance with privacy laws and regulations, such as GDPR, especially when it comes to obtaining consent for data sharing and processing.
|
||||
|
||||
# Implementing alternative authentication methods
|
||||
|
||||
Developers have several alternative authentication methods at their disposal, offering different benefits in terms of security, privacy, and user experience. Here are some noteworthy alternatives:
|
||||
|
||||
- **Email and password**: The traditional method of using a unique combination of email and password remains popular. It gives users full control over their credentials, though it requires robust security measures to prevent breaches.
|
||||
- **Biometric authentication**: Utilizing fingerprints, facial recognition, or iris scans for authentication. This method offers high security and a good user experience but requires specific hardware and can raise privacy concerns.
|
||||
- **Magic links**: These are one-time-use links sent to the user's email address. Clicking the link logs the user into the application. Magic links enhance security by eliminating the need for passwords and are user-friendly.
|
||||
- **OTP-based authentication**: This involves sending a code via SMS or email to a user, which they enter into the application. While user-friendly, this method has been criticized for security vulnerabilities (especially with SMS).
|
||||
- **Smart cards and USB keys**: Physical devices like smart cards or USB keys can be used for authentication. They provide a high level of security but require users to have the physical device on hand.
|
||||
- **Federated identity**: This involves linking the user's identity across multiple systems and services, allowing for the portability of identity and personal information. It's complex to implement but offers a seamless user experience. One major platform that leverages this method is Mastodon.
|
||||
|
||||
Of these methods, Appwrite offers email-password authentication, magic links, and OTP-based authentication as a part of its suite of authentication offerings. You can learn more about them in [Appwrite’s documentation](https://appwrite.io/docs/products/auth).
|
||||
|
||||
# Moving forward
|
||||
|
||||
Social media login is convenient but has privacy and security issues. It's important for both users and developers to understand these risks. Fortunately, there are other ways to log in, like using email and password, biometric data, magic links, etc. These alternatives can protect user privacy better in certain circumstances and reduce dependence on social media platforms. Ultimately, the choice of authentication method should be guided by a thorough understanding of its benefits and limitations, always with the end user's best interests in mind.
|
||||
|
||||
Learn more about Appwrite Authentication from our [docs](https://appwrite.io/docs/products/auth) and join our [Discord community](https://appwrite.io/discord) to interact with fellow developers using the same.
|
||||
99
src/routes/blog/post/state-of-computer-vision/+page.markdoc
Normal file
99
src/routes/blog/post/state-of-computer-vision/+page.markdoc
Normal file
@@ -0,0 +1,99 @@
|
||||
---
|
||||
layout: post
|
||||
title: State of computer vision
|
||||
description: Get up to speed on the latest trends in computer vision and how they are shaping the future of the industry.
|
||||
date: 2024-03-25
|
||||
cover: /images/blog/state-of-computer-vision/cover.png
|
||||
timeToRead: 15
|
||||
author: bradley-schofield
|
||||
category: product
|
||||
featured: false
|
||||
draft: true
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Computer vision is a field of artificial intelligence where we work towards giving machines a comprehensive understanding of visual data from a variety of sources, a few examples are: Images, Videos, Point Clouds and X-Rays and MRI's from medical devices with the goal of being able to further parse and process this information for downstream tasks
|
||||
|
||||
From rotating and scaling your images to applying your Snapchat and Instagram filters, the applications of computer vision are many fold! Computer vision technology has revolutionized many industries with it being used in the medical industry to diagnose the onset of cancer, tumors and other life threatening diseases, to the agriculture industry that uses the technology to identify weeds in their vast amount of crops, while the manufacturing sector uses it to identify faults in products before they ever come close to a customer's hands. All these new and exciting uses for the technology has resulted in the young computer vision industry to be predicted to be worth over $50bn by 2030[1].
|
||||
|
||||
The purpose of this blog post is to give you a good understanding of the fundamentals of computer vision, the most popular tasks and applications of computer vision and how we can leverage Appwrite to build computer vision enabled applications.
|
||||
|
||||
# A (not so) brief history of computer vision
|
||||
|
||||
The bedrock of which most computer vision systems are built upon was discovered from the least likely of places: the humble cat. In 1959, after a series of failures when neurophysiologists David Hubel and Torsten Wiesel were trying to map out how the brain processed images, they found completely by accident a neuron in the cat's brain lit up right when they switched slides. With this revelation they came to the conclusion that the cat and by extension the human brain processes lines and edges before moving into more complex processing.[2]
|
||||
|
||||
At the same time the very first image scanner was being developed by Russell Kirsch and his team with the first image being captures of his then three month old son. The two building blocks were now in place, we had a starting point for how to teach machines to understand what they are seeing and a sensor that allowed for them to see for the first time.
|
||||
|
||||
Jumping a bit forward, in 1966, a group within MIT's famous Project MAC (Project for Mathematics and Computing) led by Seymour Papert set out to solve the computer vision problem in a couple months[3] during a summer camp. Needless to say they were extremely optimistic and unfortunately the project was a failure, however it was still important as it is widely regarded as the birth of the field of computer vision in academic study.
|
||||
|
||||
Following the summer camp various groups kept on working in the field of computer vision and in 1974 we saw the widespread introduction of OCR (Optical Character Recognition) technology into our lives which allowed machines to read actual text for the first time.
|
||||
|
||||
1982 came and saw British neuroscientist David Marr propose that vision is hierarchical and that its main objective is to translate what we saw into a 3D representation inside our heads so we can better understand and interact with our environments[4].
|
||||
|
||||
Just as David Marr was creating his groundbreaking thesis, around 5000 miles away Japanese computer scientist Kunihiko Fukushima had proposed a neural network he called Neocognitron[5] , this network is considered the grandfather of all convolutional neural networks (CNNs) and it should be noted that Kunihiko Kukushima also created the ReLU (rectified linear unit) activation function in 1969 which didn't become widely used until 2011 when it was found to be better at training deep neural networks and even today ReLU is the most popular activation function.
|
||||
|
||||
In 1989 Yann LeCun while working on a system to recognise hand-written ZIP Codes found that creating the algorithms that allowed his neural network to detect them was laborious and time consuming. Instead he introduced a technique called “back propagation”, what this allowed the network to do was after it had calculated the result it would try and figure out how off its prediction was the intended result. It would then propagate that error backwards across the weights to figure out how much each weight contributed to the failure, after it had achieved that it would adjust the weights and try again. This removed the need for a human to try and figure out the optimal weights and instead allowed the machine to learn from its own mistakes.[6]
|
||||
|
||||
Yann LeCun would continue to experiment with this approach and later he would introduce LeNet-5. A revolutionary CNN built with 7 levels, it was designed to recognise handwritten numbers on bank cheques and did so with an astonishing 99.05% accuracy[7] but was limited to 32x32 pixel images as to process larger amounts of data required more and larger layers within the CNN which was extremely computationally intensive for the time.
|
||||
|
||||
After LeCun's innovation and a brief renaissance, the use of CNNs in the field of computer vision stagnated. As I had mentioned before, the computational power to run increasingly more complex CNNs just didn't exist. The CV industry as a whole shifted its focus away from them and onto object detection during this time more great innovations were made
|
||||
|
||||
In 2001, the first real-time facial recognition algorithm was developed by Paul Viola and Michael Jones. As the field continued to evolve so did the data they were working with, the way that data was annotated and tagged was standardized during this time and in 2010 the ImageNet dataset was released, containing over a million images all manually cleaned and tagged by humans giving all researchers an excellent dataset to train their algorithms on. With the introduction of ImageNet also came the introduction of the ImageNet Large Scale Visual Recognition Competition (ILSVRC) which pitted algorithms against each other to see which one had the highest accuracy, for two years the error rate stayed around 26%.
|
||||
|
||||
Enter, AlexNet. Created in 2012 by researcher Alex Krizhevsky and aided by Ilya Sutskever and Geoffrey Hinton was an industry changing evolution in the computer vision field. Earlier we had discussed that CNN's were too computationally expensive back when LeCun created LeNet, Well these researchers instead of using CPUs used the power of GPUs in order to train the neural networks. This wasn't the first time it was done mind you but it was the first time it had been done with such high accuracy hitting a huge decrease in error rates of 15.3%
|
||||
|
||||
After AlexNet's groundbreaking unveiling most computer vision research moved towards CNNs being powered by GPUs and a little bit later TPUs however more conventional techniques also still exist for less powerful devices.
|
||||
|
||||
### Convolutions and Kernels
|
||||
|
||||
In the history section of this page at the very beginning I mentioned that we discovered that the visual processing system our brains have detects more basic features such as lines and edges before moving onto more complex stages. You may be wondering how we can get machines to do the same thing in an efficient manner and the answer is by using convolutions. Convolution is the fundamental operation in almost all of computer vision, so it's crucial to develop an understanding of how convolutions and kernels work.
|
||||
|
||||
Let's imagine we have a photograph and we want to detect all the edges in this photograph, the first thing we would do is convert the image into numbers which represent how bright each pixel is, sometimes this is referred to as the Y value of an image or the luminance.
|
||||
|
||||
Do note that even though I am focusing on edges in this example, kernels exist that can detect a wide range of features from diagonals, spirals
|
||||
|
||||
Next, let's introduce the concept of a “kernel”, these can also be referred to as “filters”; these are small grids (that can be a square or a rectangle) with numbers in it. These numbers are not random but are instead specifically picked to detect a certain feature. For example, a filter we could use to detect edges is the sobel edge detector.
|
||||
|
||||

|
||||
|
||||
Now you have both the image as luminance values and this kernel perform the following steps:
|
||||
|
||||
You will overlay the kernel over start of the image
|
||||
Next you will times each luminance pixel with the part of the grid it corresponds to in the kernel and then add up the sum of all these numbers
|
||||
Next you will slide this kernel one pixel to the side performing the same operation as the previous step. Each time you perform this operation you are creating a new pixel to create a new image
|
||||
Once you've slid the kernel across the entire image and you have all these new values, you can create a new image from these values. This new image is called the “feature map” and if you use this edge kernel it will highlight all the edges in the image.
|
||||
|
||||
There are different kernels to compute loads of different features and they aren't always a square, sometimes they are rectangular and they can be as big or small as you want, but keep in mind that bigger kernels result in more computation.
|
||||
|
||||
Convolutions aren't only used for things like edge detection but are extremely common in the image processing world, for tools you've probably used loads without even thinking about it, such as blurring images, sharpening and embossing.
|
||||
|
||||
{% video src="/images/blog/state-of-computer-vision/convolution.mp4" /%}
|
||||
|
||||
# Applications of Computer Vision
|
||||
|
||||
Now you have a good understanding of both the history and fundamentals of computer vision, you can dive into our other guides where we provide an even deeper dive into the different types of computer vision and how to implement them in your Appwrite application.
|
||||
|
||||
{% cards %}
|
||||
{% cards_item
|
||||
href="/docs/products/ai/tutorials/image-classification"
|
||||
title="Image classification" %}
|
||||
Understand and label the contents of images
|
||||
{% /cards_item %}
|
||||
|
||||
{% cards_item
|
||||
href="/docs/products/ai/tutorials/object-detection"
|
||||
title="Object detection" %}
|
||||
Detect and label objects in images
|
||||
{% /cards_item %}
|
||||
{% /cards %}
|
||||
|
||||
# Sources
|
||||
|
||||
1. [https://www.statista.com/outlook/tmo/artificial-intelligence/computer-vision/worldwide](https://www.statista.com/outlook/tmo/artificial-intelligence/computer-vision/worldwide)
|
||||
1. [A Brief History of Computer Vision (and CNNs) - Hackernoon](https://hackernoon.com/a-brief-history-of-computer-vision-and-convolutional-neural-networks-8fe8aacc79f)
|
||||
1. [https://dspace.mit.edu/bitstream/handle/1721.1/6125/AIM-100.pdf](https://dspace.mit.edu/bitstream/handle/1721.1/6125/AIM-100.pdf)
|
||||
1. [http://mechanism.ucsd.edu/teaching/f18/David_Marr_Vision_A_Computational_Investigation...](http://mechanism.ucsd.edu/teaching/f18/David_Marr_Vision_A_Computational_Investigation_into_the_Human_Representation_and_Processing_of_Visual_Information.chapter1.pdf)
|
||||
1. [https://www.cs.princeton.edu/courses/archive/spr08/cos598B/Readings/Fukushima1980.pdf](https://www.cs.princeton.edu/courses/archive/spr08/cos598B/Readings/Fukushima1980.pdf)
|
||||
1. [http://yann.lecun.org/exdb/publis/pdf/lecun-89e.pdf](http://yann.lecun.org/exdb/publis/pdf/lecun-89e.pdf)
|
||||
1. [http://vision.stanford.edu/cs598_spring07/papers/Lecun98.pdf](http://vision.stanford.edu/cs598_spring07/papers/Lecun98.pdf)
|
||||
@@ -0,0 +1,12 @@
|
||||
---
|
||||
layout: post
|
||||
title: State of natural language processing
|
||||
description: Get up to speed on the latest trends in natural language processing and how they are shaping the future of the industry.
|
||||
date: 2024-03-27
|
||||
cover: /images/blog/state-of-natural-language-processing/cover.png
|
||||
timeToRead: 15
|
||||
author: luke-silver
|
||||
category: product
|
||||
featured: false
|
||||
draft: true
|
||||
---
|
||||
@@ -73,7 +73,7 @@ One of the data retrieval APIs the Appwrite Database offers is a list documents
|
||||
- `OR` operation: This operator allows nesting queries in an OR condition.
|
||||
- `CONTAINS` operation: The contains operator allows filtering by values that are contained in an array.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Databases, Query } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
---
|
||||
layout: post
|
||||
title: Building a Valentine's Day sonnet generator using OpenAI and Appwrite Functions
|
||||
description: How we used Appwrite Functions and OpenAI's GPT-4 API to a create a fun, yet creative project.
|
||||
date: 2024-03-08
|
||||
cover: /images/blog/valentines-day-sonnet-generator/cover.png
|
||||
timeToRead: 7
|
||||
author: aditya-oberai
|
||||
category: functions
|
||||
---
|
||||
|
||||
This year to make Valentine’s Day a little more special for all you lovebirds, you might remember that we worked on a fun little project. This project allowed a number of you to create romantic sonnets for your loved ones. Did you know, however, that this project was powered by a Node.js Appwrite Function and OpenAI’s GPT-4 API?
|
||||
|
||||
In this blog, we will share how we developed our Valentine’s Day Sonnet Generator.
|
||||
|
||||
# Setting up the OpenAI platform
|
||||
|
||||
To get an OpenAI API Key, you must create an account on the [OpenAI platform](https://platform.openai.com/). Once your account is set up, visit their [API keys](https://platform.openai.com/account/api-keys) page and create an API Key. Ensure you copy and save this key in a safe place, as the OpenAI platform will not let you view the key after it is created.
|
||||
|
||||

|
||||
|
||||
> Note: To use the GPT-4 API, your account must be upgraded to the **Usage tier 1**. To learn more, visit their [Usage tiers documentation](https://platform.openai.com/docs/guides/rate-limits/usage-tiers?context=tier-one).
|
||||
|
||||
# Preparing the Appwrite Function
|
||||
|
||||
Now that we have our OpenAI API Key, let us get the function ready on [Appwrite](https://cloud.appwrite.io/). Head over to your Appwrite project and visit the Functions page. From there, we will select the Templates tab, search for and select the Prompt ChatGPT function template.
|
||||
|
||||

|
||||
|
||||
This function requires **1 environment variable** to setup:
|
||||
|
||||
- `OPENAI_API_KEY`: API Key from our OpenAI account
|
||||
|
||||
After you have configured the environment variables, you must connect your Appwrite account with GitHub, select **Create a new repository** (this will generate a GitHub repository for you with the function), and leave the production branch and root settings as default to create this function.
|
||||
|
||||
# Developing the project
|
||||
|
||||
While the Prompt ChatGPT function provides us with a majority of the boilerplate, certain areas of project still need to be updated.
|
||||
|
||||
## Preparing the UI
|
||||
|
||||
In the project directory, visit `static/index.html` and replace the existing code with the following:
|
||||
|
||||
```html
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Valentine's Day Sonnet Generator</title>
|
||||
|
||||
<script>
|
||||
async function onSubmit(name) {
|
||||
const response = await fetch('/', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ name }),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
const json = await response.json();
|
||||
|
||||
if (!json.ok || json.error) {
|
||||
alert(json.error);
|
||||
}
|
||||
|
||||
return json.completion;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script src="//unpkg.com/alpinejs" defer></script>
|
||||
|
||||
<link rel="stylesheet" href="https://unpkg.com/@appwrite.io/pink" />
|
||||
<link rel="stylesheet" href="https://unpkg.com/@appwrite.io/pink-icons" />
|
||||
</head>
|
||||
<body>
|
||||
<main class="main-content">
|
||||
<div class="top-cover u-padding-block-end-56">
|
||||
<div class="container">
|
||||
<div
|
||||
class="u-flex u-gap-16 u-flex-justify-center u-margin-block-start-16"
|
||||
>
|
||||
<h1 class="heading-level-1">Valentine's Day Sonnet Generator ❤️</h1>
|
||||
<code class="u-un-break-text"></code>
|
||||
</div>
|
||||
<p
|
||||
class="body-text-1 u-normal u-margin-block-start-8"
|
||||
style="max-width: 50rem"
|
||||
>
|
||||
Enter your partner's name and receive a sonnet dedicated to them, courtesy of Appwrite and OpenAI
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="container u-margin-block-start-negative-56"
|
||||
x-data="{ name: '', sonnet: '', loading: false }"
|
||||
>
|
||||
<div class="card u-flex u-gap-24 u-flex-vertical">
|
||||
<div class="u-flex u-cross-center u-gap-8">
|
||||
<div
|
||||
class="input-text-wrapper is-with-end-button u-width-full-line"
|
||||
>
|
||||
<input x-model="name" type="search" placeholder="Enter name of your beloved" maxlength="70" />
|
||||
<div class="icon-heart" style="position: absolute; inset-inline-start: 1rem; inset-block-start: 0.5rem;" aria-hidden="true"></div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
class="button"
|
||||
x-bind:disabled="loading"
|
||||
x-on:click="async () => { loading = true; sonnet = ''; try { sonnet = await onSubmit(name) } catch(err) { console.error(err); } finally { loading = false; } }"
|
||||
>
|
||||
<span class="text">Submit</span>
|
||||
</button>
|
||||
</div>
|
||||
<template x-if="sonnet">
|
||||
<div class="u-flex u-flex-vertical u-gap-12">
|
||||
<div class="u-flex u-flex-vertical u-gap-12 card">
|
||||
<div class="u-flex u-gap-12">
|
||||
<h5 class="eyebrow-heading-2">Cupid:</h5>
|
||||
</div>
|
||||
|
||||
<div style="overflow-x: hidden; line-break: auto">
|
||||
<p class="u-color-text-gray" style="white-space: pre-line;" x-text="sonnet"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Updating the function logic
|
||||
|
||||
The original function provided through this template used OpenAI’s GPT-3.5-Turbo API. Since we want to upgrade this to GPT-4, we need to make a couple of changes. Firstly, we must update the version of the OpenAI library in our `package.json` file to version `4.28.0` so that it looks as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "prompt-chatgpt",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "src/main.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"keywords": [],
|
||||
"dependencies": {
|
||||
"openai": "^4.28.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
After that is done, we need to visit the `src/main.js` file and replace the existing code with the following:
|
||||
|
||||
```client-web
|
||||
import { OpenAI } from 'openai';
|
||||
import { getStaticFile, throwIfMissing } from './utils.js';
|
||||
|
||||
export default async ({ req, res, log, error }) => {
|
||||
throwIfMissing(process.env, ['OPENAI_API_KEY']);
|
||||
|
||||
if (req.method === 'GET') {
|
||||
return res.send(getStaticFile('index.html'), 200, {
|
||||
'Content-Type': 'text/html; charset=utf-8',
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
throwIfMissing(req.body, ['name']);
|
||||
} catch (err) {
|
||||
error(err.message);
|
||||
return res.json({ ok: false, error: err.message }, 400);
|
||||
}
|
||||
|
||||
const openai = new OpenAI({
|
||||
apiKey: process.env.OPENAI_API_KEY,
|
||||
});
|
||||
|
||||
try {
|
||||
const response = await openai.chat.completions.create({
|
||||
model: 'gpt-4',
|
||||
max_tokens: parseInt(process.env.OPENAI_MAX_TOKENS ?? '512'),
|
||||
messages: [{ role: 'user', content: `Write a romantic Valentine\'s Day sonnet dedicated to ${req.body.name}` }],
|
||||
});
|
||||
const completion = response.choices[0].message?.content;
|
||||
log(completion);
|
||||
return res.json({ ok: true, completion }, 200);
|
||||
} catch (err) {
|
||||
error(err.message);
|
||||
return res.json({ ok: false, error: err.message }, 500);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## Testing the function
|
||||
|
||||
Once you’ve completed all the aforementioned steps, you can push the code to the generated GitHub repository, at which point Appwrite Cloud will automatically deploy the changes to your function.
|
||||
|
||||

|
||||
|
||||
You can then go ahead and test your function by opening the function domain in your browser.
|
||||
|
||||
# Next steps
|
||||
|
||||
And with that, our Valentine’s Day sonnet generator is ready! When we released this project on Valentine’s Day this year, it was used over 300 times by people across the world. You can try it out: [apwr.dev/valentines-day-sonnet](https://apwr.dev/valentines-day-sonnet)
|
||||
|
||||

|
||||
|
||||
If you liked this project or want to investigate the full project code, visit the [GitHub repository](https://github.com/adityaoberai/valentines-day-sonnet-generator).
|
||||
|
||||
For more information about Appwrite Functions, visit the following resources:
|
||||
|
||||
- [Appwrite Function Docs](https://appwrite.io/docs/functions): These documents provide more information on how to use Appwrite Functions.
|
||||
- [Appwrite Discord](https://discord.com/invite/appwrite): Connect with other developers and the Appwrite team for discussion, questions, and collaboration.
|
||||
68
src/routes/blog/post/what-is-hipaa-compliant/+page.markdoc
Normal file
68
src/routes/blog/post/what-is-hipaa-compliant/+page.markdoc
Normal file
@@ -0,0 +1,68 @@
|
||||
---
|
||||
layout: post
|
||||
title: What is HIPAA and why should you care
|
||||
description: Being HIPAA compliant is important for any developer no matter their industry. Learn why you should care and how you can take first steps in becoming HIPAA compliant.
|
||||
date: 2024-04-11
|
||||
cover: /images/blog/hipaa.png
|
||||
timeToRead: 8
|
||||
author: vincent-ge
|
||||
category: security
|
||||
featured: false
|
||||
---
|
||||
|
||||
If you work in the health industry there is a good chance you have heard of HIPAA, but if you don’t, it might be unknown waters. HIPAA stands for the Health Insurance Portability and Accountability Act. It might sound like it’s only the business of healthcare professionals, but if you're working with healthcare apps or platforms that handle health information, HIPAA becomes your business, too. So, let’s break down what HIPAA is and why you, as a developer, need to sit up and take notice.
|
||||
|
||||
## What is HIPAA?
|
||||
|
||||
HIPAA, established in 1996, is a U.S. law designed to provide privacy standards to protect patients' medical records and other health information provided to health plans, doctors, hospitals, and other healthcare providers. It consists of several rules, but the Privacy Rule and the Security Rule are the main ones affecting digital health information.
|
||||
|
||||
## What types of apps are required to meet HIPAA regulations?
|
||||
|
||||
If you are handling data related to health, you need to adhere to the regulations. Here are some examples of applications:
|
||||
|
||||
- Healthcare apps (like Apple health)
|
||||
- Hospital applications
|
||||
- Patient portals
|
||||
- Medical results dashboard
|
||||
- Patient intake forms
|
||||
- Video apps
|
||||
- Wellness and mental health
|
||||
- Chat apps
|
||||
|
||||
There are more examples of applications, but the above are the most general.
|
||||
|
||||
## Why does it matter to you?
|
||||
|
||||
**1. Privacy is a priority**
|
||||
In an age where data breaches have become a frequent headline, ensuring the privacy of health information is critical. You must understand HIPAA to build systems that protect patient data against unauthorized access.
|
||||
|
||||
**2. Security isn't optional**
|
||||
The Security Rule within HIPAA specifies safeguards that are divided into three parts - administrative, physical, and technical. As a developer, you’re in the trenches of technical safeguards, ensuring data encryption, implementing secure access controls, and more.
|
||||
|
||||
**3. It's the law**
|
||||
Non-compliance with HIPAA can result in hefty fines, legal action, and a tarnished reputation. If your application handles protected health information (PHI), your application must comply with HIPAA regulations, making it your responsibility to handle PHI properly.
|
||||
|
||||
**4. Trust builds business**
|
||||
When users trust your application to safeguard their health information, they're more likely to use and recommend it. Compliance with HIPAA is not just about avoiding penalties; it’s about building a product that people can trust.
|
||||
|
||||
**5. Innovation opportunity**
|
||||
With the digital health market growing rapidly, there’s a huge opportunity for innovation in healthcare technology. Understanding HIPAA compliance can be a significant advantage, allowing you to create solutions that meet a critical market need while ensuring privacy and security.
|
||||
|
||||
You might still wonder, ‘Why should I care?’ I don’t work in health. But remember, if you can handle data that adheres to these strict policies, you show your users they can trust you.
|
||||
|
||||
## How you should approach HIPAA
|
||||
|
||||
- **Educate yourself and your team**
|
||||
Start with a solid understanding of HIPAA's requirements. Resources are available from the U.S. Department of Health & Human Services and other reputable sites.
|
||||
- **Implement strong security measures**
|
||||
Use encryption for data at rest and in transit, ensure proper authentication mechanisms are in place, and regularly update and patch systems.
|
||||
- **Consider HIPAA early on**
|
||||
Integrate HIPAA considerations into the design phase of your development process. It’s easier to build compliance into your application from the start than to retrofit it later.
|
||||
- **Invest in a HIPAA compliant tech stack**
|
||||
Investigate what platforms and tools ad here to HIPAA compliancy and reassure they meet both your tech and compliancy requirements.
|
||||
|
||||
## Caring for your users
|
||||
|
||||
HIPAA might seem daunting at first glance, but it’s fundamentally about protecting individuals' health information. We have the power to build applications that not only innovate healthcare but also safeguard the very personal information people entrust to them. Understanding and implementing HIPAA regulations is not just a legal requirement; it's a critical component of ethical software development in the healthcare domain. So, the next time you come across HIPAA in your development journey, remember it’s more than just compliance—it’s about caring for the data privacy and security of your users.
|
||||
|
||||
Looking for a HIPAA compliant backend provider? Looking to replace Firebase? Appwrite can be your solution. Take a look at our [documentation](https://appwrite.io/docs/advanced/security) to learn more about our security.
|
||||
26
src/routes/changelog/(entries)/2024-03-25.markdoc
Normal file
26
src/routes/changelog/(entries)/2024-03-25.markdoc
Normal file
@@ -0,0 +1,26 @@
|
||||
---
|
||||
layout: changelog
|
||||
title: Appwrite 1.5.4 released
|
||||
date: 2024-03-25
|
||||
cover: /images/changelog/2024-03-25.png
|
||||
---
|
||||
|
||||
Appwrite 1.5.4 brings several fixes and a miscellaneous update to enhance your development experience with our platform.
|
||||
|
||||
Fixes:
|
||||
* Updated executor version to resolve Docker conflict errors when running Appwrite Functions
|
||||
* Improved webhooks to fix failed connections
|
||||
* Adjusted msg91 parameters to better match their new terminology
|
||||
* Fixed 401 error displayed for Appwrite Function domains when permissions are not configured
|
||||
* Fixed Appwrite Functions build command by adjusting trim behavior
|
||||
|
||||
Misc:
|
||||
* Upgraded console to version 1.5.4 for an improved user interface and added features
|
||||
|
||||
You can update by following the [upgrade docs]( https://appwrite.io/docs/advanced/self-hosting/update).
|
||||
|
||||
Note that upgrading from 1.5.x -> 1.5.4 does not require running migration. For a detailed view of changes, visit the full [release notes](https://github.com/appwrite/appwrite/releases).
|
||||
|
||||
{% arrow_link href="https://github.com/appwrite/appwrite/releases" %}
|
||||
Visit release notes
|
||||
{% /arrow_link %}
|
||||
12
src/routes/changelog/(entries)/2024-04-11.markdoc
Normal file
12
src/routes/changelog/(entries)/2024-04-11.markdoc
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
layout: changelog
|
||||
title: Appwrite is now HIPAA compliant
|
||||
date: 2024-04-11
|
||||
cover: /images/changelog/2024-04-11.png
|
||||
---
|
||||
|
||||
We’re happy to announce that Appwrite fully complies with the Health Insurance Portability and Accountability Act (HIPAA), alowing developers who handle sensitive health data to trust Appwrite as their backend.
|
||||
|
||||
{% arrow_link href="/blog/post/announcing-appwrite-is-hipaa-compliant" %}
|
||||
Read the announcement to learn more
|
||||
{% /arrow_link %}
|
||||
14
src/routes/changelog/(entries)/2024.04.09.markdoc
Normal file
14
src/routes/changelog/(entries)/2024.04.09.markdoc
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
layout: changelog
|
||||
title: Introducing Appwrite's React Native SDK in open beta
|
||||
date: 2024-04-09
|
||||
cover: /images/changelog/2024-04-09.png
|
||||
---
|
||||
|
||||
We’re excited to announce the new React Native SDK in open beta.
|
||||
|
||||
This will allow more mobile developers to benefit from Appwrite, giving everything you need to build your mobile applications backend, without the hassle of building it yourself.
|
||||
|
||||
{% arrow_link href="/blog/post/introducing-appwrite-react-native-sdk" %}
|
||||
Read the announcement to learn more
|
||||
{% /arrow_link %}
|
||||
@@ -30,7 +30,7 @@ export const getAllChangelogEntries = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const CHANGELOG_DEPENDENCY = 'changelog';
|
||||
export const CHANGELOG_DEPENDENCY = 'dependency:changelog';
|
||||
|
||||
export const CHANGELOG_KEY = 'changelog';
|
||||
|
||||
|
||||
@@ -1,63 +1,39 @@
|
||||
<script lang="ts" context="module">
|
||||
export const events: EventCardProps[] = [
|
||||
{
|
||||
href: 'https://discord.com/events/564160730845151244/1209117134417035365',
|
||||
href: 'https://discord.com/events/564160730845151244/1218597329024843837',
|
||||
cover: {
|
||||
src: '/images/community/events/init-0.png',
|
||||
src: '/images/community/events/28march-office-hours.png',
|
||||
alt: ''
|
||||
},
|
||||
date: 'February 26th, 2024',
|
||||
date: 'March 28th, 2024',
|
||||
location: 'Discord',
|
||||
title: 'Guest speaker: Diana Pham',
|
||||
description: 'Join day zero of Init together with Vonage developer advocate Diana Pham.',
|
||||
title: 'Office Hours: Ask me anything!',
|
||||
description: 'Join us for another round of Office Hours, where we answer your questions and geek out on everything tech and Appwrite!',
|
||||
buttonText: 'View event'
|
||||
},
|
||||
{
|
||||
href: 'https://discord.com/events/564160730845151244/1209117245859569754',
|
||||
href: 'https://discord.com/events/564160730845151244/1218597959017431192',
|
||||
cover: {
|
||||
src: '/images/community/events/init-1.png',
|
||||
src: '/images/community/events/4april-office-hours.png',
|
||||
alt: ''
|
||||
},
|
||||
date: 'February 27th, 2024',
|
||||
date: 'April 4th, 2024',
|
||||
location: 'Discord',
|
||||
title: 'Guest speaker: Hitesh Choudhary',
|
||||
description: 'Join us on day one of Init together with engineer and creator Hitesh Choudhary.',
|
||||
title: 'Office Hours: Ask me anything!',
|
||||
description: 'Join us for another round of Office Hours, where we answer your questions and geek out on everything tech and Appwrite!',
|
||||
buttonText: 'View event'
|
||||
},
|
||||
{
|
||||
href: 'https://discord.com/events/564160730845151244/1209117412247609354',
|
||||
href: 'https://discord.com/events/564160730845151244/1218598369363230872',
|
||||
cover: {
|
||||
src: '/images/community/events/init-2.png',
|
||||
src: '/images/community/events/11april-office-hours.png',
|
||||
alt: ''
|
||||
},
|
||||
date: 'February 28th, 2024',
|
||||
date: 'April 11th, 2024',
|
||||
location: 'Discord',
|
||||
title: 'Guest speaker: Francesco Ciulla',
|
||||
description: 'Join us on day two of Init together with developer advocate Francesco Ciulla.',
|
||||
buttonText: 'View event'
|
||||
},
|
||||
{
|
||||
href: 'https://discord.com/events/564160730845151244/1209117457294295121',
|
||||
cover: {
|
||||
src: '/images/community/events/init-3.png',
|
||||
alt: ''
|
||||
},
|
||||
date: 'February 29th, 2024',
|
||||
location: 'Discord',
|
||||
title: 'Guest speaker: Danny Thompson',
|
||||
description: 'Join us on day three of Init together with engineer and creator Danny Thompson.',
|
||||
buttonText: 'View event'
|
||||
},
|
||||
{
|
||||
href: 'https://discord.com/events/564160730845151244/1209117535723851776',
|
||||
cover: {
|
||||
src: '/images/community/events/init-4.png',
|
||||
alt: ''
|
||||
},
|
||||
date: 'March 1st, 2024',
|
||||
location: 'Discord',
|
||||
title: 'Guest speaker: Nick Taylor',
|
||||
description: 'Join us on day four of Init together with Nick Taylor.',
|
||||
title: 'Office Hours: Ask me anything!',
|
||||
description: 'Join us for another round of Office Hours, where we answer your questions and geek out on everything tech and Appwrite!',
|
||||
buttonText: 'View event'
|
||||
}
|
||||
];
|
||||
@@ -114,7 +90,7 @@
|
||||
];
|
||||
|
||||
const metrics = [
|
||||
{ metric: '39K+', description: 'GitHub Stars' },
|
||||
{ metric: `${GITHUB_STARS}+`, description: 'GitHub Stars' },
|
||||
{ metric: '3K+', description: 'Pull Requests' },
|
||||
{ metric: '18K+', description: 'Commits' },
|
||||
{ metric: '3K+', description: 'Issues' },
|
||||
@@ -570,7 +546,7 @@
|
||||
/>
|
||||
</div>
|
||||
<div class="web-title u-margin-block-start-auto">
|
||||
38K+ stargazers
|
||||
{GITHUB_STARS}+ stargazers
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -65,9 +65,6 @@
|
||||
|
||||
<Docs variant="default">
|
||||
<Sidebar />
|
||||
<div class="u-position-absolute u-inset-inline-end-0 web-u-opacity-40-mobile" style="">
|
||||
<enhanced:img src="./blur-1.png" alt="" />
|
||||
</div>
|
||||
|
||||
<main
|
||||
class="web-main-section u-position-relative web-u-overflow-hidden-break1-to-break3"
|
||||
@@ -486,12 +483,12 @@
|
||||
.bg-overlay {
|
||||
position: absolute;
|
||||
|
||||
background: linear-gradient(to right, #ffffff00 0%, #ffffff00 10%, #ffffff);
|
||||
background: linear-gradient(to right, #ffffff00 0%, #ffffff00 400px, #ffffff);
|
||||
|
||||
top: 0;
|
||||
right: 10rem;
|
||||
translate: 100%;
|
||||
width: 25rem;
|
||||
width: 100rem;
|
||||
height: 100%;
|
||||
content: '';
|
||||
z-index: 9999;
|
||||
@@ -505,6 +502,6 @@
|
||||
}
|
||||
|
||||
:global(.theme-dark) .bg-overlay {
|
||||
background: linear-gradient(to right, #19191c00 0%, #19191c00 10%, #19191c);
|
||||
background: linear-gradient(to right, #19191c00 0%, #19191c 400px, #19191c);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,143 +1,149 @@
|
||||
<script lang="ts">
|
||||
import Sidebar, { type NavTree } from '$lib/layouts/Sidebar.svelte';
|
||||
import Sidebar, { type NavTree } from '$lib/layouts/Sidebar.svelte';
|
||||
|
||||
const navigation: NavTree = [
|
||||
{
|
||||
items: [
|
||||
{
|
||||
label: 'Home',
|
||||
href: '/docs',
|
||||
icon: 'icon-home'
|
||||
},
|
||||
{
|
||||
label: 'Quick start',
|
||||
href: '/docs/quick-starts',
|
||||
icon: 'icon-play'
|
||||
},
|
||||
{
|
||||
label: 'Tutorials',
|
||||
href: '/docs/tutorials',
|
||||
icon: 'icon-book-open'
|
||||
},
|
||||
{
|
||||
label: 'SDKs',
|
||||
href: '/docs/sdks',
|
||||
icon: 'icon-cog'
|
||||
},
|
||||
{
|
||||
label: 'API reference',
|
||||
href: '/docs/references',
|
||||
icon: 'icon-document',
|
||||
isParent: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Products',
|
||||
items: [
|
||||
{
|
||||
label: 'Auth',
|
||||
href: '/docs/products/auth',
|
||||
icon: 'icon-user-group',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Databases',
|
||||
href: '/docs/products/databases',
|
||||
icon: 'icon-database',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Functions',
|
||||
href: '/docs/products/functions',
|
||||
icon: 'icon-lightning-bolt',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Messaging',
|
||||
href: '/docs/products/messaging',
|
||||
icon: 'icon-send',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Storage',
|
||||
href: '/docs/products/storage',
|
||||
icon: 'icon-folder',
|
||||
isParent: true
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'APIS',
|
||||
items: [
|
||||
{
|
||||
label: 'Realtime',
|
||||
href: '/docs/apis/realtime',
|
||||
icon: 'icon-clock'
|
||||
},
|
||||
{
|
||||
label: 'REST',
|
||||
href: '/docs/apis/rest',
|
||||
icon: 'web-icon-rest'
|
||||
},
|
||||
{
|
||||
label: 'GraphQL',
|
||||
href: '/docs/apis/graphql',
|
||||
icon: 'icon-graphql'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Tooling',
|
||||
items: [
|
||||
{
|
||||
label: 'Command Line',
|
||||
href: '/docs/tooling/command-line/installation',
|
||||
icon: 'icon-terminal',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Command Center',
|
||||
href: '/docs/tooling/command-center',
|
||||
icon: 'web-icon-command'
|
||||
},
|
||||
{
|
||||
label: 'Assistant',
|
||||
href: '/docs/tooling/assistant',
|
||||
icon: 'icon-sparkles'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Advanced',
|
||||
items: [
|
||||
{
|
||||
label: 'Platform',
|
||||
href: '/docs/advanced/platform',
|
||||
icon: 'web-icon-platform',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Migrations',
|
||||
href: '/docs/advanced/migrations',
|
||||
icon: 'icon-refresh',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Security',
|
||||
href: '/docs/advanced/security',
|
||||
icon: 'icon-shield-check',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Self-hosting',
|
||||
href: '/docs/advanced/self-hosting',
|
||||
icon: 'icon-server',
|
||||
isParent: true
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
const navigation: NavTree = [
|
||||
{
|
||||
items: [
|
||||
{
|
||||
label: 'Home',
|
||||
href: '/docs',
|
||||
icon: 'icon-home'
|
||||
},
|
||||
{
|
||||
label: 'Quick start',
|
||||
href: '/docs/quick-starts',
|
||||
icon: 'icon-play'
|
||||
},
|
||||
{
|
||||
label: 'Tutorials',
|
||||
href: '/docs/tutorials',
|
||||
icon: 'icon-book-open'
|
||||
},
|
||||
{
|
||||
label: 'SDKs',
|
||||
href: '/docs/sdks',
|
||||
icon: 'icon-cog'
|
||||
},
|
||||
{
|
||||
label: 'API reference',
|
||||
href: '/docs/references',
|
||||
icon: 'icon-document',
|
||||
isParent: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Products',
|
||||
items: [
|
||||
{
|
||||
label: 'Auth',
|
||||
href: '/docs/products/auth',
|
||||
icon: 'icon-user-group',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Databases',
|
||||
href: '/docs/products/databases',
|
||||
icon: 'icon-database',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Functions',
|
||||
href: '/docs/products/functions',
|
||||
icon: 'icon-lightning-bolt',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Messaging',
|
||||
href: '/docs/products/messaging',
|
||||
icon: 'icon-send',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Storage',
|
||||
href: '/docs/products/storage',
|
||||
icon: 'icon-folder',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'AI',
|
||||
href: '/docs/products/ai',
|
||||
icon: 'icon-chip',
|
||||
isParent: true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'APIS',
|
||||
items: [
|
||||
{
|
||||
label: 'Realtime',
|
||||
href: '/docs/apis/realtime',
|
||||
icon: 'icon-clock'
|
||||
},
|
||||
{
|
||||
label: 'REST',
|
||||
href: '/docs/apis/rest',
|
||||
icon: 'web-icon-rest'
|
||||
},
|
||||
{
|
||||
label: 'GraphQL',
|
||||
href: '/docs/apis/graphql',
|
||||
icon: 'icon-graphql'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Tooling',
|
||||
items: [
|
||||
{
|
||||
label: 'Command Line',
|
||||
href: '/docs/tooling/command-line/installation',
|
||||
icon: 'icon-terminal',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Command Center',
|
||||
href: '/docs/tooling/command-center',
|
||||
icon: 'web-icon-command'
|
||||
},
|
||||
{
|
||||
label: 'Assistant',
|
||||
href: '/docs/tooling/assistant',
|
||||
icon: 'icon-sparkles'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Advanced',
|
||||
items: [
|
||||
{
|
||||
label: 'Platform',
|
||||
href: '/docs/advanced/platform',
|
||||
icon: 'web-icon-platform',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Migrations',
|
||||
href: '/docs/advanced/migrations',
|
||||
icon: 'icon-refresh',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Security',
|
||||
href: '/docs/advanced/security',
|
||||
icon: 'icon-shield-check',
|
||||
isParent: true
|
||||
},
|
||||
{
|
||||
label: 'Self-hosting',
|
||||
href: '/docs/advanced/self-hosting',
|
||||
icon: 'icon-server',
|
||||
isParent: true
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
<Sidebar {navigation} />
|
||||
|
||||
@@ -58,7 +58,7 @@ To begin migrating to Appwrite, follow these steps.
|
||||
|
||||
1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy.
|
||||
|
||||
1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/development).
|
||||
1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop).
|
||||
|
||||
1. Explore Appwrite's unique features by exploring the rest of the [Appwrite Documentation](/docs).
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ Before migrating to Appwrite make sure you've read the [migration overview](/doc
|
||||
|
||||
1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy.
|
||||
|
||||
1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/development).
|
||||
1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop).
|
||||
|
||||
1. Explore Appwrite's unique features by exploring the rest of the [Appwrite Documentation](/docs).
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ Before migrating to Appwrite make sure you've read the [migration overview](/doc
|
||||
|
||||
1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy.
|
||||
|
||||
1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/development).
|
||||
1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop).
|
||||
|
||||
1. Explore Appwrite's unique features by exploring the rest of the [Appwrite Documentation](/docs).
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
|
||||
const navigation: NavTree = [
|
||||
{
|
||||
label: 'Getting started',
|
||||
label: 'Platform',
|
||||
items: [
|
||||
{
|
||||
label: 'Overview',
|
||||
href: '/docs/advanced/platform'
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -93,6 +93,15 @@
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
label: 'Policy',
|
||||
items: [
|
||||
{
|
||||
label: 'Release policy',
|
||||
href: '/docs/advanced/platform/release-policy'
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
|
||||
@@ -10,18 +10,27 @@ You can subscribe to these events with Appwrite [Functions](/docs/products/funct
|
||||
|
||||
You can subscribe to events for specific resources using their ID or subscribe to changes of all resources of the same type by using a wildcard character * instead of an ID.
|
||||
You can also filter for events of specific actions like create, update, or delete.
|
||||
|
||||
|
||||
You can find a list of events for Storage, Databases, Functions, and Authentication services below.
|
||||
|
||||
|
||||
{% accordion %}
|
||||
{% accordion_item title="Authentication" %}
|
||||
{% partial file="auth-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Databases" %}
|
||||
{% partial file="databases-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Storage" %}
|
||||
{% partial file="storage-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Functions" %}
|
||||
{% partial file="functions-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Messaging" %}
|
||||
{% partial file="messaging-events.md" /%}
|
||||
{% /accordion_item %}
|
||||
{% /accordion %}
|
||||
|
||||
# Known limitations {% #known-limitations %}
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ You can send messages in different languages by setting the locale with `client.
|
||||
For example, you can send an email verification in French.
|
||||
|
||||
{% multicode %}
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Account } from "appwrite";
|
||||
|
||||
const client = new Client();
|
||||
@@ -144,7 +144,7 @@ promise.then(function (response) {
|
||||
});
|
||||
```
|
||||
|
||||
```dart
|
||||
```client-flutter
|
||||
import 'package:appwrite/appwrite.dart';
|
||||
|
||||
void main() { // Init SDK
|
||||
@@ -167,7 +167,7 @@ void main() { // Init SDK
|
||||
}
|
||||
```
|
||||
|
||||
```kotlin
|
||||
```client-android-kotlin
|
||||
import io.appwrite.Client
|
||||
import io.appwrite.services.Account
|
||||
|
||||
@@ -181,7 +181,7 @@ val account = Account(client)
|
||||
val response = account.createVerification('https://example.com')
|
||||
```
|
||||
|
||||
```swift
|
||||
```client-apple
|
||||
import Appwrite
|
||||
|
||||
let client = Client()
|
||||
|
||||
@@ -67,7 +67,7 @@ The following examples are using the [Appwrite Web SDK](https://github.com/appwr
|
||||
|
||||
In the following example, we are creating a document that can be read by anyone, edited by writers or admins, and deleted by administrators or a user with the user ID `user:5c1f88b42259e`.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Databases, Permission, Role } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
@@ -100,7 +100,7 @@ promise.then(function (response) {
|
||||
|
||||
In the following example, we are creating a document that can be read by members of the team with ID `5c1f88b87435e` and can only be edited or deleted by members of the same team that possess the team role `owner`.
|
||||
|
||||
```js
|
||||
```client-web
|
||||
import { Client, Databases, Permission, Role } from "appwrite";
|
||||
|
||||
const client = new Client()
|
||||
|
||||
171
src/routes/docs/advanced/platform/release-policy/+page.markdoc
Normal file
171
src/routes/docs/advanced/platform/release-policy/+page.markdoc
Normal file
@@ -0,0 +1,171 @@
|
||||
---
|
||||
layout: article
|
||||
title: Release policy
|
||||
description: Understand how Appwrite releases and versions its platforms and APIs.
|
||||
---
|
||||
We value the trust of developers in Appwrite as the backbone of their applications.
|
||||
Our release policy is designed to provide developers with a reliable and consistent experience when using Appwrite.
|
||||
We are committed to providing support for our API, SDKs, and product versions for a reasonable length of time,
|
||||
and we follow industry-standard versioning protocols.
|
||||
Appwrite will prioritize security updates and will release new versions as soon as possible to fix any security vulnerabilities.
|
||||
|
||||
# Schedule {% #schedule %}
|
||||
|
||||
We work to release a new minor version of the product every quarter, which will include new features and enhancements.
|
||||
|
||||
We prioritize the timely release of patch versions with bug fixes and security updates on top of these feature releases,
|
||||
and we make every effort to ensure that our releases are thoroughly tested and stable before they are made available to developers.
|
||||
|
||||
In rare cases where there are significant delays or changes to our release schedule, we will notify through our website's [changelog](https://appwrite.io/changelog), [Discord](https://appwrite.io/discord),
|
||||
newsletter, and other communication channels.
|
||||
|
||||
# Scope {% #scope %}
|
||||
Appwrite will provide two phases of continued support for older versions of Appwrite.
|
||||
|
||||
{% table %}
|
||||
* Phase {% width=100 %}
|
||||
* Scope
|
||||
---
|
||||
* Support
|
||||
* Receive continued bug fixes and security updates.
|
||||
---
|
||||
* Extended security support
|
||||
* Receives only security updates.
|
||||
{% /table %}
|
||||
|
||||
# Support {% #support %}
|
||||
Appwrite commits to the continued support of our software with extended support policies for security related fixes for older versions of Appwrite.
|
||||
Supported versions will continue to receive bug fixes and security updates. Extended security support versions will only receive security updates.
|
||||
{% table %}
|
||||
* Releases {% width=100 %}
|
||||
* Current Version
|
||||
* Support
|
||||
* Extended Security Support
|
||||
---
|
||||
* API
|
||||
* `v1`
|
||||
* 3 latest versions
|
||||
* 10 years
|
||||
---
|
||||
* SDK
|
||||
* [See list](https://appwrite.io/docs/sdks)
|
||||
* 5 latest versions
|
||||
* 10 years
|
||||
---
|
||||
* Self-hosted
|
||||
* `1.5.x`
|
||||
* Latest major version `>= 1.x.x`
|
||||
* 10 years
|
||||
---
|
||||
* Runtimes
|
||||
* [See list](https://appwrite.io/docs/products/functions/runtimes)
|
||||
* 24 months
|
||||
* Per vendor
|
||||
{% /table %}
|
||||
# API versions {% #api-versions %}
|
||||
|
||||
We are committed to providing developers with a stable and reliable API.
|
||||
Appwrite API versions don’t change very often but are reserved for breaking changes.
|
||||
|
||||
Currently, the latest stable version of the Appwrite API is `/v1`.
|
||||
We use this prefix in all our API endpoint paths to allow API versioning.
|
||||
Any new Appwrite version will retain **backward compatibility** for any supported API version
|
||||
as long as this API version is still under maintenance support.
|
||||
|
||||
We will provide standard maintenance support for the last 3 API versions.
|
||||
Once a version is no longer in this maintenance period, we will continue to provide support for security fixes for an additional ten years.
|
||||
Based on usage, we may decide to extend support for a specific version.
|
||||
Self-hosted versions of Appwrite will receive continued support for the latest major version of Appwrite.
|
||||
|
||||
If you need **extended support** for older versions of Appwrite, [contact us](https://appwrite.io/contact-us) for more information.
|
||||
|
||||
# SDK versioning {% #sdk-verversioningsions %}
|
||||
|
||||
For our different SDKs, we follow the Semantic Versioning (semver) protocol to assign versions to our releases. This means that we assign version numbers using a three-part system: major, minor, and patch. The major version changes when we make significant changes to our API or product, which may require significant changes to developers' code. The minor version changes when we add new features or functionality that do not significantly impact developers' systems. Finally, the patch version changes when we make bug fixes or minor improvements.
|
||||
|
||||
All Appwrite SDKs will have backward compatibility with the Appwrite APIs. In case a new version of the API or product has been released, you should expect your applications to continue working properly without any action from your side.
|
||||
Once we release a major version of the SDK and you decide to upgrade, look in the [changelog of the relevant SDK on GitHub](https://appwrite.io/docs/sdks) to understand what changes have been made and what adjustments are required.
|
||||
|
||||
We provide early notice to developers and slowly introduce breaking changes to let developers adjust their application at a reasonable pace.
|
||||
We will also continue to support the last five major versions of each SDK to provide developers with more flexibility and time to adjust their apps to take advantage of new features.
|
||||
|
||||
# Self-hosted versioning {% #self-hosted-versioning %}
|
||||
|
||||
When you self-host Appwrite, we also follow the Semantic Versioning (semver) protocol for versioning our releases. This means that we assign version numbers using a three-part system: major, minor, and patch. The major version changes when we make significant changes to our API or product, which may require significant changes to developers' apps. The minor version changes when we add new features or functionality that do not significantly impact developers' existing apps. Finally, the patch version changes when we make bug fixes or minor improvements.
|
||||
|
||||
All the self-hosted versions of Appwrite `>=1.x.x` continue to have support and backward compatibility with the Appwrite API and SDKs within each major version.
|
||||
In case a new version of the product has been released and you decide to update, you should expect your applications to continue working properly without any action from your side.
|
||||
|
||||
Once we release a version of the product and you decide to upgrade, look in the [changelog](https://github.com/appwrite/appwrite/releases) to understand if your version requires migration of data from your previous setup.
|
||||
This is usually required when we make adjustments to the under the hood data structure for supporting new features and improving maintainability.
|
||||
If this is the case, you could use our [built-in migration tool](/docs/advanced/self-hosting/update#running-the-migration) for helping you to upgrade your self-hosted Appwrite version.
|
||||
|
||||
{% arrow_link href="/docs/advanced/self-hosting/update" %}
|
||||
Learn more about updating self-hosted Appwrite
|
||||
{% /arrow_link %}
|
||||
|
||||
# Runtime versioning {% #runtime-versioning %}
|
||||
|
||||
[Appwrite Function runtimes](/docs/products/functions/runtimes) are built around a combination of operating system, programming language, and software libraries that are subject to maintenance and security updates.
|
||||
Appwrite will support and maintain runtimes as a package, which covers the specific combination of operating system, programming language, and software libraries.
|
||||
|
||||
Appwrite will support the latest stable versions of our [Appwrite Function runtime environment](/docs/products/functions/runtimes) for a minimum of 24 months after its initial release as long as security updates for components of the specific runtime are still provided.
|
||||
You can review the [list of supported runtimes](/docs/products/functions/runtimes) on Appwrite.
|
||||
|
||||
In most cases, the end-of-life date of a language version or operating system is known well in advance.
|
||||
The links below give end-of-life schedules for each language that Appwrite supports as a managed runtime.
|
||||
|
||||
## Runtimes language {% #runtime-languages %}
|
||||
|
||||
{% table %}
|
||||
* Language {% width=150 %}
|
||||
* LTS policy
|
||||
---
|
||||
* Node.js
|
||||
* [https://nodejs.org](https://nodejs.org)
|
||||
---
|
||||
* Python
|
||||
* [devguide.python.org](https://devguide.python.org)
|
||||
---
|
||||
* Ruby
|
||||
* [www.ruby-lang.org](https://www.ruby-lang.org)
|
||||
---
|
||||
* Java
|
||||
* [www.oracle.com](https://www.oracle.com)
|
||||
---
|
||||
* .NET Core
|
||||
* [dotnet.microsoft.com](https://dotnet.microsoft.com)
|
||||
---
|
||||
* PHP
|
||||
* [https://www.php.net](https://www.php.net)
|
||||
---
|
||||
* Dart
|
||||
* [https://dart.dev/](https://dart.dev/)
|
||||
---
|
||||
* Deno
|
||||
* [https://deno.com/runtime](https://deno.com/runtime)
|
||||
---
|
||||
* Swift
|
||||
* [https://developer.apple.com/swift](https://developer.apple.com/swift)
|
||||
---
|
||||
* Kotlin
|
||||
* [https://kotlinlang.org](https://kotlinlang.org)
|
||||
---
|
||||
* C++
|
||||
* [https://en.cppreference.com/w/](https://en.cppreference.com/w/)
|
||||
{% /table %}
|
||||
|
||||
## Runtimes OS {% #runtime-os %}
|
||||
{% table %}
|
||||
* OS {% width=150 %}
|
||||
* LTS policy
|
||||
---
|
||||
* Alpine
|
||||
* [https://www.alpinelinux.org](https://www.alpinelinux.org)
|
||||
---
|
||||
* Debian
|
||||
* [https://www.debian.org/](https://www.debian.org/)
|
||||
---
|
||||
* Ubuntu
|
||||
* [https://releases.ubuntu.com/](https://releases.ubuntu.com/)
|
||||
{% /table %}
|
||||
@@ -43,14 +43,22 @@ Appwrite has events that fire when a resource changes.
|
||||
These events cover all Appwrite resources and can reflect create, update, and delete actions.
|
||||
You can specify one or many events to subscribe to with webhooks.
|
||||
|
||||
{% accordion %}
|
||||
{% accordion_item title="Authentication events" %}
|
||||
{% partial file="auth-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Databases events" %}
|
||||
{% partial file="databases-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Storage events" %}
|
||||
{% partial file="storage-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Functions events" %}
|
||||
{% partial file="functions-events.md" /%}
|
||||
|
||||
{% /accordion_item %}
|
||||
{% accordion_item title="Messaging events" %}
|
||||
{% partial file="messaging-events.md" /%}
|
||||
{% /accordion_item %}
|
||||
{% /accordion %}
|
||||
|
||||
[Learn more about events](/docs/advanced/platform/api-keys)
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
href: '/docs/advanced/security/soc2'
|
||||
},
|
||||
{
|
||||
label: 'HIPPA (Coming soon)',
|
||||
href: '/docs/advanced/security/hippa'
|
||||
label: 'HIPAA',
|
||||
href: '/docs/advanced/security/hipaa'
|
||||
},
|
||||
{
|
||||
label: 'PCI',
|
||||
@@ -50,8 +50,8 @@
|
||||
href: '/docs/advanced/security/encryption'
|
||||
},
|
||||
{
|
||||
label: 'Two-Factor authentication',
|
||||
href: '/docs/advanced/security/2fa'
|
||||
label: 'Multi-Factor authentication',
|
||||
href: '/docs/advanced/security/mfa'
|
||||
},
|
||||
{
|
||||
label: 'HTTPS',
|
||||
|
||||
@@ -5,7 +5,7 @@ description: Learn how Appwrite keeps your project, users, and data secure throu
|
||||
---
|
||||
|
||||
Appwrite helps you build secure apps by applying various security and compliance measures.
|
||||
Appwrite is compliant with [GDPR](/docs/advanced/security/gdpr) and actively working toward [SOC 2](/docs/advanced/security/soc2) and [HIPPA](/docs/advanced/security/hippa) compliance.
|
||||
Appwrite is compliant with [GDPR](/docs/advanced/security/gdpr) and [HIPAA](/docs/advanced/security/hipaa) while actively working toward [SOC 2](/docs/advanced/security/soc2) compliance.
|
||||
|
||||
Appwrite also employs [enhanced password protection and encryption](/docs/products/auth/security), [rate limits](/docs/advanced/security/abuse-protection),
|
||||
[robust permission systems](/docs/advanced/platform/permissions), and [HTTPS/TLS](/docs/advanced/security/tls) to protect you and your users' data.
|
||||
@@ -28,10 +28,9 @@ Appwrite uses Stripe to handle payment and payment information securely. Learn a
|
||||
Coming soon
|
||||
{% /cards_item %}
|
||||
|
||||
{% cards_item href="/docs/advanced/security/hippa" title="HIPPA" %}
|
||||
Coming soon.
|
||||
{% cards_item href="/docs/advanced/security/hipaa" title="HIPAA" %}
|
||||
Appwrite is HIPAA compliant. Learn about how Appwrite's measures to protect personal health information.
|
||||
{% /cards_item %}
|
||||
|
||||
{% /cards %}
|
||||
|
||||
# Measures {% #measures %}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
---
|
||||
layout: article
|
||||
title: Two-factor Authentication
|
||||
description: Appwrite helps you secure your developer accounts with 2FA (two-factor authentication).
|
||||
---
|
||||
Two-factor authentication (2FA) adds multiple layers of authentication to your Appwrite account,
|
||||
which means a malicious actor cannot gain access to your accounts, even if one of the factors is compromised.
|
||||
Appwrite currently supports 2FA using TOTP (Time-based One-Time Password) with an authenticator app.
|
||||
More factors of authentication will be added in the future.
|
||||
|
||||
{% info title="Looking to add 2FA to your app?" %}
|
||||
This page covers 2FA for your Appwrite Console account.
|
||||
If you're looking to add 2FA to your app, follow the [Two-factor authentication journey](/docs/products/auth/2fa).
|
||||
{% /info %}
|
||||
|
||||
# Enable 2FA {% #enable-2fa %}
|
||||
To enable 2FA on your Appwrite account, navigate to your Appwrite Console > your account menu on the top right > **Your account** > **Two-factor authentication**.
|
||||
|
||||
{% only_dark %}
|
||||

|
||||
{% /only_dark %}
|
||||
{% only_light %}
|
||||

|
||||
{% /only_light %}
|
||||
|
||||
Toggle **Two-factor authentication** to enable 2FA for your account, then click **Add authentication factor**.
|
||||
|
||||
{% only_dark %}
|
||||

|
||||
{% /only_dark %}
|
||||
{% only_light %}
|
||||

|
||||
{% /only_light %}
|
||||
|
||||
Scan the QR code with your authenticator app, then enter the code from your authenticator app to verify the setup.
|
||||
Make sure to save the recovery codes in a safe place, as they are the only way to access your account if you lose access to your authenticator app.
|
||||
@@ -33,3 +33,9 @@ You can add new platforms by navigating to **Overview** > **Platforms** > **Add
|
||||
{% only_light %}
|
||||

|
||||
{% /only_light %}
|
||||
|
||||
# DDoS protection {% #ddos-protection %}
|
||||
Appwrite Cloud's infrastructure is protected with always-on DDoS protection.
|
||||
Appwrite's DDoS protection operates in Network (layer 3) and Transport (layer 4) layers.
|
||||
This protects Appwrite's infrastructure against volumetric attacks such as UDP floods, ICMP floods, TCP floods,
|
||||
and DNS reflection attacks, as well as protocol-layer attacks such as SYN floods, BGP attacks, and ping-of-death attacks.
|
||||
@@ -4,12 +4,12 @@ title: GDPR
|
||||
description: The safeguarding of your and your users' data is taken seriously at Appwrite. Learn about Appwrite's measures and compliance with European General Data Protection Regulation (GDPR).
|
||||
---
|
||||
|
||||
Appwrite compliant with the European General Data Protection Regulation (GDPR).
|
||||
Appwrite is compliant with the European General Data Protection Regulation (GDPR).
|
||||
GDPR is a EU regulation that concerns data privacy and security in the European Union and the European Economic Area.
|
||||
|
||||
By attesting that Appwrite is GDPR compliant, we have done the following:
|
||||
- Appwrite users will retain access to their personal information including the right to correct and to delete it.
|
||||
- Impose the same rules upon the organization’s sub-processors who assist in providing Appwrite’s services as described in the Terms of Service (“ToS”).
|
||||
- Impose the same rules upon the organization's sub-processors who assist in providing Appwrite's services as described in the Terms of Service (“ToS”).
|
||||
- Appwrite will notify users promptly about policy changes and/or data breaches.
|
||||
|
||||
You can learn more in our [Privacy policy](https://appwrite.io/privacy) and [Cookie policy](https://appwrite.io/cookies).
|
||||
|
||||
28
src/routes/docs/advanced/security/hipaa/+page.markdoc
Normal file
28
src/routes/docs/advanced/security/hipaa/+page.markdoc
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
layout: article
|
||||
title: HIPAA
|
||||
description: Learn about Appwrite Cloud's measures to achieve HIPAA compliance.
|
||||
---
|
||||
|
||||
Appwrite is compliant with HIPAA (Health Insurance Portability and Accountability Act) regulations.
|
||||
HIPAA is an important regulation that protects patients' health data from being disclosed without consent or knowledge.
|
||||
|
||||
If you're building apps that handle information that is considered [PHI (Personal Health Information)](https://privacyruleandresearch.nih.gov/pr_07.asp)
|
||||
for an U.S. user base, data must be stored in a HIPAA-compliant environment.
|
||||
|
||||
To attain HIPAA compliance, we've taken extensive measures, ensuring that our practices align with the highest data protection standards.
|
||||
We have implemented robust measures to safeguard personal information, updating our policies, procedures, and infrastructure to meet the strict requirements of HIPAA regulations.
|
||||
|
||||
- A strict data backup schedule.
|
||||
- An extended business continuity plan.
|
||||
- Data retention rights for individuals as outlined in our [Privacy Policy](https://appwrite.io/privacy).
|
||||
- Intrusion detection and penetration testing.
|
||||
- Encryption of data transmitted between Appwrite and users using transport layer security (TLS) and HTTP strict Transport Security,
|
||||
ensuring confidentiality both at rest and during transmission.
|
||||
- Access to environments containing customer data is strictly controlled,
|
||||
requiring authentication and authorization through multi-factor authentication (MFA).
|
||||
|
||||
Appwrite safeguards personal information to the same extent it protects its own, complying with relevant privacy laws and regulations in the jurisdictions where its services are offered.
|
||||
|
||||
Please note that while Appwrite Cloud serves as a HIPAA-compliant platform to handle data,
|
||||
it is the responsibility of developers to ensure that their application is also compliant with HIPAA regulations.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user