@tspvivek/baasix-sdk 0.1.0-alpha.9 → 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.
- package/README.md +27 -0
- package/dist/{client-BCNmu9xC.d.cts → client-C-Adq8rn.d.cts} +12 -0
- package/dist/{client-B7CU_tr7.d.ts → client-CI29EbJ6.d.ts} +12 -0
- package/dist/index.cjs +234 -1
- 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 +234 -1
- 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.d.cts +1 -1
- package/dist/modules/files.d.ts +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 {
|
|
@@ -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 {
|
package/dist/index.cjs
CHANGED
|
@@ -3030,6 +3030,9 @@ var RealtimeModule = class {
|
|
|
3030
3030
|
socketPath;
|
|
3031
3031
|
subscriptions = /* @__PURE__ */ new Map();
|
|
3032
3032
|
workflowCallbacks = /* @__PURE__ */ new Map();
|
|
3033
|
+
roomCallbacks = /* @__PURE__ */ new Map();
|
|
3034
|
+
// room -> event -> callbacks
|
|
3035
|
+
roomUserCallbacks = /* @__PURE__ */ new Map();
|
|
3033
3036
|
connectionCallbacks = /* @__PURE__ */ new Set();
|
|
3034
3037
|
reconnecting = false;
|
|
3035
3038
|
connectionPromise = null;
|
|
@@ -3037,7 +3040,7 @@ var RealtimeModule = class {
|
|
|
3037
3040
|
this.client = config.client;
|
|
3038
3041
|
this.storage = config.storage;
|
|
3039
3042
|
this.socketUrl = config.socketUrl || "";
|
|
3040
|
-
this.socketPath = config.socketPath || "/
|
|
3043
|
+
this.socketPath = config.socketPath || "/realtime";
|
|
3041
3044
|
}
|
|
3042
3045
|
/**
|
|
3043
3046
|
* Set the socket.io client instance
|
|
@@ -3139,6 +3142,26 @@ var RealtimeModule = class {
|
|
|
3139
3142
|
this.socket.on("workflow:execution:complete", (data) => {
|
|
3140
3143
|
this.handleWorkflowUpdate({ ...data, status: "complete" });
|
|
3141
3144
|
});
|
|
3145
|
+
this.socket.on("room:user:joined", (data) => {
|
|
3146
|
+
const callbacks = this.roomUserCallbacks.get(data.room);
|
|
3147
|
+
callbacks?.joined.forEach((cb) => {
|
|
3148
|
+
try {
|
|
3149
|
+
cb(data);
|
|
3150
|
+
} catch (e) {
|
|
3151
|
+
console.error("[Baasix Realtime] Error in room user joined callback:", e);
|
|
3152
|
+
}
|
|
3153
|
+
});
|
|
3154
|
+
});
|
|
3155
|
+
this.socket.on("room:user:left", (data) => {
|
|
3156
|
+
const callbacks = this.roomUserCallbacks.get(data.room);
|
|
3157
|
+
callbacks?.left.forEach((cb) => {
|
|
3158
|
+
try {
|
|
3159
|
+
cb(data);
|
|
3160
|
+
} catch (e) {
|
|
3161
|
+
console.error("[Baasix Realtime] Error in room user left callback:", e);
|
|
3162
|
+
}
|
|
3163
|
+
});
|
|
3164
|
+
});
|
|
3142
3165
|
this.socket.connect();
|
|
3143
3166
|
} catch (error) {
|
|
3144
3167
|
this.connectionPromise = null;
|
|
@@ -3166,6 +3189,8 @@ var RealtimeModule = class {
|
|
|
3166
3189
|
}
|
|
3167
3190
|
this.subscriptions.clear();
|
|
3168
3191
|
this.workflowCallbacks.clear();
|
|
3192
|
+
this.roomCallbacks.clear();
|
|
3193
|
+
this.roomUserCallbacks.clear();
|
|
3169
3194
|
}
|
|
3170
3195
|
/**
|
|
3171
3196
|
* Check if connected to the realtime server
|
|
@@ -3382,6 +3407,214 @@ var RealtimeModule = class {
|
|
|
3382
3407
|
}
|
|
3383
3408
|
}
|
|
3384
3409
|
// ===================
|
|
3410
|
+
// Custom Rooms API
|
|
3411
|
+
// ===================
|
|
3412
|
+
/**
|
|
3413
|
+
* Join a custom room for real-time communication
|
|
3414
|
+
*
|
|
3415
|
+
* @example
|
|
3416
|
+
* ```typescript
|
|
3417
|
+
* // Join a room
|
|
3418
|
+
* await baasix.realtime.joinRoom('game:lobby');
|
|
3419
|
+
*
|
|
3420
|
+
* // Listen for messages
|
|
3421
|
+
* baasix.realtime.onRoomMessage('game:lobby', 'chat', (data) => {
|
|
3422
|
+
* console.log(`${data.sender.userId}: ${data.payload.text}`);
|
|
3423
|
+
* });
|
|
3424
|
+
* ```
|
|
3425
|
+
*/
|
|
3426
|
+
async joinRoom(roomName) {
|
|
3427
|
+
if (!this.socket?.connected) {
|
|
3428
|
+
throw new Error("Not connected. Call connect() first.");
|
|
3429
|
+
}
|
|
3430
|
+
return new Promise((resolve, reject) => {
|
|
3431
|
+
this.socket.emit("room:join", { room: roomName }, (response) => {
|
|
3432
|
+
if (response.status === "success") {
|
|
3433
|
+
this.setupRoomListeners(roomName);
|
|
3434
|
+
resolve();
|
|
3435
|
+
} else {
|
|
3436
|
+
reject(new Error(response.message || "Failed to join room"));
|
|
3437
|
+
}
|
|
3438
|
+
});
|
|
3439
|
+
});
|
|
3440
|
+
}
|
|
3441
|
+
/**
|
|
3442
|
+
* Leave a custom room
|
|
3443
|
+
*
|
|
3444
|
+
* @example
|
|
3445
|
+
* ```typescript
|
|
3446
|
+
* await baasix.realtime.leaveRoom('game:lobby');
|
|
3447
|
+
* ```
|
|
3448
|
+
*/
|
|
3449
|
+
async leaveRoom(roomName) {
|
|
3450
|
+
if (!this.socket?.connected) {
|
|
3451
|
+
return;
|
|
3452
|
+
}
|
|
3453
|
+
return new Promise((resolve, reject) => {
|
|
3454
|
+
this.socket.emit("room:leave", { room: roomName }, (response) => {
|
|
3455
|
+
if (response.status === "success") {
|
|
3456
|
+
this.cleanupRoomListeners(roomName);
|
|
3457
|
+
resolve();
|
|
3458
|
+
} else {
|
|
3459
|
+
reject(new Error(response.message || "Failed to leave room"));
|
|
3460
|
+
}
|
|
3461
|
+
});
|
|
3462
|
+
});
|
|
3463
|
+
}
|
|
3464
|
+
/**
|
|
3465
|
+
* Send a message to a room
|
|
3466
|
+
*
|
|
3467
|
+
* @example
|
|
3468
|
+
* ```typescript
|
|
3469
|
+
* // Send a chat message
|
|
3470
|
+
* await baasix.realtime.sendToRoom('game:lobby', 'chat', { text: 'Hello!' });
|
|
3471
|
+
*
|
|
3472
|
+
* // Send a game event
|
|
3473
|
+
* await baasix.realtime.sendToRoom('game:123', 'move', { x: 10, y: 20 });
|
|
3474
|
+
* ```
|
|
3475
|
+
*/
|
|
3476
|
+
async sendToRoom(roomName, event, payload) {
|
|
3477
|
+
if (!this.socket?.connected) {
|
|
3478
|
+
throw new Error("Not connected. Call connect() first.");
|
|
3479
|
+
}
|
|
3480
|
+
return new Promise((resolve, reject) => {
|
|
3481
|
+
this.socket.emit(
|
|
3482
|
+
"room:message",
|
|
3483
|
+
{ room: roomName, event, payload },
|
|
3484
|
+
(response) => {
|
|
3485
|
+
if (response.status === "success") {
|
|
3486
|
+
resolve();
|
|
3487
|
+
} else {
|
|
3488
|
+
reject(new Error(response.message || "Failed to send message"));
|
|
3489
|
+
}
|
|
3490
|
+
}
|
|
3491
|
+
);
|
|
3492
|
+
});
|
|
3493
|
+
}
|
|
3494
|
+
/**
|
|
3495
|
+
* Listen for messages in a room with a specific event type
|
|
3496
|
+
*
|
|
3497
|
+
* @example
|
|
3498
|
+
* ```typescript
|
|
3499
|
+
* const unsubscribe = baasix.realtime.onRoomMessage('game:lobby', 'chat', (data) => {
|
|
3500
|
+
* console.log(`${data.sender.userId}: ${data.payload.text}`);
|
|
3501
|
+
* });
|
|
3502
|
+
*
|
|
3503
|
+
* // Later
|
|
3504
|
+
* unsubscribe();
|
|
3505
|
+
* ```
|
|
3506
|
+
*/
|
|
3507
|
+
onRoomMessage(roomName, event, callback) {
|
|
3508
|
+
if (!this.roomCallbacks.has(roomName)) {
|
|
3509
|
+
this.roomCallbacks.set(roomName, /* @__PURE__ */ new Map());
|
|
3510
|
+
}
|
|
3511
|
+
const roomEvents = this.roomCallbacks.get(roomName);
|
|
3512
|
+
if (!roomEvents.has(event)) {
|
|
3513
|
+
roomEvents.set(event, /* @__PURE__ */ new Set());
|
|
3514
|
+
}
|
|
3515
|
+
roomEvents.get(event).add(callback);
|
|
3516
|
+
return () => {
|
|
3517
|
+
const events = this.roomCallbacks.get(roomName);
|
|
3518
|
+
if (events) {
|
|
3519
|
+
const callbacks = events.get(event);
|
|
3520
|
+
if (callbacks) {
|
|
3521
|
+
callbacks.delete(callback);
|
|
3522
|
+
if (callbacks.size === 0) {
|
|
3523
|
+
events.delete(event);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
if (events.size === 0) {
|
|
3527
|
+
this.roomCallbacks.delete(roomName);
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
};
|
|
3531
|
+
}
|
|
3532
|
+
/**
|
|
3533
|
+
* Listen for users joining a room
|
|
3534
|
+
*
|
|
3535
|
+
* @example
|
|
3536
|
+
* ```typescript
|
|
3537
|
+
* const unsubscribe = baasix.realtime.onRoomUserJoined('game:lobby', (data) => {
|
|
3538
|
+
* console.log(`User ${data.userId} joined the room`);
|
|
3539
|
+
* });
|
|
3540
|
+
* ```
|
|
3541
|
+
*/
|
|
3542
|
+
onRoomUserJoined(roomName, callback) {
|
|
3543
|
+
if (!this.roomUserCallbacks.has(roomName)) {
|
|
3544
|
+
this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
|
|
3545
|
+
}
|
|
3546
|
+
this.roomUserCallbacks.get(roomName).joined.add(callback);
|
|
3547
|
+
return () => {
|
|
3548
|
+
const callbacks = this.roomUserCallbacks.get(roomName);
|
|
3549
|
+
if (callbacks) {
|
|
3550
|
+
callbacks.joined.delete(callback);
|
|
3551
|
+
if (callbacks.joined.size === 0 && callbacks.left.size === 0) {
|
|
3552
|
+
this.roomUserCallbacks.delete(roomName);
|
|
3553
|
+
}
|
|
3554
|
+
}
|
|
3555
|
+
};
|
|
3556
|
+
}
|
|
3557
|
+
/**
|
|
3558
|
+
* Listen for users leaving a room
|
|
3559
|
+
*
|
|
3560
|
+
* @example
|
|
3561
|
+
* ```typescript
|
|
3562
|
+
* const unsubscribe = baasix.realtime.onRoomUserLeft('game:lobby', (data) => {
|
|
3563
|
+
* console.log(`User ${data.userId} left the room`);
|
|
3564
|
+
* });
|
|
3565
|
+
* ```
|
|
3566
|
+
*/
|
|
3567
|
+
onRoomUserLeft(roomName, callback) {
|
|
3568
|
+
if (!this.roomUserCallbacks.has(roomName)) {
|
|
3569
|
+
this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
|
|
3570
|
+
}
|
|
3571
|
+
this.roomUserCallbacks.get(roomName).left.add(callback);
|
|
3572
|
+
return () => {
|
|
3573
|
+
const callbacks = this.roomUserCallbacks.get(roomName);
|
|
3574
|
+
if (callbacks) {
|
|
3575
|
+
callbacks.left.delete(callback);
|
|
3576
|
+
if (callbacks.joined.size === 0 && callbacks.left.size === 0) {
|
|
3577
|
+
this.roomUserCallbacks.delete(roomName);
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
};
|
|
3581
|
+
}
|
|
3582
|
+
/**
|
|
3583
|
+
* Invoke a custom server-side handler
|
|
3584
|
+
*
|
|
3585
|
+
* @example
|
|
3586
|
+
* ```typescript
|
|
3587
|
+
* const result = await baasix.realtime.invoke('game:roll-dice', { sides: 6 });
|
|
3588
|
+
* console.log('Dice result:', result);
|
|
3589
|
+
* ```
|
|
3590
|
+
*/
|
|
3591
|
+
async invoke(event, payload) {
|
|
3592
|
+
if (!this.socket?.connected) {
|
|
3593
|
+
throw new Error("Not connected. Call connect() first.");
|
|
3594
|
+
}
|
|
3595
|
+
return new Promise((resolve, reject) => {
|
|
3596
|
+
this.socket.emit("custom", { event, payload }, (response) => {
|
|
3597
|
+
if (response.status === "success") {
|
|
3598
|
+
resolve(response);
|
|
3599
|
+
} else {
|
|
3600
|
+
reject(new Error(response.message || "Custom event failed"));
|
|
3601
|
+
}
|
|
3602
|
+
});
|
|
3603
|
+
});
|
|
3604
|
+
}
|
|
3605
|
+
setupRoomListeners(roomName) {
|
|
3606
|
+
if (!this.roomCallbacks.has(roomName)) {
|
|
3607
|
+
this.roomCallbacks.set(roomName, /* @__PURE__ */ new Map());
|
|
3608
|
+
}
|
|
3609
|
+
if (!this.roomUserCallbacks.has(roomName)) {
|
|
3610
|
+
this.roomUserCallbacks.set(roomName, { joined: /* @__PURE__ */ new Set(), left: /* @__PURE__ */ new Set() });
|
|
3611
|
+
}
|
|
3612
|
+
}
|
|
3613
|
+
cleanupRoomListeners(roomName) {
|
|
3614
|
+
this.roomCallbacks.delete(roomName);
|
|
3615
|
+
this.roomUserCallbacks.delete(roomName);
|
|
3616
|
+
}
|
|
3617
|
+
// ===================
|
|
3385
3618
|
// Channel (Room) API - Supabase-style
|
|
3386
3619
|
// ===================
|
|
3387
3620
|
/**
|