Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
cb6dd00
wip
dylanvorster Aug 5, 2024
86142ce
minor changes to get rn-sb-todo working.
Chriztiaan Aug 7, 2024
3b3534f
Passing sourcemap flag to tsc instead of webpack. Added changesets en…
Chriztiaan Aug 7, 2024
c7f4088
Dev release of support packages.
Chriztiaan Aug 12, 2024
77589b8
Multiplatform prompt support for creating lists and todos.
Chriztiaan Aug 15, 2024
e1b254b
Multiplatform alert/confirm support.
Chriztiaan Aug 15, 2024
c463e3b
Introduced multi platform alert and prompt implementations. Got stora…
Chriztiaan Aug 19, 2024
b5d0383
PoC with public path workers. Using separate webpack files.
Chriztiaan Aug 21, 2024
c9788f6
Nuked public dir
Chriztiaan Aug 22, 2024
8335bd6
Moved workers back to their original dirs.
Chriztiaan Aug 22, 2024
5e65431
Minor documentation for react-native-web. Cleaned up worker bundling …
Chriztiaan Aug 26, 2024
8765494
Changed worker path flag to workers object that allows independent pa…
Chriztiaan Aug 27, 2024
5ae3377
Using SqlOpenOptions instead of web-sql-flags to configure custom wor…
Chriztiaan Sep 2, 2024
118a5a5
Merge branch 'main' into react-native-web-christiaan
Chriztiaan Sep 2, 2024
e4ee2b9
Changeset message.
Chriztiaan Sep 2, 2024
fa806be
Lock file.
Chriztiaan Sep 2, 2024
e3c76c3
Moved sharedSyncWorker config to a sync option on the web PowerSyncDa…
Chriztiaan Sep 2, 2024
e295b30
Merged shared and dedicated db worker into one worker file.
Chriztiaan Sep 4, 2024
81ce61d
Fixed bson issue that was breaking single tab mode.
Chriztiaan Sep 5, 2024
01ca78f
Passing flag options to worker factory method. Renamed webpack worker…
Chriztiaan Sep 6, 2024
e4f430f
WIP prod builds
Chriztiaan Sep 9, 2024
835a19e
Updated copy-files script to target `public/@powersync`. Webpack now …
Chriztiaan Sep 9, 2024
cf0e1c7
Merge branch 'main' into react-native-web-christiaan
Chriztiaan Sep 10, 2024
a8073a7
Update changeset entry.
Chriztiaan Sep 10, 2024
a85856d
Git ignore rule for public/@powersync
Chriztiaan Sep 10, 2024
d06b14a
Dropped node copy script in favour of a bash copy command.
Chriztiaan Sep 11, 2024
95a3562
Changed worker factory signature to return Worker or SharedWorker, in…
Chriztiaan Sep 11, 2024
de10a56
Updated /web package.json.
Chriztiaan Sep 11, 2024
cf56889
wip
Chriztiaan Sep 11, 2024
2b74ae3
Worker factory method now takes in a wider set of options instead of …
Chriztiaan Sep 11, 2024
927ac56
Updated readme to indicate use of options over flags in worker factor…
Chriztiaan Sep 11, 2024
dad54b3
Updated readme entry regarding environment setup.
Chriztiaan Sep 11, 2024
4fb9087
E2E instructions to run the RN web demo
benitav Sep 12, 2024
6d47461
Some light readme restructuring and polish
benitav Sep 12, 2024
79ec0ac
fix heading hierarchy
benitav Sep 12, 2024
fee3d43
Wording polish of UMD target
benitav Sep 12, 2024
322d37f
Moved away from Partial options for the worker factory method.
Chriztiaan Sep 12, 2024
05bdacb
Merge branch 'react-native-web-christiaan' of github.com:powersync-ja…
Chriztiaan Sep 12, 2024
537ab8f
Renamed "Require" interfaces to "Resolved.
Chriztiaan Sep 12, 2024
0c4da76
Readme polish
benitav Sep 16, 2024
97c285a
Simplify readme - migrate config instructions to docs
benitav Sep 16, 2024
ccc9a5c
Merge branch 'main' into react-native-web-christiaan
Chriztiaan Sep 16, 2024
0b2b177
Using ResolvedWebSQLFlags instead of WebSQLFlags for ResolvedWebSQLOp…
Chriztiaan Sep 16, 2024
22d6e66
Merge branch 'react-native-web-christiaan' of github.com:powersync-ja…
Chriztiaan Sep 16, 2024
78f01a9
Add RN web demo to main Readme
benitav Sep 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/light-dots-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@powersync/attachments': patch
'@powersync/common': patch
'@powersync/kysely-driver': patch
'@powersync/react': patch
'@powersync/react-native': patch
---

