Code Monkey home page Code Monkey logo

morrys / wora Goto Github PK

View Code? Open in Web Editor NEW
172.0 3.0 4.0 6.91 MB

Write Once, Render Anywhere. typescript libraries: cache-persist, apollo-offline, relay-offline, offline-first, apollo-cache, relay-store, netinfo, detect-network

Home Page: https://morrys.github.io/wora/docs/introduction

License: MIT License

TypeScript 97.51% HTML 0.11% JavaScript 2.31% CSS 0.07%
reactjs react-native wora web ios android netinfo react offline apollo-cache

wora's Introduction

the github page contains all the documentation relating to the libraries distributed by this monorepo.

Community challenge

The idea that led me to create this repository is to collect all the great work done by the community on github for react and react-native in order to create components and utilities that can be rendered anywhere.

If anyone is interested in sharing their idea, contact me (link in bio).

Contributing

  • Give a star to the repository and share it, you will help the project and the people who will find it useful

  • Create issues, your questions are a valuable help

  • PRs are welcome, but it is always better to open the issue first so as to help me and other people evaluating it

  • Please sponsor me

Sponsors

Memorang

  • a simple and efficient way to persist an object in storage: localStorage, AsyncStorage or IndexedDB. With a high configurability and the possibility of subscription and notifications
  • simple library that implements the react-native netinfo interface to use it also in the web
  • useIsConnected and useNetInfo Hooks for react and react-native and the possibility of using NetInfo of @wora/netinfo
  • Persistent Cache store for Offline-First applications, with first-class support for optimistic UI. Use with React, React Native, or any web app.
  • new way to persist the apollo cache, more efficient way and with bundle reduction.
  • integration of the offline engine within the client logic and not at the network level. with much possibility of configuration and extension (@wora/offline-first)
  • persist relay store and relay record source, ttl.
  • integration of the offline engine within the client logic and not at the network level. with much possibility of configuration and extension (@wora/offline-first)

wora's People

Contributors

dependabot[bot] avatar morrys avatar olerichter00 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

wora's Issues

wora/cache-persist V2.0.0

  • possibility of using any storage synchronously with the read and write performance that you have with javascript objects (queue debounce merge and the invocations of multiSet and multiRemove)
  • use react-native-community/async-storage and eliminate the dependency from the AsyncStorage of react-native
  • compatibility with storage created for redux (I have yet to test it)
  • fix typo
  • improved handling of the disablePersist
  • released version 2.0.0-rc.1
  • manage set, remove. delete through both queue and promise
  • test with jest (75% done)
  • evaluate how to reduce the bundle
  • evaluate creation of wora/redux-persist
  • release the other libraries

branch: perf-cache

projects github

I will create github projects to give visibility on the topics to be explored and on upcoming features.

Trouble seeing queued mutations and connection state

@morrys In our first attempts to use ApolloOffline we are simply trying to understand the correct usage with some simple boiler plate to show connection status and whether there are any mutations currently in the queue. Our code below is our attempt to do this but while it seems to be functioning, the status information doesn't appear correct and the callback event functions aren't called when the mutations finally do execute.

Any advice on how we can get some of these things working would be appreciated. If you have a more complete React Native example with this type of basic implementation you can point us at too, that would be helpful I think.

Our test consists of a couple on screen buttons:

  • One that performs a mutation.
  • One that performs the query (that React renders as some simple JSX views and text) to show if the mutation was successful.
  • One that calls the checkMorrys() function to write to the console the result of getState() and getListMutation() then set connection status into React State to show on screen whether it thinks we are online or not.

Here's our test steps:

  1. On Mac OS connect to wifi and run the React Native app in the iOS simulator
  2. Page loads with the results of the query showing on the screen in the simulator
  3. Use a tool to completely disconnect the mac from the internet
  4. Hit the RN button that calls the checkMorrys() function
  5. React state is updated with online status which is still "Online".
  6. Hit the RN button to perform a mutation while offline
  7. Hit the RN button that calls the checkMorrys() function again to see storeOffline.getState() and storeOffline.getListMutation() get written to the console as empty for both (but we expected to see the one mutation in the offline mutation queue here)
  8. Morry's is still reporting online but we believe the mutation was queued successfully despite our inability to see it.
  9. Reconnect the mac to the internet
  10. Expect to see the online state change when this happens but since it was showing online the whole time again, going back online in reality doesn't have any affect on this.
  11. Expect to see the onExecute() function get called but it does not
  12. Expect to see the mutation performed on the server which we DO SEE which tells me all is working as expected, but we just can't get accurate insights into the internals.
  13. We hit the RN button to refresh the data on screen by calling the query again and it now shows the correct data from the server with the additional rows we mutated while offline.

