diff --git a/tutorials/client/sdks/web/next-js.mdx b/client-sdk-references/javascript-web/nextjs.mdx similarity index 95% rename from tutorials/client/sdks/web/next-js.mdx rename to client-sdk-references/javascript-web/nextjs.mdx index f4018f22..8f24e997 100644 --- a/tutorials/client/sdks/web/next-js.mdx +++ b/client-sdk-references/javascript-web/nextjs.mdx @@ -1,13 +1,11 @@ --- -title: "Next.js + PowerSync" -description: "A guide for creating a new Next.js application with PowerSync for offline/local first functionality" -keywords: ["next.js", "web"] +title: "Next.js" +description: "A guide for creating a new Next.js application with PowerSync for offline/local first functionality." --- -## Introduction -In this tutorial, we’ll explore how to enhance a Next.js application with offline-first capabilities using PowerSync. In the following sections, we’ll walk through the process of integrating PowerSync into a Next.js application, setting up local-first storage, and handling synchronization efficiently. +In this guide, we'll explore how to enhance a Next.js application with offline-first capabilities using PowerSync. We'll walk through the process of integrating PowerSync into a Next.js application, setting up local-first storage, and handling synchronization efficiently. -At present PowerSync will not work with SSR enabled with Next.js and in this guide we disable SSR across the entire app. However, it is possible to have other pages, which do not require authentication for example, to still be rendered server-side. This can be done by only using the DynamicSystemProvider (covered further down in the guide) for specific pages. This means you can still have full SSR on other page which do not require PowerSync. +At present PowerSync will not work with SSR enabled with Next.js and in this guide we disable SSR across the entire app. However, it is possible to have other pages, which do not require authentication for example, to still be rendered server-side. This can be done by only using the DynamicSystemProvider (covered further down in the guide) for specific pages. This means you can still have full SSR on other pages which do not require PowerSync. ## Setup @@ -41,7 +39,7 @@ Would you like to customize the import alias (`@/*` by default)? Yes ``` - Do not use Turbopack when setting up a new Next.js project as we’ll be updating the `next.config.ts` to use Webpack. This is done because we need to enable: + Do not use Turbopack when setting up a new Next.js project as we'll be updating the `next.config.ts` to use Webpack. This is done because we need to enable: 1. asyncWebAssembly 2. topLevelWait diff --git a/docs.json b/docs.json index 176829af..c92e2991 100644 --- a/docs.json +++ b/docs.json @@ -195,6 +195,10 @@ "usage/use-case-examples/prioritized-sync", "usage/use-case-examples/query-json-in-sqlite", "usage/use-case-examples/raw-tables", + "usage/use-case-examples/sequential-id-mapping", + "usage/use-case-examples/cascading-deletes", + "usage/use-case-examples/aws-s3-storage", + "usage/use-case-examples/pdf-attachments", "usage/use-case-examples/custom-write-checkpoints" ] }, @@ -222,7 +226,8 @@ "integration-guides/supabase-+-powersync/handling-attachments", "integration-guides/supabase-+-powersync/realtime-streaming", "integration-guides/supabase-+-powersync/rls-and-sync-rules", - "integration-guides/supabase-+-powersync/local-development" + "integration-guides/supabase-+-powersync/local-development", + "integration-guides/supabase-+-powersync/connector-performance" ] }, { @@ -310,6 +315,7 @@ ] }, "client-sdk-references/javascript-web/javascript-spa-frameworks", + "client-sdk-references/javascript-web/nextjs", "client-sdk-references/javascript-web/usage-examples", "client-sdk-references/javascript-web/encryption", "client-sdk-references/javascript-web/api-reference" @@ -400,6 +406,7 @@ ] }, "self-hosting/enterprise", + "self-hosting/generate-dev-token", { "group": "Appendix", "pages": [ @@ -411,59 +418,6 @@ } ] }, - { - "tab": "Tutorials", - "groups": [ - { - "group": " ", - "pages": [ - "tutorials/overview" - ] - }, - { - "group": "Client", - "pages": [ - "tutorials/client/overview", - { - "group": "Client SDKs", - "pages": [ - "tutorials/client/sdks/web/next-js" - ] - }, - { - "group": "Attachments / Files", - "pages": [ - "tutorials/client/attachments-and-files/overview", - "tutorials/client/attachments-and-files/aws-s3-storage-adapter", - "tutorials/client/attachments-and-files/pdf-attachment" - ] - }, - { - "group": "Performance", - "pages": [ - "tutorials/client/performance/overview", - "tutorials/client/performance/supabase-connector-performance" - ] - }, - { - "group": "Data Management", - "pages": [ - "tutorials/client/data/overview", - "tutorials/client/data/cascading-delete", - "tutorials/client/data/sequential-id-mapping" - ] - } - ] - }, - { - "group": "Self-Hosting", - "pages": [ - "tutorials/self-host/overview", - "tutorials/self-host/generate-dev-token" - ] - } - ] - }, { "tab": "Resources", "groups": [ @@ -700,6 +654,58 @@ { "source": "/client-sdk-references/kotlin-multiplatform/libraries/room", "destination": "/client-sdk-references/kotlin/libraries/room" + }, + { + "source": "/tutorials/client/data/cascading-delete", + "destination": "/usage/use-case-examples/cascading-deletes" + }, + { + "source": "/tutorials/client/data/sequential-id-mapping", + "destination": "/usage/use-case-examples/sequential-id-mapping" + }, + { + "source": "/tutorials/overview", + "destination": "/usage/use-case-examples" + }, + { + "source": "/tutorials/client/overview", + "destination": "/usage/use-case-examples" + }, + { + "source": "/tutorials/client/sdks/web/next-js", + "destination": "/client-sdk-references/javascript-web/nextjs" + }, + { + "source": "/tutorials/client/attachments-and-files/overview", + "destination": "/usage/use-case-examples/attachments-files" + }, + { + "source": "/tutorials/client/attachments-and-files/aws-s3-storage-adapter", + "destination": "/usage/use-case-examples/aws-s3-storage" + }, + { + "source": "/tutorials/client/attachments-and-files/pdf-attachment", + "destination": "/usage/use-case-examples/pdf-attachments" + }, + { + "source": "/tutorials/client/performance/overview", + "destination": "/integration-guides/supabase-+-powersync/connector-performance" + }, + { + "source": "/tutorials/client/performance/supabase-connector-performance", + "destination": "/integration-guides/supabase-+-powersync/connector-performance" + }, + { + "source": "/tutorials/self-host/overview", + "destination": "/self-hosting/getting-started" + }, + { + "source": "/tutorials/self-host/generate-dev-token", + "destination": "/self-hosting/generate-dev-token" + }, + { + "source": "/tutorials/client/data/overview", + "destination": "/usage/use-case-examples" } ], "appearance": { diff --git a/tutorials/client/performance/supabase-connector-performance.mdx b/integration-guides/supabase-+-powersync/connector-performance.mdx similarity index 94% rename from tutorials/client/performance/supabase-connector-performance.mdx rename to integration-guides/supabase-+-powersync/connector-performance.mdx index 373f2ec7..3c446d22 100644 --- a/tutorials/client/performance/supabase-connector-performance.mdx +++ b/integration-guides/supabase-+-powersync/connector-performance.mdx @@ -1,21 +1,19 @@ --- -title: "Improve Supabase Connector" -description: "In this tutorial we will show you how to improve the performance of the Supabase Connector for the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist)." +title: "Connector Performance" +description: "Learn how to improve the performance of the Supabase Connector using batching strategies." --- -# Background - The demos in the [powersync-js](https://github.com/powersync-ja/powersync-js/tree/main/demos) monorepo provide a minimal working example that illustrate the use of PowerSync with different frameworks. -The demos are therefore not necessarily optimized for performance and can therefore be improved. +The demos are therefore not necessarily optimized for performance and can be improved. -This tutorial demonstrates how to improve the Supabase Connector's performance by implementing two batching strategies that reduce the number of database operations. +This guide demonstrates how to improve the Supabase Connector's performance by implementing two batching strategies that reduce the number of database operations. -# Batching Strategies +## Batching Strategies -The two batching strategies that will be implemented are: +The two batching strategies are: 1. Sequential Merge Strategy, and -2. Pre-sorted Batch Strategy +2. Pre-sorted Batch Strategy @@ -121,7 +119,7 @@ The two batching strategies that will be implemented are: - `putOps`: For `PUT` operations, organized by table name - `deleteOps`: For `DELETE` operations, organized by table name - `patchOps`: For `PATCH` operations (partial updates) - + - Loop through all operations, sort them into the three collections, and then process all operations in batches. ```typescript {8-11, 17-20, 23, 26-29, 32-53, 56, 72} @@ -209,7 +207,7 @@ The two batching strategies that will be implemented are: -# Differences +## Differences @@ -264,14 +262,14 @@ The two batching strategies that will be implemented are: -# Use cases +## Use cases You need more granular control over batch sizes You want more detailed operation logging - + You need to handle mixed operation types more efficiently
**Best for**: Mixed operation types @@ -282,7 +280,7 @@ The two batching strategies that will be implemented are:
You have a large number of similar operations. - + You want to minimize the number of network requests.

