@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.esm.js
CHANGED
|
@@ -324,10 +324,79 @@ var ServiceClient = class {
|
|
|
324
324
|
);
|
|
325
325
|
return response.data;
|
|
326
326
|
}
|
|
327
|
+
/**
|
|
328
|
+
* Get services for a tenant (full list with optional filters)
|
|
329
|
+
* GET /api/v1/services
|
|
330
|
+
*
|
|
331
|
+
* @param options - Query options
|
|
332
|
+
* @param options.tenantId - Tenant ID (UUID) - required if tenantSlug not provided
|
|
333
|
+
* @param options.tenantSlug - Tenant slug - required if tenantId not provided
|
|
334
|
+
* @param options.slotId - Slot ID (DEPRECATED - accepted but ignored for API compatibility)
|
|
335
|
+
* @param options.isActive - Filter by active status
|
|
336
|
+
* @param options.includeItems - Include nested service items (default: false)
|
|
337
|
+
* @param options.page - Page number (default: 1)
|
|
338
|
+
* @param options.limit - Items per page (default: 20, max: 100)
|
|
339
|
+
* @returns Services with optional pagination metadata
|
|
340
|
+
*/
|
|
341
|
+
async getServicesByTenant(options) {
|
|
342
|
+
if (!options.tenantId && !options.tenantSlug) {
|
|
343
|
+
return {
|
|
344
|
+
success: false,
|
|
345
|
+
error: {
|
|
346
|
+
code: "MISSING_TENANT_ID",
|
|
347
|
+
message: "tenantId or tenantSlug is required"
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
const params = {};
|
|
352
|
+
if (options.tenantId) {
|
|
353
|
+
params.tenant_id = options.tenantId;
|
|
354
|
+
}
|
|
355
|
+
if (options.tenantSlug) {
|
|
356
|
+
params.tenantSlug = options.tenantSlug;
|
|
357
|
+
}
|
|
358
|
+
if (options.slotId) {
|
|
359
|
+
params.slot_id = options.slotId;
|
|
360
|
+
}
|
|
361
|
+
if (options.isActive !== void 0) {
|
|
362
|
+
params.is_active = options.isActive;
|
|
363
|
+
}
|
|
364
|
+
if (options.includeItems) {
|
|
365
|
+
params.includeItems = true;
|
|
366
|
+
}
|
|
367
|
+
if (options.page !== void 0) {
|
|
368
|
+
params.page = options.page;
|
|
369
|
+
}
|
|
370
|
+
if (options.limit !== void 0) {
|
|
371
|
+
params.limit = Math.min(options.limit, 100);
|
|
372
|
+
}
|
|
373
|
+
const response = await this.client.get(
|
|
374
|
+
"/api/v1/services",
|
|
375
|
+
{ params }
|
|
376
|
+
);
|
|
377
|
+
return response.data;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Get services for a specific slot
|
|
381
|
+
* GET /api/v1/slots/:id/services
|
|
382
|
+
*
|
|
383
|
+
* Note: Services are tenant-level entities. This endpoint returns all active services
|
|
384
|
+
* for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').
|
|
385
|
+
*
|
|
386
|
+
* @param slotId - Slot ID (UUID)
|
|
387
|
+
* @returns Services with nested items (always includes items, only active services)
|
|
388
|
+
*/
|
|
389
|
+
async getServicesBySlot(slotId) {
|
|
390
|
+
const response = await this.client.get(
|
|
391
|
+
`/api/v1/slots/${slotId}/services`
|
|
392
|
+
);
|
|
393
|
+
return response.data;
|
|
394
|
+
}
|
|
327
395
|
/**
|
|
328
396
|
* List services by tenant slug
|
|
329
397
|
* GET /api/v1/services?tenantSlug=:slug
|
|
330
398
|
*
|
|
399
|
+
* @deprecated Consider using getServicesByTenant() for better type safety and validation
|
|
331
400
|
* @param slug - Tenant slug (or use tenant_id in list() method)
|
|
332
401
|
* @param params - Optional parameters (includeItems, page, limit, is_active)
|
|
333
402
|
* @returns List of services for the tenant
|
|
@@ -343,6 +412,7 @@ var ServiceClient = class {
|
|
|
343
412
|
* List services with optional filters
|
|
344
413
|
* GET /api/v1/services
|
|
345
414
|
*
|
|
415
|
+
* @deprecated Consider using getServicesByTenant() for better type safety and validation
|
|
346
416
|
* @param params - Query parameters (tenant_id, tenantSlug, slot_id, page, limit, is_active, includeItems)
|
|
347
417
|
* @returns Paginated list of services
|
|
348
418
|
*/
|
|
@@ -659,8 +729,11 @@ var SlotClient = class {
|
|
|
659
729
|
* Get all active services for a slot with their items
|
|
660
730
|
* GET /api/v1/slots/:id/services
|
|
661
731
|
*
|
|
662
|
-
*
|
|
663
|
-
*
|
|
732
|
+
* Note: Services are tenant-level entities. This endpoint returns all active services
|
|
733
|
+
* for the slot's tenant with items included. The response uses 'items' property (not 'serviceItems').
|
|
734
|
+
*
|
|
735
|
+
* @param id - Slot ID (UUID)
|
|
736
|
+
* @returns Services with nested items (always includes items, only active services)
|
|
664
737
|
*/
|
|
665
738
|
async getServices(id) {
|
|
666
739
|
const response = await this.client.get(
|
|
@@ -733,9 +806,6 @@ var CustomerClient = class {
|
|
|
733
806
|
/**
|
|
734
807
|
* Create a new customer
|
|
735
808
|
* POST /api/v1/customers
|
|
736
|
-
*
|
|
737
|
-
* @param data - Customer creation data (tenant_id, name, email required)
|
|
738
|
-
* @returns Created customer
|
|
739
809
|
*/
|
|
740
810
|
async create(data) {
|
|
741
811
|
const response = await this.client.post(
|
|
@@ -787,11 +857,8 @@ var CustomerClient = class {
|
|
|
787
857
|
return response.data;
|
|
788
858
|
}
|
|
789
859
|
/**
|
|
790
|
-
* Get autocomplete data from existing customers and bookings
|
|
791
|
-
* GET /api/v1/customers/autocomplete
|
|
792
|
-
*
|
|
793
|
-
* @param tenantId - Tenant ID (required)
|
|
794
|
-
* @returns Autocomplete data
|
|
860
|
+
* Get autocomplete data from existing customers and bookings.
|
|
861
|
+
* GET /api/v1/customers/autocomplete?tenantId=:tenantId
|
|
795
862
|
*/
|
|
796
863
|
async autocomplete(tenantId) {
|
|
797
864
|
const response = await this.client.get(
|
|
@@ -801,11 +868,8 @@ var CustomerClient = class {
|
|
|
801
868
|
return response.data;
|
|
802
869
|
}
|
|
803
870
|
/**
|
|
804
|
-
* Get all bookings for a customer
|
|
805
|
-
* GET /api/v1/customers/bookings
|
|
806
|
-
*
|
|
807
|
-
* @param params - Query parameters (email optional, userId optional, tenantId required)
|
|
808
|
-
* @returns Customer bookings data
|
|
871
|
+
* Get all bookings for a customer, grouped by slot.
|
|
872
|
+
* GET /api/v1/customers/bookings?tenantId=:id
|
|
809
873
|
*/
|
|
810
874
|
async getBookings(params) {
|
|
811
875
|
const response = await this.client.get(
|
|
@@ -814,6 +878,85 @@ var CustomerClient = class {
|
|
|
814
878
|
);
|
|
815
879
|
return response.data;
|
|
816
880
|
}
|
|
881
|
+
// ─── Atomic upsert ────────────────────────────────────────────────────────
|
|
882
|
+
/**
|
|
883
|
+
* Atomic upsert: find an existing customer by email within a tenant, or create one.
|
|
884
|
+
* POST /api/v1/customers/find-or-create
|
|
885
|
+
*/
|
|
886
|
+
async findOrCreate(options) {
|
|
887
|
+
const response = await this.client.post(
|
|
888
|
+
"/api/v1/customers/find-or-create",
|
|
889
|
+
options
|
|
890
|
+
);
|
|
891
|
+
return response.data;
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Resolve a customer from an IDP identity or email.
|
|
895
|
+
* Tries idpId lookup (customer_users) first, then falls back to email.
|
|
896
|
+
* POST /api/v1/customers/resolve
|
|
897
|
+
*/
|
|
898
|
+
async resolve(options) {
|
|
899
|
+
const response = await this.client.post(
|
|
900
|
+
"/api/v1/customers/resolve",
|
|
901
|
+
options
|
|
902
|
+
);
|
|
903
|
+
return response.data;
|
|
904
|
+
}
|
|
905
|
+
// ─── IDP Identity Management ─────────────────────────────────────────────
|
|
906
|
+
/**
|
|
907
|
+
* Get a customer with their linked IDP identities (customer_users rows).
|
|
908
|
+
* GET /api/v1/customers/:id?include_identities=true
|
|
909
|
+
*/
|
|
910
|
+
async getWithIdentities(id) {
|
|
911
|
+
const response = await this.client.get(
|
|
912
|
+
`/api/v1/customers/${id}`,
|
|
913
|
+
{ params: { include_identities: true } }
|
|
914
|
+
);
|
|
915
|
+
return response.data;
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Link an IDP user ID to a customer (creates a customer_users row).
|
|
919
|
+
* POST /api/v1/customers/:id/users
|
|
920
|
+
*/
|
|
921
|
+
async linkUser(customerId, idpId, options) {
|
|
922
|
+
const response = await this.client.post(
|
|
923
|
+
`/api/v1/customers/${customerId}/users`,
|
|
924
|
+
{ idp_id: idpId, role: options?.role ?? "member", is_primary: options?.is_primary ?? false }
|
|
925
|
+
);
|
|
926
|
+
return response.data;
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Unlink an IDP user from a customer (deletes the customer_users row).
|
|
930
|
+
* DELETE /api/v1/customers/:id/users/:idpId
|
|
931
|
+
*/
|
|
932
|
+
async unlinkUser(customerId, idpId) {
|
|
933
|
+
const response = await this.client.delete(
|
|
934
|
+
`/api/v1/customers/${customerId}/users/${encodeURIComponent(idpId)}`
|
|
935
|
+
);
|
|
936
|
+
return response.data;
|
|
937
|
+
}
|
|
938
|
+
// ─── Notification Preferences ────────────────────────────────────────────
|
|
939
|
+
/**
|
|
940
|
+
* Get notification preferences for a customer.
|
|
941
|
+
* GET /api/v1/customers/:id/preferences/notifications
|
|
942
|
+
*/
|
|
943
|
+
async getNotificationPreferences(customerId) {
|
|
944
|
+
const response = await this.client.get(
|
|
945
|
+
`/api/v1/customers/${customerId}/preferences/notifications`
|
|
946
|
+
);
|
|
947
|
+
return response.data;
|
|
948
|
+
}
|
|
949
|
+
/**
|
|
950
|
+
* Update notification preferences for a customer (partial merge).
|
|
951
|
+
* PATCH /api/v1/customers/:id/preferences/notifications
|
|
952
|
+
*/
|
|
953
|
+
async updateNotificationPreferences(customerId, preferences) {
|
|
954
|
+
const response = await this.client.patch(
|
|
955
|
+
`/api/v1/customers/${customerId}/preferences/notifications`,
|
|
956
|
+
preferences
|
|
957
|
+
);
|
|
958
|
+
return response.data;
|
|
959
|
+
}
|
|
817
960
|
};
|
|
818
961
|
|
|
819
962
|
// src/clients/flow-client.ts
|
|
@@ -1244,6 +1387,103 @@ var OrganizationClient = class {
|
|
|
1244
1387
|
}
|
|
1245
1388
|
};
|
|
1246
1389
|
|
|
1390
|
+
// src/clients/document-client.ts
|
|
1391
|
+
var DocumentClient = class {
|
|
1392
|
+
constructor(client) {
|
|
1393
|
+
this.base = "/api/v1/artifacts";
|
|
1394
|
+
this.client = client;
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Upload a file artifact.
|
|
1398
|
+
* Sends as multipart/form-data.
|
|
1399
|
+
*/
|
|
1400
|
+
async upload(options) {
|
|
1401
|
+
const form = new FormData();
|
|
1402
|
+
let blob;
|
|
1403
|
+
if (options.file instanceof Blob) {
|
|
1404
|
+
blob = options.file;
|
|
1405
|
+
} else {
|
|
1406
|
+
blob = new Blob([options.file], { type: options.mime_type ?? "application/octet-stream" });
|
|
1407
|
+
}
|
|
1408
|
+
form.append("file", blob, options.filename);
|
|
1409
|
+
form.append("related_entity_type", options.related_entity_type);
|
|
1410
|
+
form.append("related_entity_id", options.related_entity_id);
|
|
1411
|
+
if (options.label) form.append("label", options.label);
|
|
1412
|
+
if (options.mime_type) form.append("mime_type", options.mime_type);
|
|
1413
|
+
if (options.metadata) form.append("metadata", JSON.stringify(options.metadata));
|
|
1414
|
+
const response = await this.client.post(this.base, form, {
|
|
1415
|
+
headers: { "Content-Type": "multipart/form-data" }
|
|
1416
|
+
});
|
|
1417
|
+
const { data } = response.data;
|
|
1418
|
+
if (!data) throw new Error("No artifact returned from upload");
|
|
1419
|
+
return data;
|
|
1420
|
+
}
|
|
1421
|
+
/**
|
|
1422
|
+
* List artifacts for a specific entity.
|
|
1423
|
+
* Pass `signed: true` to get download URLs in each result.
|
|
1424
|
+
*/
|
|
1425
|
+
async listByEntity(entityType, entityId, options) {
|
|
1426
|
+
const response = await this.client.get(
|
|
1427
|
+
this.base,
|
|
1428
|
+
{
|
|
1429
|
+
params: {
|
|
1430
|
+
related_entity_type: entityType,
|
|
1431
|
+
related_entity_id: entityId,
|
|
1432
|
+
...options
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
);
|
|
1436
|
+
return response.data;
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* List artifacts with full filter options.
|
|
1440
|
+
*/
|
|
1441
|
+
async list(options) {
|
|
1442
|
+
const response = await this.client.get(
|
|
1443
|
+
this.base,
|
|
1444
|
+
{ params: options }
|
|
1445
|
+
);
|
|
1446
|
+
return response.data;
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* Get a single artifact by ID.
|
|
1450
|
+
*/
|
|
1451
|
+
async get(id, signed = false) {
|
|
1452
|
+
const response = await this.client.get(
|
|
1453
|
+
`${this.base}/${id}`,
|
|
1454
|
+
{ params: signed ? { signed: true } : void 0 }
|
|
1455
|
+
);
|
|
1456
|
+
const { data } = response.data;
|
|
1457
|
+
if (!data) throw new Error(`Artifact ${id} not found`);
|
|
1458
|
+
return data;
|
|
1459
|
+
}
|
|
1460
|
+
/**
|
|
1461
|
+
* Get a signed download URL for an artifact.
|
|
1462
|
+
* Returns the full ArtifactWithUrl including `signed_url` and `signed_url_expires_at`.
|
|
1463
|
+
*/
|
|
1464
|
+
async getUrl(id) {
|
|
1465
|
+
return this.get(id, true);
|
|
1466
|
+
}
|
|
1467
|
+
/**
|
|
1468
|
+
* Delete an artifact and its stored file.
|
|
1469
|
+
*/
|
|
1470
|
+
async delete(id) {
|
|
1471
|
+
await this.client.delete(`${this.base}/${id}`);
|
|
1472
|
+
}
|
|
1473
|
+
/**
|
|
1474
|
+
* Update artifact label or metadata.
|
|
1475
|
+
*/
|
|
1476
|
+
async update(id, patch) {
|
|
1477
|
+
const response = await this.client.patch(
|
|
1478
|
+
`${this.base}/${id}`,
|
|
1479
|
+
patch
|
|
1480
|
+
);
|
|
1481
|
+
const { data } = response.data;
|
|
1482
|
+
if (!data) throw new Error(`Artifact ${id} not found`);
|
|
1483
|
+
return data;
|
|
1484
|
+
}
|
|
1485
|
+
};
|
|
1486
|
+
|
|
1247
1487
|
// src/errors.ts
|
|
1248
1488
|
var SlotlyApiError = class _SlotlyApiError extends Error {
|
|
1249
1489
|
constructor(code, message, statusCode, details) {
|
|
@@ -1576,7 +1816,8 @@ var useSlotly = (options) => {
|
|
|
1576
1816
|
studio: new StudioClient(client),
|
|
1577
1817
|
notification: new NotificationClient(client),
|
|
1578
1818
|
dataQuality: new DataQualityClient(client),
|
|
1579
|
-
organization: new OrganizationClient(client)
|
|
1819
|
+
organization: new OrganizationClient(client),
|
|
1820
|
+
document: new DocumentClient(client)
|
|
1580
1821
|
};
|
|
1581
1822
|
};
|
|
1582
1823
|
var index_default = useSlotly;
|