Our app.js...

const client = new ApolloClient({
  link: httpLink,
  cache: new ApolloCache({
    dataIdFromObject: (o) => o.id,
  }),
});

client.setOfflineOptions({
  manualExecution: false, //optional
  link: httpLink, //optional
  start: async (mutations) => {
    //optional function that is called once the request queue has been started
    console.log('start offline', mutations);
    return mutations;
  },
  finish: async (mutations, error) => {
    //optional function that is called once the request queue has been processed
    console.log('finish offline', error, mutations);
  },
  onExecute: async (mutation) => {
    //optional function that is called before the request is sent to the network
    console.log('onExecute offline', mutation);
    return mutation;
  },
  onComplete: async (options) => {
    //optional function that is called once the request has been successfully completed. Only if the function returns the value true, the request is deleted from the queue
    console.log('onComplete offline', options);
    return true;
  },
  onDiscard: async (options) => {
    //optional function that is called when the request returns an error. Only if the function returns the value true, the mutation is deleted from the queue
    console.log('onDiscard offline', options);
    return true;
  },
  onPublish: async (offlinePayload) => {
    //optional function that is called before saving the mutation in the store
    console.log('offlinePayload', offlinePayload);
    return offlinePayload;
  },
});

export default function App() {
  client.hydrate();

  const [showAdd, setShowAdd] = useState(true);
  const [hydrated, setHydrated] = useState(false);
  const [online, setOnline] = useState(false);
  const [cache, setCache] = useState('');

  const checkMorrys = async () => {
    const storeOffline = client.getStoreOffline();
    const cacheState = storeOffline.getState();
    const cacheList = storeOffline.getListMutation();

    setHydrated(client.isRehydrated());
    setOnline(client.isOnline());
    setCache(JSON.stringify(cacheState, null, 2));

    console.log('Offline queue: ', storeOffline);
    console.log('Cache state: ', cacheState);
    console.log('Cache list: ', cacheList);
  };

wora/redux

devhub is the project in which I am performing feasibility tests

branch: perf-cache

  • migrate redux to wora/redux and adapt it to use wora/cache-persist
  • manage the use of wora / redux with and without persistence
  • manage backward compatibility with redux-persist
  • possibility to manage either the saving of the state in a single key, or to save the keys of the object individually
  • delete error messages from the source code and manage them by code
  • released the first version wora/redux 0.0.1
  • refactor for bundle size & typing

Examples Persist

import { createStore, applyMiddleware, combineReducers } from '@wora/redux'
import ReduxProvider from '@wora/redux/libs/react/ReduxProvider'
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
    rootReducer,
    composeWithDevTools(
      applyMiddleware(bugsnagMiddleware, analyticsMiddleware, sagaMiddleware),
    ),
    undefined,
    {
      key: 'root',
      version: 2,
      //multiple: boolean, to save individual status keys 
      //layers?: Array<Layer>
      //blacklist?: Array<string>, backward compatibility
      //whitelist?: Array<string>, backward compatibility
      //throttle?: number, backward compatibility
      //migrate?: (PersistedState, number) => Promise<PersistedState>, backward compatibility
      //stateReconciler?: false | StateReconciler<S>, backward compatibility
    }
  )
sagaMiddleware.run(rootSaga)
<ReduxProvider store={store} loading={null}>

Examples without Persist

import { createStore, applyMiddleware, combineReducers } from '@wora/redux'
import ReduxProvider from '@wora/redux/libs/react/ReduxProvider'
const sagaMiddleware = createSagaMiddleware()
const store = createStore(
    rootReducer,
    composeWithDevTools(
      applyMiddleware(bugsnagMiddleware, analyticsMiddleware, sagaMiddleware),
    ),
  )
sagaMiddleware.run(rootSaga)
<ReduxProvider store={store} loading={null}>

Upcoming changes in offline-first, relay-offline and apollo-offline

Add more parameters in the callback functions in the offline workflow
These changes make it easier to extend the offline workflow

