# @byted-supabase/supabase-js

[简体中文](https://unpkg.com/@byted-supabase/supabase-js/README.md)

A Supabase JavaScript runtime wrapper for Web, WeChat, Alipay, and Doubao. Application code keeps the official `@supabase/supabase-js` `createClient(url, key, options)` shape; this package only fills mini-program runtime seams such as request, storage, socket, local file upload, and required Web standard compatibility.

## Installation

```bash
pnpm add @byted-supabase/supabase-js @supabase/supabase-js
# Doubao only:
pnpm add @doubao-dev/framework@^0.6.0
```

`@supabase/supabase-js` is a peer dependency. `@doubao-dev/framework` is an optional peer dependency used only by Doubao consumers, and the current package is validated against `0.6.x`.

## Before Initialization

Prepare these items before creating the client:

- `SUPABASE_URL`
- `SUPABASE_ANON_KEY`
- The target Supabase branch already contains the tables, RLS policies, Auth providers, Storage buckets, and Edge Functions your app expects
- The mini-program host already allows your request, upload, download, and socket domains

This package initializes the client runtime only. It does not create backend resources for you.

## Initialization

For Web, WeChat, and Alipay, use the default entry:

```ts
import { createClient, getRuntimeInfo } from '@byted-supabase/supabase-js'

const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  auth: { detectSessionInUrl: false },
})

const runtimeInfo = getRuntimeInfo(supabase)
```

When `runtime` is omitted, the default entry auto-selects WeChat, Alipay, or Doubao when the expected host markers and capabilities are visible. If no mini-program host is detected, the SDK keeps the official Supabase runtime behavior. New Doubao code should still inject the host API explicitly instead of relying on a legacy/global marker. Do not pass `runtime: 'auto'`.

For Doubao, inject the host API explicitly:

```ts
import * as doubaoApi from '@doubao-dev/framework/api'
import { createClient } from '@byted-supabase/supabase-js/core'
import { doubaoAdapter } from '@byted-supabase/supabase-js/mini/adapters/doubao'

const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  runtime: doubaoAdapter(doubaoApi),
  auth: { detectSessionInUrl: false },
})
```

Entrypoint boundaries:

- Default business entry: `@byted-supabase/supabase-js`
- Use `@byted-supabase/supabase-js/core` when you need explicit adapter injection or a single-host minimal bundle
- `@byted-supabase/supabase-js/mini-client` is for demos, install-smoke, or diagnostics, not the default business client

## Common Usage

Database, RPC, Functions, Storage, and Realtime stay on the official Supabase client surface:

```ts
const { data, error } = await supabase
  .from('todos')
  .select('id,title,status')
  .limit(10)

if (error) throw error
```

Mini-program-only capabilities stay in helpers.

### Platform Login

```ts
import { login } from '@byted-supabase/supabase-js/mini/auth'

const { data, error } = await login(supabase, {
  rawOptions: {
    timeout: 10000,
  },
})

if (error) throw error
```

`login()` first asks the host runtime for a one-time login code, then follows the default Supabase Auth path for the current runtime:

- WeChat: `wx.login` -> `supabase.auth.signInWithIdToken()`
- Alipay: `my.getAuthCode` -> `supabase.auth.signInWithIdToken()`
- Doubao: official `login()` -> `/auth/v1/integrations/doubao/mcp/login` -> `/fetch-token` -> official `supabase.auth.setSession()`

Default path summary:

| Runtime | Host code | SDK default behavior | Supabase destination |
| --- | --- | --- | --- |
| `wechat` | `wx.login` | `supabase.auth.signInWithIdToken()` | matching mini-app provider |
| `alipay` | `my.getAuthCode` | `supabase.auth.signInWithIdToken()` | matching mini-app provider |
| `doubao` | `login()` -> `login_code` | `/auth/v1/integrations/doubao/mcp/login` -> `/fetch-token` -> `auth.setSession()` | Doubao Auth integration |

This is the SDK default path. It does not mean your Auth backend already supports every provider:

- WeChat and Alipay only log in directly when the matching provider is already wired up in your backend.
- Doubao requires `Doubao Intelligent Service` to be enabled and the runtime to resolve the host `appId`.

If the provider is not ready yet, or if you need custom verification, account linking, or session issuance, use `getMiniAppAuthCode()` plus an Edge Function or trusted-backend exchange instead.

### Mini-Program Local File Upload

```ts
import { uploadFile } from '@byted-supabase/supabase-js/mini'

const { data, error } = await uploadFile(supabase, {
  bucket: 'avatars',
  path: `users/${userId}/avatar.png`,
  filePath: pickedFile.filePath,
  contentType: pickedFile.type || 'image/png',
  upsert: true,
})

if (error) throw error
```

Do not pass a mini-program local `filePath` directly into the official `storage.upload()`.

## FAQ

### Does this package initialize Supabase backend resources for me?

No. It only initializes the client and runtime seam. Tables, functions, buckets, RLS, Auth providers, and host whitelists must already exist.

### Do I need to pass `runtime` manually?

Usually no. Web, WeChat, and Alipay normally work by omitting `runtime`; Doubao can also be detected by the default entry when the host marker is visible, but new code should still pass `doubaoAdapter(doubaoApi)` explicitly. If you use `@byted-supabase/supabase-js/core`, pass an adapter object instead of a built-in runtime string.

### Should I use the default entry, `/core`, or `mini-client`?

Start with `@byted-supabase/supabase-js` by default. Switch to `@byted-supabase/supabase-js/core` only when you want explicit adapter injection, a pinned host, or a smaller single-host import surface; `/core` keeps official Web/Node/SSR behavior and does not include built-in runtime-string routing. Use `mini-client` only for demos, install-smoke, or diagnostics.

### Can I keep using the official `supabase-js` API?

Yes. That is the default path. This package keeps the official `SupabaseClient`, Auth, Storage, Functions, and Realtime surface, and adds only host-specific helpers such as `mini/auth` and `uploadFile`.

### Why does platform login fail?

Common reasons are:

- The provider is not enabled in your Supabase Auth backend
- Your backend version does not support that provider yet
- The host login code is expired or invalid
- The Doubao runtime cannot resolve the host `appId`
- The mini-program host blocks the request domain, so the Auth request never reaches the backend

If the provider is not ready yet, or if you intentionally need a custom verification, account-linking, or session-issuance flow, use `getMiniAppAuthCode()` and finish the exchange in your own Edge Function or trusted backend.

### When should I fall back to `getMiniAppAuthCode()` plus a backend exchange?

Fall back directly in these cases:

- The matching WeChat or Alipay provider is not wired up in your Supabase/Auth backend yet
- You need custom verification, account linking, session issuance, or risk-control logic
- The Doubao provider is not ready yet, or the runtime cannot resolve the host `appId`

Recommended steps:

- call `getMiniAppAuthCode()` to get the host code
- exchange it through `supabase.functions.invoke(...)` or a trusted backend
- call the official `supabase.auth.setSession()`

### Why do request, upload, or Realtime fail only inside a mini-program?

Check host platform whitelists and platform limits before assuming an SDK bug. Usually you need to verify these separately:

- request domain
- upload domain
- download domain
- socket domain

Official docs:

- Doubao JS API: `https://developer.doubao.com/docs/js-api/`
- Alipay Mini API: `https://opendocs.alipay.com/mini/api`
- WeChat Mini Program API: `https://developers.weixin.qq.com/miniprogram/dev/api/`

### Why can Alipay pass `request-methods` but still fail on PostgREST `PATCH` or Storage `remove`?

Those checks prove different things. `request-methods` and `functions-methods` only show that the host can send a request and receive an HTTP response. They do not guarantee full Supabase business semantics for every HTTP shape.

In live Alipay mini-program validation we have seen two concrete patterns:

- `PATCH /rest/v1/...` returns `200`, but a follow-up `select` still reads the old value
- `DELETE /storage/v1/object/<bucket>` with a JSON body such as `{ prefixes: [...] }` reaches Storage as an invalid body and returns `body must be object`

If the same Supabase path works in curl, Node, or another host, and the Alipay runtime trace already shows that the SDK passed an object body into the host API, treat this as a host request semantic boundary first, not as missing Supabase initialization or an automatic sign that the SDK is still sending the wrong body.

Recommended approach:

- Do not rely on direct PostgREST `PATCH` for critical writes on Alipay
- Do not rely on Storage `DELETE + JSON body` for batch object removal on Alipay
- Prefer a `POST`-shaped `supabase.rpc(...)` or `supabase.functions.invoke(..., { method: 'POST' })`, and perform the real update/remove on the server

### Can I put `service_role` or platform secrets in the client?

No. Client code should use only anon keys. Platform secrets, `service_role`, signing logic, certificates, and callback verification must stay on a trusted backend.

## Contribution

See [CONTRIBUTING.md](https://unpkg.com/@byted-supabase/supabase-js/CONTRIBUTING.md).

## Code of Conduct

See [CODE_OF_CONDUCT.md](https://unpkg.com/@byted-supabase/supabase-js/CODE_OF_CONDUCT.md).

## Security

If you discover a potential security issue, please contact ByteDance Security through the [security center](https://security.bytedance.com/src) or [vulnerability reporting email](mailto:sec@bytedance.com).

Please do **not** open a public security issue.

## License

[MIT](https://unpkg.com/@byted-supabase/supabase-js/LICENSE)
