| import { |
| extractTraceContext, |
| parseTraceParent, |
| shouldPropagateToTarget, |
| getDefaultPropagationTargets, |
| type TraceContext, |
| type TracePropagationTarget, |
| } from '@supabase/tracing' |
| import type { TracePropagationOptions } from './types' |
|
|
| type Fetch = typeof fetch |
|
|
| export const resolveFetch = (customFetch?: Fetch): Fetch => { |
| if (customFetch) { |
| return (...args: Parameters<Fetch>) => customFetch(...args) |
| } |
| return (...args: Parameters<Fetch>) => fetch(...args) |
| } |
|
|
| export const resolveHeadersConstructor = () => { |
| return Headers |
| } |
|
|
| |
| |
| |
| |
| |
| |
| const isNewApiKey = (key: string): boolean => |
| key.startsWith('sb_publishable_') || key.startsWith('sb_secret_') |
|
|
| const TEMP_KEY_PREFIX = 'sb_temp_' |
|
|
| const warnedKeySubtypes = new Set<string>() |
|
|
| |
| |
| |
| |
| |
| export const checkApiKeyFormat = (key: string): void => { |
| if (!key.startsWith('sb_') || isNewApiKey(key) || key.startsWith(TEMP_KEY_PREFIX)) { |
| return |
| } |
| const subtype = key.match(/^sb_[a-zA-Z0-9]+_/)?.[0] ?? 'unknown' |
| if (warnedKeySubtypes.has(subtype)) { |
| return |
| } |
| warnedKeySubtypes.add(subtype) |
| console.warn( |
| '@supabase/supabase-js: Unrecognized Supabase API key format. The client will proceed ' + |
| 'and send this key as-is; if you see authentication errors you may need to upgrade ' + |
| '@supabase/supabase-js to a version that recognizes this key type.' |
| ) |
| } |
|
|
| export const fetchWithAuth = ( |
| supabaseKey: string, |
| supabaseUrl: string, |
| getAccessToken: () => Promise<string | null>, |
| customFetch?: Fetch, |
| tracePropagationOptions?: TracePropagationOptions, |
| options?: { omitApiKeyAsBearer?: boolean } |
| ): Fetch => { |
| const fetch = resolveFetch(customFetch) |
| const HeadersConstructor = resolveHeadersConstructor() |
|
|
| |
| |
| const traceEnabled = tracePropagationOptions?.enabled === true |
| const respectSampling = tracePropagationOptions?.respectSamplingDecision !== false |
| const traceTargets: TracePropagationTarget[] | null = traceEnabled |
| ? getDefaultPropagationTargets(supabaseUrl) |
| : null |
|
|
| |
| |
| |
| const allowKeyAsBearer = !(options?.omitApiKeyAsBearer && isNewApiKey(supabaseKey)) |
|
|
| return async (input, init) => { |
| const realToken = await getAccessToken() |
| let headers = new HeadersConstructor(init?.headers) |
|
|
| if (!headers.has('apikey')) { |
| headers.set('apikey', supabaseKey) |
| } |
|
|
| if (!headers.has('Authorization')) { |
| const bearer = realToken ?? (allowKeyAsBearer ? supabaseKey : null) |
| if (bearer) { |
| headers.set('Authorization', `Bearer ${bearer}`) |
| } |
| } |
|
|
| if (traceTargets) { |
| const traceHeaders = await getTraceHeaders(input, traceTargets, respectSampling) |
|
|
| if (traceHeaders) { |
| if (traceHeaders.traceparent && !headers.has('traceparent')) { |
| headers.set('traceparent', traceHeaders.traceparent) |
| } |
| if (traceHeaders.tracestate && !headers.has('tracestate')) { |
| headers.set('tracestate', traceHeaders.tracestate) |
| } |
| if (traceHeaders.baggage && !headers.has('baggage')) { |
| headers.set('baggage', traceHeaders.baggage) |
| } |
| } |
| } |
|
|
| return fetch(input, { ...init, headers }) |
| } |
| } |
|
|
| async function getTraceHeaders( |
| input: RequestInfo | URL, |
| targets: TracePropagationTarget[], |
| respectSampling: boolean |
| ): Promise<TraceContext | null> { |
| const targetUrl: string | URL = |
| typeof input === 'string' ? input : input instanceof URL ? input : input.url |
|
|
| if (!shouldPropagateToTarget(targetUrl, targets)) { |
| return null |
| } |
|
|
| const traceContext = await extractTraceContext() |
|
|
| if (!traceContext || !traceContext.traceparent) { |
| return null |
| } |
|
|
| if (respectSampling) { |
| const parsed = parseTraceParent(traceContext.traceparent) |
| if (parsed && !parsed.isSampled) { |
| return null |
| } |
| } |
|
|
| return traceContext |
| } |
|
|