callback functions to be modified

  • execute: (offlineRecord: OfflineRecordCache) => Promise,
  • finish?: (success: boolean, mutations: ReadonlyArray<OfflineRecordCache> ) => void,
  • onComplete?: (options: { offlineRecord: OfflineRecordCache, response: any }) => boolean;
  • onDiscard?: (options: { offlineRecord: OfflineRecordCache, error: any }) => boolean;
  • onPublish?: ( offlineRecord: OfflineRecordCache) => OfflineRecordCache,

libraries to be modified

  • wora/offline-first
    • add the store parameter set with the storeOffline
    • consider adding two new callback functions: start, preExecute
  • wora/apollo-offline
    • add the client parameter set with the apollo client
  • wora/relay-offline
    • add the client parameter set with the relay environment

error: when I'm trying to perform a mutation without optimistic response whilst offline

@morrys Thanks that worked!

However now when I'm trying to perform a mutation whilst offline, I get this error:

TypeError: Cannot read property 'updateUser' of undefined
    at bundle.esm.js:605
    at Array.forEach (<anonymous>)
    at StoreWriter../node_modules/apollo-cache-inmemory/lib/bundle.esm.js.StoreWriter.writeSelectionSetToStore (bundle.esm.js:599)
    at StoreWriter../node_modules/apollo-cache-inmemory/lib/bundle.esm.js.StoreWriter.writeResultToStore (bundle.esm.js:577)
    at ApolloCache../node_modules/apollo-cache-inmemory/lib/bundle.esm.js.InMemoryCache.write (bundle.esm.js:913)
    at bundle.esm.js:1866
    at Array.forEach (<anonymous>)
    at bundle.esm.js:1866
    at ApolloCache../node_modules/apollo-cache-inmemory/lib/bundle.esm.js.InMemoryCache.performTransaction (bundle.esm.js:979)
    at DataStore../node_modules/apollo-client/bundle.esm.js.DataStore.markMutationResult (bundle.esm.js:1865)

Originally posted by @harveyconnor in #4 (comment)

Removing stored mutations by query?

Is there a way to remove stored mutations by query? For example, if a document is saved twice offline, I'd like to only send the last mutation when they go online. This means I would remove the prior mutations for that query when a new save is made.

I see that I can get the list of stored mutations via client.getStoreOffline().getListMutation(), but I want to find the ones that are using the same mutation query. Would something like readMutations() that follows a similar API to an Apollo cache's readQuery() make sense?

// returns filtered list from client.getStoreOffline().getListMutation()
const mutations = client.getStoreOffline().getMutations({
  query: SAVE_DOCUMENT,
  variables: { id: documentId }
})

// run client.getStoreOffline().remove(id) for each result

or

// removes mutations matching query
client.getStoreOffline().removeMutations({
  query: SAVE_DOCUMENT,
  variables: { id: documentId }
})

client.cache.data.getState is not a function

Here is the stack trace.

ApolloStoreOffline.js:92 Uncaught TypeError: client.cache.data.getState is not a function
    at Object.publish (ApolloStoreOffline.js:92)
    at OfflineApolloClient../node_modules/@wora/apollo-offline/lib/ApolloClientOffline.js.OfflineApolloClient.mutate (ApolloClientOffline.js:63)
    at Mutation._this.mutate (react-apollo.esm.js:457)
    at Object.Mutation._this.runMutation [as update] (react-apollo.esm.js:432)
    at UserInfo.updateUser (Info.tsx:71)
    at UserInfo.onKeyDown (Info.tsx:63)
    at HTMLUnknownElement.callCallback (react-dom.development.js:149)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:199)
    at invokeGuardedCallback (react-dom.development.js:256)
    at invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:270)