@@ -292,4 +290,4 @@ The two batching strategies that will be implemented are:
**Trade-off**: Higher memory usage
-
\ No newline at end of file + diff --git a/tutorials/self-host/generate-dev-token.mdx b/self-hosting/generate-dev-token.mdx similarity index 83% rename from tutorials/self-host/generate-dev-token.mdx rename to self-hosting/generate-dev-token.mdx index 08a456b1..9ff8d138 100644 --- a/tutorials/self-host/generate-dev-token.mdx +++ b/self-hosting/generate-dev-token.mdx @@ -1,25 +1,23 @@ --- title: "Generate a Development Token" -description: "In this tutorial we will show you how to generate a development token for the self-hosted [PowerSync Service](https://powersync.mintlify.app/architecture/powersync-service#powersync-service)." +description: "Learn how to generate a development token for the self-hosted PowerSync Service." --- -# Introduction - Development tokens are useful for: -- getting started quickly without implementing full auth config -- sanity checking your sync rules config (were they applied correctly) -- temporarily impersonating a specific user to debug specific issues +- Getting started quickly without implementing full auth config +- Sanity checking your sync rules config (were they applied correctly) +- Temporarily impersonating a specific user to debug specific issues -# Use Case +## Use Case Development tokens can be used either with the - [test-client](https://github.com/powersync-ja/powersync-service/tree/main/test-client), or - [Sync Diagnostics Client](/resources/troubleshooting#sync-diagnostics-client) -# Generate a Development Token +## Generate a Development Token Development tokens can be generated via either - [PowerSync Cloud](/installation/authentication-setup/development-tokens/#PowerSync-Cloud-Dashboard), or -- locally with a self-hosted setup (described in this tutorial) +- Locally with a self-hosted setup (described below) @@ -72,4 +70,3 @@ Development tokens can be generated via either - diff --git a/tutorials/client/attachments-and-files/overview.mdx b/tutorials/client/attachments-and-files/overview.mdx deleted file mode 100644 index a820115a..00000000 --- a/tutorials/client/attachments-and-files/overview.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Overview" -description: "A collection of tutorials exploring storage strategies." ---- - - - - - diff --git a/tutorials/client/data/overview.mdx b/tutorials/client/data/overview.mdx deleted file mode 100644 index 7b78d52a..00000000 --- a/tutorials/client/data/overview.mdx +++ /dev/null @@ -1,9 +0,0 @@ ---- -title: "Overview" -description: "A collection of tutorials showcasing various data management strategies and use cases." ---- - - - - - diff --git a/tutorials/client/overview.mdx b/tutorials/client/overview.mdx deleted file mode 100644 index 87947f5d..00000000 --- a/tutorials/client/overview.mdx +++ /dev/null @@ -1,11 +0,0 @@ ---- -title: "Overview" -description: "A collection of tutorials for client-side use cases." ---- - - - - - - - diff --git a/tutorials/client/performance/overview.mdx b/tutorials/client/performance/overview.mdx deleted file mode 100644 index 0def40e5..00000000 --- a/tutorials/client/performance/overview.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Overview" -description: "A collection of tutorials exploring performance strategies." ---- - - - - diff --git a/tutorials/client/sdks/overview.mdx b/tutorials/client/sdks/overview.mdx deleted file mode 100644 index cf56e918..00000000 --- a/tutorials/client/sdks/overview.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Client SDK Tutorials" -description: "A collection of tutorials on how to use PowerSync in supported client SDKs." ---- - - - - diff --git a/tutorials/overview.mdx b/tutorials/overview.mdx deleted file mode 100644 index ebe78666..00000000 --- a/tutorials/overview.mdx +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "Tutorials" -sidebarTitle: "Overview" -description: "A collection of tutorials showcasing solutions to common use cases across the PowerSync stack." ---- - -## Overview - -Here you can learn how to approach various use cases and solve specific challenges when integrating PowerSync in your project. - - - We are constantly expanding our list of tutorials. If you'd like to see a solution to a use case that is not currently available, [let us know on Discord](https://discord.gg/powersync). - - -Our tutorials are currently organized into the following categories: - - - - - - -## Notable Community Tutorials - -* Building an Offline-First Chat App Using PowerSync and Supabase - * Postgres (Supabase) + React Native + Expo + Tamagui - * [https://bndkt.com/blog/2023/building-an-offline-first-chat-app-using-powersync-and-supabase](https://bndkt.com/blog/2023/building-an-offline-first-chat-app-using-powersync-and-supabase) -* Building an Offline-First Mobile App with PowerSync - * Postgres + Flutter + Nest.js + Prisma ORM + Firebase Auth - * [https://blog.stackademic.com/building-an-offline-first-mobile-app-with-powersync-40674d8b7ea1](https://blog.stackademic.com/building-an-offline-first-mobile-app-with-powersync-40674d8b7ea1) -* Implementing Local-First Architecture: A Guide to MongoDB Cluster and PowerSync Integration - * MongoDB Atlas + Next.js - * [https://blog.stackademic.com/implementing-local-first-architecture-a-guide-to-mongodb-cluster-and-powersync-integration-6b21fa8059a1](https://blog.stackademic.com/implementing-local-first-architecture-a-guide-to-mongodb-cluster-and-powersync-integration-6b21fa8059a1) - -## Additional Resources - -Haven't found what you're looking for? - -* Additional tutorial-style technical posts can be found on the [PowerSync Blog](https://www.powersync.com/blog). Popular pages include: - * [Migrating a MongoDB Atlas Device Sync App to PowerSync](https://www.powersync.com/blog/migrating-a-mongodb-atlas-device-sync-app-to-powersync) - * [PowerSync and Supabase: Just the Basics](https://www.powersync.com/blog/powersync-and-supabase-just-the-basics) - * [Flutter Tutorial: building an offline-first chat app with Supabase and PowerSync](https://www.powersync.com/blog/flutter-tutorial-building-an-offline-first-chat-app-with-supabase-and-powersync) -* See our [Use Case Examples](/usage/use-case-examples) for details about common use cases. -* See [Demo Apps / Example Projects](/resources/demo-apps-example-projects) for working implementations of PowerSync. diff --git a/tutorials/self-host/overview.mdx b/tutorials/self-host/overview.mdx deleted file mode 100644 index 01cc8d86..00000000 --- a/tutorials/self-host/overview.mdx +++ /dev/null @@ -1,8 +0,0 @@ ---- -title: "Overview" -description: "A collection of tutorials related to self-hosting." ---- - - - - \ No newline at end of file diff --git a/usage/use-case-examples.mdx b/usage/use-case-examples.mdx index ca334d24..04f458d5 100644 --- a/usage/use-case-examples.mdx +++ b/usage/use-case-examples.mdx @@ -7,7 +7,9 @@ The following examples are available to help you get started with specific use c + + @@ -17,17 +19,18 @@ The following examples are available to help you get started with specific use c + + ## Additional Resources -A growing collection of demo apps and tutorials are also available, showcasing working example implementations and solutions to additional use cases: +A growing collection of demo apps are available, showcasing working example implementations: - - + diff --git a/usage/use-case-examples/attachments-files.mdx b/usage/use-case-examples/attachments-files.mdx index 6690dd48..ab3e315d 100644 --- a/usage/use-case-examples/attachments-files.mdx +++ b/usage/use-case-examples/attachments-files.mdx @@ -18,6 +18,6 @@ We currently have these helper packages available to manage attachments: | **Kotlin** | [attachments](https://github.com/powersync-ja/powersync-kotlin/tree/main/core/src/commonMain/kotlin/com/powersync/attachments) | [To-Do List demo app](https://github.com/powersync-ja/powersync-kotlin/tree/main/demos/android-supabase-todolist) | | **Swift** | [attachments](https://github.com/powersync-ja/powersync-swift/blob/main/Sources/PowerSync/attachments/README.md) | [To-Do List demo app](https://github.com/powersync-ja/powersync-swift/tree/main/Demos/PowerSyncExample) | -The example implementations above use [Supabase Storage](https://supabase.com/docs/guides/storage) as storage provider. +The example implementations above use [Supabase Storage](https://supabase.com/docs/guides/storage) as storage provider. * For more information on the use of Supabase as the storage provider, refer to [Handling Attachments](/integration-guides/supabase-+-powersync/handling-attachments) -* To learn how to adapt the implementations to use AWS S3 as the storage provider, see [this tutorial](/tutorials/client/attachments-and-files/aws-s3-storage-adapter) +* To learn how to adapt the implementations to use AWS S3 as the storage provider, see [AWS S3 Storage](/usage/use-case-examples/aws-s3-storage) diff --git a/tutorials/client/attachments-and-files/aws-s3-storage-adapter.mdx b/usage/use-case-examples/aws-s3-storage.mdx similarity index 97% rename from tutorials/client/attachments-and-files/aws-s3-storage-adapter.mdx rename to usage/use-case-examples/aws-s3-storage.mdx index 22bd8a0e..8cedd966 100644 --- a/tutorials/client/attachments-and-files/aws-s3-storage-adapter.mdx +++ b/usage/use-case-examples/aws-s3-storage.mdx @@ -1,35 +1,34 @@ --- -title: "Use AWS S3 for attachment storage" -description: "In this tutorial, we will show you how to replace Supabase Storage with AWS S3 for handling attachments in the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist)." -sidebarTitle: "AWS S3 Storage" +title: "AWS S3 Storage" +description: "Learn how to use AWS S3 instead of Supabase Storage for handling attachments with PowerSync." --- -# Introduction +This guide shows how to replace Supabase Storage with AWS S3 for handling attachments. The implementation is based on the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist). The AWS credentials should never be exposed directly on the client - it could expose access to the entire S3 bucket to the user. -For this tutorial we have therefore decided to use the following workflow: +For this implementation we use the following workflow: 1. Client makes an API call to the app backend, using the client credentials (a [Supabase Edge Function](https://supabase.com/docs/guides/functions)). 2. The backend API has the S3 credentials. It signs a S3 upload/download URL, and returns that to the client. 3. The client uploads/downloads using the pre-signed S3 URL. -The following updates to the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) are therefore required: +The following updates to the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) are required: 1. Create Supabase Edge Functions, and 2. Update the demo app to use the AWS S3 storage adapter - The following pre-requisites are required to complete this tutorial: + The following pre-requisites are required: - Clone the [To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) repo - Follow the instructions in the [README](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/README.md) and ensure that the app runs locally - A running PowerSync Service (can be self-hosted) -# Steps +## Implementation Steps - This tutorial assumes that you have an AWS account. If you do not have an AWS account, you can create one [here](https://aws.amazon.com/). + This guide assumes that you have an AWS account. If you do not have an AWS account, you can create one [here](https://aws.amazon.com/). To enable attachment storage using AWS S3, set up an S3 bucket by following these steps: @@ -73,9 +72,9 @@ The following updates to the [React Native To-Do List demo app](https://github.c **Security Note** - The filename specified in each edge function request can pose security risks, such as enabling a user to overwrite another user’s files by using the same filename. + The filename specified in each edge function request can pose security risks, such as enabling a user to overwrite another user's files by using the same filename. To mitigate this, a common approach is to generate a random prefix or directory for each file. - While it’s likely fine to omit this safeguard in the demo — since users can already read and delete any file — this should be addressed in a **production environment**. + While it's likely fine to omit this safeguard in the demo — since users can already read and delete any file — this should be addressed in a **production environment**. Create the `s3-upload` Edge Function by running the following in your Supabase project: @@ -510,7 +509,7 @@ The following updates to the [React Native To-Do List demo app](https://github.c ``` - +
@@ -593,7 +592,7 @@ The following updates to the [React Native To-Do List demo app](https://github.c export const useSystem = () => React.useContext(SystemContext); ``` - + Ensure that all references to`AppConfig.supabaseBucket` is replaced with the S3 bucket name in the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist). @@ -605,7 +604,8 @@ The following updates to the [React Native To-Do List demo app](https://github.c
-## The complete client files used in this tutorial can be found below +## Complete Client Files + ```typescript AWSStorageAdapter.ts import * as FileSystem from 'expo-file-system'; diff --git a/tutorials/client/data/cascading-delete.mdx b/usage/use-case-examples/cascading-deletes.mdx similarity index 68% rename from tutorials/client/data/cascading-delete.mdx rename to usage/use-case-examples/cascading-deletes.mdx index 409388b7..e65b1a90 100644 --- a/tutorials/client/data/cascading-delete.mdx +++ b/usage/use-case-examples/cascading-deletes.mdx @@ -1,13 +1,11 @@ --- -title: "Cascading Delete" -description: "In this tutorial we will show you how to perform a cascading delete on the client." -keywords: ["data", "cascade", "delete"] +title: "Cascading Deletes" +description: "Learn how to perform cascading deletes on the client when using PowerSync." --- -# Introduction - Since PowerSync utilizes SQLite views instead of standard tables, SQLite features like constraints, foreign keys, or cascading deletes are not available. -Currently, there is no direct support for cascading deletes on the client. However, you can achieve this by either: + +There is no direct support for cascading deletes on the client. However, you can achieve this by either: 1. Manually deleting all the relevant tables within a **single transaction**, OR Every local mutation performed against SQLite via the PowerSync SDK will be returned in `uploadData`. So as long as you are using `.execute()` for the mutation, @@ -15,11 +13,11 @@ Currently, there is no direct support for cascading deletes on the client. Howev 2. Implementing triggers (which is more complex) - You create triggers on the [internal tables](https://docs.powersync.com/architecture/client-architecture#schema) (not the views defined by the client schema), similar to what is - done [here](https://github.com/powersync-ja/powersync-js/blob/e77b1abfbed91988de1f4c707c24855cd66b2219/demos/react-supabase-todolist/src/app/utils/fts_setup.ts#L50) + You create triggers on the [internal tables](/architecture/client-architecture#schema) (not the views defined by the client schema), similar to what is + done [here](https://github.com/powersync-ja/powersync-js/blob/e77b1abfbed91988de1f4c707c24855cd66b2219/demos/react-supabase-todolist/src/app/utils/fts_setup.ts#L50). -# Example +## Example The following example is taken from the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist). It showcases how to delete a `list` and all its associated `todos` in a single transaction. @@ -36,6 +34,6 @@ It showcases how to delete a `list` and all its associated `todos` in a single t ``` - An important thing to note is that the local SQLite database will always match the backend database, as long as the tables are in the publication, when online. + The local SQLite database will always match the backend database, as long as the tables are in the publication, when online. For example, if you delete a record from the local `lists` table and Supabase cascade deletes a record from the `todo` table, PowerSync will also delete the local `todo` record when online. - \ No newline at end of file + diff --git a/tutorials/client/attachments-and-files/pdf-attachment.mdx b/usage/use-case-examples/pdf-attachments.mdx similarity index 90% rename from tutorials/client/attachments-and-files/pdf-attachment.mdx rename to usage/use-case-examples/pdf-attachments.mdx index 44dc1b7b..08956a62 100644 --- a/tutorials/client/attachments-and-files/pdf-attachment.mdx +++ b/usage/use-case-examples/pdf-attachments.mdx @@ -1,38 +1,35 @@ --- -title: "PDF attachments" -description: "In this tutorial we will show you how to modify the [PhotoAttachmentQueue](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/library/powersync/PhotoAttachmentQueue.ts) for PDF attachments." -keywords: ["pdf", "attachment", "storage"] +title: "PDF Attachments" +description: "Learn how to extend the attachment system to support PDF files with PowerSync." --- +This guide shows how to modify the [PhotoAttachmentQueue](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/library/powersync/PhotoAttachmentQueue.ts) to support PDF attachments. The implementation is based on the [React Native To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) which implements photo attachments (specifically a `jpeg`). -# Introduction +## Overview -The current version of the [To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) implements a `PhotoAttachmentQueue` class which -enables photo attachments (specifically a `jpeg`) to be synced. This tutorial will guide you on the changes needed to support PDF attachments. - -An overview of the required changes are: +The required changes are: 1. Update the app schema by adding a `pdf_id` column to the todos table to link a pdf to a to-do item. 2. Add a `PdfAttachmentQueue` class 3. Initialize the `PdfAttachmentQueue` class - The following pre-requisites are required to complete this tutorial: + The following pre-requisites are required: - Clone the [To-Do List demo app](https://github.com/powersync-ja/powersync-js/tree/main/demos/react-native-supabase-todolist) repo - Follow the instructions in the [README](https://github.com/powersync-ja/powersync-js/blob/main/demos/react-native-supabase-todolist/README.md) and ensure that the app runs locally - A running PowerSync Service and Supabase (can be self-hosted) - [Storage configuration in Supabase](/integration-guides/supabase-+-powersync/handling-attachments#configure-storage-in-supabase) -# Steps +## Implementation Steps You can add a _nullable text_ `pdf_id` column to the to-do table via either the `Table Editor` or `SQL Editor` in Supabase. - - ## Table Editor + + ### Table Editor - ## SQL Editor + ### SQL Editor - Navigate to the `SQL Editor` tab: - Execute the following SQL: @@ -176,7 +173,7 @@ An overview of the required changes are: import { SupabaseStorageAdapter } from '../storage/SupabaseStorageAdapter'; import { type AttachmentRecord } from '@powersync/attachments'; - + import { KVStorage } from '../storage/KVStorage'; import { AppConfig } from '../supabase/AppConfig'; import { SupabaseConnector } from '../supabase/SupabaseConnector'; @@ -268,14 +265,14 @@ An overview of the required changes are: -# Usage Example +## Usage Example The newly created `attachmentPdfQueue` can now be used in a component by using the `useSystem` hook created in [step-3](#step-3-initialize-the-pdfattachmentqueue-class) above The code snippet below illustrates how a pdf could be saved when pressing a button. It uses a [DocumentPicker](https://www.npmjs.com/package/react-native-document-picker) UI component to allow the user to select a pdf. When the button is pressed, `savePdf` is called. -The `saveAttachment` method in the `PdfAttachmentQueue` class expects a base64 encoded string. We can therefore use +The `saveAttachment` method in the `PdfAttachmentQueue` class expects a base64 encoded string. We can therefore use [react-native-fs](https://www.npmjs.com/package/react-native-fs) to read the file and return the base64 encoded string which is passed to `saveAttachment`. If your use-case generates a pdf file, ensure that you return a base64 encoded string. @@ -288,27 +285,27 @@ import RNFS from 'react-native-fs'; // Within some component -// useSystem is imported from system.ts +// useSystem is imported from system.ts const system = useSystem(); -const savePdf = async (id: string) => { - if (system.attachmentPdfQueue) { - const res = await DocumentPicker.pick({ - type: [DocumentPicker.types.pdf] - }); - +const savePdf = async (id: string) => { + if (system.attachmentPdfQueue) { + const res = await DocumentPicker.pick({ + type: [DocumentPicker.types.pdf] + }); + console.log(`Selected PDF: ${res[0].uri}`); - const base64 = await RNFS.readFile(res[0].uri, 'base64'); - const { id: attachmentId } = await system.attachmentPdfQueue.saveAttachment(base64); - - await system.powersync.execute(`UPDATE ${TODO_TABLE} SET pdf_id = ? WHERE id = ?`, [attachmentId, id]); - } + const base64 = await RNFS.readFile(res[0].uri, 'base64'); + const { id: attachmentId } = await system.attachmentPdfQueue.saveAttachment(base64); + + await system.powersync.execute(`UPDATE ${TODO_TABLE} SET pdf_id = ? WHERE id = ?`, [attachmentId, id]); + } };