@zeroin.earth/appwrite-graphql 0.16.5 → 23.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,48 +1,594 @@
1
1
  # Appwrite GraphQL
2
-
3
- This is a GraphQL library for Appwrite, built with the power of [@tanstack/react-query](https://github.com/TanStack/query) and inspired by [react-appwrite](https://github.com/react-appwrite/react-appwrite).
2
+ ![Static Badge](https://img.shields.io/badge/coverage-95%25-brightgreen) ![NPM Version](https://img.shields.io/npm/v/%40zeroin.earth%2Fappwrite-graphql) ![Static Badge](https://img.shields.io/badge/appwrite-v1.8.1-%23FD366E)
3
+
4
+ Appwrite is an open source, BaaS in the same vein as Supabase and Firebase, but geared more toward self-hosting.
5
+
6
+ This is a fully featured GraphQL library built with [@tanstack/react-query](https://github.com/TanStack/query) on top of the Appwrite web SDK and is fully typed. Think of this library as the abstract wrapper you would have made yourself, but we already did it for you.
7
+
8
+ ## Getting Started
9
+ - [Installation](#installation)
10
+ - [Basic Usage](#usage)
11
+
12
+ ## Features
13
+
14
+ - Dual build for both React and React Native
15
+ - Full Appwrite SDK v23 parity using React hooks
16
+ - [Optimistic Mutations](#optimistic-mutations)
17
+ - Documents only
18
+ - [Query Caching](#query-caching)
19
+ - [QueryKey Builder](#querykey-builder)
20
+ - [Offline-first Support](#offline-first-support)
21
+ - [Built-in Offline Persisters](#built-in-offline-persisters) (localStorage, AsyncStorage)
22
+ - [Custom Offline Persister Support](#custom-offline-persister-support)
23
+ - [Conflict Resolution](#conflict-resolution)
24
+ - [SSR Support](#ssr-support)
25
+ - [Field Selection](#field-selection)
26
+ - [Suspense Queries](#suspense-queries)
27
+ - Documents
28
+ - Collections
29
+ - [Pagination Hooks](#pagination-hooks)
30
+ - Standard Pagination
31
+ - Infinite Scroll
32
+ - [Appwrite QueryBuilder](#appwrite-querybuilder)
33
+ - [React Query Devtools Support](#react-query-devtools-support)
4
34
 
5
35
  ## Installation
6
36
 
7
37
  ```bash
8
38
  npm install --save @zeroin.earth/appwrite-graphql
9
39
 
10
- yarn add @zeroin.earth/appwrite-graphql
40
+ bun add @zeroin.earth/appwrite-graphql
11
41
  ```
12
42
 
43
+ ### Peer Dependencies
44
+
45
+ - `react` - `^19.1.0`
46
+ - `appwrite` - `^23.0.0`
47
+ - `@tanstack/react-query` - `^5.70.0`
48
+
49
+ **React Native:**
50
+
51
+ - `@react-native-async-storage/async-storage`
52
+ - `@react-native-community/netinfo`
53
+ - `react-native-appwrite`
54
+
13
55
  ## Usage
14
56
 
15
- ### Set up
16
- You must provide the Appwrite URL and Project ID as environment variables. It does not matter how they are provided as long as they can be accessed from `process.env.`:
57
+ ### Provider
58
+
59
+ The library is designed to use a single wrapper, `<AppwriteProvider>`. There are multiple ways you can configure the wrapper based on your app's needs:
60
+
61
+ 1. Basic (no offline-first support) - React
17
62
 
18
- ```js
19
- /* Endpoint - Pick one */
20
- APPWRITE_ENDPOINT=
21
- NEXT_PUBLIC_APPWRITE_URL=
22
- EXPO_PUBLIC_APPWRITE_URL=
63
+ ```tsx
64
+ import {
65
+ AppwriteProvider,
66
+ createAppwriteClient
67
+ } from '@zeroin.earth/appwrite-graphql'
23
68
 
24
- /* Project ID - Pick one */
25
- APPWRITE_PROJECT_ID=
26
- NEXT_PUBLIC_APPWRITE_PROJECT_ID
27
- EXPO_PUBLIC_APPWRITE_PROJECT_ID
69
+ const client = createAppwriteClient({
70
+ endpoint: 'https://cloud.appwrite.io/v1',
71
+ projectId: 'my-project',
72
+ })
73
+
74
+ function App() {
75
+ return (
76
+ <AppwriteProvider client={client}>
77
+ {/* your app */}
78
+ </AppwriteProvider>
79
+ )
80
+ }
28
81
  ```
29
82
 
30
- ### Provider
31
- If you need to provide a custom endpoint and project ID, and can't use one of the above environment variables, you may override the default variables using the `<AppwriteProvider>`:
83
+ 2. Offline-first - React
32
84
 
33
- ```jsx
34
- <AppwriteProvider endpoint="https://api.example.com/v1" projectId="jhkeri4889dfg7fg78f7g">
35
- <App />
36
- </AppwriteProvider>
85
+ ```tsx
86
+ import {
87
+ AppwriteProvider,
88
+ createOfflineClient,
89
+ webNetworkAdapter,
90
+ } from '@zeroin.earth/appwrite-graphql'
91
+
92
+ const { appwrite, queryClient, persister } = createOfflineClient({
93
+ endpoint: 'https://cloud.appwrite.io/v1',
94
+ projectId: 'my-project',
95
+ storage: localStorage, // or any AsyncStorage-compatible interface
96
+ networkAdapter: webNetworkAdapter(),
97
+ })
98
+
99
+ function App() {
100
+ return (
101
+ <AppwriteProvider
102
+ client={appwrite}
103
+ queryClient={queryClient}
104
+ persister={persister}
105
+ onCacheRestored={() => console.log('Cache restored mutations replayed')}
106
+ >
107
+ {/* your app */}
108
+ </AppwriteProvider>
109
+ )
110
+ }
37
111
  ```
38
112
 
39
- ### Hooks
113
+ 3. Offline-first - React Native
114
+
115
+ ```tsx
116
+ import AsyncStorage from '@react-native-async-storage/async-storage'
117
+ import {
118
+ AppwriteProvider,
119
+ createOfflineClient,
120
+ } from '@zeroin.earth/appwrite-graphql'
121
+
122
+ import {
123
+ reactNativeNetworkAdapter
124
+ } from '@zeroin.earth/appwrite-graphql/react-native'
125
+
126
+ const { appwrite, queryClient, persister } = createOfflineClient({
127
+ endpoint: 'https://cloud.appwrite.io/v1',
128
+ projectId: 'my-project',
129
+ storage: AsyncStorage,
130
+ networkAdapter: reactNativeNetworkAdapter(),
131
+ })
132
+
133
+ function App() {
134
+ return (
135
+ <AppwriteProvider
136
+ client={appwrite}
137
+ queryClient={queryClient}
138
+ persister={persister}
139
+ >
140
+ {/* your app */}
141
+ </AppwriteProvider>
142
+ )
143
+ }
144
+ ```
145
+
146
+ 4. Offline-first - React with custom persister
147
+
148
+ ```tsx
149
+ import {
150
+ AppwriteProvider,
151
+ createOfflineClient,
152
+ webNetworkAdapter,
153
+ type Persister,
154
+ } from '@zeroin.earth/appwrite-graphql'
155
+
156
+ const myPersister: Persister = {
157
+ persistClient: async (client) => { /* write to your storage */ },
158
+ restoreClient: async () => { /* read from your storage */ },
159
+ removeClient: async () => { /* clear your storage */ },
160
+ }
161
+
162
+ const { appwrite, queryClient, persister } = createOfflineClient({
163
+ endpoint: 'https://cloud.appwrite.io/v1',
164
+ projectId: 'my-project',
165
+ persister: myPersister,
166
+ networkAdapter: webNetworkAdapter(),
167
+ })
168
+
169
+ function App() {
170
+ return (
171
+ <AppwriteProvider
172
+ client={appwrite}
173
+ queryClient={queryClient}
174
+ persister={persister}
175
+ >
176
+ {/* your app */}
177
+ </AppwriteProvider>
178
+ )
179
+ }
180
+ ```
181
+
182
+ 5. Offline - Imperative / non-React
183
+
184
+ ```tsx
185
+ import {
186
+ createOfflineClient,
187
+ webNetworkAdapter,
188
+ } from '@zeroin.earth/appwrite-graphql'
189
+
190
+ const client = createOfflineClient({
191
+ endpoint: 'https://cloud.appwrite.io/v1',
192
+ projectId: 'my-project',
193
+ storage: localStorage,
194
+ networkAdapter: webNetworkAdapter(),
195
+ })
196
+
197
+ // Start persistence — restores cache from storage, subscribes to
198
+ // future changes, and replays paused mutations once restored.
199
+ const { unsubscribe, restored } = client.startPersistence()
200
+
201
+ await restored
202
+ console.log('Cache restored, paused mutations replayed')
203
+
204
+ // Use client.queryClient and client.appwrite directly
205
+ // ...
206
+ // Cleanup when done
207
+
208
+ unsubscribe()
209
+ ```
210
+
211
+ ## Optimistic Mutations
212
+
213
+ For this first iteration, the project provides optimistic mutations for document-related mutation hooks: `useUpdateDocument`, `useUpsertDocument`, `useIncrementAttribute`, `useDecrementAttribute`, and `useDeleteDocument`. Optimistic Mutations can easily be added to other hooks. We wanted to make sure the most important ones were covered first.
214
+
215
+ Optimistic mutations allow us to update the query cache while the mutation is in-flight, giving us the illusion of immediate updates without waiting for a server response. If the server update fails for any reason, the optimistic update is reverted to prevent incorrect data from being displayed.
216
+
217
+ ## Query Caching
218
+
219
+ All queries are assigned a unique queryKey and provide the developer with access to the underlying `staleTime` property.
220
+
221
+ ```tsx
222
+ type Person = {
223
+ name: string
224
+ age: number
225
+ }
226
+
227
+ const person = useDocument<Person>(
228
+ {
229
+ databaseId: 'db1',
230
+ collectionId: 'col1',
231
+ documentId: 'doc1',
232
+ fields: ['name', 'age'],
233
+ },
234
+ {
235
+ staleTime: 1000 * 60, // 1 minute
236
+ },
237
+ )
238
+ ```
239
+
240
+ ### QueryKey Builder
241
+
242
+ During development, we started getting annoyed with keeping our query keys straight, so we built a factory you can use to perform manual cache eviction. We tried to keep the pattern as close to Appwrite's `Channels` as possible.
243
+
244
+ ```tsx
245
+ import { Keys } from "@zeroin.earth/appwrite-graphql";
246
+
247
+ const queryKey = Keys.database(databaseId)
248
+ .collection(collectionId)
249
+ .document(documentId)
250
+ .key()
251
+ ```
252
+
253
+ ## Offline-first Support
254
+
255
+ We wanted to give developers the freedom to build projects that didn't require continual internet connectivity. Using React Query's `offlineFirst` network modes, we built in a way for mutations to queue up and replay in order once the device reconnects to the internet. We then built an offline client to wrap it all together.
256
+
257
+ ### Built-in Offline Persisters
258
+
259
+ With mutations queuing up, we needed to persist them in the event of an online connection being days away, rather than just a temporary outage. Enter the persisters. The library comes with two out-of-the-box options: localStorage and AsyncStorage, depending on what you're building.
260
+
261
+ ```tsx
262
+ const { appwrite, queryClient, persister } = createOfflineClient({
263
+ endpoint: 'https://cloud.appwrite.io/v1',
264
+ projectId: 'my-project',
265
+ storage: localStorage, // or any AsyncStorage-compatible interface
266
+ networkAdapter: webNetworkAdapter(),
267
+ })
268
+ ```
269
+
270
+ The above example will serialize the mutations to localStorage after a set `throttleTime` elapses (defaults to 1000ms). Once the `networkAdpater` detects the device is online, the serialized mutations will instantly start replaying in order.
271
+
272
+ ### Custom Offline Persister Support
273
+
274
+ Sometimes you want to bring your own persister, or just don't want to use localStorage or AsyncStorage. For this, you can build your own.
275
+
276
+ ### Conflict Resolution
277
+
278
+ While in offline-first mode, there will be times when an update can happen on the server without your device knowing about it, and the device will push its own mutation once it comes back online. To handle this, we have built in 3 conflict resolution paths and allowed the developer to bring their own if needed.
279
+
280
+ ```tsx
281
+ createOfflineClient({
282
+ endpoint: 'https://cloud.appwrite.io/v1',
283
+ projectId: 'my-project',
284
+ storage: localStorage,
285
+ networkAdapter: webNetworkAdapter(),
286
+ conflictStrategy: 'last-write-wins'
287
+ })
288
+ ```
289
+
290
+ **last-write-wins**: This is the default behavior, where whatever is in the most recent mutation is what is applied to the database, regardless of when and where it came from. This is also the default behavior of Appwrite.
291
+
292
+ **server-wins**: If the record was changed on the server and differs from the version cached locally on the device, the replayed mutation is dropped, preserving the server's version.
293
+
294
+ **merge-shallow**: A remote copy is pulled from the server, changes between the remote and local copies are identified, and the changes are merged into a final copy, giving precedence to fields that were updated on the server if both copies changed the same field.
295
+
296
+ **custom**: A custom resolver function can be supplied with the following type:
297
+
298
+ ```tsx
299
+ conflictStrategy: ((context: ConflictContext) => Record<string, string | number | boolean | null> | 'abort')
300
+ ```
301
+
302
+ - `abort` signals to drop the replaying mutation and change nothing.
303
+
304
+ ## SSR Support
40
305
 
41
- ```jsx
306
+ We have exposed 3 of the most used queries Appwrite surfaces to be used in SSR preFetchQuery calls. This allows you to prefetch a page's content server-side:
307
+
308
+ - `getAccountQuery`
309
+ - `getDocumentQuery`
310
+ - `getCollectionQuery`
311
+
312
+ ```tsx
313
+ import * as React from "react";
314
+ import {
315
+ dehydrate,
316
+ HydrationBoundary,
317
+ QueryClient,
318
+ } from "@tanstack/react-query";
319
+
320
+ import { createAppwriteClient, useCollection } from "./";
321
+ import { getCollectionQuery } from "./";
322
+
323
+ type PostType = {
324
+ title: string;
325
+ image: string;
326
+ description: string;
327
+ };
328
+
329
+ // This could also be getServerSideProps
330
+ export async function getStaticProps() {
331
+ const appwriteClient = createAppwriteClient({
332
+ endpoint: "https://example.com/v1",
333
+ projectId: "project-id",
334
+ });
335
+
336
+ const queryClient = new QueryClient();
337
+
338
+ // Perform the prefetching of the collection query on the server.
339
+ await queryClient.prefetchQuery(
340
+ getCollectionQuery<PostType>(appwriteClient, {
341
+ databaseId: "db1",
342
+ collectionId: "col1",
343
+ fields: ["title", "image", "description"],
344
+ }),
345
+ );
346
+
347
+ // Dehydrate the query client state and pass it as a
348
+ // prop to the page component.
349
+ return {
350
+ props: {
351
+ dehydratedState: dehydrate(queryClient),
352
+ },
353
+ };
354
+ }
355
+
356
+ function Posts() {
357
+ // Since we prefetched the data on the server, this will use the
358
+ // cached data and not trigger a network request. If the cache is empty,
359
+ // it will fetch the data from the Appwrite server normally.
360
+ const { data } = useCollection<PostType>({
361
+ databaseId: "db1",
362
+ collectionId: "col1",
363
+ fields: ["title", "image", "description"],
364
+ });
365
+
366
+ return (
367
+ <div>
368
+ {data?.documents?.map((post) => (
369
+ <div key={post.$id}>
370
+ <h2>{post.title}</h2>
371
+ <img src={post.image} alt={post.title} />
372
+ <p>{post.description}</p>
373
+ </div>
374
+ ))}
375
+ </div>
376
+ );
377
+ }
378
+
379
+ // The dehydrated state from the server is passed to the HydrationBoundary,
380
+ // which allows the client-side React Query to rehydrate and use the prefetched
381
+ // data without making an additional network request.
382
+ export default function PostsRoute({ dehydratedState }) {
383
+ return (
384
+ <HydrationBoundary state={dehydratedState}>
385
+ <Posts />
386
+ </HydrationBoundary>
387
+ );
388
+ }
389
+ ```
390
+
391
+ ## Field Selection
392
+
393
+ The most used query hooks allow you to specify the fields returned by Appwrite to prevent over-fetching. These fields select out of the `data` property that is returned:
394
+
395
+ - `useDocument`
396
+ - `useCollection`
397
+ - `useCollectionWithPagination`
398
+ - `useInfiniteCollection`
399
+
400
+ ```tsx
401
+ type Person = {
402
+ name: string;
403
+ age: number;
404
+ };
405
+
406
+ const person = useDocument<Person>(
407
+ {
408
+ databaseId: "db1",
409
+ collectionId: "col1",
410
+ documentId: "doc1",
411
+ fields: ["name", "age"],
412
+ },
413
+ );
414
+ ```
415
+
416
+ ## Suspense Queries
417
+
418
+ When using a `<Suspense>` boundary within React, you are able to utilize our selection of Suspense hooks. They are using `useSuspenseQuery` on the backside and will work out of the box with React Suspense.
419
+
420
+ - `useSuspenseCreateJWT`
421
+ - `useSuspenseCollection`
422
+ - `useSuspenseCollectionWithPagination`
423
+ - `useSuspenseDocument`
424
+ - `useSuspenseFunction`
425
+
426
+ ## Pagination Hooks
427
+
428
+ We have included two pagination hooks out of the box
429
+
430
+ **With Pagination:**
431
+
432
+ ```tsx
433
+ import * as React from "react";
434
+ import { q, useCollectionWithPagination } from "./";
435
+
436
+ type Item = {
437
+ _id: string;
438
+ name: string;
439
+ };
440
+
441
+ export default function Test() {
442
+ const {
443
+ documents,
444
+ page,
445
+ total,
446
+ nextPage,
447
+ previousPage,
448
+ hasNextPage,
449
+ hasPreviousPage,
450
+ } = useCollectionWithPagination<Item>({
451
+ databaseId: "your-database-id",
452
+ collectionId: "your-collection-id",
453
+ queries: q<Item>()
454
+ .equal("name", ["John", "Jane"])
455
+ .createdBefore(new Date("2024-01-01").toDateString())
456
+ .orderAsc("name")
457
+ .build(),
458
+ limit: 10,
459
+ fields: ["name", "_id"],
460
+ });
461
+
462
+ return (
463
+ <div>
464
+ <ul>
465
+ {documents.map((item) => (
466
+ <li key={item._id}>{item.name}</li>
467
+ ))}
468
+ </ul>
469
+
470
+ <button onClick={previousPage} disabled={!hasPreviousPage}>
471
+ Previous
472
+ </button>
473
+
474
+ <button onClick={nextPage} disabled={!hasNextPage}>
475
+ Next
476
+ </button>
477
+
478
+ <p>Page: {page}</p>
479
+ <p>Total: {total}</p>
480
+ </div>
481
+ );
482
+ }
483
+ ```
484
+
485
+ **Infinite Scroll**:
486
+
487
+ ```tsx
488
+ import * as React from "react";
489
+ import { q, useInfiniteCollection } from "./";
490
+
491
+ type Item = {
492
+ _id: string;
493
+ name: string;
494
+ };
495
+
496
+ export default function Test() {
497
+ const { documents, fetchNextPage, hasNextPage } = useInfiniteCollection<Item>(
498
+ {
499
+ databaseId: "your-database-id",
500
+ collectionId: "your-collection-id",
501
+ queries: q<Item>()
502
+ .equal("name", ["John", "Jane"])
503
+ .createdBefore(new Date("2024-01-01").toDateString())
504
+ .orderAsc("name")
505
+ .build(),
506
+ limit: 25,
507
+ fields: ["name", "_id"],
508
+ },
509
+ );
510
+
511
+ return (
512
+ <div>
513
+ <ul>
514
+ {documents.map((item) => (
515
+ <li key={item._id}>{item.name}</li>
516
+ ))}
517
+ </ul>
518
+
519
+ <button onClick={fetchNextPage} disabled={!hasNextPage}>
520
+ Load More...
521
+ </button>
522
+ </div>
523
+ );
524
+ }
525
+ ```
526
+
527
+ ## Appwrite QueryBuilder
528
+
529
+ Appwrite SDK includes a built-in Query factory, but we wanted to make something a little easier for ourselves while developing this library, so we are including what we put together. All `queries` props in all the hooks can take either the built-in Query factory, ours, or both, so you can do what makes the most sense for you.
530
+
531
+ Our QueryBuilder is type safe and exposes all underlying functions from the built-in version 1 for 1.
532
+
533
+ ```tsx
534
+ import { q } from "@zeroin.earth/appwrite-graphql";
535
+
536
+ type YourType = {
537
+ name: string;
538
+ favNumber: number;
539
+ favColor: string;
540
+ favFood: string;
541
+ };
542
+
543
+ export function Profiles() {
544
+ const { documents, error, isLoading } = useCollection<YourType>({
545
+ databaseId: "your-database-id",
546
+ collectionId: "your-collection-id",
547
+ queries: q<YourType>()
548
+ .or(
549
+ (q) => q.equal("favColor", "blue").greaterThan("favNumber", 18),
550
+ (q) => q.equal("favFood", "pizza").lessThan("favNumber", 10),
551
+ (q) =>
552
+ q.and(
553
+ (q) => q.between("favNumber", 5, 15),
554
+ (q) => q.startsWith("name", "A"),
555
+ ),
556
+ )
557
+
558
+ .build(),
559
+ });
560
+
561
+ return (
562
+ <div>
563
+ {isLoading && <p>Loading...</p>}
564
+ {error?.length > 0 && <p>Error: {error[0].message}</p>}
565
+ {documents && (
566
+ <ul>
567
+ {documents.map((doc) => (
568
+ <li key={doc.$id}>
569
+ Name: {doc.name}, Fav Number: {doc.favNumber}, Fav Color:{" "}
570
+ {doc.favColor}, Fav Food: {doc.favFood}
571
+ </li>
572
+ ))}
573
+ </ul>
574
+ )}
575
+ </div>
576
+ );
577
+ }
578
+ ```
579
+
580
+ ## React Query Devtools Support
581
+
582
+ React Query Devtools are bundled and ready to go. For any additional questions and information, please consult [Tanstack Query's](https://tanstack.com/query/latest/docs/framework/react/devtools#install-and-import-the-devtools) website.
583
+
584
+ ## Examples
585
+
586
+ ```ts
42
587
  import { useLogin } from "@zeroin.earth/appwrite-graphql";
43
588
 
44
589
  export function LogIn() {
45
590
  const router = useRouter();
591
+
46
592
  const { login, oAuthLogin } = useLogin();
47
593
 
48
594
  const onSubmit: SubmitHandler<Inputs> = async (data) => {
@@ -56,14 +602,16 @@ export function LogIn() {
56
602
  const loginWithGoogle = () => {
57
603
  oAuthLogin.mutate({
58
604
  provider: "google",
59
- success: 'successUrl',
60
- failure: 'failureUrl',
605
+ success: "successUrl",
606
+ failure: "failureUrl",
61
607
  });
62
608
  };
63
609
  }
64
610
  ```
65
611
 
66
- ```jsx
612
+ ---
613
+
614
+ ```ts
67
615
  import { useFunction } from "@zeroin.earth/appwrite-graphql";
68
616
 
69
617
  export function Form() {
@@ -72,7 +620,7 @@ export function Form() {
72
620
  const onSubmit: SubmitHandler<Input> = async (data) => {
73
621
  executeFunction.mutate(
74
622
  {
75
- functionId: '6gibhbyy6tggdf',
623
+ functionId: "6gibhbyy6tggdf",
76
624
  body: {
77
625
  message: {
78
626
  ...data,
@@ -88,136 +636,3 @@ export function Form() {
88
636
  };
89
637
  }
90
638
  ```
91
-
92
- ### Using Fragments
93
-
94
- ```jsx
95
- import {
96
- fragments,
97
- getFragmentData,
98
- useAccount,
99
- } from "@zeroin.earth/appwrite-graphql";
100
-
101
- export function Profile() {
102
- const { data, isLoading } = useAccount({});
103
- const account = getFragmentData(fragments.Account_UserFragment, data);
104
-
105
- return (
106
- <div>
107
- {data && (
108
- <h2>{`Welcome, ${account?.name ?? "Visitor"}!`}</h2>
109
- )}
110
- </div>
111
- );
112
- }
113
- ```
114
-
115
- ## Work in progress
116
-
117
- We are working on matching parity with the current Appwrite SDK. After we do so, version numbers will match the currently supported version of the SDK. Until then, please feel free to use what we have finished so far!
118
-
119
- Still left to do:
120
-
121
- ### Account ✔️
122
- <details>
123
- <summary>Done</summary>
124
-
125
- - [x] Get account
126
- - [x] Create account
127
- - [x] Update email
128
- - [x] List Identities
129
- - [x] Delete Identity
130
- - [x] Create JWT
131
- - [x] List logs
132
- - [x] Update name
133
- - [x] Update password
134
- - [x] Update phone
135
- - [x] Get account preferences
136
- - [x] Update preferences
137
- - [x] Create password recovery
138
- - [x] Create password recovery (confirmation)
139
- - [x] List sessions
140
- - [x] Delete sessions
141
- - [x] Create anonymous session
142
- - [x] Create email session
143
- - [x] Create magic URL session
144
- - [x] Create magic URL session (confirmation)
145
- - [x] Create phone session
146
- - [x] Create phone session (confirmation)
147
- - [x] Get session
148
- - [x] Update OAuth session (refresh tokens)
149
- - [x] Delete session
150
- - [x] Create email verification
151
- - [x] Create email verification (confirmation)
152
- - [x] Create phone verification
153
- - [x] Create phone verification (confirmation)
154
- </details>
155
-
156
- ### Teams
157
-
158
- - [ ] List teams
159
- - [ ] Create team
160
- - [ ] Get team
161
- - [ ] Update name
162
- - [ ] Delete team
163
- - [ ] List team memberships
164
- - [ ] Create team membership
165
- - [ ] Get team membership
166
- - [ ] Update membership
167
- - [ ] Delete team membership
168
- - [ ] Update team membership status
169
- - [ ] Get team preferences
170
- - [ ] Update preferences
171
-
172
- ### Databases ✔️
173
-
174
- <details>
175
- <summary>Done</summary>
176
-
177
- - [X] List documents
178
- - [X] Create document
179
- - [X] Get document
180
- - [x] Update document
181
- - [x] Delete document
182
- </details>
183
-
184
- ### Storage
185
-
186
- - [ ] List files
187
- - [ ] Create file
188
- - [ ] Get file
189
- - [ ] Update file
190
- - [ ] Delete File
191
- - [ ] Get file for download
192
- - [ ] Get file preview
193
- - [ ] Get file for view
194
-
195
- ### Functions ✔️
196
-
197
- <details>
198
- <summary>Done</summary>
199
-
200
- - [X] Create execution
201
- - [X] Get execution
202
- </details>
203
-
204
- ### Locale
205
-
206
- - [ ] Get user locale
207
- - [ ] List Locale Codes
208
- - [ ] List continents
209
- - [ ] List countries
210
- - [ ] List EU countries
211
- - [ ] List countries phone codes
212
- - [ ] List currencies
213
- - [ ] List languages
214
-
215
- ### Avatars
216
-
217
- - [ ] Get browser icon
218
- - [ ] Get credit card icon
219
- - [ ] Get favicon
220
- - [ ] Get country flag
221
- - [ ] Get image from URL
222
- - [ ] Get user initials
223
- - [ ] Get QR code