@picobase_app/client 0.1.0 → 0.1.2
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.
- package/README.md +72 -5
- package/dist/index.d.mts +62 -2
- package/dist/index.d.ts +62 -2
- package/dist/index.js +176 -6
- package/dist/index.mjs +172 -6
- package/package.json +13 -3
package/README.md
CHANGED
|
@@ -145,6 +145,39 @@ const unsub = await pb.realtime.subscribe('posts', (event) => {
|
|
|
145
145
|
await pb.realtime.disconnectAll()
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
+
## RPC (Remote Procedure Calls)
|
|
149
|
+
|
|
150
|
+
Call custom server-side functions using the `.rpc()` method. This is especially useful for Supabase migrations.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// Simple RPC call
|
|
154
|
+
const result = await pb.rpc('calculate_cart_total', {
|
|
155
|
+
cart_id: '123'
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
// Complex RPC with typed response
|
|
159
|
+
interface DashboardStats {
|
|
160
|
+
posts: number
|
|
161
|
+
comments: number
|
|
162
|
+
followers: number
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const stats = await pb.rpc<DashboardStats>('get_dashboard_stats', {
|
|
166
|
+
user_id: currentUser.id
|
|
167
|
+
})
|
|
168
|
+
// stats.posts, stats.comments, stats.followers are typed!
|
|
169
|
+
|
|
170
|
+
// Common patterns
|
|
171
|
+
await pb.rpc('increment_views', { post_id: '123' })
|
|
172
|
+
const results = await pb.rpc('search_products', {
|
|
173
|
+
query: 'laptop',
|
|
174
|
+
min_price: 500,
|
|
175
|
+
category: 'electronics'
|
|
176
|
+
})
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
RPC calls are mapped to custom PocketBase endpoints at `/api/rpc/{functionName}`. You'll need to implement these routes in your PocketBase instance. See the [PocketBase routing docs](https://pocketbase.io/docs/js-routing/) for details.
|
|
180
|
+
|
|
148
181
|
## File Storage
|
|
149
182
|
|
|
150
183
|
PocketBase stores files as fields on records. Use the storage module to get URLs.
|
|
@@ -197,20 +230,54 @@ const pb = createClient('https://myapp.picobase.com', 'pbk_...', {
|
|
|
197
230
|
|
|
198
231
|
### Error handling
|
|
199
232
|
|
|
233
|
+
Every SDK error includes a `code` and `fix` property with actionable suggestions:
|
|
234
|
+
|
|
200
235
|
```typescript
|
|
201
|
-
import {
|
|
236
|
+
import {
|
|
237
|
+
PicoBaseError,
|
|
238
|
+
AuthorizationError,
|
|
239
|
+
InstanceUnavailableError,
|
|
240
|
+
CollectionNotFoundError,
|
|
241
|
+
RecordNotFoundError,
|
|
242
|
+
ConfigurationError,
|
|
243
|
+
RpcError,
|
|
244
|
+
} from '@picobase_app/client'
|
|
202
245
|
|
|
203
246
|
try {
|
|
204
247
|
await pb.collection('posts').getList()
|
|
205
248
|
} catch (err) {
|
|
206
|
-
if (err instanceof
|
|
207
|
-
//
|
|
208
|
-
|
|
209
|
-
//
|
|
249
|
+
if (err instanceof PicoBaseError) {
|
|
250
|
+
console.log(err.message) // "Collection 'posts' not found."
|
|
251
|
+
console.log(err.code) // "COLLECTION_NOT_FOUND"
|
|
252
|
+
console.log(err.fix) // "Make sure the collection 'posts' exists..."
|
|
210
253
|
}
|
|
211
254
|
}
|
|
212
255
|
```
|
|
213
256
|
|
|
257
|
+
**Error types:**
|
|
258
|
+
|
|
259
|
+
| Error | Code | When |
|
|
260
|
+
|---|---|---|
|
|
261
|
+
| `ConfigurationError` | `CONFIGURATION_ERROR` | Missing URL, API key, or bad config |
|
|
262
|
+
| `AuthorizationError` | `UNAUTHORIZED` | Invalid or missing API key |
|
|
263
|
+
| `CollectionNotFoundError` | `COLLECTION_NOT_FOUND` | Collection doesn't exist |
|
|
264
|
+
| `RecordNotFoundError` | `RECORD_NOT_FOUND` | Record ID not found |
|
|
265
|
+
| `InstanceUnavailableError` | `INSTANCE_UNAVAILABLE` | Instance down after retries |
|
|
266
|
+
| `RpcError` | `RPC_ERROR` | RPC function call failed (includes endpoint-specific fix hints) |
|
|
267
|
+
| `RequestError` | `REQUEST_FAILED` | Generic HTTP error (includes status-specific fix hints) |
|
|
268
|
+
|
|
269
|
+
### Typed collections with `picobase typegen`
|
|
270
|
+
|
|
271
|
+
Run `picobase typegen` to generate types from your schema. The generated file includes a typed client:
|
|
272
|
+
|
|
273
|
+
```typescript
|
|
274
|
+
import { pb } from './src/types/picobase'
|
|
275
|
+
|
|
276
|
+
// Collection names autocomplete, record fields are typed
|
|
277
|
+
const result = await pb.collection('posts').getList(1, 20)
|
|
278
|
+
result.items[0].title // string — fully typed!
|
|
279
|
+
```
|
|
280
|
+
|
|
214
281
|
## API Reference
|
|
215
282
|
|
|
216
283
|
### `createClient(url, apiKey, options?)`
|
package/dist/index.d.mts
CHANGED
|
@@ -410,6 +410,33 @@ declare class PicoBaseClient {
|
|
|
410
410
|
* Proxies to PocketBase's send() method.
|
|
411
411
|
*/
|
|
412
412
|
send<T = unknown>(path: string, options?: SendOptions): Promise<T>;
|
|
413
|
+
/**
|
|
414
|
+
* Call a remote procedure (RPC) - a convenience method for calling custom API endpoints.
|
|
415
|
+
*
|
|
416
|
+
* Maps Supabase-style RPC calls to PicoBase custom endpoints:
|
|
417
|
+
* - `pb.rpc('my_function', params)` → `POST /api/rpc/my_function` with params as body
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* // Simple RPC call
|
|
422
|
+
* const result = await pb.rpc('calculate_total', { cart_id: '123' })
|
|
423
|
+
*
|
|
424
|
+
* // Complex RPC with typed response
|
|
425
|
+
* interface DashboardStats {
|
|
426
|
+
* posts: number
|
|
427
|
+
* comments: number
|
|
428
|
+
* followers: number
|
|
429
|
+
* }
|
|
430
|
+
* const stats = await pb.rpc<DashboardStats>('get_dashboard_stats', {
|
|
431
|
+
* user_id: currentUser.id
|
|
432
|
+
* })
|
|
433
|
+
* ```
|
|
434
|
+
*
|
|
435
|
+
* @param functionName The name of the RPC function to call
|
|
436
|
+
* @param params Optional parameters to pass to the function
|
|
437
|
+
* @returns The function result
|
|
438
|
+
*/
|
|
439
|
+
rpc<T = unknown>(functionName: string, params?: Record<string, unknown>): Promise<T>;
|
|
413
440
|
/**
|
|
414
441
|
* Get the current auth token (if signed in), or empty string.
|
|
415
442
|
*/
|
|
@@ -462,12 +489,21 @@ declare function createClient(url: string, apiKey: string, options?: PicoBaseCli
|
|
|
462
489
|
|
|
463
490
|
/**
|
|
464
491
|
* Base error class for all PicoBase SDK errors.
|
|
492
|
+
*
|
|
493
|
+
* Every error includes a `code` for programmatic handling and a `fix`
|
|
494
|
+
* suggestion so developers can resolve issues without digging through docs.
|
|
465
495
|
*/
|
|
466
496
|
declare class PicoBaseError extends Error {
|
|
467
497
|
readonly code: string;
|
|
468
498
|
readonly status?: number | undefined;
|
|
469
499
|
readonly details?: unknown | undefined;
|
|
470
|
-
|
|
500
|
+
/** Actionable suggestion for how to fix this error. */
|
|
501
|
+
readonly fix?: string | undefined;
|
|
502
|
+
constructor(message: string, code: string, status?: number | undefined, details?: unknown | undefined,
|
|
503
|
+
/** Actionable suggestion for how to fix this error. */
|
|
504
|
+
fix?: string | undefined);
|
|
505
|
+
/** Formatted error string including fix suggestion. */
|
|
506
|
+
toString(): string;
|
|
471
507
|
}
|
|
472
508
|
/**
|
|
473
509
|
* Thrown when the instance is not running and cold-start retries are exhausted.
|
|
@@ -481,11 +517,35 @@ declare class InstanceUnavailableError extends PicoBaseError {
|
|
|
481
517
|
declare class AuthorizationError extends PicoBaseError {
|
|
482
518
|
constructor(message?: string);
|
|
483
519
|
}
|
|
520
|
+
/**
|
|
521
|
+
* Thrown when a collection is not found.
|
|
522
|
+
*/
|
|
523
|
+
declare class CollectionNotFoundError extends PicoBaseError {
|
|
524
|
+
constructor(collectionName: string);
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Thrown when a record is not found.
|
|
528
|
+
*/
|
|
529
|
+
declare class RecordNotFoundError extends PicoBaseError {
|
|
530
|
+
constructor(collectionName: string, recordId: string);
|
|
531
|
+
}
|
|
484
532
|
/**
|
|
485
533
|
* Thrown when a PocketBase API request fails.
|
|
486
534
|
*/
|
|
487
535
|
declare class RequestError extends PicoBaseError {
|
|
488
536
|
constructor(message: string, status: number, details?: unknown);
|
|
489
537
|
}
|
|
538
|
+
/**
|
|
539
|
+
* Thrown when the SDK is misconfigured (bad URL, missing params, etc.).
|
|
540
|
+
*/
|
|
541
|
+
declare class ConfigurationError extends PicoBaseError {
|
|
542
|
+
constructor(message: string, fix: string);
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Thrown when an RPC (remote procedure call) fails.
|
|
546
|
+
*/
|
|
547
|
+
declare class RpcError extends PicoBaseError {
|
|
548
|
+
constructor(functionName: string, status: number, details?: unknown);
|
|
549
|
+
}
|
|
490
550
|
|
|
491
|
-
export { type AuthEvent, type AuthResponse, type AuthStateChange, type AuthStateChangeCallback, AuthorizationError, type FileOptions, InstanceUnavailableError, type ListOptions, type OAuthSignInOptions, PicoBaseAuth, PicoBaseClient, type PicoBaseClientOptions, PicoBaseCollection, PicoBaseError, PicoBaseRealtime, PicoBaseStorage, type RealtimeAction, type RealtimeCallback, type RecordQueryOptions, RequestError, type SignInOptions, type SignUpOptions, type UnsubscribeFunc, createClient };
|
|
551
|
+
export { type AuthEvent, type AuthResponse, type AuthStateChange, type AuthStateChangeCallback, AuthorizationError, CollectionNotFoundError, ConfigurationError, type FileOptions, InstanceUnavailableError, type ListOptions, type OAuthSignInOptions, PicoBaseAuth, PicoBaseClient, type PicoBaseClientOptions, PicoBaseCollection, PicoBaseError, PicoBaseRealtime, PicoBaseStorage, type RealtimeAction, type RealtimeCallback, RecordNotFoundError, type RecordQueryOptions, RequestError, RpcError, type SignInOptions, type SignUpOptions, type UnsubscribeFunc, createClient };
|
package/dist/index.d.ts
CHANGED
|
@@ -410,6 +410,33 @@ declare class PicoBaseClient {
|
|
|
410
410
|
* Proxies to PocketBase's send() method.
|
|
411
411
|
*/
|
|
412
412
|
send<T = unknown>(path: string, options?: SendOptions): Promise<T>;
|
|
413
|
+
/**
|
|
414
|
+
* Call a remote procedure (RPC) - a convenience method for calling custom API endpoints.
|
|
415
|
+
*
|
|
416
|
+
* Maps Supabase-style RPC calls to PicoBase custom endpoints:
|
|
417
|
+
* - `pb.rpc('my_function', params)` → `POST /api/rpc/my_function` with params as body
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```ts
|
|
421
|
+
* // Simple RPC call
|
|
422
|
+
* const result = await pb.rpc('calculate_total', { cart_id: '123' })
|
|
423
|
+
*
|
|
424
|
+
* // Complex RPC with typed response
|
|
425
|
+
* interface DashboardStats {
|
|
426
|
+
* posts: number
|
|
427
|
+
* comments: number
|
|
428
|
+
* followers: number
|
|
429
|
+
* }
|
|
430
|
+
* const stats = await pb.rpc<DashboardStats>('get_dashboard_stats', {
|
|
431
|
+
* user_id: currentUser.id
|
|
432
|
+
* })
|
|
433
|
+
* ```
|
|
434
|
+
*
|
|
435
|
+
* @param functionName The name of the RPC function to call
|
|
436
|
+
* @param params Optional parameters to pass to the function
|
|
437
|
+
* @returns The function result
|
|
438
|
+
*/
|
|
439
|
+
rpc<T = unknown>(functionName: string, params?: Record<string, unknown>): Promise<T>;
|
|
413
440
|
/**
|
|
414
441
|
* Get the current auth token (if signed in), or empty string.
|
|
415
442
|
*/
|
|
@@ -462,12 +489,21 @@ declare function createClient(url: string, apiKey: string, options?: PicoBaseCli
|
|
|
462
489
|
|
|
463
490
|
/**
|
|
464
491
|
* Base error class for all PicoBase SDK errors.
|
|
492
|
+
*
|
|
493
|
+
* Every error includes a `code` for programmatic handling and a `fix`
|
|
494
|
+
* suggestion so developers can resolve issues without digging through docs.
|
|
465
495
|
*/
|
|
466
496
|
declare class PicoBaseError extends Error {
|
|
467
497
|
readonly code: string;
|
|
468
498
|
readonly status?: number | undefined;
|
|
469
499
|
readonly details?: unknown | undefined;
|
|
470
|
-
|
|
500
|
+
/** Actionable suggestion for how to fix this error. */
|
|
501
|
+
readonly fix?: string | undefined;
|
|
502
|
+
constructor(message: string, code: string, status?: number | undefined, details?: unknown | undefined,
|
|
503
|
+
/** Actionable suggestion for how to fix this error. */
|
|
504
|
+
fix?: string | undefined);
|
|
505
|
+
/** Formatted error string including fix suggestion. */
|
|
506
|
+
toString(): string;
|
|
471
507
|
}
|
|
472
508
|
/**
|
|
473
509
|
* Thrown when the instance is not running and cold-start retries are exhausted.
|
|
@@ -481,11 +517,35 @@ declare class InstanceUnavailableError extends PicoBaseError {
|
|
|
481
517
|
declare class AuthorizationError extends PicoBaseError {
|
|
482
518
|
constructor(message?: string);
|
|
483
519
|
}
|
|
520
|
+
/**
|
|
521
|
+
* Thrown when a collection is not found.
|
|
522
|
+
*/
|
|
523
|
+
declare class CollectionNotFoundError extends PicoBaseError {
|
|
524
|
+
constructor(collectionName: string);
|
|
525
|
+
}
|
|
526
|
+
/**
|
|
527
|
+
* Thrown when a record is not found.
|
|
528
|
+
*/
|
|
529
|
+
declare class RecordNotFoundError extends PicoBaseError {
|
|
530
|
+
constructor(collectionName: string, recordId: string);
|
|
531
|
+
}
|
|
484
532
|
/**
|
|
485
533
|
* Thrown when a PocketBase API request fails.
|
|
486
534
|
*/
|
|
487
535
|
declare class RequestError extends PicoBaseError {
|
|
488
536
|
constructor(message: string, status: number, details?: unknown);
|
|
489
537
|
}
|
|
538
|
+
/**
|
|
539
|
+
* Thrown when the SDK is misconfigured (bad URL, missing params, etc.).
|
|
540
|
+
*/
|
|
541
|
+
declare class ConfigurationError extends PicoBaseError {
|
|
542
|
+
constructor(message: string, fix: string);
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Thrown when an RPC (remote procedure call) fails.
|
|
546
|
+
*/
|
|
547
|
+
declare class RpcError extends PicoBaseError {
|
|
548
|
+
constructor(functionName: string, status: number, details?: unknown);
|
|
549
|
+
}
|
|
490
550
|
|
|
491
|
-
export { type AuthEvent, type AuthResponse, type AuthStateChange, type AuthStateChangeCallback, AuthorizationError, type FileOptions, InstanceUnavailableError, type ListOptions, type OAuthSignInOptions, PicoBaseAuth, PicoBaseClient, type PicoBaseClientOptions, PicoBaseCollection, PicoBaseError, PicoBaseRealtime, PicoBaseStorage, type RealtimeAction, type RealtimeCallback, type RecordQueryOptions, RequestError, type SignInOptions, type SignUpOptions, type UnsubscribeFunc, createClient };
|
|
551
|
+
export { type AuthEvent, type AuthResponse, type AuthStateChange, type AuthStateChangeCallback, AuthorizationError, CollectionNotFoundError, ConfigurationError, type FileOptions, InstanceUnavailableError, type ListOptions, type OAuthSignInOptions, PicoBaseAuth, PicoBaseClient, type PicoBaseClientOptions, PicoBaseCollection, PicoBaseError, PicoBaseRealtime, PicoBaseStorage, type RealtimeAction, type RealtimeCallback, RecordNotFoundError, type RecordQueryOptions, RequestError, RpcError, type SignInOptions, type SignUpOptions, type UnsubscribeFunc, createClient };
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AuthorizationError: () => AuthorizationError,
|
|
34
|
+
CollectionNotFoundError: () => CollectionNotFoundError,
|
|
35
|
+
ConfigurationError: () => ConfigurationError,
|
|
34
36
|
InstanceUnavailableError: () => InstanceUnavailableError,
|
|
35
37
|
PicoBaseAuth: () => PicoBaseAuth,
|
|
36
38
|
PicoBaseClient: () => PicoBaseClient,
|
|
@@ -38,7 +40,9 @@ __export(index_exports, {
|
|
|
38
40
|
PicoBaseError: () => PicoBaseError,
|
|
39
41
|
PicoBaseRealtime: () => PicoBaseRealtime,
|
|
40
42
|
PicoBaseStorage: () => PicoBaseStorage,
|
|
43
|
+
RecordNotFoundError: () => RecordNotFoundError,
|
|
41
44
|
RequestError: () => RequestError,
|
|
45
|
+
RpcError: () => RpcError,
|
|
42
46
|
createClient: () => createClient
|
|
43
47
|
});
|
|
44
48
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -380,32 +384,126 @@ var PicoBaseStorage = class {
|
|
|
380
384
|
|
|
381
385
|
// src/errors.ts
|
|
382
386
|
var PicoBaseError = class extends Error {
|
|
383
|
-
constructor(message, code, status, details) {
|
|
387
|
+
constructor(message, code, status, details, fix) {
|
|
384
388
|
super(message);
|
|
385
389
|
this.code = code;
|
|
386
390
|
this.status = status;
|
|
387
391
|
this.details = details;
|
|
392
|
+
this.fix = fix;
|
|
388
393
|
this.name = "PicoBaseError";
|
|
389
394
|
}
|
|
395
|
+
/** Formatted error string including fix suggestion. */
|
|
396
|
+
toString() {
|
|
397
|
+
let s = `${this.name} [${this.code}]: ${this.message}`;
|
|
398
|
+
if (this.fix) s += `
|
|
399
|
+
Fix: ${this.fix}`;
|
|
400
|
+
return s;
|
|
401
|
+
}
|
|
390
402
|
};
|
|
391
403
|
var InstanceUnavailableError = class extends PicoBaseError {
|
|
392
404
|
constructor(message = "Instance is not available. It may be stopped or starting up.") {
|
|
393
|
-
super(
|
|
405
|
+
super(
|
|
406
|
+
message,
|
|
407
|
+
"INSTANCE_UNAVAILABLE",
|
|
408
|
+
503,
|
|
409
|
+
void 0,
|
|
410
|
+
"Check your instance status in the PicoBase dashboard, or wait a few seconds and retry. If this persists, your instance may have been stopped \u2014 restart it with `picobase status`."
|
|
411
|
+
);
|
|
394
412
|
this.name = "InstanceUnavailableError";
|
|
395
413
|
}
|
|
396
414
|
};
|
|
397
415
|
var AuthorizationError = class extends PicoBaseError {
|
|
398
416
|
constructor(message = "Invalid or missing API key.") {
|
|
399
|
-
super(
|
|
417
|
+
super(
|
|
418
|
+
message,
|
|
419
|
+
"UNAUTHORIZED",
|
|
420
|
+
401,
|
|
421
|
+
void 0,
|
|
422
|
+
'Make sure PICOBASE_API_KEY is set in your .env file and matches a valid key from your dashboard. Keys start with "pbk_". You can generate a new key at https://picobase.com/dashboard.'
|
|
423
|
+
);
|
|
400
424
|
this.name = "AuthorizationError";
|
|
401
425
|
}
|
|
402
426
|
};
|
|
427
|
+
var CollectionNotFoundError = class extends PicoBaseError {
|
|
428
|
+
constructor(collectionName) {
|
|
429
|
+
super(
|
|
430
|
+
`Collection "${collectionName}" not found.`,
|
|
431
|
+
"COLLECTION_NOT_FOUND",
|
|
432
|
+
404,
|
|
433
|
+
{ collection: collectionName },
|
|
434
|
+
`Make sure the collection "${collectionName}" exists in your PicoBase instance. Collections are auto-created when you first write data, or you can create them manually in the PicoBase dashboard under Collections.`
|
|
435
|
+
);
|
|
436
|
+
this.name = "CollectionNotFoundError";
|
|
437
|
+
}
|
|
438
|
+
};
|
|
439
|
+
var RecordNotFoundError = class extends PicoBaseError {
|
|
440
|
+
constructor(collectionName, recordId) {
|
|
441
|
+
super(
|
|
442
|
+
`Record "${recordId}" not found in collection "${collectionName}".`,
|
|
443
|
+
"RECORD_NOT_FOUND",
|
|
444
|
+
404,
|
|
445
|
+
{ collection: collectionName, recordId },
|
|
446
|
+
'Check that the record ID is correct. IDs are 15-character alphanumeric strings (e.g., "abc123def456789").'
|
|
447
|
+
);
|
|
448
|
+
this.name = "RecordNotFoundError";
|
|
449
|
+
}
|
|
450
|
+
};
|
|
403
451
|
var RequestError = class extends PicoBaseError {
|
|
404
452
|
constructor(message, status, details) {
|
|
405
|
-
|
|
453
|
+
const fix = requestErrorFix(status, message);
|
|
454
|
+
super(message, "REQUEST_FAILED", status, details, fix);
|
|
406
455
|
this.name = "RequestError";
|
|
407
456
|
}
|
|
408
457
|
};
|
|
458
|
+
var ConfigurationError = class extends PicoBaseError {
|
|
459
|
+
constructor(message, fix) {
|
|
460
|
+
super(message, "CONFIGURATION_ERROR", void 0, void 0, fix);
|
|
461
|
+
this.name = "ConfigurationError";
|
|
462
|
+
}
|
|
463
|
+
};
|
|
464
|
+
var RpcError = class extends PicoBaseError {
|
|
465
|
+
constructor(functionName, status, details) {
|
|
466
|
+
const fix = rpcErrorFix(functionName, status);
|
|
467
|
+
super(
|
|
468
|
+
`RPC function "${functionName}" failed.`,
|
|
469
|
+
"RPC_ERROR",
|
|
470
|
+
status,
|
|
471
|
+
details,
|
|
472
|
+
fix
|
|
473
|
+
);
|
|
474
|
+
this.name = "RpcError";
|
|
475
|
+
}
|
|
476
|
+
};
|
|
477
|
+
function rpcErrorFix(functionName, status) {
|
|
478
|
+
if (status === 404) {
|
|
479
|
+
return `The RPC endpoint "/api/rpc/${functionName}" does not exist. Create a custom route in your PocketBase instance to handle this RPC call. See: https://pocketbase.io/docs/js-routing/`;
|
|
480
|
+
}
|
|
481
|
+
if (status === 400) {
|
|
482
|
+
return "Check the parameters you are passing to this RPC function. The function may be expecting different parameters or types.";
|
|
483
|
+
}
|
|
484
|
+
if (status === 403) {
|
|
485
|
+
return "You don't have permission to call this RPC function. Check the authentication requirements for this endpoint in your PocketBase routes.";
|
|
486
|
+
}
|
|
487
|
+
return "Check your PicoBase instance logs for details about this RPC error. Ensure the custom route is correctly implemented in your PocketBase setup.";
|
|
488
|
+
}
|
|
489
|
+
function requestErrorFix(status, message) {
|
|
490
|
+
switch (status) {
|
|
491
|
+
case 400:
|
|
492
|
+
return "Check the data you are sending \u2014 a required field may be missing or have the wrong type. Run `picobase typegen` to regenerate types and check your field names.";
|
|
493
|
+
case 403:
|
|
494
|
+
return "You don't have permission for this action. Check your collection API rules in the dashboard. By default, only authenticated users can read/write records.";
|
|
495
|
+
case 404:
|
|
496
|
+
if (message.toLowerCase().includes("collection"))
|
|
497
|
+
return "This collection does not exist yet. Write a record to auto-create it, or create it in the dashboard.";
|
|
498
|
+
return "The requested resource was not found. Double-check IDs and collection names.";
|
|
499
|
+
case 413:
|
|
500
|
+
return "The request payload is too large. Check file upload size limits in your instance settings.";
|
|
501
|
+
case 429:
|
|
502
|
+
return "Too many requests. Add a short delay between requests or implement client-side caching.";
|
|
503
|
+
default:
|
|
504
|
+
return "If this error persists, check your PicoBase dashboard for instance health and logs.";
|
|
505
|
+
}
|
|
506
|
+
}
|
|
409
507
|
|
|
410
508
|
// src/client.ts
|
|
411
509
|
var DEFAULT_OPTIONS = {
|
|
@@ -415,6 +513,24 @@ var DEFAULT_OPTIONS = {
|
|
|
415
513
|
};
|
|
416
514
|
var PicoBaseClient = class {
|
|
417
515
|
constructor(url, apiKey, options = {}) {
|
|
516
|
+
if (!url) {
|
|
517
|
+
throw new ConfigurationError(
|
|
518
|
+
"PicoBase URL is required.",
|
|
519
|
+
'Pass the URL as the first argument: createClient("https://myapp.picobase.com", "pbk_...") or set PICOBASE_URL in your .env file.'
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
if (!apiKey) {
|
|
523
|
+
throw new ConfigurationError(
|
|
524
|
+
"PicoBase API key is required.",
|
|
525
|
+
'Pass the API key as the second argument: createClient("https://...", "pbk_your_key") or set PICOBASE_API_KEY in your .env file. Get a key from your dashboard.'
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
529
|
+
throw new ConfigurationError(
|
|
530
|
+
`Invalid URL: "${url}". Must start with http:// or https://.`,
|
|
531
|
+
`Use the full URL: createClient("https://${url}", "...")`
|
|
532
|
+
);
|
|
533
|
+
}
|
|
418
534
|
this.apiKey = apiKey;
|
|
419
535
|
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
420
536
|
const baseUrl = url.replace(/\/+$/, "");
|
|
@@ -452,6 +568,44 @@ var PicoBaseClient = class {
|
|
|
452
568
|
async send(path, options) {
|
|
453
569
|
return this.pb.send(path, options ?? {});
|
|
454
570
|
}
|
|
571
|
+
/**
|
|
572
|
+
* Call a remote procedure (RPC) - a convenience method for calling custom API endpoints.
|
|
573
|
+
*
|
|
574
|
+
* Maps Supabase-style RPC calls to PicoBase custom endpoints:
|
|
575
|
+
* - `pb.rpc('my_function', params)` → `POST /api/rpc/my_function` with params as body
|
|
576
|
+
*
|
|
577
|
+
* @example
|
|
578
|
+
* ```ts
|
|
579
|
+
* // Simple RPC call
|
|
580
|
+
* const result = await pb.rpc('calculate_total', { cart_id: '123' })
|
|
581
|
+
*
|
|
582
|
+
* // Complex RPC with typed response
|
|
583
|
+
* interface DashboardStats {
|
|
584
|
+
* posts: number
|
|
585
|
+
* comments: number
|
|
586
|
+
* followers: number
|
|
587
|
+
* }
|
|
588
|
+
* const stats = await pb.rpc<DashboardStats>('get_dashboard_stats', {
|
|
589
|
+
* user_id: currentUser.id
|
|
590
|
+
* })
|
|
591
|
+
* ```
|
|
592
|
+
*
|
|
593
|
+
* @param functionName The name of the RPC function to call
|
|
594
|
+
* @param params Optional parameters to pass to the function
|
|
595
|
+
* @returns The function result
|
|
596
|
+
*/
|
|
597
|
+
async rpc(functionName, params) {
|
|
598
|
+
try {
|
|
599
|
+
return await this.send(`/api/rpc/${functionName}`, {
|
|
600
|
+
method: "POST",
|
|
601
|
+
body: params ?? {}
|
|
602
|
+
});
|
|
603
|
+
} catch (err) {
|
|
604
|
+
const status = err?.status ?? 500;
|
|
605
|
+
const details = err?.data;
|
|
606
|
+
throw new RpcError(functionName, status, details);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
455
609
|
/**
|
|
456
610
|
* Get the current auth token (if signed in), or empty string.
|
|
457
611
|
*/
|
|
@@ -493,6 +647,13 @@ var PicoBaseClient = class {
|
|
|
493
647
|
throw new AuthorizationError();
|
|
494
648
|
}
|
|
495
649
|
}
|
|
650
|
+
if (status === 404) {
|
|
651
|
+
const msg = err?.message ?? "";
|
|
652
|
+
if (msg.toLowerCase().includes("missing collection") || msg.toLowerCase().includes("not found collection")) {
|
|
653
|
+
const match = msg.match(/["']([^"']+)["']/);
|
|
654
|
+
throw new CollectionNotFoundError(match?.[1] ?? "unknown");
|
|
655
|
+
}
|
|
656
|
+
}
|
|
496
657
|
throw err;
|
|
497
658
|
}
|
|
498
659
|
}
|
|
@@ -508,8 +669,13 @@ function createClient(urlOrOptions, apiKeyOrUndefined, options) {
|
|
|
508
669
|
const url = env.PICOBASE_URL || env.NEXT_PUBLIC_PICOBASE_URL;
|
|
509
670
|
const apiKey = env.PICOBASE_API_KEY || env.NEXT_PUBLIC_PICOBASE_API_KEY;
|
|
510
671
|
if (!url || !apiKey) {
|
|
511
|
-
|
|
512
|
-
|
|
672
|
+
const missing = [
|
|
673
|
+
!url && "PICOBASE_URL (or NEXT_PUBLIC_PICOBASE_URL)",
|
|
674
|
+
!apiKey && "PICOBASE_API_KEY (or NEXT_PUBLIC_PICOBASE_API_KEY)"
|
|
675
|
+
].filter(Boolean).join(" and ");
|
|
676
|
+
throw new ConfigurationError(
|
|
677
|
+
`Missing environment variable${!url && !apiKey ? "s" : ""}: ${missing}`,
|
|
678
|
+
"Add them to your .env.local file:\n\n PICOBASE_URL=https://your-app.picobase.com\n PICOBASE_API_KEY=pbk_your_key_here\n\nOr for Next.js (client-side access), prefix with NEXT_PUBLIC_:\n\n NEXT_PUBLIC_PICOBASE_URL=https://your-app.picobase.com\n NEXT_PUBLIC_PICOBASE_API_KEY=pbk_your_key_here\n\nGet your URL and API key from: https://picobase.com/dashboard\nOr run: picobase init"
|
|
513
679
|
);
|
|
514
680
|
}
|
|
515
681
|
return new PicoBaseClient(url, apiKey, urlOrOptions);
|
|
@@ -519,6 +685,8 @@ function createClient(urlOrOptions, apiKeyOrUndefined, options) {
|
|
|
519
685
|
// Annotate the CommonJS export names for ESM import in node:
|
|
520
686
|
0 && (module.exports = {
|
|
521
687
|
AuthorizationError,
|
|
688
|
+
CollectionNotFoundError,
|
|
689
|
+
ConfigurationError,
|
|
522
690
|
InstanceUnavailableError,
|
|
523
691
|
PicoBaseAuth,
|
|
524
692
|
PicoBaseClient,
|
|
@@ -526,6 +694,8 @@ function createClient(urlOrOptions, apiKeyOrUndefined, options) {
|
|
|
526
694
|
PicoBaseError,
|
|
527
695
|
PicoBaseRealtime,
|
|
528
696
|
PicoBaseStorage,
|
|
697
|
+
RecordNotFoundError,
|
|
529
698
|
RequestError,
|
|
699
|
+
RpcError,
|
|
530
700
|
createClient
|
|
531
701
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -335,32 +335,126 @@ var PicoBaseStorage = class {
|
|
|
335
335
|
|
|
336
336
|
// src/errors.ts
|
|
337
337
|
var PicoBaseError = class extends Error {
|
|
338
|
-
constructor(message, code, status, details) {
|
|
338
|
+
constructor(message, code, status, details, fix) {
|
|
339
339
|
super(message);
|
|
340
340
|
this.code = code;
|
|
341
341
|
this.status = status;
|
|
342
342
|
this.details = details;
|
|
343
|
+
this.fix = fix;
|
|
343
344
|
this.name = "PicoBaseError";
|
|
344
345
|
}
|
|
346
|
+
/** Formatted error string including fix suggestion. */
|
|
347
|
+
toString() {
|
|
348
|
+
let s = `${this.name} [${this.code}]: ${this.message}`;
|
|
349
|
+
if (this.fix) s += `
|
|
350
|
+
Fix: ${this.fix}`;
|
|
351
|
+
return s;
|
|
352
|
+
}
|
|
345
353
|
};
|
|
346
354
|
var InstanceUnavailableError = class extends PicoBaseError {
|
|
347
355
|
constructor(message = "Instance is not available. It may be stopped or starting up.") {
|
|
348
|
-
super(
|
|
356
|
+
super(
|
|
357
|
+
message,
|
|
358
|
+
"INSTANCE_UNAVAILABLE",
|
|
359
|
+
503,
|
|
360
|
+
void 0,
|
|
361
|
+
"Check your instance status in the PicoBase dashboard, or wait a few seconds and retry. If this persists, your instance may have been stopped \u2014 restart it with `picobase status`."
|
|
362
|
+
);
|
|
349
363
|
this.name = "InstanceUnavailableError";
|
|
350
364
|
}
|
|
351
365
|
};
|
|
352
366
|
var AuthorizationError = class extends PicoBaseError {
|
|
353
367
|
constructor(message = "Invalid or missing API key.") {
|
|
354
|
-
super(
|
|
368
|
+
super(
|
|
369
|
+
message,
|
|
370
|
+
"UNAUTHORIZED",
|
|
371
|
+
401,
|
|
372
|
+
void 0,
|
|
373
|
+
'Make sure PICOBASE_API_KEY is set in your .env file and matches a valid key from your dashboard. Keys start with "pbk_". You can generate a new key at https://picobase.com/dashboard.'
|
|
374
|
+
);
|
|
355
375
|
this.name = "AuthorizationError";
|
|
356
376
|
}
|
|
357
377
|
};
|
|
378
|
+
var CollectionNotFoundError = class extends PicoBaseError {
|
|
379
|
+
constructor(collectionName) {
|
|
380
|
+
super(
|
|
381
|
+
`Collection "${collectionName}" not found.`,
|
|
382
|
+
"COLLECTION_NOT_FOUND",
|
|
383
|
+
404,
|
|
384
|
+
{ collection: collectionName },
|
|
385
|
+
`Make sure the collection "${collectionName}" exists in your PicoBase instance. Collections are auto-created when you first write data, or you can create them manually in the PicoBase dashboard under Collections.`
|
|
386
|
+
);
|
|
387
|
+
this.name = "CollectionNotFoundError";
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
var RecordNotFoundError = class extends PicoBaseError {
|
|
391
|
+
constructor(collectionName, recordId) {
|
|
392
|
+
super(
|
|
393
|
+
`Record "${recordId}" not found in collection "${collectionName}".`,
|
|
394
|
+
"RECORD_NOT_FOUND",
|
|
395
|
+
404,
|
|
396
|
+
{ collection: collectionName, recordId },
|
|
397
|
+
'Check that the record ID is correct. IDs are 15-character alphanumeric strings (e.g., "abc123def456789").'
|
|
398
|
+
);
|
|
399
|
+
this.name = "RecordNotFoundError";
|
|
400
|
+
}
|
|
401
|
+
};
|
|
358
402
|
var RequestError = class extends PicoBaseError {
|
|
359
403
|
constructor(message, status, details) {
|
|
360
|
-
|
|
404
|
+
const fix = requestErrorFix(status, message);
|
|
405
|
+
super(message, "REQUEST_FAILED", status, details, fix);
|
|
361
406
|
this.name = "RequestError";
|
|
362
407
|
}
|
|
363
408
|
};
|
|
409
|
+
var ConfigurationError = class extends PicoBaseError {
|
|
410
|
+
constructor(message, fix) {
|
|
411
|
+
super(message, "CONFIGURATION_ERROR", void 0, void 0, fix);
|
|
412
|
+
this.name = "ConfigurationError";
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
var RpcError = class extends PicoBaseError {
|
|
416
|
+
constructor(functionName, status, details) {
|
|
417
|
+
const fix = rpcErrorFix(functionName, status);
|
|
418
|
+
super(
|
|
419
|
+
`RPC function "${functionName}" failed.`,
|
|
420
|
+
"RPC_ERROR",
|
|
421
|
+
status,
|
|
422
|
+
details,
|
|
423
|
+
fix
|
|
424
|
+
);
|
|
425
|
+
this.name = "RpcError";
|
|
426
|
+
}
|
|
427
|
+
};
|
|
428
|
+
function rpcErrorFix(functionName, status) {
|
|
429
|
+
if (status === 404) {
|
|
430
|
+
return `The RPC endpoint "/api/rpc/${functionName}" does not exist. Create a custom route in your PocketBase instance to handle this RPC call. See: https://pocketbase.io/docs/js-routing/`;
|
|
431
|
+
}
|
|
432
|
+
if (status === 400) {
|
|
433
|
+
return "Check the parameters you are passing to this RPC function. The function may be expecting different parameters or types.";
|
|
434
|
+
}
|
|
435
|
+
if (status === 403) {
|
|
436
|
+
return "You don't have permission to call this RPC function. Check the authentication requirements for this endpoint in your PocketBase routes.";
|
|
437
|
+
}
|
|
438
|
+
return "Check your PicoBase instance logs for details about this RPC error. Ensure the custom route is correctly implemented in your PocketBase setup.";
|
|
439
|
+
}
|
|
440
|
+
function requestErrorFix(status, message) {
|
|
441
|
+
switch (status) {
|
|
442
|
+
case 400:
|
|
443
|
+
return "Check the data you are sending \u2014 a required field may be missing or have the wrong type. Run `picobase typegen` to regenerate types and check your field names.";
|
|
444
|
+
case 403:
|
|
445
|
+
return "You don't have permission for this action. Check your collection API rules in the dashboard. By default, only authenticated users can read/write records.";
|
|
446
|
+
case 404:
|
|
447
|
+
if (message.toLowerCase().includes("collection"))
|
|
448
|
+
return "This collection does not exist yet. Write a record to auto-create it, or create it in the dashboard.";
|
|
449
|
+
return "The requested resource was not found. Double-check IDs and collection names.";
|
|
450
|
+
case 413:
|
|
451
|
+
return "The request payload is too large. Check file upload size limits in your instance settings.";
|
|
452
|
+
case 429:
|
|
453
|
+
return "Too many requests. Add a short delay between requests or implement client-side caching.";
|
|
454
|
+
default:
|
|
455
|
+
return "If this error persists, check your PicoBase dashboard for instance health and logs.";
|
|
456
|
+
}
|
|
457
|
+
}
|
|
364
458
|
|
|
365
459
|
// src/client.ts
|
|
366
460
|
var DEFAULT_OPTIONS = {
|
|
@@ -370,6 +464,24 @@ var DEFAULT_OPTIONS = {
|
|
|
370
464
|
};
|
|
371
465
|
var PicoBaseClient = class {
|
|
372
466
|
constructor(url, apiKey, options = {}) {
|
|
467
|
+
if (!url) {
|
|
468
|
+
throw new ConfigurationError(
|
|
469
|
+
"PicoBase URL is required.",
|
|
470
|
+
'Pass the URL as the first argument: createClient("https://myapp.picobase.com", "pbk_...") or set PICOBASE_URL in your .env file.'
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
if (!apiKey) {
|
|
474
|
+
throw new ConfigurationError(
|
|
475
|
+
"PicoBase API key is required.",
|
|
476
|
+
'Pass the API key as the second argument: createClient("https://...", "pbk_your_key") or set PICOBASE_API_KEY in your .env file. Get a key from your dashboard.'
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
if (!url.startsWith("http://") && !url.startsWith("https://")) {
|
|
480
|
+
throw new ConfigurationError(
|
|
481
|
+
`Invalid URL: "${url}". Must start with http:// or https://.`,
|
|
482
|
+
`Use the full URL: createClient("https://${url}", "...")`
|
|
483
|
+
);
|
|
484
|
+
}
|
|
373
485
|
this.apiKey = apiKey;
|
|
374
486
|
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
375
487
|
const baseUrl = url.replace(/\/+$/, "");
|
|
@@ -407,6 +519,44 @@ var PicoBaseClient = class {
|
|
|
407
519
|
async send(path, options) {
|
|
408
520
|
return this.pb.send(path, options ?? {});
|
|
409
521
|
}
|
|
522
|
+
/**
|
|
523
|
+
* Call a remote procedure (RPC) - a convenience method for calling custom API endpoints.
|
|
524
|
+
*
|
|
525
|
+
* Maps Supabase-style RPC calls to PicoBase custom endpoints:
|
|
526
|
+
* - `pb.rpc('my_function', params)` → `POST /api/rpc/my_function` with params as body
|
|
527
|
+
*
|
|
528
|
+
* @example
|
|
529
|
+
* ```ts
|
|
530
|
+
* // Simple RPC call
|
|
531
|
+
* const result = await pb.rpc('calculate_total', { cart_id: '123' })
|
|
532
|
+
*
|
|
533
|
+
* // Complex RPC with typed response
|
|
534
|
+
* interface DashboardStats {
|
|
535
|
+
* posts: number
|
|
536
|
+
* comments: number
|
|
537
|
+
* followers: number
|
|
538
|
+
* }
|
|
539
|
+
* const stats = await pb.rpc<DashboardStats>('get_dashboard_stats', {
|
|
540
|
+
* user_id: currentUser.id
|
|
541
|
+
* })
|
|
542
|
+
* ```
|
|
543
|
+
*
|
|
544
|
+
* @param functionName The name of the RPC function to call
|
|
545
|
+
* @param params Optional parameters to pass to the function
|
|
546
|
+
* @returns The function result
|
|
547
|
+
*/
|
|
548
|
+
async rpc(functionName, params) {
|
|
549
|
+
try {
|
|
550
|
+
return await this.send(`/api/rpc/${functionName}`, {
|
|
551
|
+
method: "POST",
|
|
552
|
+
body: params ?? {}
|
|
553
|
+
});
|
|
554
|
+
} catch (err) {
|
|
555
|
+
const status = err?.status ?? 500;
|
|
556
|
+
const details = err?.data;
|
|
557
|
+
throw new RpcError(functionName, status, details);
|
|
558
|
+
}
|
|
559
|
+
}
|
|
410
560
|
/**
|
|
411
561
|
* Get the current auth token (if signed in), or empty string.
|
|
412
562
|
*/
|
|
@@ -448,6 +598,13 @@ var PicoBaseClient = class {
|
|
|
448
598
|
throw new AuthorizationError();
|
|
449
599
|
}
|
|
450
600
|
}
|
|
601
|
+
if (status === 404) {
|
|
602
|
+
const msg = err?.message ?? "";
|
|
603
|
+
if (msg.toLowerCase().includes("missing collection") || msg.toLowerCase().includes("not found collection")) {
|
|
604
|
+
const match = msg.match(/["']([^"']+)["']/);
|
|
605
|
+
throw new CollectionNotFoundError(match?.[1] ?? "unknown");
|
|
606
|
+
}
|
|
607
|
+
}
|
|
451
608
|
throw err;
|
|
452
609
|
}
|
|
453
610
|
}
|
|
@@ -463,8 +620,13 @@ function createClient(urlOrOptions, apiKeyOrUndefined, options) {
|
|
|
463
620
|
const url = env.PICOBASE_URL || env.NEXT_PUBLIC_PICOBASE_URL;
|
|
464
621
|
const apiKey = env.PICOBASE_API_KEY || env.NEXT_PUBLIC_PICOBASE_API_KEY;
|
|
465
622
|
if (!url || !apiKey) {
|
|
466
|
-
|
|
467
|
-
|
|
623
|
+
const missing = [
|
|
624
|
+
!url && "PICOBASE_URL (or NEXT_PUBLIC_PICOBASE_URL)",
|
|
625
|
+
!apiKey && "PICOBASE_API_KEY (or NEXT_PUBLIC_PICOBASE_API_KEY)"
|
|
626
|
+
].filter(Boolean).join(" and ");
|
|
627
|
+
throw new ConfigurationError(
|
|
628
|
+
`Missing environment variable${!url && !apiKey ? "s" : ""}: ${missing}`,
|
|
629
|
+
"Add them to your .env.local file:\n\n PICOBASE_URL=https://your-app.picobase.com\n PICOBASE_API_KEY=pbk_your_key_here\n\nOr for Next.js (client-side access), prefix with NEXT_PUBLIC_:\n\n NEXT_PUBLIC_PICOBASE_URL=https://your-app.picobase.com\n NEXT_PUBLIC_PICOBASE_API_KEY=pbk_your_key_here\n\nGet your URL and API key from: https://picobase.com/dashboard\nOr run: picobase init"
|
|
468
630
|
);
|
|
469
631
|
}
|
|
470
632
|
return new PicoBaseClient(url, apiKey, urlOrOptions);
|
|
@@ -473,6 +635,8 @@ function createClient(urlOrOptions, apiKeyOrUndefined, options) {
|
|
|
473
635
|
}
|
|
474
636
|
export {
|
|
475
637
|
AuthorizationError,
|
|
638
|
+
CollectionNotFoundError,
|
|
639
|
+
ConfigurationError,
|
|
476
640
|
InstanceUnavailableError,
|
|
477
641
|
PicoBaseAuth,
|
|
478
642
|
PicoBaseClient,
|
|
@@ -480,6 +644,8 @@ export {
|
|
|
480
644
|
PicoBaseError,
|
|
481
645
|
PicoBaseRealtime,
|
|
482
646
|
PicoBaseStorage,
|
|
647
|
+
RecordNotFoundError,
|
|
483
648
|
RequestError,
|
|
649
|
+
RpcError,
|
|
484
650
|
createClient
|
|
485
651
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@picobase_app/client",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "PicoBase client SDK — auth, database, storage, and realtime for your apps",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -18,15 +18,25 @@
|
|
|
18
18
|
"scripts": {
|
|
19
19
|
"build": "tsup src/index.ts --format cjs,esm --dts --clean",
|
|
20
20
|
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
21
|
+
"test": "vitest",
|
|
22
|
+
"test:watch": "vitest --watch",
|
|
23
|
+
"test:ui": "vitest --ui",
|
|
21
24
|
"typecheck": "tsc --noEmit",
|
|
22
|
-
"prepublishOnly": "npm run build"
|
|
25
|
+
"prepublishOnly": "npm run build",
|
|
26
|
+
"publish:dry": "npm publish --dry-run",
|
|
27
|
+
"release:patch": "npm version patch && npm publish",
|
|
28
|
+
"release:minor": "npm version minor && npm publish",
|
|
29
|
+
"release:major": "npm version major && npm publish"
|
|
23
30
|
},
|
|
24
31
|
"dependencies": {
|
|
25
32
|
"pocketbase": "^0.25.2"
|
|
26
33
|
},
|
|
27
34
|
"devDependencies": {
|
|
35
|
+
"@types/node": "^25.2.3",
|
|
36
|
+
"@vitest/ui": "^2.1.8",
|
|
28
37
|
"tsup": "^8.4.0",
|
|
29
|
-
"typescript": "^5.7.3"
|
|
38
|
+
"typescript": "^5.7.3",
|
|
39
|
+
"vitest": "^2.1.8"
|
|
30
40
|
},
|
|
31
41
|
"keywords": [
|
|
32
42
|
"picobase",
|