@tspvivek/baasix-sdk 0.1.0-alpha.9 → 0.1.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.
- package/README.md +27 -0
- package/dist/{client-B7CU_tr7.d.ts → client-DeXa-R9w.d.ts} +14 -0
- package/dist/{client-BCNmu9xC.d.cts → client-VT7NckyI.d.cts} +14 -0
- package/dist/index.cjs +240 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +105 -2
- package/dist/index.d.ts +105 -2
- package/dist/index.js +240 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/auth.cjs.map +1 -1
- package/dist/modules/auth.d.cts +1 -1
- package/dist/modules/auth.d.ts +1 -1
- package/dist/modules/auth.js.map +1 -1
- package/dist/modules/files.cjs +4 -1
- package/dist/modules/files.cjs.map +1 -1
- package/dist/modules/files.d.cts +1 -1
- package/dist/modules/files.d.ts +1 -1
- package/dist/modules/files.js +4 -1
- package/dist/modules/files.js.map +1 -1
- package/dist/modules/items.d.cts +2 -2
- package/dist/modules/items.d.ts +2 -2
- package/dist/modules/schemas.d.cts +1 -1
- package/dist/modules/schemas.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -558,6 +558,7 @@ await baasix.schemas.create({
|
|
|
558
558
|
|
|
559
559
|
```typescript
|
|
560
560
|
// Many-to-One (BelongsTo)
|
|
561
|
+
// Auto-creates index on foreign key column
|
|
561
562
|
await baasix.schemas.createRelationship('products', {
|
|
562
563
|
type: 'M2O',
|
|
563
564
|
target: 'categories',
|
|
@@ -566,14 +567,40 @@ await baasix.schemas.createRelationship('products', {
|
|
|
566
567
|
});
|
|
567
568
|
|
|
568
569
|
// Many-to-Many
|
|
570
|
+
// Auto-generates junction table: products_tags_tags_junction
|
|
569
571
|
await baasix.schemas.createRelationship('products', {
|
|
570
572
|
type: 'M2M',
|
|
571
573
|
target: 'tags',
|
|
572
574
|
name: 'tags',
|
|
573
575
|
alias: 'products',
|
|
574
576
|
});
|
|
577
|
+
|
|
578
|
+
// Many-to-Many with custom junction table name
|
|
579
|
+
// Useful when auto-generated name exceeds PostgreSQL's 63 char limit
|
|
580
|
+
await baasix.schemas.createRelationship('products', {
|
|
581
|
+
type: 'M2M',
|
|
582
|
+
target: 'tags',
|
|
583
|
+
name: 'tags',
|
|
584
|
+
alias: 'products',
|
|
585
|
+
through: 'product_tags', // Custom junction table name (max 63 chars)
|
|
586
|
+
});
|
|
587
|
+
|
|
588
|
+
// Many-to-Any (Polymorphic)
|
|
589
|
+
await baasix.schemas.createRelationship('comments', {
|
|
590
|
+
type: 'M2A',
|
|
591
|
+
name: 'commentable',
|
|
592
|
+
tables: ['posts', 'products'],
|
|
593
|
+
alias: 'comments',
|
|
594
|
+
through: 'comment_refs', // Optional custom junction table name
|
|
595
|
+
});
|
|
575
596
|
```
|
|
576
597
|
|
|
598
|
+
#### Junction Tables (M2M/M2A)
|
|
599
|
+
- **Auto-generated name**: `{source}_{target}_{name}_junction`
|
|
600
|
+
- **Custom name**: Use `through` property (max 63 characters for PostgreSQL)
|
|
601
|
+
- **Schema property**: Junction tables have `isJunction: true` in their schema
|
|
602
|
+
- **Auto-indexed**: Foreign key columns are automatically indexed
|
|
603
|
+
|
|
577
604
|
### Indexes
|
|
578
605
|
|
|
579
606
|
```typescript
|
|
@@ -374,6 +374,11 @@ interface SchemaDefinition {
|
|
|
374
374
|
name: string;
|
|
375
375
|
timestamps?: boolean;
|
|
376
376
|
paranoid?: boolean;
|
|
377
|
+
/**
|
|
378
|
+
* True for M2M/M2A junction tables (system-generated)
|
|
379
|
+
* Junction tables are auto-created when defining M2M or M2A relationships
|
|
380
|
+
*/
|
|
381
|
+
isJunction?: boolean;
|
|
377
382
|
fields: Record<string, FieldDefinition>;
|
|
378
383
|
indexes?: IndexDefinition[];
|
|
379
384
|
}
|
|
@@ -390,8 +395,15 @@ interface RelationshipDefinition {
|
|
|
390
395
|
target: string;
|
|
391
396
|
name: string;
|
|
392
397
|
alias?: string;
|
|
398
|
+
/**
|
|
399
|
+
* Custom junction table name for M2M/M2A relationships (max 63 chars for PostgreSQL)
|
|
400
|
+
* If not provided, auto-generated as: {source}_{target}_{name}_junction
|
|
401
|
+
* @example "product_tags" or "comment_refs"
|
|
402
|
+
*/
|
|
403
|
+
through?: string;
|
|
393
404
|
onDelete?: "CASCADE" | "RESTRICT" | "SET NULL";
|
|
394
405
|
onUpdate?: "CASCADE" | "RESTRICT" | "SET NULL";
|
|
406
|
+
/** Target tables for M2A (polymorphic) relationships */
|
|
395
407
|
tables?: string[];
|
|
396
408
|
}
|
|
397
409
|
interface SchemaInfo {
|
|
@@ -425,6 +437,8 @@ interface UploadOptions {
|
|
|
425
437
|
isPublic?: boolean;
|
|
426
438
|
metadata?: Record<string, unknown>;
|
|
427
439
|
onProgress?: (progress: number) => void;
|
|
440
|
+
/** Request timeout in milliseconds (default: 30000). Set to 0 for no timeout. */
|
|
441
|
+
timeout?: number;
|
|
428
442
|
}
|
|
429
443
|
interface AssetTransformOptions {
|
|
430
444
|
width?: number;
|
|
@@ -374,6 +374,11 @@ interface SchemaDefinition {
|
|
|
374
374
|
name: string;
|
|
375
375
|
timestamps?: boolean;
|
|
376
376
|
paranoid?: boolean;
|
|
377
|
+
/**
|
|
378
|
+
* True for M2M/M2A junction tables (system-generated)
|
|
379
|
+
* Junction tables are auto-created when defining M2M or M2A relationships
|
|
380
|
+
*/
|
|
381
|
+
isJunction?: boolean;
|
|
377
382
|
fields: Record<string, FieldDefinition>;
|
|
378
383
|
indexes?: IndexDefinition[];
|
|
379
384
|
}
|
|
@@ -390,8 +395,15 @@ interface RelationshipDefinition {
|
|
|
390
395
|
target: string;
|
|
391
396
|
name: string;
|
|
392
397
|
alias?: string;
|
|
398
|
+
/**
|
|
399
|
+
* Custom junction table name for M2M/M2A relationships (max 63 chars for PostgreSQL)
|
|
400
|
+
* If not provided, auto-generated as: {source}_{target}_{name}_junction
|
|
401
|
+
* @example "product_tags" or "comment_refs"
|
|
402
|
+
*/
|
|
403
|
+
through?: string;
|
|
393
404
|
onDelete?: "CASCADE" | "RESTRICT" | "SET NULL";
|
|
394
405
|
onUpdate?: "CASCADE" | "RESTRICT" | "SET NULL";
|
|
406
|
+
/** Target tables for M2A (polymorphic) relationships */
|
|
395
407
|
tables?: string[];
|
|
396
408
|
}
|
|
397
409
|
interface SchemaInfo {
|
|
@@ -425,6 +437,8 @@ interface UploadOptions {
|
|
|
425
437
|
isPublic?: boolean;
|
|
426
438
|
metadata?: Record<string, unknown>;
|
|
427
439
|
onProgress?: (progress: number) => void;
|
|
440
|
+
/** Request timeout in milliseconds (default: 30000). Set to 0 for no timeout. */
|
|
441
|
+
timeout?: number;
|
|
428
442
|
}
|
|
429
443
|
interface AssetTransformOptions {
|
|
430
444
|
width?: number;
|
package/dist/index.cjs
CHANGED
|
@@ -1770,7 +1770,10 @@ var FilesModule = class {
|
|
|
1770
1770
|
const response = await this.client.upload(
|
|
1771
1771
|
"/files",
|
|
1772
1772
|
formData,
|
|
1773
|
-
{
|
|
1773
|
+
{
|
|
1774
|
+
onProgress: options?.onProgress,
|
|
1775
|
+
timeout: options?.timeout
|
|
1776
|
+
}
|
|
1774
1777
|
);
|
|
1775
1778
|
return response.data;
|
|
1776
1779
|
}
|
|
@@ -3030,6 +3033,9 @@ var RealtimeModule = class {
|
|
|
3030
3033
|
socketPath;
|
|
3031
3034
|
subscriptions = /* @__PURE__ */ new Map();
|
|
3032
3035
|
workflowCallbacks = /* @__PURE__ */ new Map();
|
|
3036
|
+
roomCallbacks = /* @__PURE__ */ new Map();
|
|
3037
|
+
// room -> event -> callbacks
|
|
3038
|
+
roomUserCallbacks = /* @__PURE__ */ new Map();
|
|
3033
3039
|
connectionCallbacks = /* @__PURE__ */ new Set();
|
|
3034
3040
|
reconnecting = false;
|
|
3035
3041
|
connectionPromise = null;
|
|
@@ -3037,7 +3043,7 @@ var RealtimeModule = class {
|
|
|
3037
3043
|
this.client = config.client;
|
|
3038
3044
|
this.storage = config.storage;
|
|
3039
3045
|
this.socketUrl = config.socketUrl || "";
|
|
3040
|
-
this.socketPath = config.socketPath || "/
|
|
3046
|
+
this.socketPath = config.socketPath || "/realtime";
|
|
3041
3047
|
}
|
|
3042
3048
|
/**
|
|
3043
3049
|
* Set the socket.io client instance
|
|
@@ -3139,6 +3145,26 @@ var RealtimeModule = class {
|
|
|
3139
3145
|
this.socket.on("workflow:execution:complete", (data) => {
|
|
3140
3146
|
this.handleWorkflowUpdate({ ...data, status: "complete" });
|
|
3141
3147
|
});
|
|
3148
|
+
this.socket.on("room:user:joined", (data) => {
|
|
3149
|
+
const callbacks = this.roomUserCallbacks.get(data.room);
|
|
3150
|
+
callbacks?.joined.forEach((cb) => {
|
|
3151
|
+
try {
|
|
3152
|
+
cb(data);
|
|
3153
|
+
} catch (e) {
|
|
3154
|
+
console.error("[Baasix Realtime] Error in room user joined callback:", e);
|
|
3155
|
+
}
|
|
3156
|
+
});
|
|
3157
|
+
});
|
|
3158
|
+
this.socket.on("room:user:left", (data) => {
|
|
3159
|
+
const callbacks = this.roomUserCallbacks.get(data.room);
|
|
3160
|
+
callbacks?.left.forEach((cb) => {
|
|
3161
|
+
try {
|
|
3162
|
+
cb(data);
|
|
3163
|
+
} catch (e) {
|
|
3164
|
+
console.error("[Baasix Realtime] Error in room user left callback:", e);
|
|
3165
|
+
}
|
|
3166
|
+
});
|
|
3167
|
+
});
|
|
3142
3168
|
this.socket.connect();
|
|
3143
3169
|
} catch (error) {
|
|
3144
3170
|
this.connectionPromise = null;
|
|
@@ -3166,6 +3192,8 @@ var RealtimeModule = class {
|
|
|
3166
3192
|
}
|
|
3167
3193
|
this.subscriptions.clear();
|
|
3168
3194
|
this.workflowCallbacks.clear();
|
|
3195
|
+
this.roomCallbacks.clear();
|
|
3196
|
+
this.roomUserCallbacks.clear();
|
|
3169
3197
|
}
|
|
3170
3198
|
/**
|
|
3171
3199
|
* Check if connected to the realtime server
|
|
@@ -3382,6 +3410,214 @@ var RealtimeModule = class {
|
|
|
3382
3410
|
}
|
|
3383
3411
|
}
|
|
3384
3412
|
// ===================
|
|
3413
|
+
// Custom Rooms API
|
|
3414
|
+
// ===================
|
|
3415
|
+
/**
|
|
3416
|
+
* Join a custom room for real-time communication
|
|
3417
|
+
*
|
|
3418
|
+
* @example
|
|
3419
|
+
* ```typescript
|
|
3420
|
+
* // Join a room
|
|
3421
|
+
* await baasix.realtime.joinRoom('game:lobby');
|
|
3422
|
+
*
|
|
3423
|
+
* // Listen for messages
|
|
3424
|
+
* baasix.realtime.onRoomMessage('game:lobby', 'chat', (data) => {
|
|
3425
|
+
* console.log(`${data.sender.userId}: ${data.payload.text}`);
|
|
3426
|
+
* });
|
|
3427
|
+
* ```
|
|
3428
|
+
*/
|
|
3429
|
+
async joinRoom(roomName) {
|
|
3430
|
+
if (!this.socket?.connected) {
|
|
3431
|
+
throw new Error("Not connected. Call connect() first.");
|
|
3432
|
+
}
|
|
3433
|
+
return new Promise((resolve, reject) => {
|
|
3434
|
+
this.socket.emit("room:join", { room: roomName }, (response) => {
|
|
3435
|
+
if (response.status === "success") {
|
|
3436
|
+
this.setupRoomListeners(roomName);
|
|
3437
|
+
resolve();
|
|
3438
|
+
} else {
|
|
3439
|
+
reject(new Error(response.message || "Failed to join room"));
|
|
3440
|
+
}
|
|
3441
|
+
});
|
|
3442
|
+
});
|
|
3443
|
+
}
|
|
3444
|
+
/**
|
|
3445
|
+
* Leave a custom room
|
|
3446
|
+
*
|
|
3447
|
+
* @example
|
|
3448
|
+
* ```typescript
|
|
3449
|
+
* await baasix.realtime.leaveRoom('game:lobby');
|
|
3450
|
+
* ```
|
|
3451
|
+
*/
|
|
3452
|
+
async leaveRoom(roomName) {
|
|
3453
|
+
if (!this.socket?.connected) {
|
|
3454
|
+
return;
|
|
3455
|
+
}
|
|
3456
|
+
return new Promise((resolve, reject) => {
|
|
3457
|
+
this.socket.emit("room:leave", { room: roomName }, (response) => {
|
|
3458
|
+
if (response.status === "success") {
|
|
3459
|
+
this.cleanupRoomListeners(roomName);
|
|
3460
|
+
resolve();
|
|
3461
|
+
} else {
|
|
3462
|
+
reject(new Error(response.message || "Failed to leave room"));
|
|
3463
|
+
}
|
|
3464
|
+
});
|
|
3465
|
+
});
|
|
3466
|
+
}
|
|
3467
|
+
/**
|
|
3468
|
+
* Send a message to a room
|
|
3469
|
+
*
|
|
3470
|
+
* @example
|
|
3471
|
+
* ```typescript
|
|
3472
|
+
* // Send a chat message
|
|
3473
|
+
* await baasix.realtime.sendToRoom('game:lobby', 'chat', { text: 'Hello!' });
|
|
3474
|
+
*
|
|
3475
|
+
* // Send a game event
|
|
3476
|
+
* await baasix.realtime.sendToRoom('game:123', 'move', { x: 10, y: 20 });
|
|
3477
|
+
* ```
|
|
3478
|
+
*/
|
|
3479
|
+
async sendToRoom(roomName, event, payload) {
|
|
3480
|
+
if (!this.socket?.connected) {
|
|
3481
|
+
throw new Error("Not connected. Call connect() first.");
|
|
3482
|
+
}
|
|
3483
|
+
return new Promise((resolve, reject) => {
|
|
3484
|
+
this.socket.emit(
|
|
3485
|
+
"room:message",
|
|
3486
|
+
{ room: roomName, event, payload },
|
|
3487
|
+
(response) => {
|
|
3488
|
+
if (response.status === "success") {
|
|
3489
|
+
resolve();
|
|
3490
|
+
} else {
|
|
3491
|
+
reject(new Error(response.message || "Failed to send message"));
|
|
3492
|
+
}
|
|
3493
|
+
}
|
|
3494
|
+
);
|
|
3495
|
+
});
|
|
3496
|
+
}
|
|
3497
|
+
/**
|
|
3498
|
+
* Listen for messages in a room with a specific event type
|
|
3499
|
+
*
|
|
3500
|
+
* @example
|
|
3501
|
+
* ```typescript
|
|
3502
|
+
* const unsubscribe = baasix.realtime.onRoomMessage('game:lobby', 'chat', (data) => {
|
|
3503
|
+
* console.log(`${data.sender.userId}: ${data.payload.text}`);
|
|
3504
|
+
* });
|
|
3505
|
+
*
|
|
3506
|
+
* // Later
|
|
3507
|
+
* unsubscribe();
|
|
3508
|
+
* ```
|
|
3509
|
+
*/
|
|
3510
|
+
onRoomMessage(roomName, event, callback) {
|
|
3511
|
+
if (!this.roomCallbacks.has(roomName)) {
|
|
3512
|
+
this.roomCallbacks.set(roomName, /* @__PURE__ */ new Map());
|
|
3513
|
+
}
|
|
3514
|
+
const roomEvents = this.roomCallbacks.get(roomName);
|
|
3515
|
+
if (!roomEvents.has(event)) {
|
|
3516
|
+
roomEvents.set(event, /* @__PURE__ */ new Set());
|
|
3517
|
+
}
|
|
3518
|
+
roomEvents.get(event).add(callback);
|
|
3519
|
+
return () => {
|
|
3520
|
+
const events = this.roomCallbacks.get(roomName);
|
|
3521
|
+
if (events) {
|
|
3522
|
+
const callbacks = events.get(event);
|
|
3523
|
+
if (callbacks) {
|
|
3524
|
+
callbacks.delete(callback);
|
|
3525
|
+
if (callbacks.size === 0) {
|
|
3526
|
+
events.delete(event);
|
|
3527
|
+
}
|
|
3528
|
+
}
|
|
3529
|
+
if (events.size === 0) {
|
|
3530
|
+
this.roomCallbacks.delete(roomName);
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
};
|
|
3534
|
+
}
|
|
3535
|
+
/**
|
|
3536
|
+
* Listen for users joining a room
|
|
3537
|
+
*
|
|
3538
|
+
* @example
|
|
3539
|
+
* ```typescript
|
|
3540
|
+
* const unsubscribe = baasix.realtime.onRoomUserJoined('game:lobby', (data) => {
|
|
3541
|
+
* console.log(`User ${data.userId} joined the room`);
|
|
3542
|
+
* });
|
|
3543
|
+
* ```
|
|
3544
|
+
*/
|
|
3545
|
+
onRoomUserJoined(roomName, callback) {
|
|
3546
|
+
if (!this.roomUserCallbacks.has(roomName)) {
|
|
3547
|
+
this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
|
|
3548
|
+
}
|
|
3549
|
+
this.roomUserCallbacks.get(roomName).joined.add(callback);
|
|
3550
|
+
return () => {
|
|
3551
|
+
const callbacks = this.roomUserCallbacks.get(roomName);
|
|
3552
|
+
if (callbacks) {
|
|
3553
|
+
callbacks.joined.delete(callback);
|
|
3554
|
+
if (callbacks.joined.size === 0 && callbacks.left.size === 0) {
|
|
3555
|
+
this.roomUserCallbacks.delete(roomName);
|
|
3556
|
+
}
|
|
3557
|
+
}
|
|
3558
|
+
};
|
|
3559
|
+
}
|
|
3560
|
+
/**
|
|
3561
|
+
* Listen for users leaving a room
|
|
3562
|
+
*
|
|
3563
|
+
* @example
|
|
3564
|
+
* ```typescript
|
|
3565
|
+
* const unsubscribe = baasix.realtime.onRoomUserLeft('game:lobby', (data) => {
|
|
3566
|
+
* console.log(`User ${data.userId} left the room`);
|
|
3567
|
+
* });
|
|
3568
|
+
* ```
|
|
3569
|
+
*/
|
|
3570
|
+
onRoomUserLeft(roomName, callback) {
|
|
3571
|
+
if (!this.roomUserCallbacks.has(roomName)) {
|
|
3572
|
+
this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
|
|
3573
|
+
}
|
|
3574
|
+
this.roomUserCallbacks.get(roomName).left.add(callback);
|
|
3575
|
+
return () => {
|
|
3576
|
+
const callbacks = this.roomUserCallbacks.get(roomName);
|
|
3577
|
+
if (callbacks) {
|
|
3578
|
+
callbacks.left.delete(callback);
|
|
3579
|
+
if (callbacks.joined.size === 0 && callbacks.left.size === 0) {
|
|
3580
|
+
this.roomUserCallbacks.delete(roomName);
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
/**
|
|
3586
|
+
* Invoke a custom server-side handler
|
|
3587
|
+
*
|
|
3588
|
+
* @example
|
|
3589
|
+
* ```typescript
|
|
3590
|
+
* const result = await baasix.realtime.invoke('game:roll-dice', { sides: 6 });
|
|
3591
|
+
* console.log('Dice result:', result);
|
|
3592
|
+
* ```
|
|
3593
|
+
*/
|
|
3594
|
+
async invoke(event, payload) {
|
|
3595
|
+
if (!this.socket?.connected) {
|
|
3596
|
+
throw new Error("Not connected. Call connect() first.");
|
|
3597
|
+
}
|
|
3598
|
+
return new Promise((resolve, reject) => {
|
|
3599
|
+
this.socket.emit("custom", { event, payload }, (response) => {
|
|
3600
|
+
if (response.status === "success") {
|
|
3601
|
+
resolve(response);
|
|
3602
|
+
} else {
|
|
3603
|
+
reject(new Error(response.message || "Custom event failed"));
|
|
3604
|
+
}
|
|
3605
|
+
});
|
|
3606
|
+
});
|
|
3607
|
+
}
|
|
3608
|
+
setupRoomListeners(roomName) {
|
|
3609
|
+
if (!this.roomCallbacks.has(roomName)) {
|
|
3610
|
+
this.roomCallbacks.set(roomName, /* @__PURE__ */ new Map());
|
|
3611
|
+
}
|
|
3612
|
+
if (!this.roomUserCallbacks.has(roomName)) {
|
|
3613
|
+
this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
|
|
3614
|
+
}
|
|
3615
|
+
}
|
|
3616
|
+
cleanupRoomListeners(roomName) {
|
|
3617
|
+
this.roomCallbacks.delete(roomName);
|
|
3618
|
+
this.roomUserCallbacks.delete(roomName);
|
|
3619
|
+
}
|
|
3620
|
+
// ===================
|
|
3385
3621
|
// Channel (Room) API - Supabase-style
|
|
3386
3622
|
// ===================
|
|
3387
3623
|
/**
|
|
@@ -4097,7 +4333,8 @@ var Baasix = class {
|
|
|
4097
4333
|
...config,
|
|
4098
4334
|
url: normalizedUrl,
|
|
4099
4335
|
authMode: config.authMode || "jwt",
|
|
4100
|
-
timeout: config.timeout ||
|
|
4336
|
+
timeout: config.timeout || 6e5,
|
|
4337
|
+
// 10 minutes default
|
|
4101
4338
|
autoRefresh: config.autoRefresh !== false
|
|
4102
4339
|
};
|
|
4103
4340
|
this.storage = config.storage || getDefaultStorage();
|