Skip to content

Commit

Permalink
Format
Browse files Browse the repository at this point in the history
  • Loading branch information
atk authored and github-actions[bot] committed Oct 20, 2023
1 parent 41204c8 commit 392b301
Show file tree
Hide file tree
Showing 3 changed files with 100 additions and 85 deletions.
4 changes: 2 additions & 2 deletions packages/storage/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Instead of wrapping the resource itself, it is far simpler to use the `storage`
persisted signal or [deep signal](../resource/#createdeepsignal):

```ts
const [resource] = createResource(fetcher, {storage: makePersisted(createSignal())});
const [resource] = createResource(fetcher, { storage: makePersisted(createSignal()) });
```

If you are using an asynchronous storage to persist the state of a resource, it might receive an update due to being
Expand Down Expand Up @@ -246,7 +246,7 @@ cookieStorage._cookies = [CookieAbstraction, 'cookie'];
access to the storage API:

```ts
const [value, setValue] = createStorageSignal("value", {api: cookieStorage});
const [value, setValue] = createStorageSignal("value", { api: cookieStorage });

setValue("value");
value(); // 'value'
Expand Down
116 changes: 68 additions & 48 deletions packages/storage/src/cookies.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {isServer} from "solid-js/web";
import {StorageProps, StorageSignalProps, StorageWithOptions} from "./types.js";
import {addClearMethod} from "./tools.js";
import {createStorage, createStorageSignal} from "./storage.js";
import type {PageEvent} from "solid-start";
import { isServer } from "solid-js/web";
import { StorageProps, StorageSignalProps, StorageWithOptions } from "./types.js";
import { addClearMethod } from "./tools.js";
import { createStorage, createStorageSignal } from "./storage.js";
import type { PageEvent } from "solid-start";

export type CookieOptions = CookieProperties & {
getRequest?: (() => Request) | (() => PageEvent);
Expand All @@ -17,27 +17,33 @@ type CookieProperties = {
httpOnly?: boolean;
maxAge?: number;
sameSite?: "None" | "Lax" | "Strict";
}

const cookiePropertyKeys = ["domain", "expires", "path", "secure", "httpOnly", "maxAge", "sameSite"] as const;
};

const cookiePropertyKeys = [
"domain",
"expires",
"path",
"secure",
"httpOnly",
"maxAge",
"sameSite",
] as const;

function serializeCookieOptions(options?: CookieOptions) {
if (!options) {
return "";
}
let memo = "";
for (const key in options) {
if (!cookiePropertyKeys.includes(key as keyof CookieProperties))
continue;
if (!cookiePropertyKeys.includes(key as keyof CookieProperties)) continue;

const value = options[key as keyof CookieProperties];
memo +=
value instanceof Date
? `; ${key}=${value.toUTCString()}`
: typeof value === "boolean"
? `; ${key}`
: `; ${key}=${value}`;
? `; ${key}`
: `; ${key}=${value}`;
}
return memo;
}
Expand All @@ -52,9 +58,11 @@ try {
} catch (e) {
useRequest = () => {
// eslint-disable-next-line no-console
console.warn("It seems you attempt to use cookieStorage on the server without having solid-start installed or use vite.");
console.warn(
"It seems you attempt to use cookieStorage on the server without having solid-start installed or use vite.",
);
return {
request: {headers: {get: () => ""}} as unknown as Request,
request: { headers: { get: () => "" } } as unknown as Request,
} as unknown as PageEvent;
};
}
Expand All @@ -81,35 +89,45 @@ try {
export const cookieStorage: StorageWithOptions<CookieOptions> = addClearMethod({
_read: isServer
? (options?: CookieOptions) => {
const eventOrRequest = options?.getRequest?.() || useRequest();
const request = eventOrRequest && ("request" in eventOrRequest ? eventOrRequest.request : eventOrRequest);
let result = ""
if (eventOrRequest.responseHeaders) // Check if we really got a pageEvent
{
const responseHeaders = eventOrRequest.responseHeaders as Headers;
result += responseHeaders.get("Set-Cookie")?.split(",").map(cookie => !cookie.match(/\\w*\\s*=\\s*[^;]+/)).join(";") ?? "";
const eventOrRequest = options?.getRequest?.() || useRequest();
const request =
eventOrRequest && ("request" in eventOrRequest ? eventOrRequest.request : eventOrRequest);
let result = "";
if (eventOrRequest.responseHeaders) {
// Check if we really got a pageEvent
const responseHeaders = eventOrRequest.responseHeaders as Headers;
result +=
responseHeaders
.get("Set-Cookie")
?.split(",")
.map(cookie => !cookie.match(/\\w*\\s*=\\s*[^;]+/))
.join(";") ?? "";
}
return `${result};${request?.headers?.get("Cookie") ?? ""}`; // because first cookie will be preferred we don't have to worry about duplicates
}
return `${result};${request?.headers?.get("Cookie") ?? ""}`; // because first cookie will be preferred we don't have to worry about duplicates
}
: () => document.cookie,
_write: isServer
? (key: string, value: string, options?: CookieOptions) => {
if (options?.setCookie) {
options?.setCookie?.(key, value, options)
return
if (options?.setCookie) {
options?.setCookie?.(key, value, options);
return;
}
const pageEvent: PageEvent = options?.getRequest?.() || useRequest();
if (!pageEvent.responseHeaders)
// Check if we really got a pageEvent
return;
const responseHeaders = pageEvent.responseHeaders as Headers;
const cookies =
responseHeaders
.get("Set-Cookie")
?.split(",")
.filter(cookie => !cookie.match(`\\s*${key}\\s*=`)) ?? [];
cookies.push(`${key}=${value}${serializeCookieOptions(options)}`);
responseHeaders.set("Set-Cookie", cookies.join(","));
}
const pageEvent: PageEvent = options?.getRequest?.() || useRequest();
if (!pageEvent.responseHeaders) // Check if we really got a pageEvent
return
const responseHeaders = pageEvent.responseHeaders as Headers;
const cookies = responseHeaders.get("Set-Cookie")?.split(",")
.filter((cookie) => !cookie.match(`\\s*${key}\\s*=`)) ?? [];
cookies.push(`${key}=${value}${serializeCookieOptions(options)}`)
responseHeaders.set("Set-Cookie", cookies.join(","))
}
: (key: string, value: string, options?: CookieOptions) => {
document.cookie = `${key}=${value}${serializeCookieOptions(options)}`;
},
document.cookie = `${key}=${value}${serializeCookieOptions(options)}`;
},
getItem: (key: string, options?: CookieOptions) =>
deserializeCookieOptions(cookieStorage._read(options), key),
setItem: (key: string, value: string, options?: CookieOptions) => {
Expand All @@ -128,17 +146,19 @@ export const cookieStorage: StorageWithOptions<CookieOptions> = addClearMethod({
}
},
removeItem: (key: string, options?: CookieOptions) => {
cookieStorage._write(key, "deleted", {...options, expires: new Date(0)});
cookieStorage._write(key, "deleted", { ...options, expires: new Date(0) });
},
key: (index: number, options?: CookieOptions) => {
let key: string | null = null;
let count = 0;
cookieStorage._read(options).replace(/(?:^|;)\s*(.+?)\s*=\s*[^;]+/g, (_: string, found: string) => {
if (!key && found && count++ === index) {
key = found;
}
return "";
});
cookieStorage
._read(options)
.replace(/(?:^|;)\s*(.+?)\s*=\s*[^;]+/g, (_: string, found: string) => {
if (!key && found && count++ === index) {
key = found;
}
return "";
});
return key;
},
getLength: (options?: CookieOptions) => {
Expand All @@ -150,8 +170,8 @@ export const cookieStorage: StorageWithOptions<CookieOptions> = addClearMethod({
return length;
},
get length() {
return this.getLength()
}
return this.getLength();
},
});

/**
Expand All @@ -160,7 +180,7 @@ export const cookieStorage: StorageWithOptions<CookieOptions> = addClearMethod({
*/
export const createCookieStorage = <T, O = CookieOptions, A = StorageWithOptions<CookieOptions>>(
props?: Omit<StorageProps<T, A, O>, "api">,
) => createStorage<O, T>({...props, api: cookieStorage} as any);
) => createStorage<O, T>({ ...props, api: cookieStorage } as any);

/**
* creates a reactive signal, but bound to document.cookie
Expand All @@ -174,4 +194,4 @@ export const createCookieStorageSignal = <
key: string,
initialValue?: T,
props?: Omit<StorageSignalProps<T, A, O>, "api">,
) => createStorageSignal<T, O>(key, initialValue, {...props, api: cookieStorage} as any);
) => createStorageSignal<T, O>(key, initialValue, { ...props, api: cookieStorage } as any);
65 changes: 30 additions & 35 deletions packages/storage/src/persisted.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,23 @@
import type {Accessor, Setter, Signal} from "solid-js";
import {createUniqueId, untrack} from "solid-js";
import type {SetStoreFunction, Store} from "solid-js/store";
import {reconcile} from "solid-js/store";
import type {AsyncStorage, AsyncStorageWithOptions, StorageWithOptions} from "./types.js";
import type { Accessor, Setter, Signal } from "solid-js";
import { createUniqueId, untrack } from "solid-js";
import type { SetStoreFunction, Store } from "solid-js/store";
import { reconcile } from "solid-js/store";
import type { AsyncStorage, AsyncStorageWithOptions, StorageWithOptions } from "./types.js";

export type PersistenceBaseOptions<T> = {
name?: string;
serialize?: (data: T) => string;
deserialize?: (data: string) => T;
}
};

export type PersistenceOptions<T, O extends Record<string, any>> =
PersistenceBaseOptions<T> & (
{
storage: StorageWithOptions<O> | AsyncStorageWithOptions<O>;
storageOptions: O;
} |
{ storage?: Storage | AsyncStorage; })
export type PersistenceOptions<T, O extends Record<string, any>> = PersistenceBaseOptions<T> &
(
| {
storage: StorageWithOptions<O> | AsyncStorageWithOptions<O>;
storageOptions: O;
}
| { storage?: Storage | AsyncStorage }
);

/**
* Persists a signal, store or similar API
Expand All @@ -40,10 +41,9 @@ export type PersistenceOptions<T, O extends Record<string, any>> =
*/
export function makePersisted<T>(
signal: [Accessor<T>, Setter<T>],
options?: PersistenceOptions<T,{}>,
options?: PersistenceOptions<T, {}>,
): [Accessor<T>, Setter<T>];


/**
* Persists a signal, store or similar API
* ```ts
Expand Down Expand Up @@ -91,7 +91,7 @@ export function makePersisted<T, O extends Record<string, any>>(
*/
export function makePersisted<T>(
signal: [get: Store<T>, set: SetStoreFunction<T>],
options?: PersistenceOptions<T,{}>,
options?: PersistenceOptions<T, {}>,
): [get: Store<T>, set: SetStoreFunction<T>];

/**
Expand Down Expand Up @@ -119,7 +119,6 @@ export function makePersisted<T, O extends Record<string, any>>(
options: PersistenceOptions<T, O>,
): [get: Store<T>, set: SetStoreFunction<T>];


/**
* Persists a signal, store or similar API
* ```ts
Expand Down Expand Up @@ -160,30 +159,26 @@ export function makePersisted<T, O extends Record<string, any> = {}>(
: (data: string) => (signal[1] as any)(reconcile(deserialize(data)));
let unchanged = true;

if (init instanceof Promise)
init.then(data => unchanged && data && set(data));
else if (init)
set(init);
if (init instanceof Promise) init.then(data => unchanged && data && set(data));
else if (init) set(init);

return [
signal[0],
typeof signal[0] === "function"
? (value?: T | ((prev: T) => T)) => {
const output = (signal[1] as Setter<T>)(value as any);
const output = (signal[1] as Setter<T>)(value as any);

if (value)
storage.setItem(name, serialize(output), storageOptions);
else
storage.removeItem(name, storageOptions);
unchanged = false;
return output;
}
if (value) storage.setItem(name, serialize(output), storageOptions);
else storage.removeItem(name, storageOptions);
unchanged = false;
return output;
}
: (...args: any[]) => {
(signal[1] as any)(...args);
const value = serialize(untrack(() => signal[0] as any));
// @ts-ignore
storage.setItem(name, value, storageOptions);
unchanged = false;
},
(signal[1] as any)(...args);
const value = serialize(untrack(() => signal[0] as any));
// @ts-ignore
storage.setItem(name, value, storageOptions);
unchanged = false;
},
] as typeof signal;
}

0 comments on commit 392b301

Please sign in to comment.