@pawabase/client 0.0.0-stage → 0.1.0

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 (243) hide show
  1. package/README.md +313 -2
  2. package/dist/cjs/admin.d.ts +187 -0
  3. package/dist/cjs/admin.d.ts.map +1 -0
  4. package/dist/cjs/admin.js +235 -0
  5. package/dist/cjs/admin.js.map +1 -0
  6. package/dist/cjs/auth.d.ts +448 -0
  7. package/dist/cjs/auth.d.ts.map +1 -0
  8. package/dist/cjs/auth.js +1016 -0
  9. package/dist/cjs/auth.js.map +1 -0
  10. package/dist/cjs/client.d.ts +103 -0
  11. package/dist/cjs/client.d.ts.map +1 -0
  12. package/dist/cjs/client.js +144 -0
  13. package/dist/cjs/client.js.map +1 -0
  14. package/dist/cjs/data.d.ts +220 -0
  15. package/dist/cjs/data.d.ts.map +1 -0
  16. package/dist/cjs/data.js +490 -0
  17. package/dist/cjs/data.js.map +1 -0
  18. package/dist/cjs/errors.d.ts +167 -0
  19. package/dist/cjs/errors.d.ts.map +1 -0
  20. package/dist/cjs/errors.js +316 -0
  21. package/dist/cjs/errors.js.map +1 -0
  22. package/dist/cjs/files.d.ts +80 -0
  23. package/dist/cjs/files.d.ts.map +1 -0
  24. package/dist/cjs/files.js +167 -0
  25. package/dist/cjs/files.js.map +1 -0
  26. package/dist/cjs/functions.d.ts +66 -0
  27. package/dist/cjs/functions.d.ts.map +1 -0
  28. package/dist/cjs/functions.js +109 -0
  29. package/dist/cjs/functions.js.map +1 -0
  30. package/dist/cjs/http.d.ts +101 -0
  31. package/dist/cjs/http.d.ts.map +1 -0
  32. package/dist/cjs/http.js +249 -0
  33. package/dist/cjs/http.js.map +1 -0
  34. package/dist/cjs/index.d.ts +22 -0
  35. package/dist/cjs/index.d.ts.map +1 -0
  36. package/dist/cjs/index.js +45 -0
  37. package/dist/cjs/index.js.map +1 -0
  38. package/dist/cjs/manage/access.d.ts +136 -0
  39. package/dist/cjs/manage/access.d.ts.map +1 -0
  40. package/dist/cjs/manage/access.js +162 -0
  41. package/dist/cjs/manage/access.js.map +1 -0
  42. package/dist/cjs/manage/automation.d.ts +106 -0
  43. package/dist/cjs/manage/automation.d.ts.map +1 -0
  44. package/dist/cjs/manage/automation.js +144 -0
  45. package/dist/cjs/manage/automation.js.map +1 -0
  46. package/dist/cjs/manage/base.d.ts +52 -0
  47. package/dist/cjs/manage/base.d.ts.map +1 -0
  48. package/dist/cjs/manage/base.js +69 -0
  49. package/dist/cjs/manage/base.js.map +1 -0
  50. package/dist/cjs/manage/data.d.ts +100 -0
  51. package/dist/cjs/manage/data.d.ts.map +1 -0
  52. package/dist/cjs/manage/data.js +141 -0
  53. package/dist/cjs/manage/data.js.map +1 -0
  54. package/dist/cjs/manage/files.d.ts +45 -0
  55. package/dist/cjs/manage/files.d.ts.map +1 -0
  56. package/dist/cjs/manage/files.js +73 -0
  57. package/dist/cjs/manage/files.js.map +1 -0
  58. package/dist/cjs/manage/functions.d.ts +48 -0
  59. package/dist/cjs/manage/functions.d.ts.map +1 -0
  60. package/dist/cjs/manage/functions.js +61 -0
  61. package/dist/cjs/manage/functions.js.map +1 -0
  62. package/dist/cjs/manage/index.d.ts +76 -0
  63. package/dist/cjs/manage/index.d.ts.map +1 -0
  64. package/dist/cjs/manage/index.js +134 -0
  65. package/dist/cjs/manage/index.js.map +1 -0
  66. package/dist/cjs/manage/lifecycle.d.ts +128 -0
  67. package/dist/cjs/manage/lifecycle.d.ts.map +1 -0
  68. package/dist/cjs/manage/lifecycle.js +167 -0
  69. package/dist/cjs/manage/lifecycle.js.map +1 -0
  70. package/dist/cjs/manage/mail.d.ts +16 -0
  71. package/dist/cjs/manage/mail.d.ts.map +1 -0
  72. package/dist/cjs/manage/mail.js +24 -0
  73. package/dist/cjs/manage/mail.js.map +1 -0
  74. package/dist/cjs/manage/observe.d.ts +149 -0
  75. package/dist/cjs/manage/observe.d.ts.map +1 -0
  76. package/dist/cjs/manage/observe.js +168 -0
  77. package/dist/cjs/manage/observe.js.map +1 -0
  78. package/dist/cjs/manage/realtime.d.ts +52 -0
  79. package/dist/cjs/manage/realtime.d.ts.map +1 -0
  80. package/dist/cjs/manage/realtime.js +71 -0
  81. package/dist/cjs/manage/realtime.js.map +1 -0
  82. package/dist/cjs/package.json +1 -0
  83. package/dist/cjs/realtime.d.ts +207 -0
  84. package/dist/cjs/realtime.d.ts.map +1 -0
  85. package/dist/cjs/realtime.js +704 -0
  86. package/dist/cjs/realtime.js.map +1 -0
  87. package/dist/cjs/session-store.d.ts +16 -0
  88. package/dist/cjs/session-store.d.ts.map +1 -0
  89. package/dist/cjs/session-store.js +37 -0
  90. package/dist/cjs/session-store.js.map +1 -0
  91. package/dist/cjs/typegen.d.ts +26 -0
  92. package/dist/cjs/typegen.d.ts.map +1 -0
  93. package/dist/cjs/typegen.js +167 -0
  94. package/dist/cjs/typegen.js.map +1 -0
  95. package/dist/cjs/types.d.ts +178 -0
  96. package/dist/cjs/types.d.ts.map +1 -0
  97. package/dist/cjs/types.js +4 -0
  98. package/dist/cjs/types.js.map +1 -0
  99. package/dist/cjs/util.d.ts +27 -0
  100. package/dist/cjs/util.d.ts.map +1 -0
  101. package/dist/cjs/util.js +115 -0
  102. package/dist/cjs/util.js.map +1 -0
  103. package/dist/cjs/version.d.ts +2 -0
  104. package/dist/cjs/version.d.ts.map +1 -0
  105. package/dist/cjs/version.js +5 -0
  106. package/dist/cjs/version.js.map +1 -0
  107. package/dist/esm/admin.d.ts +187 -0
  108. package/dist/esm/admin.d.ts.map +1 -0
  109. package/dist/esm/admin.js +222 -0
  110. package/dist/esm/admin.js.map +1 -0
  111. package/dist/esm/auth.d.ts +448 -0
  112. package/dist/esm/auth.d.ts.map +1 -0
  113. package/dist/esm/auth.js +1012 -0
  114. package/dist/esm/auth.js.map +1 -0
  115. package/dist/esm/cli/gen-types.d.ts +2 -0
  116. package/dist/esm/cli/gen-types.d.ts.map +1 -0
  117. package/dist/esm/cli/gen-types.js +100 -0
  118. package/dist/esm/cli/gen-types.js.map +1 -0
  119. package/dist/esm/client.d.ts +103 -0
  120. package/dist/esm/client.d.ts.map +1 -0
  121. package/dist/esm/client.js +139 -0
  122. package/dist/esm/client.js.map +1 -0
  123. package/dist/esm/data.d.ts +220 -0
  124. package/dist/esm/data.d.ts.map +1 -0
  125. package/dist/esm/data.js +485 -0
  126. package/dist/esm/data.js.map +1 -0
  127. package/dist/esm/errors.d.ts +167 -0
  128. package/dist/esm/errors.d.ts.map +1 -0
  129. package/dist/esm/errors.js +293 -0
  130. package/dist/esm/errors.js.map +1 -0
  131. package/dist/esm/files.d.ts +80 -0
  132. package/dist/esm/files.d.ts.map +1 -0
  133. package/dist/esm/files.js +162 -0
  134. package/dist/esm/files.js.map +1 -0
  135. package/dist/esm/functions.d.ts +66 -0
  136. package/dist/esm/functions.d.ts.map +1 -0
  137. package/dist/esm/functions.js +103 -0
  138. package/dist/esm/functions.js.map +1 -0
  139. package/dist/esm/http.d.ts +101 -0
  140. package/dist/esm/http.d.ts.map +1 -0
  141. package/dist/esm/http.js +245 -0
  142. package/dist/esm/http.js.map +1 -0
  143. package/dist/esm/index.d.ts +22 -0
  144. package/dist/esm/index.d.ts.map +1 -0
  145. package/dist/esm/index.js +12 -0
  146. package/dist/esm/index.js.map +1 -0
  147. package/dist/esm/manage/access.d.ts +136 -0
  148. package/dist/esm/manage/access.d.ts.map +1 -0
  149. package/dist/esm/manage/access.js +155 -0
  150. package/dist/esm/manage/access.js.map +1 -0
  151. package/dist/esm/manage/automation.d.ts +106 -0
  152. package/dist/esm/manage/automation.d.ts.map +1 -0
  153. package/dist/esm/manage/automation.js +134 -0
  154. package/dist/esm/manage/automation.js.map +1 -0
  155. package/dist/esm/manage/base.d.ts +52 -0
  156. package/dist/esm/manage/base.d.ts.map +1 -0
  157. package/dist/esm/manage/base.js +63 -0
  158. package/dist/esm/manage/base.js.map +1 -0
  159. package/dist/esm/manage/data.d.ts +100 -0
  160. package/dist/esm/manage/data.d.ts.map +1 -0
  161. package/dist/esm/manage/data.js +130 -0
  162. package/dist/esm/manage/data.js.map +1 -0
  163. package/dist/esm/manage/files.d.ts +45 -0
  164. package/dist/esm/manage/files.d.ts.map +1 -0
  165. package/dist/esm/manage/files.js +68 -0
  166. package/dist/esm/manage/files.js.map +1 -0
  167. package/dist/esm/manage/functions.d.ts +48 -0
  168. package/dist/esm/manage/functions.d.ts.map +1 -0
  169. package/dist/esm/manage/functions.js +57 -0
  170. package/dist/esm/manage/functions.js.map +1 -0
  171. package/dist/esm/manage/index.d.ts +76 -0
  172. package/dist/esm/manage/index.d.ts.map +1 -0
  173. package/dist/esm/manage/index.js +115 -0
  174. package/dist/esm/manage/index.js.map +1 -0
  175. package/dist/esm/manage/lifecycle.d.ts +128 -0
  176. package/dist/esm/manage/lifecycle.d.ts.map +1 -0
  177. package/dist/esm/manage/lifecycle.js +161 -0
  178. package/dist/esm/manage/lifecycle.js.map +1 -0
  179. package/dist/esm/manage/mail.d.ts +16 -0
  180. package/dist/esm/manage/mail.d.ts.map +1 -0
  181. package/dist/esm/manage/mail.js +19 -0
  182. package/dist/esm/manage/mail.js.map +1 -0
  183. package/dist/esm/manage/observe.d.ts +149 -0
  184. package/dist/esm/manage/observe.d.ts.map +1 -0
  185. package/dist/esm/manage/observe.js +161 -0
  186. package/dist/esm/manage/observe.js.map +1 -0
  187. package/dist/esm/manage/realtime.d.ts +52 -0
  188. package/dist/esm/manage/realtime.d.ts.map +1 -0
  189. package/dist/esm/manage/realtime.js +66 -0
  190. package/dist/esm/manage/realtime.js.map +1 -0
  191. package/dist/esm/package.json +1 -0
  192. package/dist/esm/realtime.d.ts +207 -0
  193. package/dist/esm/realtime.d.ts.map +1 -0
  194. package/dist/esm/realtime.js +699 -0
  195. package/dist/esm/realtime.js.map +1 -0
  196. package/dist/esm/session-store.d.ts +16 -0
  197. package/dist/esm/session-store.d.ts.map +1 -0
  198. package/dist/esm/session-store.js +32 -0
  199. package/dist/esm/session-store.js.map +1 -0
  200. package/dist/esm/typegen.d.ts +26 -0
  201. package/dist/esm/typegen.d.ts.map +1 -0
  202. package/dist/esm/typegen.js +163 -0
  203. package/dist/esm/typegen.js.map +1 -0
  204. package/dist/esm/types.d.ts +178 -0
  205. package/dist/esm/types.d.ts.map +1 -0
  206. package/dist/esm/types.js +3 -0
  207. package/dist/esm/types.js.map +1 -0
  208. package/dist/esm/util.d.ts +27 -0
  209. package/dist/esm/util.d.ts.map +1 -0
  210. package/dist/esm/util.js +102 -0
  211. package/dist/esm/util.js.map +1 -0
  212. package/dist/esm/version.d.ts +2 -0
  213. package/dist/esm/version.d.ts.map +1 -0
  214. package/dist/esm/version.js +2 -0
  215. package/dist/esm/version.js.map +1 -0
  216. package/package.json +84 -4
  217. package/src/admin.ts +311 -0
  218. package/src/auth.ts +1180 -0
  219. package/src/cli/gen-types.ts +105 -0
  220. package/src/client.ts +189 -0
  221. package/src/data.ts +576 -0
  222. package/src/errors.ts +330 -0
  223. package/src/files.ts +208 -0
  224. package/src/functions.ts +131 -0
  225. package/src/http.ts +354 -0
  226. package/src/index.ts +56 -0
  227. package/src/manage/access.ts +206 -0
  228. package/src/manage/automation.ts +162 -0
  229. package/src/manage/base.ts +83 -0
  230. package/src/manage/data.ts +159 -0
  231. package/src/manage/files.ts +79 -0
  232. package/src/manage/functions.ts +69 -0
  233. package/src/manage/index.ts +132 -0
  234. package/src/manage/lifecycle.ts +208 -0
  235. package/src/manage/mail.ts +22 -0
  236. package/src/manage/observe.ts +226 -0
  237. package/src/manage/realtime.ts +95 -0
  238. package/src/realtime.ts +765 -0
  239. package/src/session-store.ts +36 -0
  240. package/src/typegen.ts +192 -0
  241. package/src/types.ts +195 -0
  242. package/src/util.ts +114 -0
  243. package/src/version.ts +1 -0
