@slotchain/sdk 1.4.0 → 1.6.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.
@@ -0,0 +1,52 @@
1
+ import type { AxiosInstance } from 'axios';
2
+ import type { ApiResponse, SlotNotice, ListNoticesOptions } from '../types/api';
3
+
4
+ /**
5
+ * NoticesClient — read active slot-scoped operational notices.
6
+ *
7
+ * Notices are a product concept (early closure, venue change, general alert)
8
+ * backed by `slot_moments` internally — the SDK surface reflects the product,
9
+ * not the storage model. Each notice's attached graphic (if any) is already
10
+ * resolved to a signed `imageUrl` server-side.
11
+ *
12
+ * @example List active notices for a tenant
13
+ * ```ts
14
+ * const { data } = await slotly.notices.list({ tenantId });
15
+ * ```
16
+ */
17
+ export class NoticesClient {
18
+ private readonly client: AxiosInstance;
19
+ private readonly base = '/api/v1/notices';
20
+
21
+ constructor(client: AxiosInstance) {
22
+ this.client = client;
23
+ }
24
+
25
+ /**
26
+ * List active notices for a tenant.
27
+ * Returns only notices where visible_until > activeAt (default: now).
28
+ */
29
+ async list(options: ListNoticesOptions): Promise<ApiResponse<SlotNotice[]>> {
30
+ const response = await this.client.get<ApiResponse<SlotNotice[]>>(this.base, {
31
+ params: {
32
+ tenant_id: options.tenantId,
33
+ active_at: options.activeAt,
34
+ slot_id: options.slotId,
35
+ types: options.types?.join(','),
36
+ },
37
+ });
38
+ return response.data;
39
+ }
40
+
41
+ /**
42
+ * Get a single notice by its slot_moment id.
43
+ */
44
+ async getById(id: string, tenantId: string): Promise<SlotNotice> {
45
+ const response = await this.client.get<ApiResponse<SlotNotice>>(`${this.base}/${id}`, {
46
+ params: { tenant_id: tenantId },
47
+ });
48
+ const { data } = response.data;
49
+ if (!data) throw new Error(`Notice ${id} not found`);
50
+ return data;
51
+ }
52
+ }
@@ -172,7 +172,23 @@ export class TenantClient {
172
172
  `/api/v1/tenants/${slug}`,
173
173
  { params: { includeServices } }
174
174
  );
175
- return response.data;
175
+
176
+ // Strip soft-deleted and withdrawn items so consumers never have to
177
+ // guard against them — a deleted service or withdrawn role should be
178
+ // invisible to anything built on the SDK.
179
+ const data = response.data;
180
+ if (data?.data?.services) {
181
+ data.data.services = data.data.services
182
+ .filter((s) => !s.deleted_at)
183
+ .map((s) => ({
184
+ ...s,
185
+ serviceItems: (s.serviceItems ?? []).filter(
186
+ (item) => !item.deleted_at && !item.withdrawn_at,
187
+ ),
188
+ }));
189
+ }
190
+
191
+ return data;
176
192
  }
177
193
  }
178
194
 
package/src/index.ts CHANGED
@@ -11,6 +11,7 @@ import { NotificationClient } from './clients/notification-client';
11
11
  import { DataQualityClient } from './clients/data-quality-client';
12
12
  import { OrganizationClient } from './clients/organization-client';
13
13
  import { DocumentClient } from './clients/document-client';
14
+ import { NoticesClient } from './clients/notices-client';
14
15
  import { setupRequestInterceptor, setupResponseInterceptor, setupErrorInterceptor } from './interceptors';
15
16
  import { setupRetryInterceptor } from './retry';
16
17
  import { SlotlyConfigurationError } from './errors';
@@ -55,6 +56,10 @@ export type {
55
56
  ArtifactMimeCategory,
56
57
  ListArtifactsOptions,
57
58
  UploadArtifactOptions,
59
+ SlotNotice,
60
+ NoticeMomentType,
61
+ NoticeCta,
62
+ ListNoticesOptions,
58
63
  } from './types/api';
59
64
 
60
65
  // Re-export errors
@@ -123,6 +128,8 @@ export interface SlotlyApi {
123
128
  organization: OrganizationClient;
124
129
  /** Upload and retrieve file artifacts (CVs, invoices, images) linked to any Slotly entity */
125
130
  document: DocumentClient;
131
+ /** List slot-scoped operational notices (early closure, venue change, general alerts) */
132
+ notices: NoticesClient;
126
133
  }
127
134
 
128
135
  const defaultBaseURL = typeof process !== 'undefined' && process.env?.SLOTLY_API_URL