publish @ ApolloStoreOffline.js:92
./node_modules/@wora/apollo-offline/lib/ApolloClientOffline.js.OfflineApolloClient.mutate @ ApolloClientOffline.js:63
Mutation._this.mutate @ react-apollo.esm.js:457
Mutation._this.runMutation @ react-apollo.esm.js:432
UserInfo.updateUser @ Info.tsx:71
UserInfo.onKeyDown @ Info.tsx:63
callCallback @ react-dom.development.js:149
invokeGuardedCallbackDev @ react-dom.development.js:199
invokeGuardedCallback @ react-dom.development.js:256
invokeGuardedCallbackAndCatchFirstError @ react-dom.development.js:270
executeDispatch @ react-dom.development.js:561
executeDispatchesInOrder @ react-dom.development.js:583
executeDispatchesAndRelease @ react-dom.development.js:680
executeDispatchesAndReleaseTopLevel @ react-dom.development.js:688
forEachAccumulated @ react-dom.development.js:662
runEventsInBatch @ react-dom.development.js:816
runExtractedEventsInBatch @ react-dom.development.js:824
handleTopLevel @ react-dom.development.js:4826
batchedUpdates$1 @ react-dom.development.js:20439
batchedUpdates @ react-dom.development.js:2151
dispatchEvent @ react-dom.development.js:4905
(anonymous) @ react-dom.development.js:20490
unstable_runWithPriority @ scheduler.development.js:255
interactiveUpdates$1 @ react-dom.development.js:20489
interactiveUpdates @ react-dom.development.js:2170
dispatchInteractiveEvent @ react-dom.development.js:4882

Here's my client file:

import ApolloClientIDB from '@wora/apollo-offline/lib/ApolloClientIDB';
import { createHttpLink } from 'apollo-link-http';
import ApolloCache from '@wora/apollo-cache';

const httpLink = createHttpLink({
  uri: `${process.env.API_URL}/graphql`,
});

const cacheOptions = {
  dataIdFromObject: (o: any) => o.id,
};

const client = ApolloClientIDB.create(
  { link: httpLink },
  cacheOptions,
);

export default client;

Relay Offline with MMKV

Have you considered creating an MMKV layer for React Native apps that we use for your libraries? Async storage works well, but it involves a lot of data going over the bridge (particularly with the volume of data Relay uses), so in theory MMKV should be much more performant.

I realise you'd probably need to customise this at the cache-persist layer. If this isn't on your roadmap, is there a guide for how we might switch out the storage layer? I've seen simple files like this, but not sure how we'd plug that in at the relay offline layer.

How to clear IndexedDB

How can i clear IndexedDB when user logout or clear existing user data from indexDB and store new login user data?

Proposal: Replace `useRestore` with `HydrationGuard`

Throughout the day, I have been troubleshooting a perplexing issue with the branching logic of 'react-relay-offline', specifically with the online/offline behavior. Finally, I identified that the problem lies with the useRestore function.

Please see the following code.

const MyRelayEnvironmentProvider = () => {
  // ...

  const environment = useMemo(() => {
    // ...
    return new Environment({ network, store })
  }, [userId, token])

  const isRehydrated = useRestore(environment)
  if(isRehydrated) {
    return <Loading />
  }

  return (
    <RelayEnvironmentProvider environment={environment}>
      {props.children}
    </RelayEnvironmentProvider>
  );
}

I think this is a quite common pattern to initialize environment using useMemo to support multiple users.
However, useRestore is not designed to support this pattern.
useRestore uses useState internally to keep the state of hydration, so that it doesn't rehydrate the new environment when userId or token is changed.
First I tried to modify useRestore to throw suspense when it's not rehydrated. But it requires an external store like 'recoil' to keep the state of rehydration. And it's not a good idea to add another dependency to react-relay-offline to solve this small problem.

So my current solution in my project looks like this.

const HydrationGuard = memo((props: PropsWithChildren) => {
  const environment = useRelayEnvironment();

  if (!environment.isRehydrated()) {
    throw environment.hydrate();
  }

  return <>{props.children}</>;
});

And this is how to use HydrationGuard

<Suspense fallback={<Loading />}>
  <MyRelayEnvironmentProvider>
    <HydrationGuard>
      <App />
    </HydrationGuard>
  </MyRelayEnvironmentProvider>
</Suspense>

I'm quite satisfied with this solution and think supporting HydrationGuard in react-relay-offline is a good idea.
What do you guys think? I'm happy to make a PR if you guys think it's a good idea.

relay-store: Enabling TSLint strict flag results in type errors

Hi @morrys ! ๐Ÿ‘‹

Firstly, thanks for your amazing work! ๐Ÿ™‚

We are using @wora/relay-store 6.0.0 in our project Eigen and ran into a type issue with strict mode enabled.

I've create a PR to fix the type issues we encountered and here is the diff that solved my problem (from patch-package):

