Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
580 changes: 12 additions & 568 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion packages/borsh/jest.config.js

This file was deleted.

1 change: 1 addition & 0 deletions packages/borsh/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../config/jest.config.js')
1 change: 0 additions & 1 deletion packages/borsh/tsconfig.cjs.json

This file was deleted.

11 changes: 11 additions & 0 deletions packages/borsh/tsconfig.cjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../config/tsconfig.cjs.json",
"compilerOptions": {
"outDir": "./lib/cjs",
"declaration": true,
"esModuleInterop": true,
"module": "commonjs"
},
"include": ["src/**/*"]
}
1 change: 0 additions & 1 deletion packages/borsh/tsconfig.esm.json

This file was deleted.

9 changes: 9 additions & 0 deletions packages/borsh/tsconfig.esm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../config/tsconfig.esm.json",
"compilerOptions": {
"outDir": "./lib/esm",
"esModuleInterop": true
},
"include": ["src/**/*"]
}
6 changes: 5 additions & 1 deletion packages/borsh/tsconfig.json
6 changes: 5 additions & 1 deletion packages/borsh/tsconfig.test.json
1 change: 0 additions & 1 deletion packages/borsh/tsconfig.types.json

This file was deleted.

11 changes: 11 additions & 0 deletions packages/borsh/tsconfig.types.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../config/tsconfig.types.json",
"compilerOptions": {
"declarationDir": "./lib/types",
"emitDeclarationOnly": true,
"declaration": true,
"declarationMap": true
},
"include": ["src/**/*"]
}
2 changes: 2 additions & 0 deletions packages/config/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ module.exports = {
'ts-jest',
{
tsconfig: './tsconfig.test.json',
diagnostics: false,
isolatedModules: true,
},
],
},
Expand Down
1 change: 0 additions & 1 deletion packages/sdk-core/jest.config.js

This file was deleted.

1 change: 1 addition & 0 deletions packages/sdk-core/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('../config/jest.config.js')
1 change: 0 additions & 1 deletion packages/sdk-core/tsconfig.cjs.json

This file was deleted.

11 changes: 11 additions & 0 deletions packages/sdk-core/tsconfig.cjs.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../config/tsconfig.cjs.json",
"compilerOptions": {
"outDir": "./lib/cjs",
"declaration": true,
"esModuleInterop": true,
"module": "commonjs"
},
"include": ["src/**/*"]
}
1 change: 0 additions & 1 deletion packages/sdk-core/tsconfig.esm.json

This file was deleted.

9 changes: 9 additions & 0 deletions packages/sdk-core/tsconfig.esm.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../config/tsconfig.esm.json",
"compilerOptions": {
"outDir": "./lib/esm",
"esModuleInterop": true
},
"include": ["src/**/*"]
}
6 changes: 5 additions & 1 deletion packages/sdk-core/tsconfig.json
6 changes: 5 additions & 1 deletion packages/sdk-core/tsconfig.test.json
1 change: 0 additions & 1 deletion packages/sdk-core/tsconfig.types.json

This file was deleted.

11 changes: 11 additions & 0 deletions packages/sdk-core/tsconfig.types.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": "../config/tsconfig.types.json",
"compilerOptions": {
"declarationDir": "./lib/types",
"emitDeclarationOnly": true,
"declaration": true,
"declarationMap": true
},
"include": ["src/**/*"]
}
2 changes: 1 addition & 1 deletion packages/sdk-facade/jest.config.js
5 changes: 5 additions & 0 deletions packages/sdk-facade/src/facade-transport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
} from '@race-foundation/sdk-core'
import { deserialize } from '@race-foundation/borsh'
import { FacadeWallet } from './facade-wallet'
import { FacadeGuestAuthClient } from './guest-client'

