Skip to content

Commit

Permalink
updated docs
Browse files Browse the repository at this point in the history
  • Loading branch information
christianmat committed Jan 8, 2024
1 parent b74edc1 commit 423d83d
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 23 deletions.
2 changes: 1 addition & 1 deletion packages/js-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,4 +107,4 @@ localStorage is a browser API that allows you to store data in the browser. The

#### Can't anyone just guess a user ID and access someone else's data?

Yes, but that's why you should use a non-iterable UUID for your user IDs. This makes it impossible for users to guess other user IDs and access their data unless they know the user ID.
Yes. For this reason, we recommend using a non-iterable UUID for your user IDs. This makes it nearly impossible for users to guess other user IDs and access their data unless they know the user ID.
50 changes: 42 additions & 8 deletions packages/js-client/src/core/remote-storage.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,48 @@
import fetch from 'cross-fetch'
import { uuid } from './utils'
import { isWeb, uuid } from './utils'
import { HEADER_REMOTE_STORAGE_INSTANCE_ID, HEADER_REMOTE_STORAGE_USER_ID } from './constants'

const apiPrefix = `/entities/`

interface RemoteStorageProps {
serverAddress: string
instanceId?: string
userId?: string
instanceId?: string
}

export class RemoteStorage {
private readonly serverAddress: string
private readonly instanceId: string
private readonly userId: string

constructor({ serverAddress, instanceId, userId }: RemoteStorageProps) {
constructor({ serverAddress, userId, instanceId }: RemoteStorageProps) {
this.serverAddress = serverAddress
this.instanceId = instanceId ?? uuid()
this.userId = userId ?? uuid()
this.instanceId = instanceId ?? 'default'
this.userId = userId ?? this.getUserId()
}

async getItem<T>(key: string): Promise<T> {
const response = await this.call('GET', `${apiPrefix}${key}`, null)
return await response.json()
// Check for 404 and return null if so
if (response.status === 404) {
return null
}
const data = await response.text()
// Check if valid JSON
if (!data.startsWith('{')) {
if (data === 'true') {
return true as unknown as T
}
if (data === 'false') {
return false as unknown as T
}
if (!isNaN(Number(data))) {
return Number(data) as unknown as T
}

return data as T
}
return JSON.parse(data) as T
}

async setItem<T>(key: string, value: T): Promise<void> {
Expand All @@ -38,10 +58,24 @@ export class RemoteStorage {
method: method,
headers: {
'Content-Type': 'application/json',
HEADER_REMOTE_STORAGE_INSTANCE_ID: this.instanceId,
HEADER_REMOTE_STORAGE_USER_ID: this.userId,
[HEADER_REMOTE_STORAGE_INSTANCE_ID]: this.instanceId,
[HEADER_REMOTE_STORAGE_USER_ID]: this.userId,
},
body: data ? JSON.stringify(data) : undefined,
})
}

private getUserId(): string | null {
const key = `rs-user-id`
if (isWeb()) {
if (window.localStorage.getItem(key)) {
return window.localStorage.getItem(key)
}
}
const userId = uuid()
if (isWeb()) {
window.localStorage.setItem(key, userId)
}
return userId
}
}
4 changes: 4 additions & 0 deletions packages/js-client/src/core/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ export function uuid() {
return (c == 'x' ? r : (r & 0x7) | 0x8).toString(16)
})
}

export function isWeb() {
return typeof window !== 'undefined'
}
66 changes: 52 additions & 14 deletions packages/js-client/test/remote-storage.test.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,37 @@
import { RemoteStorage } from '../src'
import { uuid } from '../src/core/utils'

describe('global storage', () => {
// it('should be able to set and get an item', async () => {
// const remoteStorage = new RemoteStorage('http://localhost:3000', 'instanceId', 'userId')
// await remoteStorage.setItem('key', 'value')
// const value = await remoteStorage.getItem('key')
// expect(value).toEqual('value')
// })
//
// it('should be able to set and remove an item', async () => {
// const remoteStorage = new RemoteStorage('http://localhost:3000', 'instanceId', 'userId')
// await remoteStorage.setItem('key', 'value')
// await remoteStorage.removeItem('key')
// const value = await remoteStorage.getItem('key')
// expect(value).toEqual(null)
// })
function getConfig() {
return {
serverAddress: 'https://rs.frigade.com',
instanceId: uuid(),
userId: uuid(),
}
}

it('should be able to set and get an item', async () => {
const remoteStorage = new RemoteStorage(getConfig())
await remoteStorage.setItem('key', 'value')
const value = await remoteStorage.getItem('key')
expect(value).toEqual('value')
})

it('should be able to set and remove an item', async () => {
const remoteStorage = new RemoteStorage(getConfig())
await remoteStorage.setItem('key', 'value')
await remoteStorage.removeItem('key')
const value = await remoteStorage.getItem('key')
console.log(value, typeof value)
expect(value).toEqual(null)
})

it('should be able to set and get a boolean', async () => {
const remoteStorage = new RemoteStorage(getConfig())
await remoteStorage.setItem('key', true)
const value = await remoteStorage.getItem<boolean>('key')
expect(value).toEqual(true)
})

it('should throw an error if not initialized', async () => {
const remoteStorage = new RemoteStorage({ serverAddress: '', instanceId: '', userId: '' })
Expand All @@ -24,4 +41,25 @@ describe('global storage', () => {
expect(error.message).toEqual('Invalid base URL: ')
}
})

it('should be able to set and get a number', async () => {
const remoteStorage = new RemoteStorage(getConfig())
await remoteStorage.setItem('key', 123)
const value = await remoteStorage.getItem<number>('key')
expect(value).toEqual(123)
})

it('should be able to set and get a string', async () => {
const remoteStorage = new RemoteStorage(getConfig())
await remoteStorage.setItem('key', 'value')
const value = await remoteStorage.getItem<string>('key')
expect(value).toEqual('value')
})

it('should be able to set and get an object', async () => {
const remoteStorage = new RemoteStorage(getConfig())
await remoteStorage.setItem('key', { foo: 'bar' })
const value = await remoteStorage.getItem<{ foo: string }>('key')
expect(value).toEqual({ foo: 'bar' })
})
})

0 comments on commit 423d83d

Please sign in to comment.