@polardbx/pxbaas-client 0.0.0-stage → 0.1.0-beta.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +56 -2
  2. package/dist/drivers/apps.driver.d.ts +128 -0
  3. package/dist/drivers/apps.driver.d.ts.map +1 -0
  4. package/dist/drivers/apps.driver.js +90 -0
  5. package/dist/drivers/apps.driver.js.map +1 -0
  6. package/dist/drivers/auth-admin.driver.d.ts +78 -0
  7. package/dist/drivers/auth-admin.driver.d.ts.map +1 -0
  8. package/dist/drivers/auth-admin.driver.js +145 -0
  9. package/dist/drivers/auth-admin.driver.js.map +1 -0
  10. package/dist/drivers/functions.driver.d.ts +75 -0
  11. package/dist/drivers/functions.driver.d.ts.map +1 -0
  12. package/dist/drivers/functions.driver.js +173 -0
  13. package/dist/drivers/functions.driver.js.map +1 -0
  14. package/dist/drivers/meta.driver.d.ts +80 -0
  15. package/dist/drivers/meta.driver.d.ts.map +1 -0
  16. package/dist/drivers/meta.driver.js +198 -0
  17. package/dist/drivers/meta.driver.js.map +1 -0
  18. package/dist/drivers/share-links.driver.d.ts +42 -0
  19. package/dist/drivers/share-links.driver.d.ts.map +1 -0
  20. package/dist/drivers/share-links.driver.js +55 -0
  21. package/dist/drivers/share-links.driver.js.map +1 -0
  22. package/dist/drivers/storage.driver.d.ts +87 -0
  23. package/dist/drivers/storage.driver.d.ts.map +1 -0
  24. package/dist/drivers/storage.driver.js +182 -0
  25. package/dist/drivers/storage.driver.js.map +1 -0
  26. package/dist/drivers/tenant-admin.driver.d.ts +130 -0
  27. package/dist/drivers/tenant-admin.driver.d.ts.map +1 -0
  28. package/dist/drivers/tenant-admin.driver.js +222 -0
  29. package/dist/drivers/tenant-admin.driver.js.map +1 -0
  30. package/dist/drivers/tenant-ddl.driver.d.ts +106 -0
  31. package/dist/drivers/tenant-ddl.driver.d.ts.map +1 -0
  32. package/dist/drivers/tenant-ddl.driver.js +131 -0
  33. package/dist/drivers/tenant-ddl.driver.js.map +1 -0
  34. package/dist/drivers/zero.driver.d.ts +125 -0
  35. package/dist/drivers/zero.driver.d.ts.map +1 -0
  36. package/dist/drivers/zero.driver.js +165 -0
  37. package/dist/drivers/zero.driver.js.map +1 -0
  38. package/dist/errors.d.ts +37 -0
  39. package/dist/errors.d.ts.map +1 -0
  40. package/dist/errors.js +64 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/index.d.ts +27 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +37 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/types.d.ts +26 -0
  47. package/dist/types.d.ts.map +1 -0
  48. package/dist/types.js +5 -0
  49. package/dist/types.js.map +1 -0
  50. package/package.json +57 -3
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Tenant DDL Driver — 多租户「普通租户」自助 DDL / RLS 注册客户端。
3
+ *
4
+ * 对接 Studio BFF 的租户自助端点(Aone #87795993):
5
+ * - POST /api/tenant-ddl/query 在租户自有库执行 DDL/DML
6
+ * - POST /api/tenant-ddl/rls/tables 开/关表级 RLS
7
+ * - GET /api/tenant-ddl/rls/tables 列出本租户已注册 RLS 的表
8
+ * - DELETE /api/tenant-ddl/rls/tables 移除一张表的 RLS 注册(开关行)
9
+ * - POST /api/tenant-ddl/rls/policies 增/改一条 RLS 策略
10
+ * - GET /api/tenant-ddl/rls/policies 列出本租户策略(可按 table 过滤)
11
+ * - DELETE /api/tenant-ddl/rls/policies 删除一条策略
12
+ *
13
+ * 认证模型(务必遵守,见方案文档「三、认证与信任链」):
14
+ * 只发送 `Authorization: Bearer <per-tenant service_role key>`。**绝不**自行拼
15
+ * `X-Tenant-Id`——Kong 入口会剥离客户端伪造的该头、验签 per-tenant JWT 后注入
16
+ * 可信 X-Tenant-Id,并把下游 Authorization 替换为全局 key。租户身份完全由网关推导。
17
+ *
18
+ * 成功响应统一为 `{ data: ... }`,失败为 `{ code, message }`;本 driver 解包 data、
19
+ * 并把失败规范化为 TenantDdlError(携带 code/message/status)。
20
+ */
21
+ /** RLS 命令行枚举(与服务端 resolver 白名单一致)。 */
22
+ export type RlsCommand = "ALL" | "SELECT" | "INSERT" | "UPDATE" | "DELETE";
23
+ export interface TenantDdlDriverOptions {
24
+ endpoint: string;
25
+ /** per-tenant service_role key(带 tenant_id claim)。不可用全局 key。 */
26
+ serviceRoleKey: string;
27
+ timeout?: number;
28
+ }
29
+ export interface RlsTableInput {
30
+ table_name: string;
31
+ /** 默认 true(启用 RLS)。 */
32
+ rls_enabled?: boolean;
33
+ /** 默认 false。 */
34
+ rls_forced?: boolean;
35
+ }
36
+ export interface RlsPolicyInput {
37
+ table_name: string;
38
+ policy_name: string;
39
+ /** `*` 或 `[a-zA-Z0-9_]`;缺省服务端按 `*` 处理。 */
40
+ role_name?: string;
41
+ command?: RlsCommand | string;
42
+ using_expr?: string | null;
43
+ check_expr?: string | null;
44
+ permissive?: boolean;
45
+ }
46
+ /** GET /rls/tables 的一行(rls_* 以 tinyint 0/1 返回)。 */
47
+ export interface RlsTableRow {
48
+ table_schema: string;
49
+ table_name: string;
50
+ rls_enabled: number | boolean;
51
+ rls_forced: number | boolean;
52
+ }
53
+ /** GET /rls/policies 的一行。 */
54
+ export interface RlsPolicyRow {
55
+ table_schema: string;
56
+ table_name: string;
57
+ policy_name: string;
58
+ role_name: string;
59
+ command: string;
60
+ using_expr: string | null;
61
+ check_expr: string | null;
62
+ permissive: number | boolean;
63
+ }
64
+ /** 租户自助 DDL/RLS 调用的统一错误(携带机器码 + HTTP 状态)。 */
65
+ export declare class TenantDdlError extends Error {
66
+ readonly code: string;
67
+ readonly status?: number;
68
+ constructor(code: string, message: string, status?: number);
69
+ }
70
+ export declare class TenantDdlDriver {
71
+ private readonly client;
72
+ constructor(options: TenantDdlDriverOptions);
73
+ /**
74
+ * Execute a DDL/DML statement on the tenant's OWN database. The tenant MySQL
75
+ * account (GRANT ALL ON own_db.* only) is the hard isolation boundary; the
76
+ * server additionally pre-checks and rejects privilege/instance-level statements.
77
+ * Returns the raw pg-meta rows (`data`), or `[]` for statements with no result set.
78
+ */
79
+ query(sql: string): Promise<unknown[]>;
80
+ /** Enable/force RLS on one of the tenant's tables (central registry, schema server-bound). */
81
+ upsertRlsTable(input: RlsTableInput): Promise<void>;
82
+ /** List the tenant's own RLS-registered tables. */
83
+ listRlsTables(): Promise<RlsTableRow[]>;
84
+ /**
85
+ * Remove a table's RLS registration (the central enable/force toggle row),
86
+ * symmetric to {@link deleteRlsPolicy}. The server binds table_schema to the
87
+ * tenant db and does NOT require the table to still exist, so this is safe to
88
+ * call after a DROP (idempotent cleanup).
89
+ */
90
+ deleteRlsTable(tableName: string): Promise<void>;
91
+ /** Insert/update one RLS policy for the tenant (schema server-bound). */
92
+ upsertRlsPolicy(input: RlsPolicyInput): Promise<void>;
93
+ /** List the tenant's own policies, optionally filtered by table name. */
94
+ listRlsPolicies(tableName?: string): Promise<RlsPolicyRow[]>;
95
+ /** Delete one of the tenant's policies (scoped by table + policy name). */
96
+ deleteRlsPolicy(tableName: string, policyName: string): Promise<void>;
97
+ private request;
98
+ }
99
+ /**
100
+ * Map any failure to a TenantDdlError. Server errors carry `{ code, message }`
101
+ * (e.g. PERMISSION_DENIED / GLOBAL_KEY_NOT_ALLOWED / ROLE_NOT_ALLOWED /
102
+ * TENANT_NOT_ACTIVE / STATEMENT_NOT_ALLOWED); fall back to an HTTP-status code
103
+ * or a network code when the body is absent.
104
+ */
105
+ export declare function normalizeTenantDdlError(error: unknown): TenantDdlError;
106
+ //# sourceMappingURL=tenant-ddl.driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-ddl.driver.d.ts","sourceRoot":"","sources":["../../src/drivers/tenant-ddl.driver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH,sCAAsC;AACtC,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAE3E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,gBAAgB;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9B,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED,6BAA6B;AAC7B,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED,6CAA6C;AAC7C,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;gBAEb,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAM3D;AAQD,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,OAAO,EAAE,sBAAsB;IAW3C;;;;;OAKG;IACG,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IAO5C,8FAA8F;IACxF,cAAc,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAMzD,mDAAmD;IAC7C,aAAa,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAO7C;;;;;OAKG;IACG,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtD,yEAAyE;IACnE,eAAe,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAM3D,yEAAyE;IACnE,eAAe,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IASlE,2EAA2E;IACrE,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAQ7D,OAAO;CAUtB;AAQD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAwBtE"}
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Tenant DDL Driver — 多租户「普通租户」自助 DDL / RLS 注册客户端。
3
+ *
4
+ * 对接 Studio BFF 的租户自助端点(Aone #87795993):
5
+ * - POST /api/tenant-ddl/query 在租户自有库执行 DDL/DML
6
+ * - POST /api/tenant-ddl/rls/tables 开/关表级 RLS
7
+ * - GET /api/tenant-ddl/rls/tables 列出本租户已注册 RLS 的表
8
+ * - DELETE /api/tenant-ddl/rls/tables 移除一张表的 RLS 注册(开关行)
9
+ * - POST /api/tenant-ddl/rls/policies 增/改一条 RLS 策略
10
+ * - GET /api/tenant-ddl/rls/policies 列出本租户策略(可按 table 过滤)
11
+ * - DELETE /api/tenant-ddl/rls/policies 删除一条策略
12
+ *
13
+ * 认证模型(务必遵守,见方案文档「三、认证与信任链」):
14
+ * 只发送 `Authorization: Bearer <per-tenant service_role key>`。**绝不**自行拼
15
+ * `X-Tenant-Id`——Kong 入口会剥离客户端伪造的该头、验签 per-tenant JWT 后注入
16
+ * 可信 X-Tenant-Id,并把下游 Authorization 替换为全局 key。租户身份完全由网关推导。
17
+ *
18
+ * 成功响应统一为 `{ data: ... }`,失败为 `{ code, message }`;本 driver 解包 data、
19
+ * 并把失败规范化为 TenantDdlError(携带 code/message/status)。
20
+ */
21
+ import axios from "axios";
22
+ /** 租户自助 DDL/RLS 调用的统一错误(携带机器码 + HTTP 状态)。 */
23
+ export class TenantDdlError extends Error {
24
+ code;
25
+ status;
26
+ constructor(code, message, status) {
27
+ super(message);
28
+ this.name = "TenantDdlError";
29
+ this.code = code;
30
+ this.status = status;
31
+ }
32
+ }
33
+ export class TenantDdlDriver {
34
+ client;
35
+ constructor(options) {
36
+ const endpoint = options.endpoint.replace(/\/$/, "");
37
+ this.client = axios.create({
38
+ baseURL: `${endpoint}/api/tenant-ddl`,
39
+ timeout: options.timeout ?? 60_000,
40
+ // Only the per-tenant service_role bearer. Never send X-Tenant-Id here —
41
+ // Kong strips any client-supplied value and injects the trusted one.
42
+ headers: { Authorization: `Bearer ${options.serviceRoleKey}` },
43
+ });
44
+ }
45
+ /**
46
+ * Execute a DDL/DML statement on the tenant's OWN database. The tenant MySQL
47
+ * account (GRANT ALL ON own_db.* only) is the hard isolation boundary; the
48
+ * server additionally pre-checks and rejects privilege/instance-level statements.
49
+ * Returns the raw pg-meta rows (`data`), or `[]` for statements with no result set.
50
+ */
51
+ async query(sql) {
52
+ const data = await this.request(() => this.client.post("/query", { sql }));
53
+ return data ?? [];
54
+ }
55
+ /** Enable/force RLS on one of the tenant's tables (central registry, schema server-bound). */
56
+ async upsertRlsTable(input) {
57
+ await this.request(() => this.client.post("/rls/tables", compact(input)));
58
+ }
59
+ /** List the tenant's own RLS-registered tables. */
60
+ async listRlsTables() {
61
+ const data = await this.request(() => this.client.get("/rls/tables"));
62
+ return data ?? [];
63
+ }
64
+ /**
65
+ * Remove a table's RLS registration (the central enable/force toggle row),
66
+ * symmetric to {@link deleteRlsPolicy}. The server binds table_schema to the
67
+ * tenant db and does NOT require the table to still exist, so this is safe to
68
+ * call after a DROP (idempotent cleanup).
69
+ */
70
+ async deleteRlsTable(tableName) {
71
+ await this.request(() => this.client.delete("/rls/tables", {
72
+ params: { table_name: tableName },
73
+ }));
74
+ }
75
+ /** Insert/update one RLS policy for the tenant (schema server-bound). */
76
+ async upsertRlsPolicy(input) {
77
+ await this.request(() => this.client.post("/rls/policies", compact(input)));
78
+ }
79
+ /** List the tenant's own policies, optionally filtered by table name. */
80
+ async listRlsPolicies(tableName) {
81
+ const data = await this.request(() => this.client.get("/rls/policies", {
82
+ params: tableName ? { table_name: tableName } : undefined,
83
+ }));
84
+ return data ?? [];
85
+ }
86
+ /** Delete one of the tenant's policies (scoped by table + policy name). */
87
+ async deleteRlsPolicy(tableName, policyName) {
88
+ await this.request(() => this.client.delete("/rls/policies", {
89
+ params: { table_name: tableName, policy_name: policyName },
90
+ }));
91
+ }
92
+ async request(operation) {
93
+ try {
94
+ const response = await operation();
95
+ return response.data?.data;
96
+ }
97
+ catch (error) {
98
+ throw normalizeTenantDdlError(error);
99
+ }
100
+ }
101
+ }
102
+ function compact(value) {
103
+ return Object.fromEntries(Object.entries(value).filter(([, entry]) => entry !== undefined));
104
+ }
105
+ /**
106
+ * Map any failure to a TenantDdlError. Server errors carry `{ code, message }`
107
+ * (e.g. PERMISSION_DENIED / GLOBAL_KEY_NOT_ALLOWED / ROLE_NOT_ALLOWED /
108
+ * TENANT_NOT_ACTIVE / STATEMENT_NOT_ALLOWED); fall back to an HTTP-status code
109
+ * or a network code when the body is absent.
110
+ */
111
+ export function normalizeTenantDdlError(error) {
112
+ if (!axios.isAxiosError(error)) {
113
+ const message = error instanceof Error ? error.message : String(error);
114
+ return new TenantDdlError("TENANT_DDL_UNKNOWN_ERROR", message);
115
+ }
116
+ const axiosError = error;
117
+ const status = axiosError.response?.status;
118
+ const body = axiosError.response?.data;
119
+ const code = typeof body?.code === "string"
120
+ ? body.code
121
+ : status
122
+ ? `TENANT_DDL_HTTP_${status}`
123
+ : "TENANT_DDL_NETWORK_ERROR";
124
+ const message = typeof body?.message === "string"
125
+ ? body.message
126
+ : status
127
+ ? `Tenant DDL request failed (HTTP ${status})`
128
+ : axiosError.message || "Tenant DDL network request failed";
129
+ return new TenantDdlError(code, message, status);
130
+ }
131
+ //# sourceMappingURL=tenant-ddl.driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tenant-ddl.driver.js","sourceRoot":"","sources":["../../src/drivers/tenant-ddl.driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Zero Driver — PolarDB-X Zero PXBaas provisioning client.
3
+ *
4
+ * Wraps the unauthenticated Zero API that claims a disposable, Supabase-compatible
5
+ * BaaS instance from a pre-warmed pool (15-day TTL, no renewal).
6
+ *
7
+ * Contract source: https://zero.polardbx.com/BAAS-SKILL.md (polardbx-zero-pxbaas v0.1.0)
8
+ *
9
+ * Endpoints:
10
+ * - POST /api/v1/supabase/instances claim (body: { whitelistIp? })
11
+ * - GET /api/v1/supabase/instances list (needs pxz_token cookie)
12
+ * - DELETE /api/v1/supabase/instances/{id} release (needs pxz_token cookie; id = sbx_*)
13
+ * - GET /api/v1/supabase/instances/{cloudId}/whitelist query whitelist (Studio-credential hash; cloudId = pxsp-*)
14
+ * - PUT /api/v1/supabase/instances/{cloudId}/whitelist append whitelist (Studio-credential hash; append-only)
15
+ *
16
+ * Ownership: the claim response returns a `token` (also set as the `pxz_token`
17
+ * cookie). list/release must send it back via `Cookie: pxz_token=<token>`.
18
+ *
19
+ * The whitelist self-service API uses a DIFFERENT auth + id space: an
20
+ * `X-Studio-User: supabase` / `X-Studio-Hash: sha256hex("supabase:"+dashboardPassword)`
21
+ * pair, and the cloud instance id (`pxsp-*`, derived from the public endpoint host),
22
+ * not the `sbx_*` ownership id. Callers compute the hash (see apps/baas
23
+ * instance/zero-whitelist.ts) and pass it in; the password/hash is never logged.
24
+ */
25
+ import { AxiosError } from 'axios';
26
+ export interface ZeroInstance {
27
+ id: string;
28
+ status: string;
29
+ region?: string;
30
+ zoneId?: string;
31
+ aliyunInstanceId?: string;
32
+ /** host:8000 WITHOUT scheme, e.g. "pxsp-xxxhttp.polardbxaisupabase.rds.aliyuncs.com:8000" */
33
+ publicEndpoint: string;
34
+ dashboardUrl?: string;
35
+ /** Canonical App origin returned by the platform; clients must not derive it. */
36
+ appEndpoint?: string;
37
+ appDomain?: {
38
+ hostname: string;
39
+ status: string;
40
+ tlsStatus: string;
41
+ };
42
+ apiKey: string;
43
+ serviceRoleKey: string;
44
+ dbPassword?: string;
45
+ dashboardPassword?: string;
46
+ whitelistIp?: string;
47
+ assignedAt?: string;
48
+ expiresAt?: string;
49
+ createdAt?: string;
50
+ }
51
+ export interface ZeroClaimResponse {
52
+ instance: ZeroInstance;
53
+ token: string;
54
+ }
55
+ /** Result of `GET .../{cloudId}/whitelist` (flat success body). */
56
+ export interface ZeroWhitelist {
57
+ instanceId: string;
58
+ groupName: string;
59
+ /** Comma-separated effective entries (excludes the system 127.0.0.1 baseline). */
60
+ whitelist: string;
61
+ /** Where the value came from, e.g. "zero-record". */
62
+ source: string;
63
+ expiresAt?: string;
64
+ updatedAt?: string;
65
+ }
66
+ /** Result of `PUT .../{cloudId}/whitelist` (append-only; flat success body). */
67
+ export interface ZeroWhitelistAppendResult {
68
+ instanceId: string;
69
+ groupName: string;
70
+ appliedIps: string;
71
+ effectiveWhitelist: string;
72
+ cloudRequestId?: string;
73
+ }
74
+ export interface ZeroDriverOptions {
75
+ /** Zero API base URL. Defaults to https://zero.polardbx.com (override via BAAS_ZERO_ENDPOINT). */
76
+ baseUrl?: string;
77
+ timeout?: number;
78
+ }
79
+ /** Error codes returned by Zero (`{ error: { code, message } }`). */
80
+ export type ZeroErrorCode = 'INVALID_WHITELIST_IP' | 'INSTANCE_NOT_FOUND' | 'RATE_LIMIT_EXCEEDED' | 'SUPABASE_LIMIT_REACHED' | 'SUPABASE_POOL_EXHAUSTED' | 'SUPABASE_DISABLED' | 'INTERNAL_ERROR' | 'NETWORK_ERROR' | 'UNKNOWN' | 'INVALID_PARAMETER' | 'IP_MISMATCH' | 'ASSIGNMENT_EXPIRED' | 'STUDIO_CREDENTIALS_INVALID' | 'INSTANCE_NOT_ACCESSIBLE' | 'INSTANCE_BUSY' | 'CONCURRENT_UPDATE' | 'CREDENTIALS_UNAVAILABLE' | 'WHITELIST_MODIFY_FAILED';
81
+ export declare class ZeroError extends Error {
82
+ code: ZeroErrorCode;
83
+ status?: number;
84
+ constructor(code: ZeroErrorCode, message: string, status?: number);
85
+ }
86
+ export declare class ZeroDriver {
87
+ private client;
88
+ /** The whitelist API fixes the Studio user to `supabase` (see spec). */
89
+ private static readonly STUDIO_USER;
90
+ constructor(options?: ZeroDriverOptions);
91
+ /** Claim a new instance. Unauthenticated. Optionally whitelist extra IPs. */
92
+ claim(whitelistIp?: string): Promise<ZeroClaimResponse>;
93
+ /** List the caller's non-released instances. Requires the ownership token. */
94
+ list(token: string): Promise<ZeroInstance[]>;
95
+ /** Release (destroy) an instance. Requires the ownership token. */
96
+ release(id: string, token: string): Promise<void>;
97
+ /**
98
+ * Query the effective IP whitelist of a Zero instance.
99
+ * Auth: Studio-credential hash (NOT the pxz_token). `cloudInstanceId` is the
100
+ * `pxsp-*` id (see ZeroDriver.cloudInstanceId), not the `sbx_*` ownership id.
101
+ */
102
+ getWhitelist(cloudInstanceId: string, studioHash: string): Promise<ZeroWhitelist>;
103
+ /**
104
+ * Append IPs/CIDRs to the whitelist (append-only and idempotent: existing
105
+ * entries are kept, duplicates are not added). Same auth/id space as getWhitelist.
106
+ */
107
+ appendWhitelist(cloudInstanceId: string, ips: string, studioHash: string): Promise<ZeroWhitelistAppendResult>;
108
+ /**
109
+ * Derive the cloud instance id (`pxsp-*`) from a public/intranet endpoint or
110
+ * bare host. The platform inserts an `http`/`https` infix before the registrable
111
+ * domain on the public host (e.g. `pxsp-abc123http.pxbaas...`); strip scheme,
112
+ * path, port, then the trailing infix from the first label.
113
+ */
114
+ static cloudInstanceId(endpointOrHost: string): string;
115
+ /**
116
+ * Normalize the publicEndpoint (host:8000, no scheme) into a base URL.
117
+ * Prefers dashboardUrl when it already carries a scheme.
118
+ */
119
+ static toEndpoint(instance: ZeroInstance, scheme?: string): string;
120
+ private toError;
121
+ private codeFromStatus;
122
+ }
123
+ /** Wrap a network-level axios failure into a ZeroError. */
124
+ export declare function isZeroNetworkError(e: unknown): e is AxiosError;
125
+ //# sourceMappingURL=zero.driver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zero.driver.d.ts","sourceRoot":"","sources":["../../src/drivers/zero.driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Zero Driver — PolarDB-X Zero PXBaas provisioning client.
3
+ *
4
+ * Wraps the unauthenticated Zero API that claims a disposable, Supabase-compatible
5
+ * BaaS instance from a pre-warmed pool (15-day TTL, no renewal).
6
+ *
7
+ * Contract source: https://zero.polardbx.com/BAAS-SKILL.md (polardbx-zero-pxbaas v0.1.0)
8
+ *
9
+ * Endpoints:
10
+ * - POST /api/v1/supabase/instances claim (body: { whitelistIp? })
11
+ * - GET /api/v1/supabase/instances list (needs pxz_token cookie)
12
+ * - DELETE /api/v1/supabase/instances/{id} release (needs pxz_token cookie; id = sbx_*)
13
+ * - GET /api/v1/supabase/instances/{cloudId}/whitelist query whitelist (Studio-credential hash; cloudId = pxsp-*)
14
+ * - PUT /api/v1/supabase/instances/{cloudId}/whitelist append whitelist (Studio-credential hash; append-only)
15
+ *
16
+ * Ownership: the claim response returns a `token` (also set as the `pxz_token`
17
+ * cookie). list/release must send it back via `Cookie: pxz_token=<token>`.
18
+ *
19
+ * The whitelist self-service API uses a DIFFERENT auth + id space: an
20
+ * `X-Studio-User: supabase` / `X-Studio-Hash: sha256hex("supabase:"+dashboardPassword)`
21
+ * pair, and the cloud instance id (`pxsp-*`, derived from the public endpoint host),
22
+ * not the `sbx_*` ownership id. Callers compute the hash (see apps/baas
23
+ * instance/zero-whitelist.ts) and pass it in; the password/hash is never logged.
24
+ */
25
+ import axios from 'axios';
26
+ export class ZeroError extends Error {
27
+ code;
28
+ status;
29
+ constructor(code, message, status) {
30
+ super(message);
31
+ this.name = 'ZeroError';
32
+ this.code = code;
33
+ this.status = status;
34
+ }
35
+ }
36
+ const DEFAULT_BASE_URL = 'https://zero.polardbx.com';
37
+ export class ZeroDriver {
38
+ client;
39
+ /** The whitelist API fixes the Studio user to `supabase` (see spec). */
40
+ static STUDIO_USER = 'supabase';
41
+ constructor(options = {}) {
42
+ const baseUrl = options.baseUrl ?? process.env.BAAS_ZERO_ENDPOINT ?? DEFAULT_BASE_URL;
43
+ this.client = axios.create({
44
+ baseURL: baseUrl.replace(/\/$/, ''),
45
+ timeout: options.timeout ?? 30000,
46
+ // NOTE: do NOT set a default Content-Type. axios adds application/json
47
+ // automatically for the claim() POST object body, but a DELETE/GET carrying
48
+ // Content-Type: application/json with no body makes Zero return HTTP 400.
49
+ // Do not throw on non-2xx; we map errors ourselves.
50
+ validateStatus: () => true,
51
+ });
52
+ }
53
+ /** Claim a new instance. Unauthenticated. Optionally whitelist extra IPs. */
54
+ async claim(whitelistIp) {
55
+ const body = {};
56
+ if (whitelistIp)
57
+ body.whitelistIp = whitelistIp;
58
+ const res = await this.client.post('/api/v1/supabase/instances', body);
59
+ if (res.status !== 200 && res.status !== 201) {
60
+ throw this.toError(res.status, res.data);
61
+ }
62
+ const data = res.data;
63
+ if (!data?.instance?.id || !data?.token) {
64
+ throw new ZeroError('UNKNOWN', 'Malformed claim response: missing instance.id or token', res.status);
65
+ }
66
+ return data;
67
+ }
68
+ /** List the caller's non-released instances. Requires the ownership token. */
69
+ async list(token) {
70
+ const res = await this.client.get('/api/v1/supabase/instances', {
71
+ headers: { Cookie: `pxz_token=${token}` },
72
+ });
73
+ if (res.status !== 200) {
74
+ throw this.toError(res.status, res.data);
75
+ }
76
+ const data = res.data;
77
+ if (Array.isArray(data))
78
+ return data;
79
+ const obj = data;
80
+ return obj?.instances ?? [];
81
+ }
82
+ /** Release (destroy) an instance. Requires the ownership token. */
83
+ async release(id, token) {
84
+ const res = await this.client.delete(`/api/v1/supabase/instances/${encodeURIComponent(id)}`, {
85
+ headers: { Cookie: `pxz_token=${token}` },
86
+ });
87
+ if (res.status !== 200 && res.status !== 204) {
88
+ throw this.toError(res.status, res.data);
89
+ }
90
+ }
91
+ /**
92
+ * Query the effective IP whitelist of a Zero instance.
93
+ * Auth: Studio-credential hash (NOT the pxz_token). `cloudInstanceId` is the
94
+ * `pxsp-*` id (see ZeroDriver.cloudInstanceId), not the `sbx_*` ownership id.
95
+ */
96
+ async getWhitelist(cloudInstanceId, studioHash) {
97
+ const res = await this.client.get(`/api/v1/supabase/instances/${encodeURIComponent(cloudInstanceId)}/whitelist`, { headers: { 'X-Studio-User': ZeroDriver.STUDIO_USER, 'X-Studio-Hash': studioHash } });
98
+ if (res.status !== 200) {
99
+ throw this.toError(res.status, res.data);
100
+ }
101
+ return res.data;
102
+ }
103
+ /**
104
+ * Append IPs/CIDRs to the whitelist (append-only and idempotent: existing
105
+ * entries are kept, duplicates are not added). Same auth/id space as getWhitelist.
106
+ */
107
+ async appendWhitelist(cloudInstanceId, ips, studioHash) {
108
+ const res = await this.client.put(`/api/v1/supabase/instances/${encodeURIComponent(cloudInstanceId)}/whitelist`, { ips }, { headers: { 'X-Studio-User': ZeroDriver.STUDIO_USER, 'X-Studio-Hash': studioHash } });
109
+ if (res.status !== 200) {
110
+ throw this.toError(res.status, res.data);
111
+ }
112
+ return res.data;
113
+ }
114
+ /**
115
+ * Derive the cloud instance id (`pxsp-*`) from a public/intranet endpoint or
116
+ * bare host. The platform inserts an `http`/`https` infix before the registrable
117
+ * domain on the public host (e.g. `pxsp-abc123http.pxbaas...`); strip scheme,
118
+ * path, port, then the trailing infix from the first label.
119
+ */
120
+ static cloudInstanceId(endpointOrHost) {
121
+ const host = endpointOrHost.replace(/^https?:\/\//, '').split('/')[0].split(':')[0];
122
+ const firstLabel = host.split('.')[0] ?? '';
123
+ const id = firstLabel.replace(/https?$/, '');
124
+ if (!/^pxsp-/.test(id)) {
125
+ throw new ZeroError('INVALID_PARAMETER', `Cannot derive a pxsp- cloud instance id from '${endpointOrHost}'`);
126
+ }
127
+ return id;
128
+ }
129
+ /**
130
+ * Normalize the publicEndpoint (host:8000, no scheme) into a base URL.
131
+ * Prefers dashboardUrl when it already carries a scheme.
132
+ */
133
+ static toEndpoint(instance, scheme = 'http') {
134
+ if (instance.dashboardUrl && /^https?:\/\//.test(instance.dashboardUrl)) {
135
+ return instance.dashboardUrl.replace(/\/$/, '');
136
+ }
137
+ const host = instance.publicEndpoint.replace(/^https?:\/\//, '').replace(/\/$/, '');
138
+ return `${scheme}://${host}`;
139
+ }
140
+ toError(status, data) {
141
+ const err = data?.error;
142
+ const code = err?.code ?? this.codeFromStatus(status);
143
+ const message = err?.message ?? `Zero API error (HTTP ${status})`;
144
+ return new ZeroError(code, message, status);
145
+ }
146
+ codeFromStatus(status) {
147
+ if (status === 429)
148
+ return 'RATE_LIMIT_EXCEEDED';
149
+ if (status === 503)
150
+ return 'SUPABASE_POOL_EXHAUSTED';
151
+ if (status === 404)
152
+ return 'INSTANCE_NOT_FOUND';
153
+ if (status >= 500)
154
+ return 'INTERNAL_ERROR';
155
+ // 400 is not mapped to a specific code: INVALID_WHITELIST_IP is claim-only and
156
+ // comes from the response body's error.code (preferred in toError). A bare 400
157
+ // on other calls (e.g. release) must not be mislabeled as a whitelist error.
158
+ return 'UNKNOWN';
159
+ }
160
+ }
161
+ /** Wrap a network-level axios failure into a ZeroError. */
162
+ export function isZeroNetworkError(e) {
163
+ return axios.isAxiosError(e);
164
+ }
165
+ //# sourceMappingURL=zero.driver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zero.driver.js","sourceRoot":"","sources":["../../src/drivers/zero.driver.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared API error formatting for all drivers.
3
+ *
4
+ * WHY: Storage/Meta error bodies are `{ statusCode, error, message }` where
5
+ * `error` is a coarse category (literally "Error" for Storage 400s) and
6
+ * `message` carries the actionable detail. Each driver used to prefer `error`
7
+ * and hard-coded 401/403/404 texts that swallowed the server `message`
8
+ * entirely, so users saw e.g. `Storage API error (400): Error` instead of
9
+ * `body must have required property 'prefix'`.
10
+ *
11
+ * Contract: always throws a plain `Error` whose message starts with
12
+ * `<source> API error (<status>): ` — upper layers match on that text, so do
13
+ * not introduce custom error classes or codes here.
14
+ */
15
+ /** Minimal view of an AxiosResponse so drivers can pass plain object literals. */
16
+ export interface ApiErrorInfo {
17
+ status?: number;
18
+ data?: unknown;
19
+ /** Transport-level message (axiosError.message); used when there is no response body. */
20
+ fallbackMessage?: string;
21
+ /** Debug context appended verbatim under `--debug`. */
22
+ debug?: {
23
+ method?: string;
24
+ url?: string;
25
+ /** Response body serialized by the caller. */
26
+ responseBody?: string;
27
+ };
28
+ }
29
+ export interface FormatApiErrorOptions {
30
+ /** Friendly texts per HTTP status; the server message (if any) is appended after them. */
31
+ statusTexts?: Partial<Record<401 | 403 | 404, string>>;
32
+ }
33
+ /**
34
+ * Build the error for a failed API call and throw it as a plain `Error`.
35
+ */
36
+ export declare function formatApiError(source: string, info: ApiErrorInfo, options?: FormatApiErrorOptions): never;
37
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yFAAyF;IACzF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,uDAAuD;IACvD,KAAK,CAAC,EAAE;QACN,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,8CAA8C;QAC9C,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;CACH;AAED,MAAM,WAAW,qBAAqB;IACpC,0FAA0F;IAC1F,WAAW,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;CACxD;AAaD;;GAEG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,YAAY,EAClB,OAAO,GAAE,qBAA0B,GAClC,KAAK,CAoCP"}