interface JoinInstruction {
playerAddr: string
Expand Down Expand Up @@ -136,6 +137,10 @@ export class FacadeTransport implements ITransport<FacadeWallet> {
this.#url = url
}

createGuestAuthClient(): FacadeGuestAuthClient {
return new FacadeGuestAuthClient(this.#url)
}

get chain(): string {
return 'facade'
}
Expand Down
114 changes: 114 additions & 0 deletions packages/sdk-facade/src/guest-client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { makeid } from './utils'

export interface FacadeGuestRegisterRequest {
nick: string
}

export interface FacadeGuestSessionRequest {
sessionToken: string
}

export interface FacadeGuestAccountSummary {
guestId: string
playerAddr: string
nick: string
status: string
}

export interface FacadeGuestProfile {
addr: string
nick: string
pfp?: string
credentials: number[]
}

export type FacadeGuestBalanceSummary = Record<string, number>

export interface FacadeGuestIdentityResponse {
guest: FacadeGuestAccountSummary
profile: FacadeGuestProfile
balances: FacadeGuestBalanceSummary
sessionExpiresAt: number
}

export interface FacadeGuestRegisterResponse {
guest: FacadeGuestAccountSummary
profile: FacadeGuestProfile
balances: FacadeGuestBalanceSummary
sessionToken: string
expiresAt: number
}

export interface FacadeGuestLogoutResponse {
ok: boolean
}

interface JsonRpcSuccess<T> {
jsonrpc: string
id: string | number
result: T
}

interface JsonRpcFailure {
jsonrpc: string
id: string | number | null
error: {
code: number
message: string
data?: unknown
}
}

type JsonRpcResponse<T> = JsonRpcSuccess<T> | JsonRpcFailure

export class FacadeGuestAuthClient {
#url: string

constructor(url: string = 'http://localhost:12002') {
this.#url = url
}

async guestRegister(params: FacadeGuestRegisterRequest): Promise<FacadeGuestRegisterResponse> {
return this.request('guest_register', [params])
}

async guestResumeSession(params: FacadeGuestSessionRequest): Promise<FacadeGuestIdentityResponse> {
return this.request('guest_resume_session', [params])
}

async guestGetMe(params: FacadeGuestSessionRequest): Promise<FacadeGuestIdentityResponse> {
return this.request('guest_get_me', [params])
}

async guestLogout(params: FacadeGuestSessionRequest): Promise<FacadeGuestLogoutResponse> {
return this.request('guest_logout', [params])
}

private async request<T>(method: string, params: unknown[]): Promise<T> {
const reqData = JSON.stringify({
jsonrpc: '2.0',
method,
id: makeid(16),
params,
})

const resp = await fetch(this.#url, {
method: 'POST',
body: reqData,
headers: {
'Content-Type': 'application/json',
},
})

if (!resp.ok) {
throw new Error(`Facade guest RPC ${method} failed with HTTP ${resp.status}`)
}

const payload: JsonRpcResponse<T> = await resp.json()
if ('error' in payload) {
throw new Error(`Facade guest RPC ${method} failed: ${payload.error.message}`)
}

return payload.result
}
}
1 change: 1 addition & 0 deletions packages/sdk-facade/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './facade-transport'
export * from './facade-wallet'
export * from './guest-client'
115 changes: 115 additions & 0 deletions packages/sdk-facade/tests/guest-client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { assert } from 'chai'
import {
FacadeGuestAuthClient,
FacadeGuestIdentityResponse,
FacadeGuestLogoutResponse,
FacadeGuestRegisterResponse,
} from '../src/guest-client'

describe('FacadeGuestAuthClient', () => {
const originalFetch = (global as any).fetch

afterEach(() => {
;(global as any).fetch = originalFetch
})

it('wraps guest register -> resume -> get me -> logout', async () => {
const registerResponse: FacadeGuestRegisterResponse = {
guest: {
guestId: 'guest_1',
playerAddr: 'guest_player_1',
nick: 'SmokeGuest',
status: 'active',
},
profile: {
addr: 'guest_player_1',
nick: 'SmokeGuest',
pfp: undefined,
credentials: [1, 2, 3],
},
balances: {
FACADE_GUEST_CHIPS: 1000000,
},
sessionToken: 'session-token-1',
expiresAt: 1770000000000,
}

const identityResponse: FacadeGuestIdentityResponse = {
guest: registerResponse.guest,
profile: registerResponse.profile,
balances: registerResponse.balances,
sessionExpiresAt: registerResponse.expiresAt,
}

const logoutResponse: FacadeGuestLogoutResponse = { ok: true }

const fetchMock = ((global as any).fetch = async (_input: unknown, init?: { body?: unknown }) => {
const body = JSON.parse(String(init?.body))
const method = body.method

if (method === 'guest_register') {
assert.deepEqual(body.params, [{ nick: 'SmokeGuest' }])
return {
ok: true,
json: async () => ({ jsonrpc: '2.0', id: body.id, result: registerResponse }),
} as any
}

if (method === 'guest_resume_session' || method === 'guest_get_me') {
assert.deepEqual(body.params, [{ sessionToken: 'session-token-1' }])
return {
ok: true,
json: async () => ({ jsonrpc: '2.0', id: body.id, result: identityResponse }),
} as any
}

if (method === 'guest_logout') {
assert.deepEqual(body.params, [{ sessionToken: 'session-token-1' }])
return {
ok: true,
json: async () => ({ jsonrpc: '2.0', id: body.id, result: logoutResponse }),
} as any
}

throw new Error(`Unexpected RPC method: ${method}`)
}) as any

const client = new FacadeGuestAuthClient('http://localhost:12002')

const registered = await client.guestRegister({ nick: 'SmokeGuest' })
const resumed = await client.guestResumeSession({ sessionToken: registered.sessionToken })
const me = await client.guestGetMe({ sessionToken: registered.sessionToken })
const loggedOut = await client.guestLogout({ sessionToken: registered.sessionToken })

assert.equal(typeof fetchMock, 'function')
assert.equal(registered.guest.guestId, 'guest_1')
assert.equal(resumed.guest.playerAddr, 'guest_player_1')
assert.equal(me.balances.FACADE_GUEST_CHIPS, 1000000)
assert.equal(loggedOut.ok, true)
})

it('throws the facade rpc message on guest error', async () => {
;(global as any).fetch = (async () => {
return {
ok: true,
json: async () => ({
jsonrpc: '2.0',
id: '1',
error: {
code: 1,
message: 'session-revoked',
},
}),
} as any
}) as any

const client = new FacadeGuestAuthClient('http://localhost:12002')

try {
await client.guestResumeSession({ sessionToken: 'bad-token' })
assert.fail('Expected guestResumeSession to throw')
} catch (error) {
assert.include(String(error), 'session-revoked')
}
})
})
Loading
Loading