onlybase-sdk 0.0.1

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 (3) hide show
  1. package/PUBLISH_NPM.md +120 -0
  2. package/index.ts +155 -0
  3. package/package.json +10 -0
package/PUBLISH_NPM.md ADDED
@@ -0,0 +1,120 @@
1
+ # Publish the SDK to npm (under your account)
2
+
3
+ Publish **without** the private `@onlybase` scope so the package lives under your npm user.
4
+
5
+ ---
6
+
7
+ ## 1. Choose the package name
8
+
9
+ - **Unscoped** (recommended): `onlybase-sdk` — install with `npm install onlybase-sdk`. The name must be free on npm.
10
+ - **Scoped under your user**: `@YOUR_NPM_USERNAME/onlybase-sdk` — install with `npm install @YOUR_NPM_USERNAME/onlybase-sdk`. Replace `YOUR_NPM_USERNAME` with your npm login.
11
+
12
+ Edit `packages/sdk/package.json` and set `"name"` to your choice (see step 3).
13
+
14
+ ---
15
+
16
+ ## 2. Log in to npm
17
+
18
+ If you don’t have an account: [sign up at npmjs.com](https://www.npmjs.com/signup).
19
+
20
+ In a terminal:
21
+
22
+ ```bash
23
+ npm login
24
+ ```
25
+
26
+ Enter your npm **username**, **password**, and **email** when asked. You can use a profile or access token instead of password if you use 2FA.
27
+
28
+ Check you’re logged in:
29
+
30
+ ```bash
31
+ npm whoami
32
+ ```
33
+
34
+ ---
35
+
36
+ ## 2b. If you get "403 - Two-factor authentication required"
37
+
38
+ npm requires **two-factor authentication (2FA)** to publish packages (or a token that can bypass it).
39
+
40
+ **Option A — Enable 2FA (recommended):**
41
+
42
+ 1. Go to [npmjs.com](https://www.npmjs.com) → log in → click your avatar → **Account settings**.
43
+ 2. Under **Security**, enable **Two-Factor Authentication** (auth-only or auth-and-writes).
44
+ 3. Run `npm publish` again. npm will prompt for your one-time code (app or SMS).
45
+
46
+ **Option B — Use an automation token (e.g. for CI):**
47
+
48
+ 1. On npm: **Account settings** → **Access Tokens** → **Generate New Token**.
49
+ 2. Choose **Granular Access Token**; set package access and enable **Bypass 2FA for publish** if you need to publish without a code.
50
+ 3. Use the token when logging in: `npm login` and use the token as the password, or set `NPM_TOKEN` in the environment.
51
+
52
+ After 2FA is enabled or the token is set up, run `npm publish` again from `packages/sdk`.
53
+
54
+ ---
55
+
56
+ ## 3. Set the package name and version
57
+
58
+ From the **repo root**:
59
+
60
+ ```bash
61
+ cd packages/sdk
62
+ ```
63
+
64
+ Edit `package.json`:
65
+
66
+ - Set **name** to your chosen name, e.g.:
67
+ - `"name": "onlybase-sdk"` (unscoped), or
68
+ - `"name": "@YOUR_NPM_USERNAME/onlybase-sdk"` (scoped).
69
+ - Bump **version** if you’ve already published before (e.g. `0.0.2`). For the first publish, `0.0.1` is fine.
70
+
71
+ Optional but recommended for the npm listing:
72
+
73
+ - **description**: short one-liner.
74
+ - **keywords**: e.g. `["onlybase", "backend", "sdk", "realtime", "api"]`.
75
+ - **repository**: your Git URL.
76
+ - **license**: e.g. `"MIT"`.
77
+
78
+ ---
79
+
80
+ ## 4. Publish
81
+
82
+ From **packages/sdk**:
83
+
84
+ ```bash
85
+ npm publish
86
+ ```
87
+
88
+ - **Unscoped** (`onlybase-sdk`): publishes as a public package (no extra flags).
89
+ - **Scoped** (`@youruser/onlybase-sdk`): npm will treat it as restricted by default. To make it public:
90
+
91
+ ```bash
92
+ npm publish --access public
93
+ ```
94
+
95
+ After a short delay the package will appear on [npmjs.com](https://www.npmjs.com) and users can install it with the name you chose.
96
+
97
+ ---
98
+
99
+ ## 5. Update your apps to use the published package
100
+
101
+ Once the package is on npm, you can stop using the workspace alias in apps that use it:
102
+
103
+ - In `apps/dashboard`, `apps/example`, etc., in `package.json` replace:
104
+ - `"@onlybase/sdk": "workspace:*"`
105
+ with
106
+ - `"onlybase-sdk": "^0.0.1"` (or `"@YOUR_NPM_USERNAME/onlybase-sdk": "^0.0.1"`).
107
+
108
+ Then run `bun install` (or `npm install`) and update imports from `@onlybase/sdk` to your published package name (e.g. `onlybase-sdk`).
109
+ If you keep the same export names in the SDK, only the import path changes.
110
+
111
+ ---
112
+
113
+ ## Quick reference
114
+
115
+ | Step | Command / action |
116
+ |------|-------------------|
117
+ | Login | `npm login` then `npm whoami` |
118
+ | Name in package.json | `"onlybase-sdk"` or `"@YOUR_USER/onlybase-sdk"` |
119
+ | Publish (unscoped) | `cd packages/sdk && npm publish` |
120
+ | Publish (scoped, public) | `cd packages/sdk && npm publish --access public` |
package/index.ts ADDED
@@ -0,0 +1,155 @@
1
+ const defaultBaseUrl = 'https://api.onlybase.app';
2
+ const defaultBaseWsUrl = 'wss://api.onlybase.app/ws';
3
+
4
+ type Result<T> = {
5
+ data: T;
6
+ error?: string;
7
+ };
8
+
9
+ /** Payload shape for subscription events: insert, update, delete */
10
+ export type SubscriptionEvent = 'insert' | 'update' | 'delete';
11
+
12
+ /** Message received on subscription; server sends { event, collection, payload } */
13
+ export type SubscriptionMessage = {
14
+ event: string;
15
+ collection: string;
16
+ payload: unknown;
17
+ };
18
+
19
+ function getBaseUrl(baseUrl?: string): string {
20
+ return baseUrl ?? defaultBaseUrl;
21
+ }
22
+
23
+ function getWsUrl(baseUrl?: string): string {
24
+ const base = getBaseUrl(baseUrl);
25
+ try {
26
+ const u = new URL(base);
27
+ u.protocol = u.protocol === 'https:' ? 'wss:' : 'ws:';
28
+ u.pathname = u.pathname.replace(/\/?$/, '') + '/ws';
29
+ return u.toString();
30
+ } catch {
31
+ return defaultBaseWsUrl;
32
+ }
33
+ }
34
+
35
+ function client(apiKey: string, baseUrl?: string) {
36
+ const base = getBaseUrl(baseUrl);
37
+ const headers: Record<string, string> = {
38
+ 'Content-Type': 'application/json',
39
+ 'x-api-key': apiKey,
40
+ };
41
+
42
+ return {
43
+ collection: <T>(name: string) => ({
44
+ async create(data: T | T[]) {
45
+ const response = await fetch(
46
+ `${base}/v1/collections/${encodeURIComponent(name)}/rows`,
47
+ {
48
+ method: 'POST',
49
+ headers,
50
+ body: JSON.stringify(data),
51
+ }
52
+ );
53
+ return response.json() as Promise<Result<T | T[]>>;
54
+ },
55
+ async list(params?: { limit?: number; offset?: number; orderBy?: string; order?: 'asc' | 'desc' }) {
56
+ const { limit = 100, offset = 0, orderBy, order } = params || {};
57
+ const url = new URL(
58
+ `${base}/v1/collections/${encodeURIComponent(name)}/rows`
59
+ );
60
+ url.searchParams.set('limit', String(limit));
61
+ url.searchParams.set('offset', String(offset));
62
+ if (orderBy) url.searchParams.set('order_by', orderBy);
63
+ if (order) url.searchParams.set('order', order);
64
+ const response = await fetch(url.toString(), { method: 'GET', headers });
65
+ return response.json() as Promise<Result<T[]>>;
66
+ },
67
+ async one(id: string): Promise<Result<T>> {
68
+ const response = await fetch(
69
+ `${base}/v1/collections/${encodeURIComponent(name)}/rows/${encodeURIComponent(id)}`,
70
+ { method: 'GET', headers }
71
+ );
72
+ return response.json() as Promise<Result<T>>;
73
+ },
74
+ async update(id: string, data: Partial<T>) {
75
+ const response = await fetch(
76
+ `${base}/v1/collections/${encodeURIComponent(name)}/rows/${encodeURIComponent(id)}`,
77
+ {
78
+ method: 'PATCH',
79
+ headers,
80
+ body: JSON.stringify(data),
81
+ }
82
+ );
83
+ return response.json() as Promise<Result<T>>;
84
+ },
85
+ async delete(id: string) {
86
+ const response = await fetch(
87
+ `${base}/v1/collections/${encodeURIComponent(name)}/rows/${encodeURIComponent(id)}`,
88
+ { method: 'DELETE', headers }
89
+ );
90
+ return response.json() as Promise<Result<{ success: boolean }>>;
91
+ },
92
+
93
+ subscribe(
94
+ events: SubscriptionEvent,
95
+ onMessage: (message: SubscriptionMessage) => void
96
+ ) {
97
+ const wsBase = getWsUrl(baseUrl);
98
+ const url = new URL(wsBase);
99
+ url.searchParams.set('api_key', apiKey);
100
+ url.searchParams.set('collection', name);
101
+ url.searchParams.set('events', events);
102
+
103
+ let ws: WebSocket;
104
+ let closed = false;
105
+ const reconnectDelayMs = 2000;
106
+
107
+ function connect() {
108
+ if (closed) return;
109
+ ws = new WebSocket(url.toString());
110
+
111
+ ws.onmessage = (e) => {
112
+ try {
113
+ const msg = JSON.parse(e.data as string) as SubscriptionMessage;
114
+ if (msg.event && msg.collection !== undefined) {
115
+ onMessage(msg);
116
+ }
117
+ } catch {
118
+ // ignore parse errors
119
+ }
120
+ };
121
+
122
+ ws.onclose = () => {
123
+ if (closed) return;
124
+ setTimeout(connect, reconnectDelayMs);
125
+ };
126
+
127
+ ws.onerror = () => {
128
+ // close will follow; reconnect there
129
+ };
130
+ }
131
+
132
+ connect();
133
+
134
+ return {
135
+ unsubscribe() {
136
+ closed = true;
137
+ if (ws && (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING)) {
138
+ ws.close();
139
+ }
140
+ },
141
+ };
142
+ },
143
+ }),
144
+ };
145
+ }
146
+
147
+ // Factory for creating a configured OnlyBase client
148
+ export const OnlyBase = client;
149
+
150
+ // Convenience alias so you can do: only(apiKey, baseUrl).collection('users').list()
151
+ export const only = client;
152
+
153
+ export default OnlyBase;
154
+
155
+ export type OnlyBaseClient = ReturnType<typeof client>;
package/package.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "onlybase-sdk",
3
+ "version": "0.0.1",
4
+ "description": "JavaScript SDK for OnlyBase: collections, rows, and real-time subscriptions",
5
+ "type": "module",
6
+ "main": "index.ts",
7
+ "types": "index.ts",
8
+ "keywords": ["onlybase", "backend", "sdk", "realtime", "api", "collections"],
9
+ "license": "MIT"
10
+ }