TSConfig Error Message:

node_modules/@wora/relay-store/lib/RecordSource.d.ts:22:5 - error TS2416: Property 'toJSON' in type 'RecordSource' is not assignable to the same property in base type 'IMutableRecordSourceOffline'.
  Type '() => RecordMap' is not assignable to type '() => { [key: string]: Record<{}>; }'.
    Type 'RecordMap' is not assignable to type '{ [key: string]: Record<{}>; }'.
      'string' index signatures are incompatible.
        Type 'Record<{}> | null | undefined' is not assignable to type 'Record<{}>'.
          Type 'undefined' is not assignable to type 'Record<{}>'.

22     toJSON(): RecordMap;
       ~~~~~~
```diff
diff --git a/node_modules/@wora/relay-store/lib/RecordSource.d.ts b/node_modules/@wora/relay-store/lib/RecordSource.d.ts
index 422b7bf..74cfe72 100644
--- a/node_modules/@wora/relay-store/lib/RecordSource.d.ts
+++ b/node_modules/@wora/relay-store/lib/RecordSource.d.ts
@@ -1,5 +1,5 @@
 import { RecordState } from 'relay-runtime';
-import { MutableRecordSource, Record, RecordMap } from 'relay-runtime/lib/store/RelayStoreTypes';
+import { MutableRecordSource, Record } from 'relay-runtime/lib/store/RelayStoreTypes';
 import { DataCache, CacheOptions } from '@wora/cache-persist';
 export interface IMutableRecordSourceOffline extends MutableRecordSource {
     restore(): Promise<DataCache>;
@@ -19,6 +19,6 @@ export declare class RecordSource implements IMutableRecordSourceOffline {
     remove(dataID: string): void;
     set(dataID: string, record: Record): void;
     size(): number;
-    toJSON(): RecordMap;
+    toJSON(): { [key: string]: Record };
 }
 //# sourceMappingURL=RecordSource.d.ts.map

This issue body was partially generated by patch-package.

Handling file uploads?

Hi,

I know this isn't really an issue with your excellent packages, but I'm stuck. I have an app used by engineers to take photos of a work site. They're often offline. I used to use the AWS AppSync SDK which had a feature that would transparently upload photos to S3. Unfortunately they're not maintaining it now and it doesn't work with the latest React Native, Apollo or Expo, so hunting around I found these packages which work really well.

Unfortunately I can't find a way to handle images though. I tried turning the image into Base64 and then setting a property. This works OK as long as the image isn't very big. But I soon got errors from our AppSync server with medium-sized photos. I also got problems on the device saying the data was too large for the cache.

I've just been looking at Expo SDK38's new FileSystem.uploadAsync. This looks very neat because it works in the background, but I can't make it work with Android, only iOS so far and I'm not sure how to integrate it with GraphQL.

Any ideas anyone?
Thanks

How to cache only specific query result?

Hi

in my project i have two query

1st one is list data by PK
2nd one is list data by GSI1

now i want to store this two query data and also i want to update data according to that when i call mutation

how can i achieve this can you please help me in this?

Stop processing queue at the middle of the process

Do we have an recommend way to stop to process an queue at the middle of the process and keep them at the queue? Like, today we have an middlware at our project which try to refresh the authentication token, but you have a limit time so your token can expire and you gonna need to logout. To us, after the first mutation failure because of the refresh token failure, we know that the rest don't gonna work anyway and we want to keep all these mutations at the queue. Today I achieve it with this configuration:

  let stopToProcessQueue = false

  environment.setOfflineOptions({
    start: (mutations) => {
      stopToProcessQueue = false
      
      return Promise.resolve(mutations)
    },
    onExecute: (mutation) => {
      if (stopToProcessQueue) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        return Promise.resolve(undefined) as any
      }

      return Promise.resolve(mutation)
    },
    onDiscard: (options) => {
      if (options.error instanceof RefreshTokenError) {
        stopToProcessQueue = true

        return Promise.resolve(false)
      }

      return Promise.resolve(true)
    },
  })

This works because the current implementation at offline-first/src/index.ts:

                        const processMutation = await onExecute(mutation);
                        if (processMutation) {
                            if (!processMutation.serial) {
                                parallelPromises.push(this.executeMutation(processMutation));
                            } else {
                                await Promise.all(parallelPromises)
                                    .then(() => this.executeMutation(processMutation))
                                    .catch((error) => {
                                        throw error;
                                    });
                                parallelPromises = [];
                            }
                        }

But you can see that I am using eslint-disable-next-line @typescript-eslint/no-explicit-any at my code, because the onExecute type doesn't support to return undefined | null, so I am not sure if this implementation gonna keep safe at new releases of the project.

Do you think that this use case makes sense? If it does, I gonna open an PR to update the type of the onExecute function.

No initial query from server

Hi @morrys !

Thanks again for this awesome package! I need your help ... again.

Following situation:

  • 2 apps: one main app running MongoDB and a react-app, second app running react and your apollo-offline package and all that
  • second app navigates to React component viewing some documents via a standard <Query/> - documents matching the query are displayed and cached - all good!
  • second app navigates to another view
  • main server inserts some documents into a mongoDB collection also matching the query used by the second app in the <Query/> component
  • after this insert, the second app navigates to the same <Query/> view again - the new inserts do not show up! The <Query/> still only shows the results in the cache, but is NOT querying the server again to get the the just inserted new documents.

To put it a bit differently:
For some reason your Apollo client seems to NOT query the server after mounting a new <Query/> of some sort, it always just shows the documents from the cache. If the server data updated since this cache was saved, these changes do NOT show up.

What the hell am I doing wrong? ๐Ÿ˜ข

Crash on app start

Lately I've been getting these reports from a react-native app (running on iOS 14 - not sure if it's related).
I can't reproduce the error yet, any idea where to start to narrow it down?

TypeError: null is not an object (evaluating 'o.fetchTime')
  at ? (node_modules/@wora/relay-store/lib/Store.js:57:65)
  at forEach([native code])
  at dispose(node_modules/@wora/relay-store/lib/Store.js:56:39)
  at disposeRetain(node_modules/react-relay-offline/node_modules/relay-hooks/lib/QueryFetcher.js:33:56)
  at _destroy(node_modules/react-relay-offline/node_modules/relay-hooks/lib/QueryFetcher.js:29:14)
  at b(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:5074:19)
  at runWithPriority(node_modules/scheduler/cjs/scheduler.production.min.js:19:467)
  at commitUnmount(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:5065:9)
  at unmountHostComponents(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:5315:12)
  at Ml(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:6435:15)
  at Ml([native code])
  at runWithPriority(node_modules/scheduler/cjs/scheduler.production.min.js:19:467)
  at commitRoot(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:6337:3)
  at performSyncWorkOnRoot(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:5990:3)
  at Tl([native code])
  at b(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1797:25)
  at runWithPriority(node_modules/scheduler/cjs/scheduler.production.min.js:19:467)
  at flushSyncCallbackQueueImpl(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1794:7)
  at flushSyncCallbackQueue(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:1786:3)
  at scheduleWork(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:5664:45)
  at enqueueSetState(node_modules/react-native/Libraries/Renderer/implementations/ReactNativeRenderer-prod.js:2175:5)
  at setState(node_modules/react/cjs/react.production.min.js:12:369)
  at call(src/components/ConfigProvider/ConfigProvider.js:18:9)
  at tryCatch(node_modules/regenerator-runtime/runtime.js:45:40)
  at call(node_modules/regenerator-runtime/runtime.js:274:22)
  at tryCatch(node_modules/regenerator-runtime/runtime.js:45:40)
  at invoke(node_modules/regenerator-runtime/runtime.js:135:20)
  at handler(node_modules/regenerator-runtime/runtime.js:145:13)
  at run(node_modules/@babel/polyfill/node_modules/core-js/modules/es6.promise.js:75:22)
  at fn(node_modules/@babel/polyfill/node_modules/core-js/modules/es6.promise.js:92:30)
  at fn(node_modules/@babel/polyfill/node_modules/core-js/modules/_microtask.js:18:9)
  at tryCallOne(node_modules/react-native/node_modules/promise/setimmediate/core.js:37:12)
  at callback(node_modules/react-native/node_modules/promise/setimmediate/core.js:123:15)
  at _callTimer(node_modules/react-native/Libraries/Core/Timers/JSTimers.js:130:7)
  at _callImmediatesPass(node_modules/react-native/Libraries/Core/Timers/JSTimers.js:181:5)
  at _immediatesCallback(node_modules/react-native/Libraries/Core/Timers/JSTimers.js:441:12)
  at __callImmediates(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:387:12)
  at fn(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:135:12)
  at __guard(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:364:9)
  at value(node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:134:10)
  at value([native code])
  at value([native code])

[Question] GraphQL Code Generator support?

Using GCG became defacto standard for Apollo and GraphQL.js based servers. For client side queries developers getting nice hooks to use in their apps. Wondering about how to integrate wora in this example.
GCG will generate something like
useCreateUserMutation

support apollo-client v3.0.0

  • adapt apollo-cache to the new apollo-client 3.0 cache management (80% done)
  • adapt apollo-offline with the new apollo-client 3.0 mutation management (80%)
  • adapt the todo example project
  • adapt the sample project in nextjs & SSR (there are problems with the compilation, the library is not distributed with the use of tslib
  • test garbage collector
  • open a PR in Apollo to expose internal APIs cache & mutation)

branch wora: https://github.com/morrys/wora/tree/apollo-client-3.0
branch examples: https://github.com/morrys/offline-examples/tree/apollo-client.3.0

AsyncStorage deprecation warning.

When using this package in React Native (via react-relay-offline), there are warnings shown about using AsyncStorage from react-native as opposed to @react-native-community/async-storage.

Warning: Async Storage has been extracted from react-native core and will be removed in a future release. It can now be installed and imported from '@react-native-community/async-storage' instead of 'react-native'. See https://github.com/react-native-community/react-native-async-storage

Importing from both react-native and @react-native-community/async-storage creates a race condition between the packages which can cause hard to debug issues.

This could probably be resolved fairly easily by changing the dependencies to include @react-native-community/async-storage and the storage.native.ts file.

Subscribe to the offline queue?

I'd like to display an icon to show if there are pending mutations while offline, I can't see any options to find out how big the queue is. Is there a way?

Thanks!

Cache is not updating and new queries are not being displayed

The cache gets persisted to the localStorage and it works offline but it never updates when the app gets online.
Once the cache gets persisted nothing will be changed until I clear the persisted cache/data from localStorage but it will only update for only one request and it will be stuck there with the new query data.

So basically what is happening is if there is persisted cached/data the query won't display or persist anything new.

Here is the code:

import React, { Component } from 'react'
import { ApolloClient } from "@wora/apollo-offline";
import { HttpLink } from "apollo-link-http";
import ApolloCache from '@wora/apollo-cache';
import { ApolloProvider } from '@apollo/react-hooks'

import { Query } from '@apollo/react-components';
import gql from 'graphql-tag'

const GET_BOOKS = gql`
{
    books {
        title
        id
    }
}
`



class App extends Component {
  state = {
    isLoading: true,
    client: null
  }

  async componentDidMount() {
    const httpLink = new HttpLink({
      uri: "http://localhost:8000/graphql"
    });

    const client = new ApolloClient({
      link: httpLink,
      cache: new ApolloCache({
        dataIdFromObject: o => o.id
      })
    });
    await client.hydrated()
    this.setState({
      isLoading: false,
      client
    })
  }

  render() {
    if(this.state.isLoading) return <div>Loading...</div>
    return (
      <ApolloProvider client={this.state.client}>
        <Query query={GET_BOOKS}>
          {({ loading, error, data }) => {
            if (loading) return <p>Loading...</p>;
            if (error) return <p>Error :(</p>;

            return data.books.map(({ id, title }) => (
                <div key={id}>
                <p>
                    {id}: {title}
                </p>
                </div>
            ));
          }}
        </Query>
      </ApolloProvider>
    )
  }
}

export default App

ApolloClient

It seems like your instance of ApolloClient doesn't support local state management.

AsyncStorage running out of space?

Hi @morrys

You helped me last year set up a connection to AWS Amplify and Apollo using your ApolloClient and ApolloCache in Expo and it's been working well.

However, I'm getting the following errors in production database or disk is full (code 13 SQLITE_FULL[13]), from AsyncStorage.

I thought that maybe they're coming from a different part of the app, but I've mostly ruled that out. Do you think it's likely to be coming from the ApolloCache? Are there any alternatives to using AsyncStorage in React Native (specifically Expo managed)?

Thanks!

Error when using with relay-runtime 11.0.2

When using relay-runtime 11.0.2, I get:

error - ./node_modules/@wora/relay-offline/lib/Environment.js:5:0
Module not found: Can't resolve 'relay-runtime/lib/store/RelayModernQueryExecutor'

Downgrading back to relay-runtime 11.0.1 fixes the error.

fix relay-store documentation

The documentation on https://morrys.github.io/wora/docs/relay-store has not been updated with the changes made in these releases:

Example of use of relay-store:

import { RecordSource, Store } from '@wora/relay-store';
import { CacheOptions } from "@wora/cache-persist";
import { Environment } from 'relay-runtime';

const defaultTTL: number = 10 * 60 * 1000; // optional, default
const persistOptions: CacheOptions = { defaultTTL }; // optional, default
const persistOptionsRecords: CacheOptions = {}; // optional, default
const recordSource = new RecordSource(persistOptionsRecords);
const store = new Store(recordSource, persistOptions);
const environment = new Environment({network, store});

// ...

await store.hydrate();

Examples of integration with react-relay-offline https://github.com/morrys/offline-examples/tree/master/relay

Architecture documentation

Can you provide more info how you see offline functionalities being developed and how you see future of this library going forward?
Any info will be useful

relay-offline 2.1.0

  • refactor typing RelayOfflineTypes.ts
  • created the public function executeMutationOffline in the environment and used by the environment when the executeMutation is performed and the application is offline #28
  • removed the RelayStoreOffline file, now the store is created in the environment's constructor
  • allow offline execution of mutations that do not modify the store morrys/react-relay-offline#35
  • integration tests in the example projects
  • release relay-offline 2.1.0

Storage encryption

Hello @morrys !

Thank you for this awesome package!

I just want to ask if you will support storage encryption?
if not, maybe you can give me some insights on how to do it?

Thank you again!

ApolloClientIDB is not passing all cache-persist options

Is there a reason that ApolloClientIDB is only passing on the serialize and persist options for cache-persist? I'd like to use the mutateKeys option specifically

const serialize: boolean = persistOptions.serialize;
const prefix: string = persistOptions.prefix;
if (typeof window !== 'undefined') {
const idbStorages: Array<ICacheStorage> = IDBStorage.create({
name: prefix || 'apollo',
storeNames: ['store', 'offline'],
onUpgrade: idbOptions.onUpgrade,
version: idbOptions.version,
});
idbStore = {
storage: idbStorages[0],
serialize: serialize || false,
prefix: null,
};
idbOffline = {
storage: idbStorages[1],
serialize: serialize || false,
prefix: null,
};
}
const cache = new ApolloCache(cacheOptions, idbStore);
return new ApolloClientOffline({ ...config, cache }, idbOffline);

Filter mutations in onPublish?

Is there any way to filter mutations out to exclude them from being added to the offline queue? Based on criteria, e.g. a value provided in context of a mutation?

bug in apollo-client 2.6.9 - fixed in apollo 2.6.10 - Can't resolve 'apollo-client/util/observableToPromise'

Yesterday I got the the following error.
Module not found: Can't resolve 'apollo-client/util/observableToPromise' in '***\node_modules@wora\apollo-offline\lib'

It turned out to be @wora/apollo-offline having references to apollo-client/util/observableToPromise. The problem here is that since [email protected] the folder structure changed. Solved it for now by adding apollo-client to my own project on a fixed version. Since [email protected] the folder structure changed from apollo-client/util/observableToPromise to apollo-client/bin/util/observableToPromise.

In ApolloClientOffline there is a reference to a file within apollo-client by following the old folder structure.

var observables_1 = require("apollo-client/util/observables");
var observableToPromise_1 = tslib_1.__importDefault(require("apollo-client/util/observableToPromise"));

new release - support relay v9.0.0

react-relay-offline issue: morrys/react-relay-offline#34

netinfo

  • added tests
  • fix dispose listeners
  • fix netinfo addEventListener, removeEventListener method

offline-first

  • added tests
  • remove addNetInfoListener, now you must use NetInfo

detect-network

  • update netinfo dependency

relay-store

  • add tests
  • check the compatibility between the query TTL and the new Relay store data invalidation feature
  • upgrade relay-runtime 9.0.0

relay-offline

  • update netinfo dependency
  • mutateOffline
  • fix offline options type
  • upgrade relay-runtime 9.0.0
  • add tests

release

  • publish to npm

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.