@ysk-kit/sdk 1.0.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.
Files changed (62) hide show
  1. package/LICENSE +21 -0
  2. package/dist/http.d.ts +18 -0
  3. package/dist/http.d.ts.map +1 -0
  4. package/dist/http.js +113 -0
  5. package/dist/http.js.map +1 -0
  6. package/dist/index.d.ts +341 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +41 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/ports/device.d.ts +5 -0
  11. package/dist/ports/device.d.ts.map +1 -0
  12. package/dist/ports/device.js +2 -0
  13. package/dist/ports/device.js.map +1 -0
  14. package/dist/ports/file-picker.d.ts +7 -0
  15. package/dist/ports/file-picker.d.ts.map +1 -0
  16. package/dist/ports/file-picker.js +2 -0
  17. package/dist/ports/file-picker.js.map +1 -0
  18. package/dist/realtime.d.ts +11 -0
  19. package/dist/realtime.d.ts.map +1 -0
  20. package/dist/realtime.js +17 -0
  21. package/dist/realtime.js.map +1 -0
  22. package/dist/resources/api-keys.d.ts +27 -0
  23. package/dist/resources/api-keys.d.ts.map +1 -0
  24. package/dist/resources/api-keys.js +9 -0
  25. package/dist/resources/api-keys.js.map +1 -0
  26. package/dist/resources/audit.d.ts +18 -0
  27. package/dist/resources/audit.d.ts.map +1 -0
  28. package/dist/resources/audit.js +13 -0
  29. package/dist/resources/audit.js.map +1 -0
  30. package/dist/resources/auth.d.ts +103 -0
  31. package/dist/resources/auth.d.ts.map +1 -0
  32. package/dist/resources/auth.js +74 -0
  33. package/dist/resources/auth.js.map +1 -0
  34. package/dist/resources/billing.d.ts +36 -0
  35. package/dist/resources/billing.d.ts.map +1 -0
  36. package/dist/resources/billing.js +20 -0
  37. package/dist/resources/billing.js.map +1 -0
  38. package/dist/resources/devices.d.ts +20 -0
  39. package/dist/resources/devices.d.ts.map +1 -0
  40. package/dist/resources/devices.js +6 -0
  41. package/dist/resources/devices.js.map +1 -0
  42. package/dist/resources/llm.d.ts +30 -0
  43. package/dist/resources/llm.d.ts.map +1 -0
  44. package/dist/resources/llm.js +49 -0
  45. package/dist/resources/llm.js.map +1 -0
  46. package/dist/resources/notifications.d.ts +20 -0
  47. package/dist/resources/notifications.d.ts.map +1 -0
  48. package/dist/resources/notifications.js +12 -0
  49. package/dist/resources/notifications.js.map +1 -0
  50. package/dist/resources/organizations.d.ts +62 -0
  51. package/dist/resources/organizations.d.ts.map +1 -0
  52. package/dist/resources/organizations.js +33 -0
  53. package/dist/resources/organizations.js.map +1 -0
  54. package/dist/resources/users.d.ts +38 -0
  55. package/dist/resources/users.d.ts.map +1 -0
  56. package/dist/resources/users.js +15 -0
  57. package/dist/resources/users.js.map +1 -0
  58. package/dist/token-store.d.ts +13 -0
  59. package/dist/token-store.d.ts.map +1 -0
  60. package/dist/token-store.js +35 -0
  61. package/dist/token-store.js.map +1 -0
  62. package/package.json +35 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 YSK Limited
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/http.d.ts ADDED
@@ -0,0 +1,18 @@
1
+ import { type Platform } from '@ysk-kit/contracts';
2
+ import type { TokenStore } from './token-store';
3
+ export declare class HttpClient {
4
+ private readonly opts;
5
+ private refreshing;
6
+ constructor(opts: {
7
+ baseUrl: string;
8
+ tokenStore: TokenStore;
9
+ platform: Platform;
10
+ fetchImpl?: typeof fetch;
11
+ onRefreshed?: (access: string, refresh: string) => Promise<void>;
12
+ });
13
+ request<T>(path: string, init?: RequestInit, didRefresh?: boolean): Promise<T>;
14
+ requestLocation(path: string): Promise<string>;
15
+ private refreshOnce;
16
+ private doRefresh;
17
+ }
18
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,qBAAa,UAAU;IAInB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHvB,OAAO,CAAC,UAAU,CAAiC;gBAGhC,IAAI,EAAE;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,UAAU,CAAC;QACvB,QAAQ,EAAE,QAAQ,CAAC;QACnB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;QACzB,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KAClE;IAGG,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,EAAE,UAAU,UAAQ,GAAG,OAAO,CAAC,CAAC,CAAC;IAsChF,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IA4BpD,OAAO,CAAC,WAAW;YASL,SAAS;CAuCxB"}
package/dist/http.js ADDED
@@ -0,0 +1,113 @@
1
+ import { ErrSchema } from '@ysk-kit/contracts';
2
+ import { AppError } from '@ysk-kit/domain-kernel';
3
+ export class HttpClient {
4
+ opts;
5
+ refreshing = null;
6
+ constructor(opts) {
7
+ this.opts = opts;
8
+ }
9
+ async request(path, init = {}, didRefresh = false) {
10
+ const fetchImpl = this.opts.fetchImpl ?? fetch;
11
+ const token = await this.opts.tokenStore.get();
12
+ const headers = new Headers(init.headers);
13
+ if (!headers.has('content-type') && init.body)
14
+ headers.set('content-type', 'application/json');
15
+ headers.set('x-ysk-platform', this.opts.platform);
16
+ if (token)
17
+ headers.set('authorization', `Bearer ${token}`);
18
+ const res = await fetchImpl(`${this.opts.baseUrl}${path}`, { ...init, headers });
19
+ const json = await res.json().catch(() => null);
20
+ const failed = ErrSchema.safeParse(json);
21
+ if (failed.success &&
22
+ failed.data.error.code === 'UNAUTHENTICATED' &&
23
+ !didRefresh &&
24
+ token &&
25
+ !path.startsWith('/v1/auth/')) {
26
+ const ok = await this.refreshOnce();
27
+ if (ok)
28
+ return this.request(path, init, true);
29
+ }
30
+ if (failed.success) {
31
+ throw new AppError(failed.data.error.code, failed.data.error.message, res.status, failed.data.error.details);
32
+ }
33
+ if (!res.ok) {
34
+ throw new AppError('INTERNAL', `HTTP ${res.status}`, res.status);
35
+ }
36
+ if (typeof json === 'object' && json !== null && 'ok' in json && 'data' in json) {
37
+ return json.data;
38
+ }
39
+ throw new AppError('INTERNAL', 'Malformed response', res.status);
40
+ }
41
+ async requestLocation(path) {
42
+ const fetchImpl = this.opts.fetchImpl ?? fetch;
43
+ const token = await this.opts.tokenStore.get();
44
+ const headers = new Headers();
45
+ headers.set('x-ysk-platform', this.opts.platform);
46
+ if (token)
47
+ headers.set('authorization', `Bearer ${token}`);
48
+ const res = await fetchImpl(`${this.opts.baseUrl}${path}`, {
49
+ method: 'GET',
50
+ headers,
51
+ redirect: 'manual',
52
+ });
53
+ if (res.status === 302 || res.status === 301) {
54
+ const location = res.headers.get('location');
55
+ if (location)
56
+ return location;
57
+ }
58
+ const json = await res.json().catch(() => null);
59
+ const failed = ErrSchema.safeParse(json);
60
+ if (failed.success) {
61
+ throw new AppError(failed.data.error.code, failed.data.error.message, res.status, failed.data.error.details);
62
+ }
63
+ throw new AppError('NOT_FOUND', 'Invoice PDF not found', res.status);
64
+ }
65
+ refreshOnce() {
66
+ if (!this.refreshing) {
67
+ this.refreshing = this.doRefresh().finally(() => {
68
+ this.refreshing = null;
69
+ });
70
+ }
71
+ return this.refreshing;
72
+ }
73
+ async doRefresh() {
74
+ const refresh = await this.opts.tokenStore.getRefresh?.();
75
+ if (!refresh) {
76
+ await this.opts.tokenStore.clear();
77
+ return false;
78
+ }
79
+ try {
80
+ const fetchImpl = this.opts.fetchImpl ?? fetch;
81
+ const res = await fetchImpl(`${this.opts.baseUrl}/v1/auth/refresh`, {
82
+ method: 'POST',
83
+ headers: {
84
+ 'content-type': 'application/json',
85
+ 'x-ysk-platform': this.opts.platform,
86
+ },
87
+ body: JSON.stringify({ refreshToken: refresh }),
88
+ });
89
+ const json = await res.json();
90
+ if (typeof json === 'object' &&
91
+ json !== null &&
92
+ 'ok' in json &&
93
+ json.ok === true &&
94
+ 'data' in json) {
95
+ const data = json.data;
96
+ if (this.opts.tokenStore.setPair) {
97
+ await this.opts.tokenStore.setPair(data.accessToken, data.refreshToken);
98
+ }
99
+ else {
100
+ await this.opts.tokenStore.set(data.accessToken);
101
+ }
102
+ await this.opts.onRefreshed?.(data.accessToken, data.refreshToken);
103
+ return true;
104
+ }
105
+ }
106
+ catch {
107
+ /* fall through */
108
+ }
109
+ await this.opts.tokenStore.clear();
110
+ return false;
111
+ }
112
+ }
113
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAiB,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,MAAM,OAAO,UAAU;IAIF;IAHX,UAAU,GAA4B,IAAI,CAAC;IAEnD,YACmB,IAMhB;QANgB,SAAI,GAAJ,IAAI,CAMpB;IACA,CAAC;IAEJ,KAAK,CAAC,OAAO,CAAI,IAAY,EAAE,OAAoB,EAAE,EAAE,UAAU,GAAG,KAAK;QACvE,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,IAAI;YAAE,OAAO,CAAC,GAAG,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;QAC/F,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC;QAE3D,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACjF,MAAM,IAAI,GAAY,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACzC,IACE,MAAM,CAAC,OAAO;YACd,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,iBAAiB;YAC5C,CAAC,UAAU;YACX,KAAK;YACL,CAAC,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAC7B,CAAC;YACD,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC;YACpC,IAAI,EAAE;gBAAE,OAAO,IAAI,CAAC,OAAO,CAAI,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACnD,CAAC;QACD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,IAAI,QAAQ,CAChB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EACtB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EACzB,GAAG,CAAC,MAAM,EACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAC1B,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,QAAQ,GAAG,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACnE,CAAC;QACD,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YAChF,OAAQ,IAA8B,CAAC,IAAI,CAAC;QAC9C,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,oBAAoB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,IAAY;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;QAC/C,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;QAC/C,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,KAAK;YAAE,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,UAAU,KAAK,EAAE,CAAC,CAAC;QAC3D,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;YACzD,MAAM,EAAE,KAAK;YACb,OAAO;YACP,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC7C,MAAM,QAAQ,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC7C,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAC;QAChC,CAAC;QACD,MAAM,IAAI,GAAY,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,MAAM,GAAG,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,MAAM,IAAI,QAAQ,CAChB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EACtB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,EACzB,GAAG,CAAC,MAAM,EACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAC1B,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,QAAQ,CAAC,WAAW,EAAE,uBAAuB,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACvE,CAAC;IAEO,WAAW;QACjB,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;YACrB,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;gBAC9C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;YACzB,CAAC,CAAC,CAAC;QACL,CAAC;QACD,OAAO,IAAI,CAAC,UAAU,CAAC;IACzB,CAAC;IAEO,KAAK,CAAC,SAAS;QACrB,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,UAAU,EAAE,EAAE,CAAC;QAC1D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;YACnC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;YAC/C,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,kBAAkB,EAAE;gBAClE,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE;oBACP,cAAc,EAAE,kBAAkB;oBAClC,gBAAgB,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;iBACrC;gBACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;aAChD,CAAC,CAAC;YACH,MAAM,IAAI,GAAY,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;YACvC,IACE,OAAO,IAAI,KAAK,QAAQ;gBACxB,IAAI,KAAK,IAAI;gBACb,IAAI,IAAI,IAAI;gBACX,IAAwB,CAAC,EAAE,KAAK,IAAI;gBACrC,MAAM,IAAI,IAAI,EACd,CAAC;gBACD,MAAM,IAAI,GAAI,IAAgE,CAAC,IAAI,CAAC;gBACpF,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;oBACjC,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;gBAC1E,CAAC;qBAAM,CAAC;oBACN,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;gBACnD,CAAC;gBACD,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC;gBACnE,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;QACD,MAAM,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC;QACnC,OAAO,KAAK,CAAC;IACf,CAAC;CACF"}
@@ -0,0 +1,341 @@
1
+ import type { Platform } from '@ysk-kit/contracts';
2
+ import { connectRealtime } from './realtime';
3
+ import { createWebStorageTokenStore, memoryTokenStore, type TokenStore } from './token-store';
4
+ export declare function createYskClient(opts: {
5
+ baseUrl: string;
6
+ platform: Platform;
7
+ tokenStore?: TokenStore;
8
+ fetchImpl?: typeof fetch;
9
+ }): {
10
+ auth: {
11
+ register: (body: import("@ysk-kit/contracts").RegisterCommand) => Promise<{
12
+ accessToken: string;
13
+ refreshToken: string;
14
+ expiresIn: number;
15
+ user: {
16
+ id: string;
17
+ email: string | null;
18
+ phone: string | null;
19
+ displayName: string;
20
+ role: "USER" | "ADMIN" | "OPS";
21
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
22
+ createdAt: string;
23
+ };
24
+ }>;
25
+ login: (body: import("@ysk-kit/contracts").LoginPasswordCommand) => Promise<{
26
+ accessToken: string;
27
+ refreshToken: string;
28
+ expiresIn: number;
29
+ user: {
30
+ id: string;
31
+ email: string | null;
32
+ phone: string | null;
33
+ displayName: string;
34
+ role: "USER" | "ADMIN" | "OPS";
35
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
36
+ createdAt: string;
37
+ };
38
+ }>;
39
+ requestOtp: (body: import("@ysk-kit/contracts").RequestOtpCommand) => Promise<{
40
+ sent: true;
41
+ }>;
42
+ verifyOtp: (body: import("@ysk-kit/contracts").VerifyOtpCommand) => Promise<{
43
+ accessToken: string;
44
+ refreshToken: string;
45
+ expiresIn: number;
46
+ user: {
47
+ id: string;
48
+ email: string | null;
49
+ phone: string | null;
50
+ displayName: string;
51
+ role: "USER" | "ADMIN" | "OPS";
52
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
53
+ createdAt: string;
54
+ };
55
+ }>;
56
+ refresh: (body: import("@ysk-kit/contracts").RefreshCommand) => Promise<{
57
+ accessToken: string;
58
+ refreshToken: string;
59
+ expiresIn: number;
60
+ user: {
61
+ id: string;
62
+ email: string | null;
63
+ phone: string | null;
64
+ displayName: string;
65
+ role: "USER" | "ADMIN" | "OPS";
66
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
67
+ createdAt: string;
68
+ };
69
+ }>;
70
+ logout: () => Promise<void>;
71
+ me: () => Promise<{
72
+ id: string;
73
+ email: string | null;
74
+ phone: string | null;
75
+ displayName: string;
76
+ role: "USER" | "ADMIN" | "OPS";
77
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
78
+ createdAt: string;
79
+ }>;
80
+ requestAdminOtp: (body: import("@ysk-kit/contracts").RequestAdminOtpCommand) => Promise<{
81
+ sent: true;
82
+ }>;
83
+ verifyAdminOtp: (body: import("@ysk-kit/contracts").VerifyAdminOtpCommand) => Promise<{
84
+ accessToken: string;
85
+ refreshToken: string;
86
+ expiresIn: number;
87
+ user: {
88
+ id: string;
89
+ email: string | null;
90
+ phone: string | null;
91
+ displayName: string;
92
+ role: "USER" | "ADMIN" | "OPS";
93
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
94
+ createdAt: string;
95
+ };
96
+ }>;
97
+ forgot: (body: {
98
+ email: string;
99
+ }) => Promise<{
100
+ accepted: true;
101
+ }>;
102
+ reset: (body: {
103
+ token: string;
104
+ password: string;
105
+ }) => Promise<{
106
+ accepted: true;
107
+ }>;
108
+ };
109
+ apiKeys: {
110
+ list: () => Promise<{
111
+ id: string;
112
+ name: string;
113
+ prefix: string;
114
+ last4: string;
115
+ permissions: ("user.create" | "user.suspend" | "audit.read" | "file.upload" | "llm.use" | "billing.checkout")[];
116
+ createdAt: string;
117
+ lastUsedAt: string | null;
118
+ }[]>;
119
+ create: (body: import("@ysk-kit/contracts").CreateApiKeyCommand) => Promise<{
120
+ id: string;
121
+ name: string;
122
+ prefix: string;
123
+ last4: string;
124
+ permissions: ("user.create" | "user.suspend" | "audit.read" | "file.upload" | "llm.use" | "billing.checkout")[];
125
+ createdAt: string;
126
+ lastUsedAt: string | null;
127
+ token: string;
128
+ }>;
129
+ revoke: (id: string) => Promise<{
130
+ revoked: true;
131
+ }>;
132
+ };
133
+ audit: {
134
+ list: (query?: {
135
+ cursor?: string;
136
+ limit?: number;
137
+ }) => Promise<{
138
+ items: {
139
+ id: string;
140
+ actorId: string | null;
141
+ action: "user.create" | "user.suspend" | "file.upload" | "auth.register" | "auth.login" | "auth.logout" | "auth.reset" | "org.create" | "org.invite" | "org.member.remove" | "api_key.create" | "api_key.revoke";
142
+ resourceType: string;
143
+ resourceId: string;
144
+ createdAt: string;
145
+ }[];
146
+ nextCursor: string | null;
147
+ }>;
148
+ };
149
+ billing: {
150
+ plans: () => Promise<{
151
+ code: "free" | "pro";
152
+ name: string;
153
+ amountHkdCents: number;
154
+ interval: "month";
155
+ }[]>;
156
+ subscription: (organizationId: string) => Promise<{
157
+ planCode: "free" | "pro";
158
+ status: "active" | "canceled";
159
+ currentPeriodEnd: string | null;
160
+ seatCount: number;
161
+ }>;
162
+ invoices: (organizationId: string) => Promise<{
163
+ id: string;
164
+ number: string | null;
165
+ status: string;
166
+ amountDue: number;
167
+ currency: string;
168
+ hostedInvoiceUrl: string | null;
169
+ createdAt: string;
170
+ }[]>;
171
+ invoicePdfUrl: (id: string, organizationId: string) => Promise<string>;
172
+ checkout: (body: import("@ysk-kit/contracts").CheckoutCommand) => Promise<{
173
+ url: string;
174
+ }>;
175
+ cancel: (body: import("@ysk-kit/contracts").CancelCommand) => Promise<{
176
+ canceled: true;
177
+ }>;
178
+ portal: (body: import("@ysk-kit/contracts").PortalCommand) => Promise<{
179
+ url: string;
180
+ }>;
181
+ };
182
+ users: {
183
+ list: (query?: {
184
+ cursor?: string;
185
+ limit?: number;
186
+ }) => Promise<{
187
+ items: {
188
+ id: string;
189
+ email: string | null;
190
+ phone: string | null;
191
+ displayName: string;
192
+ role: "USER" | "ADMIN" | "OPS";
193
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
194
+ createdAt: string;
195
+ }[];
196
+ nextCursor: string | null;
197
+ }>;
198
+ create: (body: import("@ysk-kit/contracts").CreateUserCommand) => Promise<{
199
+ id: string;
200
+ email: string | null;
201
+ phone: string | null;
202
+ displayName: string;
203
+ role: "USER" | "ADMIN" | "OPS";
204
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
205
+ createdAt: string;
206
+ }>;
207
+ suspend: (id: string) => Promise<{
208
+ id: string;
209
+ email: string | null;
210
+ phone: string | null;
211
+ displayName: string;
212
+ role: "USER" | "ADMIN" | "OPS";
213
+ status: "ACTIVE" | "INVITED" | "SUSPENDED" | "DELETED";
214
+ createdAt: string;
215
+ }>;
216
+ };
217
+ notifications: {
218
+ list: () => Promise<{
219
+ items: {
220
+ id: string;
221
+ type: "auth.reset" | "auth.welcome" | "user.created" | "org.invited";
222
+ title: string;
223
+ body: string;
224
+ readAt: string | null;
225
+ createdAt: string;
226
+ }[];
227
+ nextCursor: string | null;
228
+ }>;
229
+ markRead: (id: string) => Promise<{
230
+ read: true;
231
+ }>;
232
+ unread: () => Promise<import("@ysk-kit/contracts").NotificationDto[]>;
233
+ };
234
+ devices: {
235
+ list: () => Promise<{
236
+ id: string;
237
+ platform: "ios" | "android";
238
+ tokenSuffix: string;
239
+ createdAt: string;
240
+ }[]>;
241
+ register: (body: import("@ysk-kit/contracts").RegisterDeviceCommand) => Promise<{
242
+ id: string;
243
+ platform: "ios" | "android";
244
+ tokenSuffix: string;
245
+ createdAt: string;
246
+ }>;
247
+ remove: (id: string) => Promise<{
248
+ removed: true;
249
+ }>;
250
+ };
251
+ organizations: {
252
+ create: (body: import("@ysk-kit/contracts").CreateOrganizationCommand) => Promise<{
253
+ id: string;
254
+ name: string;
255
+ createdAt: string;
256
+ }>;
257
+ list: () => Promise<{
258
+ id: string;
259
+ name: string;
260
+ createdAt: string;
261
+ }[]>;
262
+ get: (organizationId: string) => Promise<{
263
+ id: string;
264
+ name: string;
265
+ createdAt: string;
266
+ }>;
267
+ update: (organizationId: string, body: import("@ysk-kit/contracts").UpdateOrganizationCommand) => Promise<{
268
+ id: string;
269
+ name: string;
270
+ createdAt: string;
271
+ }>;
272
+ members: (organizationId: string) => Promise<{
273
+ id: string;
274
+ organizationId: string;
275
+ userId: string;
276
+ email: string | null;
277
+ displayName: string;
278
+ role: "ADMIN" | "OWNER" | "MEMBER";
279
+ createdAt: string;
280
+ }[]>;
281
+ invite: (organizationId: string, body: import("@ysk-kit/contracts").InviteMemberCommand) => Promise<{
282
+ id: string;
283
+ organizationId: string;
284
+ email: string;
285
+ role: "ADMIN" | "MEMBER";
286
+ createdAt: string;
287
+ expiresAt: string;
288
+ }>;
289
+ invites: (organizationId: string) => Promise<{
290
+ id: string;
291
+ organizationId: string;
292
+ email: string;
293
+ role: "ADMIN" | "MEMBER";
294
+ createdAt: string;
295
+ expiresAt: string;
296
+ }[]>;
297
+ revokeInvite: (organizationId: string, id: string) => Promise<{
298
+ removed: true;
299
+ }>;
300
+ removeMember: (organizationId: string, userId: string) => Promise<{
301
+ removed: true;
302
+ }>;
303
+ leave: (organizationId: string) => Promise<{
304
+ left: true;
305
+ }>;
306
+ acceptInvite: (body: import("@ysk-kit/contracts").AcceptInviteCommand) => Promise<{
307
+ accepted: true;
308
+ }>;
309
+ };
310
+ llm: {
311
+ complete: (body: import("@ysk-kit/contracts").LlmCompleteCommand) => Promise<{
312
+ text: string;
313
+ model: string;
314
+ usage: {
315
+ promptTokens: number;
316
+ completionTokens: number;
317
+ totalTokens: number;
318
+ };
319
+ }>;
320
+ models: () => Promise<{
321
+ items: {
322
+ id: string;
323
+ }[];
324
+ }>;
325
+ stream: (body: import("@ysk-kit/contracts").LlmCompleteCommand, handlers: {
326
+ onDelta: (delta: string) => void;
327
+ onDone: (usage?: import("@ysk-kit/contracts").LlmUsage) => void;
328
+ onError?: (message: string) => void;
329
+ }) => Promise<void>;
330
+ };
331
+ connectRealtime: () => Promise<{
332
+ on: (event: string, handler: (payload: unknown) => void) => void;
333
+ close: () => void;
334
+ }>;
335
+ };
336
+ export type YskClient = ReturnType<typeof createYskClient>;
337
+ export type { DevicePort } from './ports/device';
338
+ export type { FilePickerPort } from './ports/file-picker';
339
+ export type { TokenStore } from './token-store';
340
+ export { connectRealtime, createWebStorageTokenStore, memoryTokenStore };
341
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAU7C,OAAO,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,KAAK,UAAU,EAAE,MAAM,eAAe,CAAC;AAE9F,wBAAgB,eAAe,CAAC,IAAI,EAAE;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAV6D,CAAC;iBACpD,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;kBAAO,CAAC;iBAAe,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0BAEkD,CAAC;mBAE9D,CAAC;;;;;;;EA+BzB;AAED,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,eAAe,CAAC,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,YAAY,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,41 @@
1
+ import { HttpClient } from './http';
2
+ import { connectRealtime } from './realtime';
3
+ import { apiKeysResource } from './resources/api-keys';
4
+ import { auditResource } from './resources/audit';
5
+ import { authResource } from './resources/auth';
6
+ import { billingResource } from './resources/billing';
7
+ import { devicesResource } from './resources/devices';
8
+ import { llmResource } from './resources/llm';
9
+ import { notificationsResource } from './resources/notifications';
10
+ import { organizationsResource } from './resources/organizations';
11
+ import { usersResource } from './resources/users';
12
+ import { createWebStorageTokenStore, memoryTokenStore } from './token-store';
13
+ export function createYskClient(opts) {
14
+ const tokenStore = opts.tokenStore ?? memoryTokenStore();
15
+ const baseUrl = opts.baseUrl.replace(/\/$/, '');
16
+ const http = new HttpClient({
17
+ baseUrl,
18
+ platform: opts.platform,
19
+ tokenStore,
20
+ ...(opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}),
21
+ });
22
+ return {
23
+ auth: authResource(http, tokenStore),
24
+ apiKeys: apiKeysResource(http),
25
+ audit: auditResource(http),
26
+ billing: billingResource(http),
27
+ users: usersResource(http),
28
+ notifications: notificationsResource(http),
29
+ devices: devicesResource(http),
30
+ organizations: organizationsResource(http),
31
+ llm: llmResource(http, {
32
+ baseUrl,
33
+ platform: opts.platform,
34
+ tokenStore,
35
+ ...(opts.fetchImpl ? { fetchImpl: opts.fetchImpl } : {}),
36
+ }),
37
+ connectRealtime: () => connectRealtime({ baseUrl, platform: opts.platform, tokenStore }),
38
+ };
39
+ }
40
+ export { connectRealtime, createWebStorageTokenStore, memoryTokenStore };
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,0BAA0B,EAAE,gBAAgB,EAAmB,MAAM,eAAe,CAAC;AAE9F,MAAM,UAAU,eAAe,CAAC,IAK/B;IACC,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,gBAAgB,EAAE,CAAC;IACzD,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC;QAC1B,OAAO;QACP,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,UAAU;QACV,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzD,CAAC,CAAC;IACH,OAAO;QACL,IAAI,EAAE,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC;QACpC,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC;QAC9B,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC;QAC1B,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC;QAC9B,KAAK,EAAE,aAAa,CAAC,IAAI,CAAC;QAC1B,aAAa,EAAE,qBAAqB,CAAC,IAAI,CAAC;QAC1C,OAAO,EAAE,eAAe,CAAC,IAAI,CAAC;QAC9B,aAAa,EAAE,qBAAqB,CAAC,IAAI,CAAC;QAC1C,GAAG,EAAE,WAAW,CAAC,IAAI,EAAE;YACrB,OAAO;YACP,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,UAAU;YACV,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACzD,CAAC;QACF,eAAe,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC;KACzF,CAAC;AACJ,CAAC;AAMD,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,gBAAgB,EAAE,CAAC"}
@@ -0,0 +1,5 @@
1
+ export interface DevicePort {
2
+ platform: 'ios' | 'android';
3
+ registerPushToken(token: string): Promise<void>;
4
+ }
5
+ //# sourceMappingURL=device.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.d.ts","sourceRoot":"","sources":["../../src/ports/device.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IAC5B,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACjD"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=device.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"device.js","sourceRoot":"","sources":["../../src/ports/device.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ export interface FilePickerPort {
2
+ pickImage(): Promise<{
3
+ uri: string;
4
+ mime: string;
5
+ } | null>;
6
+ }
7
+ //# sourceMappingURL=file-picker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-picker.d.ts","sourceRoot":"","sources":["../../src/ports/file-picker.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,SAAS,IAAI,OAAO,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CAC5D"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=file-picker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-picker.js","sourceRoot":"","sources":["../../src/ports/file-picker.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ import type { Platform } from '@ysk-kit/contracts';
2
+ import type { TokenStore } from './token-store';
3
+ export declare const connectRealtime: (opts: {
4
+ baseUrl: string;
5
+ platform: Platform;
6
+ tokenStore: TokenStore;
7
+ }) => Promise<{
8
+ on: (event: string, handler: (payload: unknown) => void) => void;
9
+ close: () => void;
10
+ }>;
11
+ //# sourceMappingURL=realtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAEnD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,eAAO,MAAM,eAAe,GAAU,MAAM;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,QAAQ,CAAC;IACnB,UAAU,EAAE,UAAU,CAAC;CACxB,KAAG,OAAO,CAAC;IACV,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,KAAK,IAAI,CAAC;IACjE,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB,CAcA,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { io } from 'socket.io-client';
2
+ export const connectRealtime = async (opts) => {
3
+ const token = await opts.tokenStore.get();
4
+ const socket = io(opts.baseUrl, {
5
+ auth: { token, platform: opts.platform },
6
+ transports: ['websocket', 'polling'],
7
+ });
8
+ return {
9
+ on: (event, handler) => {
10
+ socket.on(event, handler);
11
+ },
12
+ close: () => {
13
+ socket.close();
14
+ },
15
+ };
16
+ };
17
+ //# sourceMappingURL=realtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../src/realtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,EAAE,EAAe,MAAM,kBAAkB,CAAC;AAGnD,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAAE,IAIrC,EAGE,EAAE;IACH,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC;IAC1C,MAAM,MAAM,GAAW,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE;QACtC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE;QACxC,UAAU,EAAE,CAAC,WAAW,EAAE,SAAS,CAAC;KACrC,CAAC,CAAC;IACH,OAAO;QACL,EAAE,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;YACrB,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAC5B,CAAC;QACD,KAAK,EAAE,GAAG,EAAE;YACV,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC,CAAC"}