Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@nanostores/query

Package Overview
Dependencies
Maintainers
4
Versions
28
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nanostores/query - npm Package Compare versions

Comparing version 0.0.7 to 0.1.0

3

dist/main.d.ts

@@ -26,5 +26,8 @@ import { MapStore, ReadableAtom } from "nanostores";

loading: boolean;
promise?: Promise<T>;
};
export declare type FetcherStore<T = any, E = any> = MapStore<FetcherValue<T, E>> & {
key?: string;
invalidate: (...args: any[]) => void;
mutate: (data?: T) => void;
};

@@ -31,0 +34,0 @@ export declare type FetcherStoreCreator<T = any, E = Error> = (keys: KeyInput, settings?: CommonSettings<T>) => FetcherStore<T, E>;

103

dist/nanoquery.js

@@ -16,12 +16,13 @@ import { map, onStart, onStop, atom } from "nanostores";

subscribe("online", () => events.emit(RECONNECT));
const _refetchOnInterval = /* @__PURE__ */ new Map(), _lastFetch = /* @__PURE__ */ new Map(), _runningFetches = /* @__PURE__ */ new Set(), _latestStoreKey = /* @__PURE__ */ new Map();
const _refetchOnInterval = /* @__PURE__ */ new Map(), _lastFetch = /* @__PURE__ */ new Map(), _runningFetches = /* @__PURE__ */ new Set();
let rewrittenSettings = {};
const runFetcher = async ([key, keyParts], store, settings, force) => {
var _a;
_latestStoreKey.set(store, key);
const isKeyStillSame = () => _latestStoreKey.get(store) === key;
if (!focus)
return;
const isKeyStillSame = () => store.key === key;
const set = (v) => {
if (isKeyStillSame()) {
store.set(v);
events.emit(SET_KEY, key, v);
events.emit(SET_CACHE, key, v, true);
}

@@ -33,4 +34,2 @@ }, setKey = (k, v) => {

};
if (!focus)
return;
const { dedupeTime = 4e3, fetcher } = {

@@ -42,8 +41,5 @@ ...settings,

if (!force) {
tick().then(() => {
const cached = cache.get(key);
if (store.value.data !== cached)
set(cached ? { data: cached, loading: false } : loading);
});
await tick();
const cached = cache.get(key);
if (store.value.data !== cached)
set(cached ? { data: cached, ...notLoading } : { ...loading });
const last = _lastFetch.get(key);

@@ -61,10 +57,11 @@ if (last && last + dedupeTime > now) {

try {
const res = await fetcher(...keyParts);
const promise = fetcher(...keyParts);
setKey("promise", promise);
const res = await promise;
cache.set(key, res);
set({ data: res, loading: false });
set({ data: res, ...notLoading });
_lastFetch.set(key, getNow());
} catch (error) {
(_a = settings.onError) == null ? void 0 : _a.call(settings, error);
setKey("error", error);
setKey("loading", false);
set({ data: store.value.data, error, ...notLoading });
} finally {

@@ -84,4 +81,16 @@ _runningFetches.delete(key);

const fetcherStore = map({
loading: true
...notLoading
}), settings = { ...globalSettings, ...fetcherSettings, fetcher };
fetcherStore.invalidate = () => {
const { key } = fetcherStore;
if (key) {
invalidateKeys(key);
}
};
fetcherStore.mutate = (data) => {
const { key } = fetcherStore;
if (key) {
mutateCache(key, data);
}
};
let keysInternalUnsub, prevKey, prevKeyParts, keyUnsub, keyStore;

@@ -108,4 +117,2 @@ let evtUnsubs = [];

handleNewListener();
} else {
tick().then(() => fetcherStore.set(loading));
}

@@ -132,13 +139,2 @@ const {

evtUnsubs.push(
events.on(MUTATE_CACHE, (keySelector, data) => {
if (prevKey && testKeyAgainstSelector(prevKey, keySelector)) {
if (data === void 0) {
cache.delete(prevKey);
_lastFetch.delete(prevKey);
} else {
cache.set(prevKey, data);
}
fetcherStore.setKey("data", data);
}
}),
events.on(INVALIDATE_KEYS, (keySelector) => {

@@ -149,5 +145,8 @@ if (prevKey && testKeyAgainstSelector(prevKey, keySelector)) {

}),
events.on(SET_KEY, (key, value) => {
if (key === prevKey && fetcherStore.value !== value)
fetcherStore.set(value);
events.on(SET_CACHE, (keySelector, data, full) => {
if (prevKey && testKeyAgainstSelector(prevKey, keySelector) && fetcherStore.value !== data && fetcherStore.value.data !== data) {
fetcherStore.set(
full ? data : { data, ...notLoading }
);
}
})

@@ -160,8 +159,10 @@ );

};
const originListen = fetcherStore.listen;
fetcherStore.listen = (listener) => {
const newImplFactory = (origin) => (listener) => {
handleNewListener();
return originListen(listener);
return origin(listener);
};
fetcherStore.listen = newImplFactory(fetcherStore.listen);
fetcherStore.subscribe = newImplFactory(fetcherStore.subscribe);
onStop(fetcherStore, () => {
fetcherStore.value = { ...notLoading };
keysInternalUnsub == null ? void 0 : keysInternalUnsub();

@@ -177,7 +178,24 @@ evtUnsubs.forEach((fn) => fn());

};
const nukeKey = (key) => {
cache.delete(key);
_lastFetch.delete(key);
};
const iterOverCache = (keySelector, cb) => {
for (const key of cache.keys()) {
if (testKeyAgainstSelector(key, keySelector))
cb(key);
}
};
const invalidateKeys = (keySelector) => {
iterOverCache(keySelector, nukeKey);
events.emit(INVALIDATE_KEYS, keySelector);
};
const mutateCache = (keySelector, data) => {
events.emit(MUTATE_CACHE, keySelector, data);
iterOverCache(keySelector, (key) => {
if (data === void 0)
nukeKey(key);
else
cache.set(key, data);
});
events.emit(SET_CACHE, keySelector, data);
};

@@ -192,5 +210,5 @@ function createMutatorStore(mutator) {

error: void 0,
loading: true,
data: void 0,
mutate
mutate,
...loading
});

@@ -224,3 +242,3 @@ const result = await newMutator({

mutate,
loading: false
...notLoading
});

@@ -272,3 +290,3 @@ return store;

};
const FOCUS = 1, RECONNECT = 2, INVALIDATE_KEYS = 3, MUTATE_CACHE = 4, SET_KEY = 5;
const FOCUS = 1, RECONNECT = 2, INVALIDATE_KEYS = 3, SET_CACHE = 4;
const subscribe = (name, fn) => {

@@ -289,6 +307,5 @@ const isServer = typeof window === "undefined";

const getNow = () => new Date().getTime();
const tick = () => new Promise((r) => r());
const loading = Object.freeze({ loading: true });
const loading = { loading: true }, notLoading = { loading: false };
export {
nanoquery
};
{
"name": "@nanostores/query",
"version": "0.0.7",
"version": "0.1.0",
"description": "Tiny remote data fetching library for Nano Stores",

@@ -32,2 +32,9 @@ "scripts": {

"types": "./dist/main.d.ts",
"exports": {
".": {
"types": "./dist/main.d.ts",
"import": "./dist/nanoquery.js",
"require": "./dist/nanoquery.umd.cjs"
}
},
"dependencies": {

@@ -34,0 +41,0 @@ "nanoevents": "7"

@@ -8,3 +8,3 @@ # Nano Stores Query

- **Small**. 1.65 Kb (minified and gzipped).
- **Small**. 1.61 Kb (minified and gzipped).
- **Familiar DX**. If you've used [`swr`](https://swr.vercel.app/) or

@@ -41,3 +41,3 @@ [`react-query`](https://react-query-v3.tanstack.com/), you'll get the same treatment,

### Query
### Context

@@ -173,2 +173,45 @@ First, we define the context. It allows us to share the default fetcher

## _Third returned item_
(we didn't come up with a name for it 😅)
`nanoquery` function returns a third item that gives you a bit more manual control over the behavior of the cache.
```ts
// store/fetcher.ts
import { nanoquery } from '@nanostores/query';
export const [,, { invalidateKeys, mutateCache }] = nanoquery();
```
`invalidateKeys` does 2 things:
1. nukes all cache for the specified keys;
2. asks all the fetcher stores that used those keys to refresh data immediately, if they have active subscribers.
It accepts one argument—the keys—in 3 different forms, that we call _key selector_.
```ts
// Single key
invalidateKeys("/api/whoAmI");
// Array of keys
invalidateKeys(["/api/dashboard", "/api/projects"]);
/**
* A function that will be called against all keys in cache.
* Must return `true` if key should be invalidated.
*/
invalidateKeys((key) => key.startsWith("/api/job"));
```
`mutateCache` does one thing only: it mutates cache for those keys and refreshes all fetcher stores that have those keys currently.
```ts
/**
* Accepts key in the same form as `invalidateKeys`: single, array and a function.
*/
mutateCache((key) => key === "/api/whoAmI", { title: "I'm Batman!" });
```
Keep in mind: we're talking about the serialized singular form of keys here. You cannot pass stuff like `['/api', '/v1', $someStore]`, it needs to be the full key in its string form.
## Recipes

@@ -199,1 +242,29 @@

not give up the flexibility of component-level data fetching.
### Refetching and manual mutation
We've already walked through all the primitives needed for refetching and mutation, but the interface is rather bizarre with all those string-based keys. Often all we actually want is to refetch _current_ key (say, you have this refresh button in the UI), ot mutate _current_ key, right?
For these cases we have 3 additional things on fetcher stores:
1. `fetcherStore.invalidate`. It's a function that invalidates current key for the fetcher. Doesn't accept any arguments.
2. `fetcherStore.mutate`. It's a function that mutates current key for the fetcher. Accepts the new value.
3. `fetcherStore.key`. Well, it holds current key in serialized form (as a string).
Typically, those 3 are more than enough to make all look very good.
### Dependencies, but not in keys
Let's say, you have a dependency for your fetcher, but you don't wish for it to be in your fetcher keys. For example, this could be your `refreshToken`—that would be a hassle to put it _everywhere_, but you need it, because once you change your user, you don't want to have stale cache from the previous user.
The idea here is to wipe the cache manually. For something as big as a new refresh token you can go and do a simple "wipe everything you find":
```ts
onSet($refreshToken, () => invalidateKeys(() => true))
```
But if your store is somehow dependant on other store, but it shouldn't be reflected in the key, you should do the same, but more targetly:
```ts
onSet($someOutsideFactor, $specificStore.invalidate)
```

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc