@slotchain/sdk 1.1.3 → 1.2.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/dist/index.cjs.js +257 -16
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.mts +324 -28
- package/dist/index.d.ts +324 -28
- package/dist/index.esm.js +257 -16
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -2
- package/src/clients/__tests__/service-client.spec.ts +450 -0
- package/src/clients/customer-client.ts +129 -29
- package/src/clients/customer-client.ts.bak +165 -0
- package/src/clients/document-client.ts +148 -0
- package/src/clients/service-client.ts +87 -1
- package/src/clients/slot-client.ts +8 -5
- package/src/index.ts +17 -0
- package/src/types/api.ts +172 -7
- package/src/types/next-ambient.d.ts +29 -0
package/dist/index.cjs.js
CHANGED
|
@@ -365,10 +365,79 @@ var ServiceClient = class {
|
|
|
365
365
|
);
|
|
366
366
|
return response.data;
|
|
367
367
|
}
|
|
368
|
+
/**
|
|
369
|
+
* Get services for a tenant (full list with optional filters)
|
|
370
|
+
* GET /api/v1/services
|
|
371
|
+
*
|
|
372
|
+
* @param options - Query options
|
|
373
|
+
* @param options.tenantId - Tenant ID (UUID) - required if tenantSlug not provided
|
|
374
|
+
* @param options.tenantSlug - Tenant slug - required if tenantId not provided
|
|
375
|
+
* @param options.slotId - Slot ID (DEPRECATED - accepted but ignored for API compatibility)
|
|
376
|
+
* @param options.isActive - Filter by active status
|
|
377
|
+
* @param options.includeItems - Include nested service items (default: false)
|
|
378
|
+
* @param options.page - Page number (default: 1)
|
|
379
|
+
* @param options.limit - Items per page (default: 20, max: 100)
|
|
380
|
+
* @returns Services with optional pagination metadata
|
|
381
|
+
*/
|
|
382
|
+
async getServicesByTenant(options) {
|
|
383
|
+
if (!options.tenantId && !options.tenantSlug) {
|
|
384
|
+
return {
|
|
385
|
+
success: false,
|
|
386
|
+
error: {
|
|
387
|
+
code: "MISSING_TENANT_ID",
|
|
388
|
+
message: "tenantId or tenantSlug is required"
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
const params = {};
|
|
393
|
+
if (options.tenantId) {
|
|
394
|
+
params.tenant_id = options.tenantId;
|
|
395
|
+
}
|
|
396
|
+
if (options.tenantSlug) {
|
|
397
|
+
params.tenantSlug = options.tenantSlug;
|
|
398
|
+
}
|
|
399
|
+
if (options.slotId) {
|
|
400
|
+
params.slot_id = options.slotId;
|
|
401
|
+
}
|
|
402
|
+
if (options.isActive !== void 0) {
|
|
403
|
+
params.is_active = options.isActive;
|
|
404
|
+
}
|
|
405
|
+
if (options.includeItems) {
|
|
406
|
+
params.includeItems = true;
|
|
407
|
+
}
|
|
408
|
+
if (options.page !== void 0) {
|
|
409
|
+
params.page = options.page;
|
|
410
|
+
}
|
|
411
|
+
if (options.limit !== void 0) {
|
|
412
|
+
params.limit = Math.min(options.limit, 100);
|
|
413
|
+
}
|
|
414
|
+
const response = await this.client.get(
|
|
415
|
+
"/api/v1/services",
|
|
416
|
+
{ params }
|
|
417
|
+
);
|
|
418
|
+
return response.data;
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Get services for a specific slot
|
|
422
|
+
* GET /api/v1/slots/:id/services
|
|
423
|
+
*
|
|
424
|
+
* Note: Services are tenant-level entities. This endpoint returns all active services
|
|
425
|
+
* for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').
|
|
426
|
+
*
|
|
427
|
+
* @param slotId - Slot ID (UUID)
|
|
428
|
+
* @returns Services with nested items (always includes items, only active services)
|
|
429
|
+
*/
|
|
430
|
+
async getServicesBySlot(slotId) {
|
|
431
|
+
const response = await this.client.get(
|
|
432
|
+
`/api/v1/slots/${slotId}/services`
|
|
433
|
+
);
|
|
434
|
+
return response.data;
|
|
435
|
+
}
|
|
368
436
|
/**
|
|
369
437
|
* List services by tenant slug
|
|
370
438
|
* GET /api/v1/services?tenantSlug=:slug
|
|
371
439
|
*
|
|
440
|
+
* @deprecated Consider using getServicesByTenant() for better type safety and validation
|
|
372
441
|
* @param slug - Tenant slug (or use tenant_id in list() method)
|
|
373
442
|
* @param params - Optional parameters (includeItems, page, limit, is_active)
|
|
374
443
|
* @returns List of services for the tenant
|
|
@@ -384,6 +453,7 @@ var ServiceClient = class {
|
|
|
384
453
|
* List services with optional filters
|
|
385
454
|
* GET /api/v1/services
|
|
386
455
|
*
|
|
456
|
+
* @deprecated Consider using getServicesByTenant() for better type safety and validation
|
|
387
457
|
* @param params - Query parameters (tenant_id, tenantSlug, slot_id, page, limit, is_active, includeItems)
|
|
388
458
|
* @returns Paginated list of services
|
|
389
459
|
*/
|
|
@@ -700,8 +770,11 @@ var SlotClient = class {
|
|
|
700
770
|
* Get all active services for a slot with their items
|
|
701
771
|
* GET /api/v1/slots/:id/services
|
|
702
772
|
*
|
|
703
|
-
*
|
|
704
|
-
*
|
|
773
|
+
* Note: Services are tenant-level entities. This endpoint returns all active services
|
|
774
|
+
* for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').
|
|
775
|
+
*
|
|
776
|
+
* @param id - Slot ID (UUID)
|
|
777
|
+
* @returns Services with nested items (always includes items, only active services)
|
|
705
778
|
*/
|
|
706
779
|
async getServices(id) {
|
|
707
780
|
const response = await this.client.get(
|
|
@@ -774,9 +847,6 @@ var CustomerClient = class {
|
|
|
774
847
|
/**
|
|
775
848
|
* Create a new customer
|
|
776
849
|
* POST /api/v1/customers
|
|
777
|
-
*
|
|
778
|
-
* @param data - Customer creation data (tenant_id, name, email required)
|
|
779
|
-
* @returns Created customer
|
|
780
850
|
*/
|
|
781
851
|
async create(data) {
|
|
782
852
|
const response = await this.client.post(
|
|
@@ -828,11 +898,8 @@ var CustomerClient = class {
|
|
|
828
898
|
return response.data;
|
|
829
899
|
}
|
|
830
900
|
/**
|
|
831
|
-
* Get autocomplete data from existing customers and bookings
|
|
832
|
-
* GET /api/v1/customers/autocomplete
|
|
833
|
-
*
|
|
834
|
-
* @param tenantId - Tenant ID (required)
|
|
835
|
-
* @returns Autocomplete data
|
|
901
|
+
* Get autocomplete data from existing customers and bookings.
|
|
902
|
+
* GET /api/v1/customers/autocomplete?tenantId=:tenantId
|
|
836
903
|
*/
|
|
837
904
|
async autocomplete(tenantId) {
|
|
838
905
|
const response = await this.client.get(
|
|
@@ -842,11 +909,8 @@ var CustomerClient = class {
|
|
|
842
909
|
return response.data;
|
|
843
910
|
}
|
|
844
911
|
/**
|
|
845
|
-
* Get all bookings for a customer
|
|
846
|
-
* GET /api/v1/customers/bookings
|
|
847
|
-
*
|
|
848
|
-
* @param params - Query parameters (email optional, userId optional, tenantId required)
|
|
849
|
-
* @returns Customer bookings data
|
|
912
|
+
* Get all bookings for a customer, grouped by slot.
|
|
913
|
+
* GET /api/v1/customers/bookings?tenantId=:id
|
|
850
914
|
*/
|
|
851
915
|
async getBookings(params) {
|
|
852
916
|
const response = await this.client.get(
|
|
@@ -855,6 +919,85 @@ var CustomerClient = class {
|
|
|
855
919
|
);
|
|
856
920
|
return response.data;
|
|
857
921
|
}
|
|
922
|
+
// ─── Atomic upsert ────────────────────────────────────────────────────────
|
|
923
|
+
/**
|
|
924
|
+
* Atomic upsert: find an existing customer by email within a tenant, or create one.
|
|
925
|
+
* POST /api/v1/customers/find-or-create
|
|
926
|
+
*/
|
|
927
|
+
async findOrCreate(options) {
|
|
928
|
+
const response = await this.client.post(
|
|
929
|
+
"/api/v1/customers/find-or-create",
|
|
930
|
+
options
|
|
931
|
+
);
|
|
932
|
+
return response.data;
|
|
933
|
+
}
|
|
934
|
+
/**
|
|
935
|
+
* Resolve a customer from an IDP identity or email.
|
|
936
|
+
* Tries idpId lookup (customer_users) first, then falls back to email.
|
|
937
|
+
* POST /api/v1/customers/resolve
|
|
938
|
+
*/
|
|
939
|
+
async resolve(options) {
|
|
940
|
+
const response = await this.client.post(
|
|
941
|
+
"/api/v1/customers/resolve",
|
|
942
|
+
options
|
|
943
|
+
);
|
|
944
|
+
return response.data;
|
|
945
|
+
}
|
|
946
|
+
// ─── IDP Identity Management ─────────────────────────────────────────────
|
|
947
|
+
/**
|
|
948
|
+
* Get a customer with their linked IDP identities (customer_users rows).
|
|
949
|
+
* GET /api/v1/customers/:id?include_identities=true
|
|
950
|
+
*/
|
|
951
|
+
async getWithIdentities(id) {
|
|
952
|
+
const response = await this.client.get(
|
|
953
|
+
`/api/v1/customers/${id}`,
|
|
954
|
+
{ params: { include_identities: true } }
|
|
955
|
+
);
|
|
956
|
+
return response.data;
|
|
957
|
+
}
|
|
958
|
+
/**
|
|
959
|
+
* Link an IDP user ID to a customer (creates a customer_users row).
|
|
960
|
+
* POST /api/v1/customers/:id/users
|
|
961
|
+
*/
|
|
962
|
+
async linkUser(customerId, idpId, options) {
|
|
963
|
+
const response = await this.client.post(
|
|
964
|
+
`/api/v1/customers/${customerId}/users`,
|
|
965
|
+
{ idp_id: idpId, role: options?.role ?? "member", is_primary: options?.is_primary ?? false }
|
|
966
|
+
);
|
|
967
|
+
return response.data;
|
|
968
|
+
}
|
|
969
|
+
/**
|
|
970
|
+
* Unlink an IDP user from a customer (deletes the customer_users row).
|
|
971
|
+
* DELETE /api/v1/customers/:id/users/:idpId
|
|
972
|
+
*/
|
|
973
|
+
async unlinkUser(customerId, idpId) {
|
|
974
|
+
const response = await this.client.delete(
|
|
975
|
+
`/api/v1/customers/${customerId}/users/${encodeURIComponent(idpId)}`
|
|
976
|
+
);
|
|
977
|
+
return response.data;
|
|
978
|
+
}
|
|
979
|
+
// ─── Notification Preferences ────────────────────────────────────────────
|
|
980
|
+
/**
|
|
981
|
+
* Get notification preferences for a customer.
|
|
982
|
+
* GET /api/v1/customers/:id/preferences/notifications
|
|
983
|
+
*/
|
|
984
|
+
async getNotificationPreferences(customerId) {
|
|
985
|
+
const response = await this.client.get(
|
|
986
|
+
`/api/v1/customers/${customerId}/preferences/notifications`
|
|
987
|
+
);
|
|
988
|
+
return response.data;
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Update notification preferences for a customer (partial merge).
|
|
992
|
+
* PATCH /api/v1/customers/:id/preferences/notifications
|
|
993
|
+
*/
|
|
994
|
+
async updateNotificationPreferences(customerId, preferences) {
|
|
995
|
+
const response = await this.client.patch(
|
|
996
|
+
`/api/v1/customers/${customerId}/preferences/notifications`,
|
|
997
|
+
preferences
|
|
998
|
+
);
|
|
999
|
+
return response.data;
|
|
1000
|
+
}
|
|
858
1001
|
};
|
|
859
1002
|
|
|
860
1003
|
// src/clients/flow-client.ts
|
|
@@ -1285,6 +1428,103 @@ var OrganizationClient = class {
|
|
|
1285
1428
|
}
|
|
1286
1429
|
};
|
|
1287
1430
|
|
|
1431
|
+
// src/clients/document-client.ts
|
|
1432
|
+
var DocumentClient = class {
|
|
1433
|
+
constructor(client) {
|
|
1434
|
+
this.base = "/api/v1/artifacts";
|
|
1435
|
+
this.client = client;
|
|
1436
|
+
}
|
|
1437
|
+
/**
|
|
1438
|
+
* Upload a file artifact.
|
|
1439
|
+
* Sends as multipart/form-data.
|
|
1440
|
+
*/
|
|
1441
|
+
async upload(options) {
|
|
1442
|
+
const form = new FormData();
|
|
1443
|
+
let blob;
|
|
1444
|
+
if (options.file instanceof Blob) {
|
|
1445
|
+
blob = options.file;
|
|
1446
|
+
} else {
|
|
1447
|
+
blob = new Blob([options.file], { type: options.mime_type ?? "application/octet-stream" });
|
|
1448
|
+
}
|
|
1449
|
+
form.append("file", blob, options.filename);
|
|
1450
|
+
form.append("related_entity_type", options.related_entity_type);
|
|
1451
|
+
form.append("related_entity_id", options.related_entity_id);
|
|
1452
|
+
if (options.label) form.append("label", options.label);
|
|
1453
|
+
if (options.mime_type) form.append("mime_type", options.mime_type);
|
|
1454
|
+
if (options.metadata) form.append("metadata", JSON.stringify(options.metadata));
|
|
1455
|
+
const response = await this.client.post(this.base, form, {
|
|
1456
|
+
headers: { "Content-Type": "multipart/form-data" }
|
|
1457
|
+
});
|
|
1458
|
+
const { data } = response.data;
|
|
1459
|
+
if (!data) throw new Error("No artifact returned from upload");
|
|
1460
|
+
return data;
|
|
1461
|
+
}
|
|
1462
|
+
/**
|
|
1463
|
+
* List artifacts for a specific entity.
|
|
1464
|
+
* Pass `signed: true` to get download URLs in each result.
|
|
1465
|
+
*/
|
|
1466
|
+
async listByEntity(entityType, entityId, options) {
|
|
1467
|
+
const response = await this.client.get(
|
|
1468
|
+
this.base,
|
|
1469
|
+
{
|
|
1470
|
+
params: {
|
|
1471
|
+
related_entity_type: entityType,
|
|
1472
|
+
related_entity_id: entityId,
|
|
1473
|
+
...options
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
);
|
|
1477
|
+
return response.data;
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* List artifacts with full filter options.
|
|
1481
|
+
*/
|
|
1482
|
+
async list(options) {
|
|
1483
|
+
const response = await this.client.get(
|
|
1484
|
+
this.base,
|
|
1485
|
+
{ params: options }
|
|
1486
|
+
);
|
|
1487
|
+
return response.data;
|
|
1488
|
+
}
|
|
1489
|
+
/**
|
|
1490
|
+
* Get a single artifact by ID.
|
|
1491
|
+
*/
|
|
1492
|
+
async get(id, signed = false) {
|
|
1493
|
+
const response = await this.client.get(
|
|
1494
|
+
`${this.base}/${id}`,
|
|
1495
|
+
{ params: signed ? { signed: true } : void 0 }
|
|
1496
|
+
);
|
|
1497
|
+
const { data } = response.data;
|
|
1498
|
+
if (!data) throw new Error(`Artifact ${id} not found`);
|
|
1499
|
+
return data;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* Get a signed download URL for an artifact.
|
|
1503
|
+
* Returns the full ArtifactWithUrl including `signed_url` and `signed_url_expires_at`.
|
|
1504
|
+
*/
|
|
1505
|
+
async getUrl(id) {
|
|
1506
|
+
return this.get(id, true);
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Delete an artifact and its stored file.
|
|
1510
|
+
*/
|
|
1511
|
+
async delete(id) {
|
|
1512
|
+
await this.client.delete(`${this.base}/${id}`);
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Update artifact label or metadata.
|
|
1516
|
+
*/
|
|
1517
|
+
async update(id, patch) {
|
|
1518
|
+
const response = await this.client.patch(
|
|
1519
|
+
`${this.base}/${id}`,
|
|
1520
|
+
patch
|
|
1521
|
+
);
|
|
1522
|
+
const { data } = response.data;
|
|
1523
|
+
if (!data) throw new Error(`Artifact ${id} not found`);
|
|
1524
|
+
return data;
|
|
1525
|
+
}
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1288
1528
|
// src/errors.ts
|
|
1289
1529
|
var SlotlyApiError = class _SlotlyApiError extends Error {
|
|
1290
1530
|
constructor(code, message, statusCode, details) {
|
|
@@ -1617,7 +1857,8 @@ var useSlotly = (options) => {
|
|
|
1617
1857
|
studio: new StudioClient(client),
|
|
1618
1858
|
notification: new NotificationClient(client),
|
|
1619
1859
|
dataQuality: new DataQualityClient(client),
|
|
1620
|
-
organization: new OrganizationClient(client)
|
|
1860
|
+
organization: new OrganizationClient(client),
|
|
1861
|
+
document: new DocumentClient(client)
|
|
1621
1862
|
};
|
|
1622
1863
|
};
|
|
1623
1864
|
var index_default = useSlotly;
|