@crimson-education/sdk 0.3.7 → 0.3.8
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/core/account.d.ts +7 -1
- package/dist/core/account.js +10 -0
- package/dist/core/client.d.ts +9 -2
- package/dist/core/client.js +53 -2
- package/dist/core/types.d.ts +14 -0
- package/dist/react/provider.js +4 -0
- package/package.json +1 -1
package/dist/core/account.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { CrimsonClient } from "./client";
|
|
2
|
-
import type { CurrentUserRoles, StudentSummary, UserProfile } from "./types";
|
|
2
|
+
import type { CurrentUserRoles, StudentSummary, UserProfile, LinkedTenantsResponse } from "./types";
|
|
3
3
|
export declare class AccountApi {
|
|
4
4
|
private client;
|
|
5
5
|
constructor(client: CrimsonClient);
|
|
@@ -37,4 +37,10 @@ export declare class AccountApi {
|
|
|
37
37
|
* @returns User profile information
|
|
38
38
|
*/
|
|
39
39
|
getMyProfile(): Promise<UserProfile>;
|
|
40
|
+
/**
|
|
41
|
+
* Get the list of tenants linked to the current user
|
|
42
|
+
*
|
|
43
|
+
* @returns List of linked tenants and current tenant info
|
|
44
|
+
*/
|
|
45
|
+
getLinkedTenants(): Promise<LinkedTenantsResponse>;
|
|
40
46
|
}
|
package/dist/core/account.js
CHANGED
|
@@ -62,5 +62,15 @@ class AccountApi {
|
|
|
62
62
|
return this.client.fetch("/api/v1/account/me/profile");
|
|
63
63
|
});
|
|
64
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Get the list of tenants linked to the current user
|
|
67
|
+
*
|
|
68
|
+
* @returns List of linked tenants and current tenant info
|
|
69
|
+
*/
|
|
70
|
+
getLinkedTenants() {
|
|
71
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
72
|
+
return this.client.fetch("/api/v1/account/linked-tenants");
|
|
73
|
+
});
|
|
74
|
+
}
|
|
65
75
|
}
|
|
66
76
|
exports.AccountApi = AccountApi;
|
package/dist/core/client.d.ts
CHANGED
|
@@ -19,12 +19,19 @@ export declare class CrimsonClient {
|
|
|
19
19
|
private appName;
|
|
20
20
|
private appTenant;
|
|
21
21
|
private oauthAdapter?;
|
|
22
|
+
private tenantDomain?;
|
|
23
|
+
private isResolvingDomain;
|
|
24
|
+
private tenantDomainPromise?;
|
|
22
25
|
constructor(config: CrimsonClientConfig);
|
|
23
26
|
/**
|
|
24
|
-
* Initialize the client (required for OAuth mode)
|
|
25
|
-
* Call this after creating the client to load stored tokens
|
|
27
|
+
* Initialize the client (required for OAuth mode and tenant resolution)
|
|
28
|
+
* Call this after creating the client to load stored tokens and resolve tenant
|
|
26
29
|
*/
|
|
27
30
|
initialize(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Resolve the x-tenant-domain dynamically
|
|
33
|
+
*/
|
|
34
|
+
resolveTenantDomain(): Promise<void>;
|
|
28
35
|
/**
|
|
29
36
|
* Get the OAuth adapter (only available in OAuth mode)
|
|
30
37
|
*/
|
package/dist/core/client.js
CHANGED
|
@@ -45,6 +45,7 @@ function isOAuthConfig(config) {
|
|
|
45
45
|
class CrimsonClient {
|
|
46
46
|
constructor(config) {
|
|
47
47
|
this.config = config;
|
|
48
|
+
this.isResolvingDomain = false;
|
|
48
49
|
this.missions = new missions_1.MissionsApi(this);
|
|
49
50
|
this.tasks = new tasks_1.TasksApi(this);
|
|
50
51
|
this.roadmap = new roadmap_1.RoadmapApi(this);
|
|
@@ -81,14 +82,56 @@ class CrimsonClient {
|
|
|
81
82
|
}
|
|
82
83
|
}
|
|
83
84
|
/**
|
|
84
|
-
* Initialize the client (required for OAuth mode)
|
|
85
|
-
* Call this after creating the client to load stored tokens
|
|
85
|
+
* Initialize the client (required for OAuth mode and tenant resolution)
|
|
86
|
+
* Call this after creating the client to load stored tokens and resolve tenant
|
|
86
87
|
*/
|
|
87
88
|
initialize() {
|
|
88
89
|
return __awaiter(this, void 0, void 0, function* () {
|
|
89
90
|
if (this.oauthAdapter) {
|
|
90
91
|
yield this.oauthAdapter.initialize();
|
|
91
92
|
}
|
|
93
|
+
yield this.resolveTenantDomain();
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Resolve the x-tenant-domain dynamically
|
|
98
|
+
*/
|
|
99
|
+
resolveTenantDomain() {
|
|
100
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
101
|
+
if (this.tenantDomain)
|
|
102
|
+
return;
|
|
103
|
+
if (!this.tenantDomainPromise) {
|
|
104
|
+
this.isResolvingDomain = true;
|
|
105
|
+
this.tenantDomainPromise = (() => __awaiter(this, void 0, void 0, function* () {
|
|
106
|
+
var _a, _b;
|
|
107
|
+
try {
|
|
108
|
+
// A newer version of profile will return domain
|
|
109
|
+
const profile = yield this.account.getMyProfile();
|
|
110
|
+
if ((_a = profile.tenant) === null || _a === void 0 ? void 0 : _a.domain) {
|
|
111
|
+
this.tenantDomain = profile.tenant.domain;
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Use getLinkedtenants as a safe fallback when getMyProfile does not return a domain.
|
|
115
|
+
// Can be removed later.
|
|
116
|
+
const linkedRes = yield this.account.getLinkedTenants();
|
|
117
|
+
if (linkedRes.linkedTenants && linkedRes.linkedTenants.length > 0) {
|
|
118
|
+
// find domain.tenantId equals to currentTenantId
|
|
119
|
+
const domain = (_b = linkedRes.linkedTenants.find(t => t.tenantId === linkedRes.currentTenantId)) === null || _b === void 0 ? void 0 : _b.tenantDomain;
|
|
120
|
+
if (domain) {
|
|
121
|
+
this.tenantDomain = domain;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
catch (err) {
|
|
127
|
+
console.warn('[CrimsonSDK] Failed to resolve tenant domain:', err);
|
|
128
|
+
}
|
|
129
|
+
finally {
|
|
130
|
+
this.isResolvingDomain = false;
|
|
131
|
+
}
|
|
132
|
+
}))();
|
|
133
|
+
}
|
|
134
|
+
return this.tenantDomainPromise;
|
|
92
135
|
});
|
|
93
136
|
}
|
|
94
137
|
/**
|
|
@@ -192,6 +235,10 @@ class CrimsonClient {
|
|
|
192
235
|
}
|
|
193
236
|
fetch(path_1) {
|
|
194
237
|
return __awaiter(this, arguments, void 0, function* (path, options = {}) {
|
|
238
|
+
// If it's a roadmap endpoint, wait for tenant domain to be resolved first
|
|
239
|
+
if (path.includes("/roadmap") && this.tenantDomainPromise) {
|
|
240
|
+
yield this.tenantDomainPromise;
|
|
241
|
+
}
|
|
195
242
|
const token = yield this.getToken();
|
|
196
243
|
if (!token) {
|
|
197
244
|
throw new Error("No authentication token available");
|
|
@@ -207,6 +254,10 @@ class CrimsonClient {
|
|
|
207
254
|
if (this.appTenant) {
|
|
208
255
|
headers["X-App-Tenant"] = this.appTenant;
|
|
209
256
|
}
|
|
257
|
+
console.log(`tenantDomain = ${this.tenantDomain}`);
|
|
258
|
+
if (this.tenantDomain) {
|
|
259
|
+
headers["x-tenant-domain"] = this.tenantDomain;
|
|
260
|
+
}
|
|
210
261
|
const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
211
262
|
const response = yield fetch(url, Object.assign(Object.assign({}, options), { headers }));
|
|
212
263
|
if (!response.ok) {
|
package/dist/core/types.d.ts
CHANGED
|
@@ -494,8 +494,22 @@ export interface UserProfile {
|
|
|
494
494
|
tenant: {
|
|
495
495
|
id: string;
|
|
496
496
|
name: string;
|
|
497
|
+
domain?: string;
|
|
497
498
|
};
|
|
498
499
|
}
|
|
500
|
+
export interface LinkedTenant {
|
|
501
|
+
tenantId: string;
|
|
502
|
+
tenantName: string;
|
|
503
|
+
tenantDomain: string | null;
|
|
504
|
+
tenantLevel: number;
|
|
505
|
+
isCurrent: boolean;
|
|
506
|
+
userEmail: string;
|
|
507
|
+
}
|
|
508
|
+
export interface LinkedTenantsResponse {
|
|
509
|
+
currentUserId: string;
|
|
510
|
+
currentTenantId: string;
|
|
511
|
+
linkedTenants: LinkedTenant[];
|
|
512
|
+
}
|
|
499
513
|
/**
|
|
500
514
|
* Prefilled field with value and source information
|
|
501
515
|
*/
|
package/dist/react/provider.js
CHANGED
|
@@ -34,6 +34,10 @@ function CrimsonProvider({ children, apiUrl, allowedParentOrigins, queryClient:
|
|
|
34
34
|
appName,
|
|
35
35
|
appTenant,
|
|
36
36
|
}), [apiUrl, clientId, appName, appTenant]);
|
|
37
|
+
// trigger initialization, we need to determine tenant domain at first place.
|
|
38
|
+
(0, react_1.useEffect)(() => {
|
|
39
|
+
client.initialize();
|
|
40
|
+
}, [client]);
|
|
37
41
|
(0, react_1.useEffect)(() => {
|
|
38
42
|
const origins = allowedParentOrigins || (0, iframe_1.getDefaultAllowedOrigins)();
|
|
39
43
|
const cleanup = (0, iframe_1.setupIframeListener)(origins);
|