mirror of
https://github.com/vercel/commerce.git
synced 2025-07-25 11:11:24 +00:00
Making progress on api operations
This commit is contained in:
@@ -1,13 +1,19 @@
|
||||
import type { NextApiHandler } from 'next'
|
||||
import type { RequestInit } from '@vercel/fetch'
|
||||
import {
|
||||
CommerceAPI as CoreCommerceAPI,
|
||||
CommerceAPIConfig,
|
||||
} from '@commerce/api'
|
||||
import { CommerceAPI, CommerceAPIConfig } from '@commerce/api'
|
||||
import fetchGraphqlApi from './utils/fetch-graphql-api'
|
||||
import fetchStoreApi from './utils/fetch-store-api'
|
||||
|
||||
import type { CartAPI } from './cart'
|
||||
import login from './operations/login'
|
||||
import {
|
||||
Operations,
|
||||
defaultOperations,
|
||||
AllowedOperations,
|
||||
OPERATIONS,
|
||||
getOperations,
|
||||
APIOperations,
|
||||
} from '@commerce/api/operations'
|
||||
|
||||
export interface BigcommerceConfig extends CommerceAPIConfig {
|
||||
// Indicates if the returned metadata with translations should be applied to the
|
||||
@@ -103,25 +109,29 @@ const config2: BigcommerceConfig = {
|
||||
|
||||
export const provider = {
|
||||
config: config2,
|
||||
operations: { login },
|
||||
}
|
||||
|
||||
export type Provider = typeof provider
|
||||
|
||||
export type APIs = CartAPI
|
||||
|
||||
export class CommerceAPI extends CoreCommerceAPI<Provider> {
|
||||
constructor(customProvider: Provider = provider) {
|
||||
super(customProvider)
|
||||
}
|
||||
export function getCommerceApi<P extends Provider>(
|
||||
customProvider: P = provider as any
|
||||
) {
|
||||
const commerce = new CommerceAPI(customProvider)
|
||||
const operations = getOperations(customProvider.operations, { commerce })
|
||||
|
||||
endpoint<E extends APIs>(
|
||||
context: E['endpoint'] & {
|
||||
config?: Provider['config']
|
||||
options?: E['schema']['endpoint']['options']
|
||||
}
|
||||
): NextApiHandler {
|
||||
return super.endpoint(context)
|
||||
}
|
||||
return Object.assign(commerce, operations, {
|
||||
endpoint<E extends APIs>(
|
||||
context: E['endpoint'] & {
|
||||
config?: P['config']
|
||||
options?: E['schema']['endpoint']['options']
|
||||
}
|
||||
): NextApiHandler {
|
||||
return super.endpoint(context)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
export function getConfig(userConfig?: Partial<BigcommerceConfig>) {
|
||||
|
78
framework/bigcommerce/api/operations/login.ts
Normal file
78
framework/bigcommerce/api/operations/login.ts
Normal file
@@ -0,0 +1,78 @@
|
||||
import type { ServerResponse } from 'http'
|
||||
import type { OperationContext } from '@commerce/api/operations'
|
||||
import type { LoginMutation, LoginMutationVariables } from '../../schema'
|
||||
import type { RecursivePartial } from '../utils/types'
|
||||
import concatHeader from '../utils/concat-cookie'
|
||||
import type { BigcommerceConfig, Provider } from '..'
|
||||
|
||||
export const loginMutation = /* GraphQL */ `
|
||||
mutation login($email: String!, $password: String!) {
|
||||
login(email: $email, password: $password) {
|
||||
result
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export type LoginResult<T extends { result?: any } = { result?: string }> = T
|
||||
|
||||
export type LoginVariables = LoginMutationVariables
|
||||
|
||||
function loginOperation({ commerce }: OperationContext<Provider>) {
|
||||
async function login(opts: {
|
||||
variables: LoginVariables
|
||||
config?: BigcommerceConfig
|
||||
res: ServerResponse
|
||||
}): Promise<LoginResult>
|
||||
|
||||
async function login<T extends { result?: any }, V = any>(opts: {
|
||||
query: string
|
||||
variables: V
|
||||
res: ServerResponse
|
||||
config?: BigcommerceConfig
|
||||
}): Promise<LoginResult<T>>
|
||||
|
||||
async function login({
|
||||
query = loginMutation,
|
||||
variables,
|
||||
res: response,
|
||||
config,
|
||||
}: {
|
||||
query?: string
|
||||
variables: LoginVariables
|
||||
res: ServerResponse
|
||||
config?: BigcommerceConfig
|
||||
}): Promise<LoginResult> {
|
||||
config = commerce.getConfig(config)
|
||||
|
||||
const { data, res } = await config.fetch<RecursivePartial<LoginMutation>>(
|
||||
query,
|
||||
{ variables }
|
||||
)
|
||||
// Bigcommerce returns a Set-Cookie header with the auth cookie
|
||||
let cookie = res.headers.get('Set-Cookie')
|
||||
|
||||
if (cookie && typeof cookie === 'string') {
|
||||
// In development, don't set a secure cookie or the browser will ignore it
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
cookie = cookie.replace('; Secure', '')
|
||||
// SameSite=none can't be set unless the cookie is Secure
|
||||
// bc seems to sometimes send back SameSite=None rather than none so make
|
||||
// this case insensitive
|
||||
cookie = cookie.replace(/; SameSite=none/gi, '; SameSite=lax')
|
||||
}
|
||||
|
||||
response.setHeader(
|
||||
'Set-Cookie',
|
||||
concatHeader(response.getHeader('Set-Cookie'), cookie)!
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
result: data.login?.result,
|
||||
}
|
||||
}
|
||||
|
||||
return login
|
||||
}
|
||||
|
||||
export default loginOperation
|
@@ -1,73 +0,0 @@
|
||||
import type { ServerResponse } from 'http'
|
||||
import type { LoginMutation, LoginMutationVariables } from '../schema'
|
||||
import type { RecursivePartial } from '../api/utils/types'
|
||||
import concatHeader from '../api/utils/concat-cookie'
|
||||
import { BigcommerceConfig, getConfig } from '../api'
|
||||
|
||||
export const loginMutation = /* GraphQL */ `
|
||||
mutation login($email: String!, $password: String!) {
|
||||
login(email: $email, password: $password) {
|
||||
result
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export type LoginResult<T extends { result?: any } = { result?: string }> = T
|
||||
|
||||
export type LoginVariables = LoginMutationVariables
|
||||
|
||||
async function login(opts: {
|
||||
variables: LoginVariables
|
||||
config?: BigcommerceConfig
|
||||
res: ServerResponse
|
||||
}): Promise<LoginResult>
|
||||
|
||||
async function login<T extends { result?: any }, V = any>(opts: {
|
||||
query: string
|
||||
variables: V
|
||||
res: ServerResponse
|
||||
config?: BigcommerceConfig
|
||||
}): Promise<LoginResult<T>>
|
||||
|
||||
async function login({
|
||||
query = loginMutation,
|
||||
variables,
|
||||
res: response,
|
||||
config,
|
||||
}: {
|
||||
query?: string
|
||||
variables: LoginVariables
|
||||
res: ServerResponse
|
||||
config?: BigcommerceConfig
|
||||
}): Promise<LoginResult> {
|
||||
config = getConfig(config)
|
||||
|
||||
const { data, res } = await config.fetch<RecursivePartial<LoginMutation>>(
|
||||
query,
|
||||
{ variables }
|
||||
)
|
||||
// Bigcommerce returns a Set-Cookie header with the auth cookie
|
||||
let cookie = res.headers.get('Set-Cookie')
|
||||
|
||||
if (cookie && typeof cookie === 'string') {
|
||||
// In development, don't set a secure cookie or the browser will ignore it
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
cookie = cookie.replace('; Secure', '')
|
||||
// SameSite=none can't be set unless the cookie is Secure
|
||||
// bc seems to sometimes send back SameSite=None rather than none so make
|
||||
// this case insensitive
|
||||
cookie = cookie.replace(/; SameSite=none/gi, '; SameSite=lax')
|
||||
}
|
||||
|
||||
response.setHeader(
|
||||
'Set-Cookie',
|
||||
concatHeader(response.getHeader('Set-Cookie'), cookie)!
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
result: data.login?.result,
|
||||
}
|
||||
}
|
||||
|
||||
export default login
|
Reference in New Issue
Block a user