@lilaquadrat/sdk 0.0.4

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/index.ts ADDED
@@ -0,0 +1,728 @@
1
+ import axios, { AxiosResponse, AxiosRequestConfig, HttpStatusCode } from 'axios';
2
+ import { Content, CustomerPerson, Customers, DataObject, List, ListOfModels, ListParticipants, ListPartiticpantsDetails } from '@lilaquadrat/interfaces';
3
+ import { hardCopy } from '@lilaquadrat/studio/lib/esm/frontend';
4
+
5
+ // const mockJs = {};
6
+ // const ISMOCK = false;
7
+
8
+ export type SDKResponse<T> = {
9
+ data: T
10
+ status: HttpStatusCode
11
+ cacheLifetime?: number
12
+ cacheTime?: number;
13
+ isCache?: boolean
14
+ };
15
+
16
+ export type SDKCache = {
17
+ group?: string
18
+ action?: string
19
+ id?: string
20
+ cacheLifetime?: number
21
+ cacheTime?: number;
22
+ };
23
+
24
+ export type SDKModes = 'live' | 'next' | 'custom';
25
+
26
+ export type SDKCallOptions = {
27
+ /**
28
+ * ignore the cache and always execute the call
29
+ */
30
+ bypassCache?: boolean
31
+ group?: string,
32
+ action?: string,
33
+ /**
34
+ * if a id is given, use it as key for atomic cache flushing
35
+ *
36
+ * e.g. ``flushId(id)``
37
+ *
38
+ * instead of the whole action category
39
+ *
40
+ * e.g. ``flushCache(group, action)``
41
+ *
42
+ */
43
+ id?: string
44
+ /**
45
+ * in milliseconds
46
+ */
47
+ cacheLifetime?: number
48
+ };
49
+
50
+ let cachedCalls: Record<string, SDKResponse<unknown> & SDKCache> = {};
51
+
52
+ export default class StudioSDK {
53
+
54
+ readonly endpoints = {
55
+ live: {
56
+ api: 'https://api.lilaquadrat.de',
57
+ media: 'https://media.lilaquadrat.de',
58
+ },
59
+ next: {
60
+ api: 'https://next-api.lilaquadrat.de',
61
+ media: 'https://next-media.lilaquadrat.de',
62
+ },
63
+ };
64
+
65
+ customEndpoints = {
66
+ api: '',
67
+ media: '',
68
+ };
69
+
70
+ authToken!: string;
71
+
72
+ mode: 'live' | 'next' | 'custom' = 'custom';
73
+
74
+ company!: string;
75
+
76
+ project!: string;
77
+
78
+ app: string;
79
+
80
+ universalModel!: string;
81
+
82
+ options: {
83
+ company?: string,
84
+ project?: string,
85
+ authToken?: string,
86
+ mode?: SDKModes,
87
+ customEndpoints?: { api: string, media: string }
88
+ universalModel?: string
89
+ } = {};
90
+
91
+ constructor(
92
+ app: string,
93
+ options: StudioSDK['options'],
94
+ ) {
95
+
96
+ if (options.authToken) this.authToken = options.authToken;
97
+
98
+ if (options.customEndpoints) this.customEndpoints = options.customEndpoints;
99
+
100
+ this.mode = options.customEndpoints ? 'custom' : options.mode || 'live';
101
+
102
+ if (options.company) this.company = options.company;
103
+
104
+ if (options.project) this.project = options.project;
105
+
106
+ this.app = app;
107
+
108
+ if (options.universalModel) this.universalModel = options.universalModel;
109
+
110
+ }
111
+
112
+ private getUrl(type: 'api' | 'media', methodArray: string[]) {
113
+
114
+ const method = methodArray.filter((single) => single);
115
+ const urlArray: string[] = [];
116
+ let useEndpoint: string;
117
+
118
+ if (this.mode === 'custom') {
119
+
120
+ useEndpoint = this.customEndpoints[type];
121
+
122
+ } else {
123
+
124
+ useEndpoint = this.endpoints[this.mode][type];
125
+
126
+ }
127
+
128
+ urlArray.push(useEndpoint);
129
+ urlArray.push(...method);
130
+
131
+ return urlArray.filter((single) => single).join('/');
132
+
133
+ }
134
+
135
+ private getHeaders() {
136
+
137
+ const headers: Record<string, string> = {
138
+ 'studio-app': this.app,
139
+ };
140
+
141
+ if (this.authToken) {
142
+
143
+ headers.Authorization = `bearer ${this.authToken}`;
144
+
145
+ }
146
+
147
+ return headers;
148
+
149
+ }
150
+
151
+ static getCacheKeyMock(url: string) {
152
+
153
+ const key = new URL(url);
154
+
155
+ return key.pathname + key.search;
156
+
157
+ }
158
+
159
+ static getCacheKey(url: string) {
160
+
161
+ let key: string = url;
162
+
163
+ key = key.replace(/:|\/|\?|=|&/ig, '-');
164
+
165
+ return key;
166
+
167
+ }
168
+
169
+ static getCache() {
170
+
171
+ return cachedCalls;
172
+
173
+ }
174
+
175
+ static handleCall<T, D = unknown>(call: AxiosRequestConfig<D>, options?: SDKCallOptions): Promise<SDKResponse<T>> {
176
+
177
+ // if (ISMOCK) {
178
+
179
+ // if (call.method !== 'GET') return Promise.resolve({ data: {} as T, status: 200 });
180
+
181
+ // const key = StudioSDK.getCacheKeyMock(call.url as string);
182
+
183
+ // console.group(`SDK_MOCK_CALL: [${call.method}] ${key}`);
184
+
185
+ // // if url is not in MockJs.ts, error will be thrown
186
+ // if (!mockJs[key]) {
187
+
188
+ // console.error(key);
189
+ // console.groupEnd();
190
+ // throw new Error('MOCK_DATA_MISSING');
191
+
192
+ // }
193
+
194
+ // console.log({ data: mockJs[key].data as T, status: mockJs[key].status });
195
+ // console.groupEnd();
196
+
197
+ // return Promise.resolve({ data: mockJs[key].data as T, status: mockJs[key].status });
198
+
199
+ // }
200
+
201
+ if (call.method === 'GET' && !options?.bypassCache) {
202
+
203
+ const cacheHit = StudioSDK.cache<T>(axios.getUri(call), undefined, options);
204
+
205
+ if (cacheHit) return Promise.resolve(cacheHit);
206
+
207
+ }
208
+
209
+ return axios.request(call)
210
+ .then((response) => {
211
+
212
+ if (call.method === 'GET') StudioSDK.cache(axios.getUri(call), response, options);
213
+
214
+ return response;
215
+
216
+ })
217
+ .then((response) => ({ data: response.data, status: response.status }));
218
+
219
+ }
220
+
221
+ static cache<T>(url: string, response?: AxiosResponse<T>, options?: SDKCallOptions) {
222
+
223
+ const key = options?.id ? options.id : StudioSDK.getCacheKey(url);
224
+
225
+ if (response) {
226
+
227
+ const useKey = options?.id
228
+ ? options.id
229
+ : key;
230
+
231
+ cachedCalls[useKey] = {
232
+ data: response.data,
233
+ status: response.status,
234
+ action: options?.action,
235
+ group: options?.group,
236
+ cacheLifetime: options?.cacheLifetime ? Date.now() + (options?.cacheLifetime || 0) : null,
237
+ cacheTime: Date.now(),
238
+ } as SDKResponse<T> & SDKCache;
239
+
240
+ return undefined;
241
+
242
+ }
243
+
244
+ const useCache = cachedCalls[key] as SDKResponse<T> & SDKCache;
245
+
246
+ if (!useCache) return null;
247
+
248
+ if (useCache.cacheLifetime && useCache.cacheLifetime < Date.now()) {
249
+
250
+ console.debug('cache found but lifetime');
251
+
252
+ delete cachedCalls[key];
253
+ return null;
254
+
255
+ }
256
+
257
+ const returnCache = hardCopy(useCache);
258
+
259
+ delete returnCache?.action;
260
+ delete returnCache?.group;
261
+ delete returnCache?.id;
262
+
263
+ returnCache.isCache = true;
264
+
265
+ return returnCache;
266
+
267
+ }
268
+
269
+ static flushCache(group?: string, action?: string) {
270
+
271
+ if (group || action) {
272
+
273
+ Object.keys(cachedCalls).forEach((key) => {
274
+
275
+ let flush: boolean = false;
276
+ const singleCache = cachedCalls[key];
277
+
278
+ if (group && action) {
279
+
280
+ if (singleCache.group === group && singleCache.action === action) flush = true;
281
+
282
+ } else if (group) {
283
+
284
+ if (singleCache.group === group) flush = true;
285
+
286
+ } else if (action) {
287
+
288
+ if (singleCache.action === action) flush = true;
289
+
290
+ }
291
+
292
+ if (flush) {
293
+
294
+ delete cachedCalls[key];
295
+
296
+ }
297
+
298
+ });
299
+
300
+ } else {
301
+
302
+ cachedCalls = {};
303
+
304
+ }
305
+
306
+ }
307
+
308
+ static flushId(id: string) {
309
+
310
+ delete cachedCalls[id];
311
+
312
+ }
313
+
314
+ public = {
315
+ content: {
316
+
317
+ fetch: (type: string, link: string, options?: { state?: 'draft' | 'publish' }) => StudioSDK.handleCall<Content>(
318
+ {
319
+ method: 'GET',
320
+ url: this.getUrl('api', ['public', 'content', type, link]),
321
+ headers: this.getHeaders(),
322
+ params: options,
323
+ },
324
+ ),
325
+
326
+ search: (type: string, search: string, site: number = 1, options?: { state?: 'draft' | 'publish' }) => {
327
+
328
+ const params = { search, ...options };
329
+
330
+ return StudioSDK.handleCall<Content>(
331
+ {
332
+ method: 'GET',
333
+ url: this.getUrl('api', ['public', 'content', type, 'search', site.toString()]),
334
+ headers: this.getHeaders(),
335
+ params,
336
+ },
337
+ );
338
+
339
+ },
340
+
341
+ predefined: (id: string) => StudioSDK.handleCall<Content>(
342
+ {
343
+ method: 'GET',
344
+ url: this.getUrl('api', ['public', 'content', 'lilaquadrat', 'studio', id]),
345
+ headers: this.getHeaders(),
346
+ },
347
+ {
348
+ group: 'editor',
349
+ action: 'single',
350
+ id,
351
+ },
352
+ ),
353
+
354
+ predefinedLatest: (categories: string[]) => StudioSDK.handleCall<Content>(
355
+ {
356
+ method: 'GET',
357
+ url: this.getUrl('api', ['public', 'content', 'lilaquadrat', 'studio', 'latest']),
358
+ headers: this.getHeaders(),
359
+ params: {
360
+ category: categories,
361
+ },
362
+ },
363
+ {
364
+ group: 'editor',
365
+ action: 'single',
366
+ },
367
+ ),
368
+
369
+ getById: (id: string) => StudioSDK.handleCall<Content>(
370
+ {
371
+ method: 'GET',
372
+ url: this.getUrl('api', ['public', 'content', this.company, this.project, id]),
373
+ headers: this.getHeaders(),
374
+ },
375
+ {
376
+ group: 'editor',
377
+ action: 'single',
378
+ id,
379
+ },
380
+ ),
381
+
382
+ getByInternalId: (id: string) => StudioSDK.handleCall<Content>(
383
+ {
384
+ method: 'GET',
385
+ url: this.getUrl('api', ['public', 'content', this.company, this.project, 'internal', id]),
386
+ headers: this.getHeaders(),
387
+ },
388
+ {
389
+ group: 'editor',
390
+ action: 'single',
391
+ id,
392
+ },
393
+ ),
394
+
395
+ },
396
+
397
+ lists: {
398
+ join: (listId: string, person: CustomerPerson, message: string, category: string, agreements: any) => StudioSDK.handleCall<Customers>(
399
+ {
400
+ method: 'POST',
401
+ url: this.getUrl('api', ['public', 'lists', 'participants', this.company, this.project, listId, 'join']),
402
+ headers: this.getHeaders(),
403
+ data: {
404
+ person,
405
+ agreements,
406
+ message,
407
+ category,
408
+ },
409
+ },
410
+ ),
411
+ address: (address: string) => StudioSDK.handleCall<ListOfModels<Location>>(
412
+ {
413
+ method: 'get',
414
+ url: this.getUrl('api', ['public', 'lists', 'participants', this.company, this.project, 'address']),
415
+ headers: this.getHeaders(),
416
+ params: {
417
+ address,
418
+ },
419
+ },
420
+ ),
421
+ state: (listId: string) => StudioSDK.handleCall<ListPartiticpantsDetails>(
422
+ {
423
+ method: 'get',
424
+ url: this.getUrl('api', ['public', 'lists', this.company, this.project, listId, 'state']),
425
+ headers: this.getHeaders(),
426
+ },
427
+ ),
428
+ },
429
+ };
430
+
431
+
432
+ editor = {
433
+ getById: (id: string) => StudioSDK.handleCall<Content>(
434
+ {
435
+ method: 'GET',
436
+ url: this.getUrl('api', ['editor', this.company, this.project, id]),
437
+ headers: this.getHeaders(),
438
+ },
439
+ {
440
+ group: 'editor',
441
+ action: 'single',
442
+ id,
443
+ },
444
+ ),
445
+
446
+ getByInternalId: (id: string) => StudioSDK.handleCall<Content>(
447
+ {
448
+ method: 'GET',
449
+ url: this.getUrl('api', ['editor', this.company, this.project, 'internal', id]),
450
+ headers: this.getHeaders(),
451
+ },
452
+ {
453
+ group: 'editor',
454
+ action: 'single',
455
+ id,
456
+ },
457
+ ),
458
+
459
+
460
+ settings: (data: { company: string, project: string }) => StudioSDK.handleCall<Content>(
461
+ {
462
+ method: 'GET',
463
+ url: this.getUrl('api', ['editor', data.company, data.project, 'settings']),
464
+ headers: this.getHeaders(),
465
+ },
466
+ {
467
+ group: 'editor',
468
+ action: 'settings',
469
+ },
470
+ ),
471
+
472
+ list: (site: number = 0, sort?: string, order?: number, options?: { layout?: boolean, partial?: boolean, active?: boolean, search?: string, tags?: string[] }) => {
473
+
474
+ const params = {
475
+ sort,
476
+ order,
477
+ ...(options || {}),
478
+ };
479
+
480
+ return StudioSDK.handleCall<ListOfModels<Content>>(
481
+ {
482
+ method: 'GET',
483
+ url: this.getUrl('api', ['editor', this.company, this.project, 'list', site.toString()]),
484
+ headers: this.getHeaders(),
485
+ params,
486
+ },
487
+ {
488
+ group: 'editor',
489
+ action: 'list',
490
+ },
491
+ );
492
+
493
+ },
494
+ };
495
+
496
+ health = {
497
+
498
+ health: () => StudioSDK.handleCall<void>(
499
+ {
500
+ method: 'GET',
501
+ url: this.getUrl('api', ['health']),
502
+ headers: this.getHeaders(),
503
+ },
504
+ ),
505
+
506
+ };
507
+
508
+ customers = {
509
+
510
+ list: (site: number = 0, search?: string, tags?: string[], type?: string, sort?: number, order?: string) => StudioSDK.handleCall<DataObject<Customers>>(
511
+ {
512
+ method: 'GET',
513
+ url: this.getUrl('api', ['customers', this.company, this.project, 'list', site.toString()]),
514
+ headers: this.getHeaders(),
515
+ params: {
516
+ search,
517
+ tags,
518
+ sort,
519
+ order,
520
+ type,
521
+ },
522
+ },
523
+ {
524
+ group: 'customers',
525
+ action: 'list',
526
+ },
527
+ ),
528
+
529
+ single: (id: string) => StudioSDK.handleCall<Customers>(
530
+ {
531
+ method: 'GET',
532
+ url: this.getUrl('api', ['customers', this.company, this.project, id]),
533
+ headers: this.getHeaders(),
534
+ },
535
+ {
536
+ group: 'customers',
537
+ action: 'single',
538
+ id,
539
+ },
540
+ ),
541
+
542
+ tags: (search: string) => StudioSDK.handleCall<string[]>(
543
+ {
544
+ method: 'GET',
545
+ url: this.getUrl('api', ['customers', this.company, this.project, 'tags', search]),
546
+ headers: this.getHeaders(),
547
+ },
548
+ {
549
+ group: 'customers',
550
+ action: 'tags',
551
+ },
552
+ ),
553
+
554
+ update: (id: string, data: Customers) => StudioSDK.handleCall<Customers>(
555
+ {
556
+ method: 'PUT',
557
+ url: this.getUrl('api', ['customers', this.company, this.project, id]),
558
+ headers: this.getHeaders(),
559
+ data,
560
+ },
561
+ ),
562
+
563
+ add: (data: Customers) => StudioSDK.handleCall<Customers>(
564
+ {
565
+ method: 'POST',
566
+ url: this.getUrl('api', ['customers', this.company, this.project]),
567
+ headers: this.getHeaders(),
568
+ data,
569
+ },
570
+ ),
571
+
572
+ remove: (id: string) => StudioSDK.handleCall<Customers>(
573
+ {
574
+ method: 'DELETE',
575
+ url: this.getUrl('api', ['customers', this.company, this.project, id]),
576
+ headers: this.getHeaders(),
577
+ },
578
+ ),
579
+
580
+ };
581
+
582
+ lists = {
583
+
584
+ single: (id: string) => StudioSDK.handleCall<List>(
585
+ {
586
+ method: 'GET',
587
+ url: this.getUrl('api', ['lists', this.company, this.project, id]),
588
+ headers: this.getHeaders(),
589
+ },
590
+ {
591
+ group: 'lists',
592
+ action: 'single',
593
+ id,
594
+ },
595
+ ),
596
+
597
+ add: (data: List) => StudioSDK.handleCall<List>(
598
+ {
599
+ method: 'POST',
600
+ url: this.getUrl('api', ['lists', this.company, this.project]),
601
+ headers: this.getHeaders(),
602
+ data,
603
+ },
604
+ ),
605
+
606
+ update: (id: string, data: List) => StudioSDK.handleCall<List>(
607
+ {
608
+ method: 'PUT',
609
+ url: this.getUrl('api', ['lists', this.company, this.project, id]),
610
+ headers: this.getHeaders(),
611
+ data,
612
+ },
613
+ ),
614
+
615
+ remove: (id: string) => StudioSDK.handleCall<List>(
616
+ {
617
+ method: 'DELETE',
618
+ url: this.getUrl('api', ['lists', this.company, this.project, id]),
619
+ headers: this.getHeaders(),
620
+ },
621
+ ),
622
+
623
+ getByInternalId: (id: string) => StudioSDK.handleCall<List>(
624
+ {
625
+ method: 'GET',
626
+ url: this.getUrl('api', ['lists', this.company, this.project, id]),
627
+ headers: this.getHeaders(),
628
+ },
629
+ {
630
+ group: 'lists',
631
+ action: 'single',
632
+ id,
633
+ },
634
+ ),
635
+
636
+ list: (site: number = 0, search?: string, tags?: string[], state?: string, sort?: string, order?: number) => StudioSDK.handleCall<DataObject<List[]>>(
637
+ {
638
+ method: 'GET',
639
+ url: this.getUrl('api', ['lists', this.company, this.project, 'list', site.toString()]),
640
+ headers: this.getHeaders(),
641
+ params: {
642
+ search,
643
+ tags,
644
+ sort,
645
+ order,
646
+ state,
647
+ },
648
+ },
649
+ {
650
+ group: 'lists',
651
+ action: 'list',
652
+ },
653
+ ),
654
+
655
+ participants: {
656
+
657
+ single: (listId: string, id: string) => StudioSDK.handleCall<ListParticipants>(
658
+ {
659
+ method: 'GET',
660
+ url: this.getUrl('api', ['lists', 'participants', this.company, this.project, listId, id]),
661
+ headers: this.getHeaders(),
662
+ },
663
+ {
664
+ group: 'listParticipants',
665
+ action: 'single',
666
+ id,
667
+ },
668
+ ),
669
+
670
+ udpateState: (listId: string, id: string, state: ListParticipants['state']) => StudioSDK.handleCall<ListParticipants>(
671
+ {
672
+ method: 'PUT',
673
+ url: this.getUrl('api', ['lists', 'participants', this.company, this.project, listId, 'state', id]),
674
+ headers: this.getHeaders(),
675
+ data: { state },
676
+ },
677
+ {
678
+ group: 'listParticipants',
679
+ action: 'single',
680
+ id,
681
+ },
682
+ ),
683
+
684
+ udpateNote: (listId: string, id: string, note: ListParticipants['note']) => StudioSDK.handleCall<ListParticipants>(
685
+ {
686
+ method: 'PUT',
687
+ url: this.getUrl('api', ['lists', 'participants', this.company, this.project, listId, 'note', id]),
688
+ headers: this.getHeaders(),
689
+ data: { note },
690
+ },
691
+ {
692
+ group: 'listParticipants',
693
+ action: 'single',
694
+ id,
695
+ },
696
+ ),
697
+
698
+ remove: (listId: string, id: string) => StudioSDK.handleCall<ListParticipants>(
699
+ {
700
+ method: 'DELETE',
701
+ url: this.getUrl('api', ['lists', 'participants', this.company, this.project, listId, id]),
702
+ headers: this.getHeaders(),
703
+ },
704
+ ),
705
+
706
+ list: (listId: string, site: number = 0, search?: string, tags?: string[], state?: string[], sort?: string, order?: number) => StudioSDK.handleCall<DataObject<ListParticipants>>(
707
+ {
708
+ method: 'GET',
709
+ url: this.getUrl('api', ['lists', 'participants', this.company, this.project, listId, 'list', site.toString()]),
710
+ headers: this.getHeaders(),
711
+ params: {
712
+ search,
713
+ tags,
714
+ sort,
715
+ order,
716
+ state,
717
+ },
718
+ },
719
+ {
720
+ group: 'listParticipants',
721
+ action: 'list',
722
+ },
723
+ ),
724
+
725
+ },
726
+ };
727
+
728
+ }