package/README.md CHANGED
@@ -1,3 +1,314 @@
1
- # Temporary Holding Version
1
+ # @pawabase/client
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ The official TypeScript client for [Pawabase](https://pawabase.com): records, auth, storage,
4
+ functions, flows and realtime, with typed errors, safe retries and one shared session.
5
+
6
+ - **Zero dependencies.** Standard `fetch` and `WebSocket` only. Tested on Node 26 and against a live stack; it uses no Node-only APIs in the library, so browsers and other runtimes with `fetch` should work (bring a `storage` on React Native).
7
+ - **Typed end to end.** Generate a `Database` type from your project and resource names, rows, inserts and filters are checked.
8
+ - **Built for the failures.** Rate limits and `502/503/504` are retried with backoff and `Retry-After`; refresh tokens are exchanged once, even from many tabs; errors are classes, not strings.
9
+ - **ESM and CommonJS**, with types.
10
+
11
+ ```bash
12
+ npm install @pawabase/client
13
+ ```
14
+
15
+ ```ts
16
+ import { createClient } from "@pawabase/client";
17
+
18
+ const pawabase = createClient({
19
+ url: "https://api.example.com", // your gateway
20
+ apiKey: "pb_pk_…", // a publishable key
21
+ });
22
+
23
+ await pawabase.auth.signInWithPassword({ email: "ada@example.com", password: "…" });
24
+
25
+ const { data, total } = await pawabase
26
+ .from("posts")
27
+ .eq("status", "live")
28
+ .order("created_at", "desc")
29
+ .perPage(20);
30
+ ```
31
+
32
+ ## Contents
33
+
34
+ - [Keys](#keys) · [Records](#records) · [Auth](#auth) · [Storage](#storage) · [Functions, flows and routes](#functions-flows-and-routes) · [Realtime](#realtime)
35
+ - [Managing an environment](#managing-an-environment-secret-key) · [Types](#types) · [Errors](#errors) · [Retries and timeouts](#retries-and-timeouts) · [Servers and SSR](#servers-and-ssr) · [Testing](#testing-your-app)
36
+
37
+ ## Keys
38
+
39
+ Every request carries your project key in the `apikey` header; a signed-in user's token goes in
40
+ `Authorization` automatically.
41
+
42
+ | Key | Where | What it does |
43
+ | --- | --- | --- |
44
+ | `pb_pk_…` publishable | Browsers, mobile apps | Anonymous role. **Policies apply.** |
45
+ | `pb_sk_…` secret | Servers only | Bypasses every policy. |
46
+
47
+ A secret key in a browser is refused (`ConfigError`), because anyone can read it. Set
48
+ `dangerouslyAllowBrowser: true` only if you know why you must.
49
+
50
+ ## Records
51
+
52
+ ```ts
53
+ const posts = pawabase.from("posts");
54
+
55
+ await posts.create({ title: "Hello" }); // → the created row
56
+ await posts.get(1, { expand: ["author"] }); // 404 → NotFoundError
57
+ await posts.maybeGet(1); // 404 → null
58
+ await posts.update(1, { title: "Hi" }); // PATCH
59
+ await posts.delete(1);
60
+ ```
61
+
62
+ ### Queries
63
+
64
+ A query is built with chained methods, is immutable (reuse a base query freely), and runs when awaited.
65
+
66
+ ```ts
67
+ const live = pawabase.from("posts").eq("status", "live");
68
+
69
+ await live.gte("views", 100).order("views", "desc").perPage(50).page(2);
70
+ await live.like("title", "Intro*").first(); // Row | null
71
+ await live.count(); // number
72
+ await live.all({ maxRecords: 1000 }); // every row, across pages
73
+ for await (const post of live) { /* lazily, page by page */ }
74
+
75
+ await pawabase.from("posts").where({ status: "live", views: { gte: 10 }, org_id: null });
76
+ await pawabase.from("posts").in("id", [1, 2, 3]).select("id", "title").expand("author");
77
+ ```
78
+
79
+ | Method | Server operator |
80
+ | --- | --- |
81
+ | `eq` `neq` `gt` `gte` `lt` `lte` | `eq` `neq` `gt` `gte` `lt` `lte` |
82
+ | `like` `ilike` | `like` `ilike` (`*` or `%` match any run) |
83
+ | `in` `notIn` | `in` `nin` |
84
+ | `is` `isNot` | `is` `isnot` (`null`, `true`, `false`) |
85
+
86
+ The client protects you from three server behaviours that would otherwise return wrong data without an error:
87
+
88
+ 1. **One filter per field.** The server keeps only the last filter on a repeated field, so a two-sided range
89
+ (`gte` + `lte` on one field) cannot be written. The client throws `InvalidQueryError` instead of dropping a bound.
90
+ 2. **Booleans.** `filter[flag]=eq.false` matches the wrong rows. `eq(col, false)` is sent as `is.false`.
91
+ 3. **`in` lists are split on commas**, so a value containing a comma is refused.
92
+
93
+ `page.total` is `null` when a per-row policy makes the count unknowable; pages can then be short or empty with
94
+ more behind them, and `all()` stops at the first empty page (`stopAfterEmptyPages` to be more patient).
95
+ `select()` leaves unselected columns in the row as `null`.
96
+
97
+ `createMany(rows)` creates a few at a time and returns `{ created, failed }`. It is **not atomic.**
98
+
99
+ ## Auth
100
+
101
+ ```ts
102
+ const { session, verificationRequired } = await pawabase.auth.signUp({ email, password, data: { plan: "free" } });
103
+
104
+ const result = await pawabase.auth.signInWithPassword({ email, password });
105
+ if (result.status === "mfa_required") await result.verify(codeFromAuthenticator);
106
+
107
+ pawabase.auth.onAuthStateChange((event, session) => { /* INITIAL_SESSION | SIGNED_IN | TOKEN_REFRESHED | USER_UPDATED | SIGNED_OUT */ });
108
+
109
+ await pawabase.auth.getUser();
110
+ await pawabase.auth.updateUser({ name: "Ada", data: { theme: "dark" } });
111
+ await pawabase.auth.signOut(); // { scope: "global" } ends every session
112
+ ```
113
+
114
+ **The session is managed for you.** It is stored (`localStorage` in browsers, memory elsewhere; pass `auth.storage`
115
+ for anything else), refreshed shortly before it expires, and refreshed **once** at a time. Akountz rotates refresh tokens and
116
+ treats a reused one as theft, so concurrent refreshes would sign the user out: concurrent requests share one exchange,
117
+ and across tabs the Web Locks API serialises it where the browser has it (tab-to-tab behaviour is covered by a simulated test, not a real browser). A `401` on a request triggers one refresh and a replay.
118
+
119
+ Also: `signInWithMagicLink` / `verifyMagicLink`, `requestPasswordReset` / `resetPassword`, `verifyEmail`,
120
+ `resendVerification`, `confirmEmailChange`, `mfa.*` (enroll, verify, disable, recovery codes), `sessions.*`,
121
+ `orgs.*` (members, invitations, teams), `devices.*`, `apiKeys.*` (keys a user makes for themselves), `exchangeCode(code)`, `switchOrg(slug)`, `settings()`.
122
+
123
+ Also: **guest sessions** (`signInAnonymously()`, then `upgradeAnonymous({ email, password })` keeps what the guest made), **emailed codes**
124
+ (`sendEmailCode({ email })`, `verifyEmailCode({ email, code })`), **passkeys** (in a browser `auth.passkeys.register()` and
125
+ `auth.passkeys.signIn()` do the whole WebAuthn ceremony; `list`, `remove`, and the `request…` / `finish…` pairs are there for native apps and tests),
126
+ `issueToken("billing")` for a short-lived token for another service, and `jwks()` for the public keys that verify it.
127
+
128
+ **Social sign-in** needs the `environment` in the options, because the provider URL names it (a publishable key only: a secret key is refused):
129
+
130
+ ```ts
131
+ const pawabase = createClient({ url, apiKey, environment: "production" });
132
+ pawabase.auth.signInWithOAuth("github", { redirectTo: location.origin }); // redirects
133
+ // On return, the tokens in the URL fragment are picked up automatically (detectSessionInUrl).
134
+ ```
135
+
136
+ ## Storage
137
+
138
+ ```ts
139
+ const avatars = pawabase.storage.from("avatars");
140
+
141
+ await avatars.upload("u1/me.png", file); // Blob, File, bytes, string or stream
142
+ const blob = await avatars.download("u1/me.png");
143
+ const { files, prefixes, cursor } = await avatars.list({ prefix: "u1/" });
144
+ for await (const file of avatars.listAll({ prefix: "u1/" })) { … }
145
+ await avatars.remove("u1/me.png");
146
+
147
+ avatars.getPublicUrl("u1/me.png"); // public bucket, for <img src>
148
+ const { url } = await avatars.createSignedUrl("u1/me.png", { expiresIn: 300 });
149
+ const slot = await avatars.createSignedUploadUrl("u1/new.png", { contentType: "image/png", maxBytes: 1e6 });
150
+ await avatars.uploadToSignedUrl(slot.url, file); // sends no key: the URL is the credential
151
+ ```
152
+
153
+ ## Functions, flows and routes
154
+
155
+ ```ts
156
+ await pawabase.functions.invoke<{ total: number }>("price", { sku: "a" }); // unwraps { data }
157
+ await pawabase.flows.run("whoami"); // the flow's response body
158
+ await pawabase.routes.post("checkout/start", { cart: 1 }, { query: { dry: true } });
159
+ await pawabase.request("GET", "/v1/anything"); // raw, with auth and retries
160
+ ```
161
+
162
+ ## Realtime
163
+
164
+ ```ts
165
+ const room = pawabase.realtime.channel<{ text: string }>("chat:lobby", { presence: { name: "Ada" }, replay: 50 });
166
+
167
+ room.on("message", (m) => console.log(m.from, m.payload.text));
168
+ room.onEvent("typing", (m) => …);
169
+ room.on("presence", ({ joins, leaves, members }) => …);
170
+
171
+ await room.subscribe(); // rejects with RealtimeError("forbidden") if the channel's rule refuses
172
+ await room.send("message", { text: "hi" }); // resolves when the server accepted it
173
+ await room.track({ name: "Ada", typing: true });
174
+ await room.history(20);
175
+ for await (const m of room) { … } // or iterate
176
+ await room.unsubscribe();
177
+ ```
178
+
179
+ The connection reconnects with backoff, rejoins every channel, and with `replay: n` fetches what you missed
180
+ and delivers it once (messages are de-duplicated by id). Pings run every 25 s and a silent link is recycled.
181
+ A refreshed access token is sent to the open socket without reconnecting.
182
+
183
+ No socket needed: `for await (const frame of pawabase.realtime.stream(["chat:lobby"])) …` listens over Server-Sent Events (stop with `break` or an
184
+ `AbortSignal`), and `pawabase.realtime.publish(...)` sends. Channel rules and dashboards are managed with `manage(client).realtimeChannels` and
185
+ `manage(client).dashboards`.
186
+
187
+ On Node 20 there is no global `WebSocket`; pass one: `realtime: { webSocket: WebSocket }` from the `ws` package.
188
+
189
+ HTTP counterparts need no socket: `realtime.publish(channel, event, payload)`, `realtime.presence(channel)`, `realtime.history(channel)`.
190
+
191
+ ## Managing an environment (secret key)
192
+
193
+ Everything Studio does is available to your servers and scripts with an environment's secret key (`pb_sk_…`), as two subpath imports that stay out of
194
+ your browser bundle unless you import them:
195
+
196
+ ```ts
197
+ import { createClient } from "@pawabase/client";
198
+ import { manage } from "@pawabase/client/manage";
199
+ import { admin } from "@pawabase/client/admin";
200
+
201
+ const pawabase = createClient({ url, apiKey: process.env.PAWABASE_SECRET_KEY!, environment: "production" });
202
+ const m = manage(pawabase);
203
+
204
+ await m.secrets.set("STRIPE_KEY", "sk_live_…");
205
+ await m.firewall.ban("203.0.113.7", { seconds: 3600 });
206
+ await m.jobs.replay({ job: "send_mail", sinceMinutes: 60, dryRun: true });
207
+ await m.backups.snapshot("before-launch");
208
+ await manage(pawabase, "staging").flows.list(); // the same API for another environment the key may manage
209
+
210
+ const a = admin(pawabase); // the people who sign in to your application
211
+ await a.users.create({ email: "ada@example.com", password: "…", roles: ["editor"] });
212
+ await a.users.update(userId, { disabled: true });
213
+ await a.orgs.addMember("acme", { email: "ada@example.com", role: "admin" });
214
+ ```
215
+
216
+ `manage()` groups the platform by what you are doing: **data** (`resources`, `schema`, `policies`, `schemas`, `transformers`, `routes`, `database`, `runtime`),
217
+ **automation** (`flows`, `schedules`, `subscriptions`, `events`, `webhooks`, `inboundHooks`, `jobs`, `functions`), **files and mail** (`buckets`, `cache`, `mail`,
218
+ `mailTemplates`), **access** (`keys`, `secrets`, `domains`, `firewall`), **observe** (`observability`, `alarms`, `statusPage`, `health`) and **lifecycle**
219
+ (`environments`, `releases`, `backups`). Definitions (`flows`, `policies`, `webhooks`…) share `list`, `getOne`, `create`, `replace` and `remove`, and take
220
+ `{ branch }` to work on a feature branch. `admin()` has `users`, `roles`, `orgs`, `invitations`, `sessions`, `apiKeys`, `devices` and `insight`
221
+ (events, statistics, identity backup, hosted pages). Both refuse a publishable key, and a key manages only its own environment.
222
+
223
+ To write the functions themselves in TypeScript, see [`@pawabase/functions`](https://github.com/Pawabase/pawabase-functions-js).
224
+
225
+ ## Types
226
+
227
+ Generate a `Database` type from your environment's OpenAPI document:
228
+
229
+ ```bash
230
+ npx pawabase-types --url https://api.example.com --project acme --env production --out src/pawabase.types.ts
231
+ # or, with the document saved from Studio's API Explorer:
232
+ npx pawabase-types --file openapi.json --out src/pawabase.types.ts
233
+ ```
234
+
235
+ ```ts
236
+ import type { Database } from "./pawabase.types";
237
+ const pawabase = createClient<Database>({ url, apiKey });
238
+
239
+ await pawabase.from("posts").create({ title: "ok" }); // checked
240
+ await pawabase.from("posts").create({ views: 3 }); // error: title is required
241
+ pawabase.from("posts").eq("nope", 1); // error: no such column
242
+ ```
243
+
244
+ The gateway serves the document when the environment's **public docs** setting is on. Run `pawabase-types --check` in CI to catch drift.
245
+ Relations you `expand` are not in the document; add them to a row type yourself:
246
+ `pawabase.resource<Post & { author: Author }>("posts")`.
247
+
248
+ ## Errors
249
+
250
+ Everything thrown is a `PawabaseError`. Server answers are `ApiError`s (the server sends several body shapes, normalised here):
251
+
252
+ | Class | When | Useful fields |
253
+ | --- | --- | --- |
254
+ | `AuthenticationError` | `401`: bad key (`code: "invalid_api_key"`), signed out, expired | |
255
+ | `PermissionError` | `403` | `policy`: the refusing policy, when the server names it |
256
+ | `NotFoundError` | `404`: no record, or a read policy hides it | |
257
+ | `ValidationError` | `422` | `issues`, `fieldError("email")`, `byField()` |
258
+ | `ConflictError` | `409` | |
259
+ | `RateLimitError` | `429` | `retryAfter` (seconds) |
260
+ | `ServerError` | `5xx` | |
261
+ | `NetworkError` / `TimeoutError` / `AbortError` | no response | |
262
+ | `ConfigError` / `InvalidQueryError` / `RealtimeError` | misuse, refused query, socket refusals | |
263
+
264
+ Every `ApiError` has `status`, `code`, `message`, `details`, `body` and **`requestId`**: quote it to find the request in Studio → Observability.
265
+
266
+ ```ts
267
+ try { await pawabase.from("posts").create(input); }
268
+ catch (e) {
269
+ if (e instanceof ValidationError) showFieldErrors(e.byField());
270
+ else if (e instanceof PermissionError) console.warn(`refused by policy ${e.policy}`);
271
+ else throw e;
272
+ }
273
+ ```
274
+
275
+ ## Retries and timeouts
276
+
277
+ | Situation | Retried? |
278
+ | --- | --- |
279
+ | `429` | Yes, any method (it is answered before a handler runs), waiting `Retry-After` up to `maxRetryAfterMs` (30 s), else surfaced |
280
+ | `502` `503` `504`, network failure, timeout | Yes for `GET` `PUT` `DELETE`; **not** for `POST` / `PATCH` unless `idempotent: true` |
281
+ | `500`, `4xx` | No |
282
+ | Token refresh | Never retried on a network failure: a replayed refresh token looks like theft |
283
+
284
+ Defaults: 2 retries, full-jitter backoff 300 ms → 8 s, 30 s timeout per attempt.
285
+ Configure with `retry`, `timeoutMs`; every call also takes an `AbortSignal` (`query.withOptions({ signal })`, `{ signal }`).
286
+
287
+ `hooks: { onRequest, onResponse, onRetry, onError }` observe traffic (API keys and tokens are masked).
288
+
289
+ ## Servers and SSR
290
+
291
+ ```ts
292
+ // A server acting for the signed-in user of this request: no session, no refresh, no storage.
293
+ const asUser = pawabase.asUser(tokenFromTheRequest);
294
+ await asUser.from("tasks").all();
295
+
296
+ // A server acting as itself, bypassing policies.
297
+ const server = createClient({ url, apiKey: process.env.PAWABASE_SECRET_KEY! });
298
+ ```
299
+
300
+ ## Testing your app
301
+
302
+ Pass your own `fetch`, or point `url` at a local stack. `auth.storage` takes any `{ getItem, setItem, removeItem }`,
303
+ and `client.dispose()` stops timers and the socket.
304
+
305
+ ## Development
306
+
307
+ ```bash
308
+ npm install
309
+ npm test # unit tests against local fake servers
310
+ PAWABASE_LIVE_CONFIG=/tmp/pb/config.json npm test # plus contract tests against a real stack
311
+ ```
312
+
313
+ The live config (`url`, `project`, `environment`, `publishable`, `secret`) is written by `scripts/live-provision.py`
314
+ after the stack is up (`scripts/dev.sh`). Without it the live tests are skipped.
@@ -0,0 +1,187 @@
1
+ /**
2
+ * Administer the environment's users, organizations and roles, with the environment's secret key (`pb_sk_…`).
3
+ *
4
+ * These are the people who sign in to *your* application, not the project's own team. Every call is scoped to one environment;
5
+ * a user of one environment is never visible in another.
6
+ *
7
+ * ```ts
8
+ * import { createClient } from "@pawabase/client";
9
+ * import { admin } from "@pawabase/client/admin";
10
+ *
11
+ * const a = admin(createClient({ url, apiKey: "pb_sk_…", environment: "production" }));
12
+ * await a.users.create({ email: "ada@example.com", password: "…", roles: ["editor"] });
13
+ * await a.users.update(userId, { disabled: true });
14
+ * await a.orgs.addMember("acme", { email: "ada@example.com", role: "admin" });
15
+ * ```
16
+ */
17
+ import type { PawabaseClient } from "./client.js";
18
+ import type { HttpClient } from "./http.js";
19
+ import { Service, type Api, type Body } from "./manage/base.js";
20
+ declare class AdminService extends Service {
21
+ protected path(suffix?: string): string;
22
+ }
23
+ export interface NewUser {
24
+ email: string;
25
+ password?: string;
26
+ username?: string;
27
+ name?: string;
28
+ /** Default `true`: an operator vouches for the address. */
29
+ emailVerified?: boolean;
30
+ /** Visible to the user and editable by them. */
31
+ userMetadata?: Body;
32
+ /** Visible to your server only. */
33
+ appMetadata?: Body;
34
+ roles?: string[];
35
+ }
36
+ export interface UserChanges {
37
+ name?: string;
38
+ emailVerified?: boolean;
39
+ /** Blocks sign-in and ends the user's sessions. */
40
+ disabled?: boolean;
41
+ password?: string;
42
+ userMetadata?: Body;
43
+ appMetadata?: Body;
44
+ /** Replaces the user's roles. */
45
+ roles?: string[];
46
+ /** Clears a lockout after failed sign-ins. */
47
+ unlock?: boolean;
48
+ }
49
+ export declare class Users extends AdminService {
50
+ /** `search` matches email, username and name. `status`: `disabled`, `unverified`, `locked`, `mfa`, `no_mfa`. */
51
+ search(options?: {
52
+ search?: string;
53
+ status?: string;
54
+ limit?: number;
55
+ offset?: number;
56
+ }): Promise<Api>;
57
+ getUser(userId: string): Promise<Api>;
58
+ /** Create an account without the sign-up restrictions (allow-lists; the password policy still applies). */
59
+ create(user: NewUser): Promise<Api>;
60
+ update(userId: string, changes: UserChanges): Promise<Api>;
61
+ deleteUser(userId: string): Promise<Api>;
62
+ /** The user's recent sign-ins and security events. */
63
+ history(userId: string): Promise<Api>;
64
+ /** Remove the user's second factors, so they can sign in with a password alone and enrol again. */
65
+ resetMfa(userId: string): Promise<Api>;
66
+ /** Give the user permissions directly, beyond their roles' (`posts:write`, `billing:*`). */
67
+ grant(userId: string, permissions: string[]): Promise<Api>;
68
+ revoke(userId: string, permissions: string[]): Promise<Api>;
69
+ /** Sign the user out everywhere. */
70
+ revokeSessions(userId: string): Promise<Api>;
71
+ revokeSession(userId: string, sessionId: string): Promise<Api>;
72
+ devices(userId: string): Promise<Api>;
73
+ forgetDevice(userId: string, deviceId: string): Promise<Api>;
74
+ /** The user's own API keys (never the secrets). */
75
+ apiKeys(userId: string): Promise<Api>;
76
+ }
77
+ export declare class Roles extends AdminService {
78
+ /** Roles with their permissions. */
79
+ list(): Promise<Api>;
80
+ /** Create or replace a role. Names are lowercase (`editor`, `org:billing`); permissions are `resource:action` patterns with `*` wildcards. */
81
+ define(name: string, permissions: string[], options?: {
82
+ description?: string;
83
+ }): Promise<Api>;
84
+ remove(name: string): Promise<Api>;
85
+ }
86
+ /** Organizations (tenants) and their members. A member's role is `owner`, `admin` or `member`. */
87
+ export declare class Orgs extends AdminService {
88
+ list(): Promise<Api>;
89
+ getOrg(slug: string): Promise<Api>;
90
+ create(slug: string, name: string, options?: {
91
+ ownerEmail?: string;
92
+ metadata?: Body;
93
+ }): Promise<Api>;
94
+ update(slug: string, changes: {
95
+ name?: string;
96
+ metadata?: Body;
97
+ }): Promise<Api>;
98
+ remove(slug: string): Promise<Api>;
99
+ /** Add an existing user straight in. */
100
+ addMember(slug: string, member: {
101
+ email: string;
102
+ role?: string;
103
+ }): Promise<Api>;
104
+ setMemberRole(slug: string, userId: string, role: string): Promise<Api>;
105
+ removeMember(slug: string, userId: string): Promise<Api>;
106
+ /** Mail an invitation; `redirectTo` must be one of the environment's allowed redirect URLs. */
107
+ invite(slug: string, invitation: {
108
+ email: string;
109
+ role?: string;
110
+ redirectTo?: string;
111
+ }): Promise<Api>;
112
+ }
113
+ export declare class Invitations extends AdminService {
114
+ /** Pending and past invitations across organizations. */
115
+ list(): Promise<Api>;
116
+ resend(invitationId: string, options?: {
117
+ redirectTo?: string;
118
+ }): Promise<Api>;
119
+ revoke(invitationId: string): Promise<Api>;
120
+ }
121
+ export declare class Sessions extends AdminService {
122
+ /** Active sessions across users. */
123
+ list(options?: {
124
+ limit?: number;
125
+ }): Promise<Api>;
126
+ /** End one session (all its refresh tokens). */
127
+ revoke(family: string): Promise<Api>;
128
+ }
129
+ /** API keys users made for themselves. */
130
+ export declare class ApiKeys extends AdminService {
131
+ list(options?: {
132
+ limit?: number;
133
+ }): Promise<Api>;
134
+ revoke(keyId: string): Promise<Api>;
135
+ }
136
+ export declare class Devices extends AdminService {
137
+ /** Recent devices people signed in from. */
138
+ list(options?: {
139
+ limit?: number;
140
+ }): Promise<Api>;
141
+ }
142
+ /** Events, statistics, identity backup and the hosted pages. */
143
+ export declare class Insight extends AdminService {
144
+ /** Authentication events (sign-ins, sign-ups, resets, MFA…). `failed` for failures only. */
145
+ events(options?: {
146
+ kind?: string;
147
+ failed?: boolean;
148
+ limit?: number;
149
+ }): Promise<Api>;
150
+ /** Counts of users, sign-ins, MFA use and failures. */
151
+ stats(): Promise<Api>;
152
+ /** Every identity (users, organizations, roles, factors) as a document. */
153
+ backup(): Promise<Api>;
154
+ /** Apply the `identities` of a backup. `dryRun` reports what would change. */
155
+ restore(identities: Body, options?: {
156
+ replace?: boolean;
157
+ dryRun?: boolean;
158
+ }): Promise<Api>;
159
+ /** The HTML a hosted sign-in page is served as for the branding being edited (the saved branding when omitted). */
160
+ /** The claims a token profile would put in a token for this user (and organization), without issuing one. */
161
+ previewTokenProfile(profile: Body, userId: string, options?: {
162
+ org?: string;
163
+ }): Promise<Api>;
164
+ hostedSource(page: string, options?: {
165
+ branding?: Body;
166
+ form?: Body;
167
+ }): Promise<Api>;
168
+ }
169
+ export declare class Admin {
170
+ private readonly http;
171
+ readonly environment: string;
172
+ readonly users: Users;
173
+ readonly roles: Roles;
174
+ readonly orgs: Orgs;
175
+ readonly invitations: Invitations;
176
+ readonly sessions: Sessions;
177
+ readonly apiKeys: ApiKeys;
178
+ readonly devices: Devices;
179
+ readonly insight: Insight;
180
+ constructor(http: HttpClient, environment: string);
181
+ /** The same services for another environment the key may manage. */
182
+ withEnvironment(name: string): Admin;
183
+ }
184
+ /** User administration for the client's environment (or `environment`). Needs a secret key. */
185
+ export declare function admin(client: PawabaseClient<any>, environment?: string): Admin;
186
+ export {};
187
+ //# sourceMappingURL=admin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../../src/admin.ts"],"names":[],"mappings":"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"}