@@ -317,6 +324,7 @@ export const useSlotly = (options: SlotlyClientOptions): SlotlyApi => {
317
324
  dataQuality: new DataQualityClient(client),
318
325
  organization: new OrganizationClient(client),
319
326
  document: new DocumentClient(client),
327
+ notices: new NoticesClient(client),
320
328
  };
321
329
  };
322
330
 
package/src/types/api.ts CHANGED
@@ -68,6 +68,10 @@ export interface ServiceItem {
68
68
  sort_order?: number;
69
69
  created_at: string;
70
70
  updated_at: string;
71
+ /** Set when the item has been soft-deleted. Filtered out by the SDK. */
72
+ deleted_at?: string | null;
73
+ /** Set when the item was withdrawn by the publisher (syndication). Filtered out by the SDK. */
74
+ withdrawn_at?: string | null;
71
75
  }
72
76
 
73
77
  /**
@@ -170,6 +174,8 @@ export interface Service {
170
174
  price?: number;
171
175
  created_at: string;
172
176
  updated_at: string;
177
+ /** Set when the service has been soft-deleted. Filtered out by the SDK. */
178
+ deleted_at?: string | null;
173
179
  }
174
180
 
175
181
  /**
@@ -424,7 +430,7 @@ export interface GetOrganizationOptions {
424
430
  /**
425
431
  * Artifact / document attached to a customer or booking
426
432
  */
427
- export type ArtifactEntityType = 'customer' | 'booking' | 'slot' | 'service' | 'tenant';
433
+ export type ArtifactEntityType = 'customer' | 'booking' | 'slot' | 'service' | 'tenant' | 'slot_moment';
428
434
 
429
435
  export type ArtifactMimeCategory = 'pdf' | 'document' | 'image' | 'spreadsheet' | 'video' | 'audio' | 'other';
430
436
 
@@ -488,6 +494,67 @@ export interface UploadArtifactOptions {
488
494
  metadata?: Record<string, unknown>;
489
495
  }
490
496
 
497
+ /**
498
+ * Slot-scoped operational notice (early closure, venue change, general alert).
499
+ * Backed by a `slot_moment` — see NOTICES_PLAN.md in slotly-admin.
500
+ */
501
+ export type NoticeMomentType =
502
+ | 'general_notice'
503
+ | 'early_closure'
504
+ | 'closure_notice'
505
+ | 'venue_change';
506
+
507
+ /**
508
+ * Optional call-to-action button attached to a notice.
509
+ * `url` is either an absolute http(s) URL or a site-relative path ('/contact-us').
510
+ * Only returned when both halves are present — a partial CTA is dropped server-side.
511
+ */
512
+ export interface NoticeCta {
513
+ label: string;
514
+ url: string;
515
+ /** Open the link in a new tab. Defaults to true for notices created without the flag. */
516
+ newTab: boolean;
517
+ }
518
+
519
+ export interface SlotNotice {
520
+ id: string;
521
+ slotId: string;
522
+ tenantId: string;
523
+ momentType: NoticeMomentType;
524
+ createdAt: string;
525
+ createdBy: string | null;
526
+ notice: {
527
+ type: string;
528
+ title: string;
529
+ message: string;
530
+ /** YYYY-MM-DD — the day the notice applies to */
531
+ affectedDate: string;
532
+ /** HH:MM — only present for early_closure notices */
533
+ closesAt?: string;
534
+ severity: 'info' | 'warning' | 'urgent';
535
+ visibleFrom: string;
536
+ visibleUntil: string;
537
+ dismissible: boolean;
538
+ /** Signed URL for the notice's attached graphic, if one was uploaded */
539
+ imageUrl?: string | null;
540
+ /** Staff-picked display treatment — 'banner' (compact, stacks) or 'modal' (full-screen, one at a time) */
541
+ presentation: 'banner' | 'modal';
542
+ /** Call-to-action button, or null when the notice has none */
543
+ cta?: NoticeCta | null;
544
+ };
545
+ affectedBookingIds: string[];
546
+ }
547
+
548
+ export interface ListNoticesOptions {
549
+ tenantId: string;
550
+ /** Filter to notices active at this ISO timestamp. Defaults to now. */
551
+ activeAt?: string;
552
+ /** Filter to a specific slot */
553
+ slotId?: string;
554
+ /** Specific notice types to include. Defaults to all notice types. */
555
+ types?: NoticeMomentType[];
556
+ }
557
+
491
558
  /**
492
559
  * Full tenant configuration including branding, services, and service items
493
560
  * Service items are nested within each service object (not as a separate top-level array)