Added react-native-web support.
5 changes: 5 additions & 0 deletions .changeset/two-bats-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/web': patch
---

Added react-native-web support.
2 changes: 1 addition & 1 deletion demos/react-native-supabase-todolist/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Stack } from 'expo-router';
import React, { useMemo } from 'react';
import { useSystem } from '../library/powersync/system';
import { PowerSyncContext } from '@powersync/react-native';
import { PowerSyncContext } from '@powersync/react';

/**
* This App uses a nested navigation stack.
Expand Down
2 changes: 1 addition & 1 deletion demos/react-native-supabase-todolist/app/views/console.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import _ from 'lodash';
import React from 'react';
import { Table, Row } from 'react-native-reanimated-table';
import { QueryResult } from '@powersync/react-native';
import { QueryResult } from '@powersync/common';
import { useSystem } from '../../library/powersync/system';
import { ScrollView, TextInput } from 'react-native-gesture-handler';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { ATTACHMENT_TABLE, AttachmentRecord } from '@powersync/attachments';
import { usePowerSync, useQuery } from '@powersync/react-native';
import { usePowerSync, useQuery } from '@powersync/react';
import { CameraCapturedPicture } from 'expo-camera';
import _ from 'lodash';
import * as React from 'react';
import { StatusBar } from 'expo-status-bar';
import { ScrollView, View, Text } from 'react-native';
import { FAB } from 'react-native-elements';
import { Stack, useLocalSearchParams } from 'expo-router';
import prompt from 'react-native-prompt-android';
import { TODO_TABLE, TodoRecord, LIST_TABLE } from '../../../../library/powersync/AppSchema';
import { useSystem } from '../../../../library/powersync/system';
import { TodoItemWidget } from '../../../../library/widgets/TodoItemWidget';
import { prompt } from '../../../../library/utils/prompt';

type TodoEntry = TodoRecord & Partial<Omit<AttachmentRecord, 'id'>> & { todo_id: string; attachment_id: string | null };

Expand Down Expand Up @@ -147,7 +147,7 @@ const TodoView: React.FC = () => {

return createNewTodo(text);
},
{ placeholder: 'Todo description', style: 'shimo' }
{ placeholder: 'Todo description' }
);
}}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import * as React from 'react';
import { StatusBar } from 'expo-status-bar';
import { ScrollView, View } from 'react-native';
import { FAB, Text } from 'react-native-elements';
import prompt from 'react-native-prompt-android';

import { router, Stack } from 'expo-router';
import { LIST_TABLE, TODO_TABLE, ListRecord } from '../../../library/powersync/AppSchema';
import { useSystem } from '../../../library/powersync/system';
import { useQuery, useStatus } from '@powersync/react-native';
import { useQuery, useStatus } from '@powersync/react';
import { ListItemWidget } from '../../../library/widgets/ListItemWidget';
import { prompt } from '../../../library/utils/prompt';

const description = (total: number, completed: number = 0) => {
return `${total - completed} pending, ${completed} completed`;
Expand Down Expand Up @@ -63,7 +63,7 @@ const ListsViewWidget: React.FC = () => {
icon={{ name: 'add', color: 'white' }}
size="small"
placement="right"
onPress={() => {
onPress={async () => {
prompt(
'Add a new list',
'',
Expand All @@ -73,7 +73,7 @@ const ListsViewWidget: React.FC = () => {
}
await createNewList(name);
},
{ placeholder: 'List name', style: 'shimo' }
{ placeholder: 'List name' }
);
}}
/>
Expand Down
30 changes: 30 additions & 0 deletions demos/react-native-supabase-todolist/copy-files.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const fs = require('fs');
const path = require('path');

const sourceDir = path.join(__dirname, 'node_modules', '@powersync', 'web', 'dist');
const destDir = path.join(__dirname, 'public');

function copyRecursiveSync(src, dest) {
if (fs.existsSync(src) && fs.statSync(src).isDirectory()) {
// Create the destination directory if it doesn't exist
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest, { recursive: true });
}
const files = fs.readdirSync(src);
// Copy each file/directory
files.forEach((file) => {
const srcFile = path.join(src, file);
const destFile = path.join(dest, file);
if (fs.statSync(srcFile).isDirectory()) {
copyRecursiveSync(srcFile, destFile);
} else {
fs.copyFileSync(srcFile, destFile);
}
});
} else {
console.error(`Source directory ${src} does not exist or is not a directory.`);
}
}

copyRecursiveSync(sourceDir, destDir);
console.log(`Files copied from ${sourceDir} to ${destDir} successfully.`);
6 changes: 6 additions & 0 deletions demos/react-native-supabase-todolist/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1241,6 +1241,8 @@ PODS:
- React-logger (= 0.74.1)
- React-perflogger (= 0.74.1)
- React-utils (= 0.74.1)
- RNCAsyncStorage (1.23.1):
- React-Core
- RNCMaskedView (0.1.11):
- React
- RNGestureHandler (2.16.2):
Expand Down Expand Up @@ -1407,6 +1409,7 @@ DEPENDENCIES:
- React-runtimescheduler (from `../../../node_modules/react-native/ReactCommon/react/renderer/runtimescheduler`)
- React-utils (from `../../../node_modules/react-native/ReactCommon/react/utils`)
- ReactCommon/turbomodule/core (from `../../../node_modules/react-native/ReactCommon`)
- "RNCAsyncStorage (from `../../../node_modules/@react-native-async-storage/async-storage`)"
- "RNCMaskedView (from `../../../node_modules/@react-native-community/masked-view`)"
- RNGestureHandler (from `../../../node_modules/react-native-gesture-handler`)
- RNReanimated (from `../../../node_modules/react-native-reanimated`)
Expand Down Expand Up @@ -1558,6 +1561,8 @@ EXTERNAL SOURCES:
:path: "../../../node_modules/react-native/ReactCommon/react/utils"
ReactCommon:
:path: "../../../node_modules/react-native/ReactCommon"
RNCAsyncStorage:
:path: "../../../node_modules/@react-native-async-storage/async-storage"
RNCMaskedView:
:path: "../../../node_modules/@react-native-community/masked-view"
RNGestureHandler:
Expand Down Expand Up @@ -1641,6 +1646,7 @@ SPEC CHECKSUMS:
React-runtimescheduler: e2152ed146b6a35c07386fc2ac4827b27e6aad12
React-utils: 3285151c9d1e3a28a9586571fc81d521678c196d
ReactCommon: f42444e384d82ab89184aed5d6f3142748b54768
RNCAsyncStorage: 826b603ae9c0f88b5ac4e956801f755109fa4d5c
RNCMaskedView: 0e1bc4bfa8365eba5fbbb71e07fbdc0555249489
RNGestureHandler: 2282cfbcf86c360d29f44ace393203afd5c6cff7
RNReanimated: 33c6135cdf421b795c2f1173075a11cca2a39bf2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/EXConstants.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/EXConstants/ExpoConstants_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/ExpoFileSystem/ExpoFileSystem_privacy.bundle",
"${PODS_CONFIGURATION_BUILD_DIR}/RNCAsyncStorage/RNCAsyncStorage_resources.bundle",
"${PODS_ROOT}/../../../../node_modules/react-native-vector-icons/Fonts/AntDesign.ttf",
"${PODS_ROOT}/../../../../node_modules/react-native-vector-icons/Fonts/Entypo.ttf",
"${PODS_ROOT}/../../../../node_modules/react-native-vector-icons/Fonts/EvilIcons.ttf",
Expand All @@ -318,6 +319,7 @@
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EXConstants.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoConstants_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/ExpoFileSystem_privacy.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/RNCAsyncStorage_resources.bundle",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/AntDesign.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/Entypo.ttf",
"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/EvilIcons.ttf",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AttachmentTable } from '@powersync/attachments';
import { Column, ColumnType, Index, IndexedColumn, Schema, Table } from '@powersync/react-native';
import { Column, ColumnType, Index, IndexedColumn, Schema, Table } from '@powersync/common';

export const TODO_TABLE = 'todos';
export const LIST_TABLE = 'lists';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import * as FileSystem from 'expo-file-system';
import { randomUUID } from 'expo-crypto';
import { AppConfig } from '../supabase/AppConfig';
import { AbstractAttachmentQueue, AttachmentRecord, AttachmentState } from '@powersync/attachments';
import { AbstractAttachmentQueue, AttachmentRecord, AttachmentState, EncodingType } from '@powersync/attachments';
import { TODO_TABLE } from './AppSchema';
import { FileSystem } from '../storage/FileSystem';

export class PhotoAttachmentQueue extends AbstractAttachmentQueue {
async init() {
Expand Down Expand Up @@ -38,7 +38,7 @@ export class PhotoAttachmentQueue extends AbstractAttachmentQueue {
const photoAttachment = await this.newAttachmentRecord();
photoAttachment.local_uri = this.getLocalFilePathSuffix(photoAttachment.filename);
const localUri = this.getLocalUri(photoAttachment.local_uri);
await this.storage.writeFile(localUri, base64Data, { encoding: FileSystem.EncodingType.Base64 });
await this.storage.writeFile(localUri, base64Data, { encoding: EncodingType.Base64 });

const fileInfo = await FileSystem.getInfoAsync(localUri);
if (fileInfo.exists) {
Expand Down
33 changes: 24 additions & 9 deletions demos/react-native-supabase-todolist/library/powersync/system.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import '@azure/core-asynciterator-polyfill';

import React from 'react';
import { PowerSyncDatabase, SyncStreamConnectionMethod } from '@powersync/react-native';
import { PowerSyncDatabase as PowerSyncDatabaseNative } from '@powersync/react-native';
import { PowerSyncDatabase as PowerSyncDatabaseWeb } from '@powersync/web/umd';
import { AbstractPowerSyncDatabase, SyncStreamConnectionMethod } from '@powersync/common';
import { SupabaseStorageAdapter } from '../storage/SupabaseStorageAdapter';

import { AppSchema } from './AppSchema';
Expand All @@ -18,19 +20,32 @@ export class System {
kvStorage: KVStorage;
storage: SupabaseStorageAdapter;
supabaseConnector: SupabaseConnector;
powersync: PowerSyncDatabase;
powersync: AbstractPowerSyncDatabase;
attachmentQueue: PhotoAttachmentQueue | undefined = undefined;

constructor() {
this.kvStorage = new KVStorage();
this.supabaseConnector = new SupabaseConnector(this);
this.storage = this.supabaseConnector.storage;
this.powersync = new PowerSyncDatabase({
schema: AppSchema,
database: {
dbFilename: 'sqlite.db'
}
});
if (PowerSyncDatabaseNative) {
this.powersync = new PowerSyncDatabaseNative({
schema: AppSchema,
database: {
dbFilename: 'sqlite.db'
}
});
} else {
this.powersync = new PowerSyncDatabaseWeb({
schema: AppSchema,
database: {
dbFilename: 'sqlite.db'
},
flags: {
// Only works when `enableMultiTabs` is true.
workerPath: '/node_modules/@powersync/web/dist/'
}
});
}

if (AppConfig.supabaseBucket) {
this.attachmentQueue = new PhotoAttachmentQueue({
Expand All @@ -51,7 +66,7 @@ export class System {

async init() {
await this.powersync.init();
await this.powersync.connect(this.supabaseConnector, { connectionMethod: SyncStreamConnectionMethod.WEB_SOCKET });
await this.powersync.connect(this.supabaseConnector);

if (this.attachmentQueue) {
await this.attachmentQueue.init();
Expand Down
37 changes: 37 additions & 0 deletions demos/react-native-supabase-todolist/library/storage/FileSystem.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import * as ExpoFileSystem from 'expo-file-system';
import { Platform } from 'react-native';

class WebFileSystem {
static documentDirectory = '';

static async getInfoAsync(...args: any[]): Promise<ExpoFileSystem.FileInfo> {
return {
exists: false,
isDirectory: false,
uri: ''
};
}

static async writeAsStringAsync(...args: any[]): Promise<void> {
// No operation, mock implementation
}

static async readAsStringAsync(...args: any[]): Promise<string> {
return ''; // Return an empty string as mock data
}

static async deleteAsync(...args: any[]): Promise<void> {
// No operation, mock implementation
}

static async makeDirectoryAsync(...args: any[]): Promise<void> {
// No operation, mock implementation
}

static async copyAsync(...args: any[]): Promise<void> {
// No operation, mock implementation
}
}

const isWeb = Platform.OS === 'web';
export const FileSystem = isWeb ? WebFileSystem : ExpoFileSystem;
35 changes: 30 additions & 5 deletions demos/react-native-supabase-todolist/library/storage/KVStorage.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { deleteItemAsync, getItemAsync, setItemAsync } from 'expo-secure-store';
import * as ExpoStorage from 'expo-secure-store';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Platform } from 'react-native';

export class KVStorage {
class ExpoKVStorage {
async getItem(key: string): Promise<string | null> {
try {
const session = await getItemAsync(key);
const session = await ExpoStorage.getItemAsync(key);
return session ?? null;
} catch (error) {
// There was an error on the native side
Expand All @@ -12,10 +14,33 @@ export class KVStorage {
}

async setItem(key: string, value: string): Promise<void> {
await setItemAsync(key, value);
await ExpoStorage.setItemAsync(key, value);
}

async removeItem(key: string): Promise<void> {
await deleteItemAsync(key);
await ExpoStorage.deleteItemAsync(key);
}
}

class WebKVStorage {
async getItem(key: string): Promise<string | null> {
try {
const value = await AsyncStorage.getItem(key);
return value ?? null;
} catch (error) {
// There was an error
return null;
}
}

async setItem(key: string, value: string): Promise<void> {
await AsyncStorage.setItem(key, value);
}

async removeItem(key: string): Promise<void> {
await AsyncStorage.removeItem(key);
}
}

const isWeb = Platform.OS === 'web';
export const KVStorage = isWeb ? WebKVStorage : ExpoKVStorage;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { SupabaseClient } from '@supabase/supabase-js';
import { decode as decodeBase64 } from 'base64-arraybuffer';
import * as FileSystem from 'expo-file-system';
import { AppConfig } from '../supabase/AppConfig';
import { StorageAdapter } from '@powersync/attachments';
import { EncodingType, StorageAdapter } from '@powersync/attachments';
import { FileSystem } from './FileSystem';

export interface SupabaseStorageAdapterOptions {
client: SupabaseClient;
Expand Down Expand Up @@ -49,23 +49,20 @@ export class SupabaseStorageAdapter implements StorageAdapter {
fileURI: string,
base64Data: string,
options?: {
encoding?: FileSystem.EncodingType;
encoding?: EncodingType;
}
): Promise<void> {
const { encoding = FileSystem.EncodingType.UTF8 } = options ?? {};
const { encoding = EncodingType.UTF8 } = options ?? {};
await FileSystem.writeAsStringAsync(fileURI, base64Data, { encoding });
}
async readFile(
fileURI: string,
options?: { encoding?: FileSystem.EncodingType; mediaType?: string }
): Promise<ArrayBuffer> {
const { encoding = FileSystem.EncodingType.UTF8 } = options ?? {};
async readFile(fileURI: string, options?: { encoding?: EncodingType; mediaType?: string }): Promise<ArrayBuffer> {
const { encoding = EncodingType.UTF8 } = options ?? {};
const { exists } = await FileSystem.getInfoAsync(fileURI);
if (!exists) {
throw new Error(`File does not exist: ${fileURI}`);
}
const fileContent = await FileSystem.readAsStringAsync(fileURI, options);
if (encoding === FileSystem.EncodingType.Base64) {
if (encoding === EncodingType.Base64) {
return this.base64ToArrayBuffer(fileContent);
}
return this.stringToArrayBuffer(fileContent);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AbstractPowerSyncDatabase, CrudEntry, PowerSyncBackendConnector, UpdateType } from '@powersync/react-native';
import { AbstractPowerSyncDatabase, CrudEntry, PowerSyncBackendConnector, UpdateType } from '@powersync/common';

import { SupabaseClient, createClient } from '@supabase/supabase-js';
import { AppConfig } from './AppConfig';
Expand Down
Loading