@healthcloudai/hc-login-connector 0.0.13 → 0.0.15

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/README.md CHANGED
@@ -18,8 +18,8 @@ below follow the current behavior implemented in `src/client.ts`.
18
18
  5. Patient login with in-memory access, refresh, and ID token storage
19
19
  6. Password reset initiation and password reset confirmation
20
20
  7. Access token, ID token, tenant, and base URL helper methods
21
- 8. Token refresh using the current authenticated token state
22
- 9. Authenticated patient header retrieval through `getUserInfo()` and `getHeader()`
21
+ 8. Token refresh using the stored refresh token
22
+ 9. Authenticated patient header retrieval through `getUserInfo()`
23
23
  10. Built on the shared Healthcheck HttpClient layer
24
24
 
25
25
  ---
@@ -71,9 +71,27 @@ The configuration example above updates local client state only.
71
71
  It stores the tenant configuration locally for later requests.
72
72
 
73
73
 
74
-
75
74
  ---
76
75
 
76
+
77
+ ## API Key
78
+
79
+ Use `setApiKey(...)` to include an API key header with requests made by `HCLoginClient`.
80
+
81
+ ```ts
82
+ const apiKey = process.env.HEALTHCLOUD_API_KEY;
83
+
84
+ if (!apiKey) {
85
+ throw new Error("HEALTHCLOUD_API_KEY is required.");
86
+ }
87
+
88
+ loginClient.setApiKey("x-api-key", apiKey);
89
+ ```
90
+
91
+ The first argument is the header name and the second argument is the API key value. After it is configured, the API key header is included automatically with registration, onboarding, login, token refresh, password reset, and authenticated patient header requests.
92
+
93
+ If your environment does not require an API key, you can skip this step.
94
+
77
95
  ## Methods
78
96
 
79
97
  ### Get Base URL
@@ -388,7 +406,7 @@ Request sent for the usage example above:
388
406
  }
389
407
  ```
390
408
 
391
- #### Example Response
409
+ #### API response
392
410
 
393
411
  Status:
394
412
 
@@ -770,7 +788,7 @@ Status:
770
788
  Public signature: `loginClient.login(email, password)`
771
789
 
772
790
  `login(...)` accepts only `email` and `password`.
773
- The client builds the full backend `Data` payload internally, and stores the
791
+ The client builds the login `Data` payload internally, and stores the
774
792
  returned tokens in memory.
775
793
  On tenants that require onboarding completion, login may depend on the relevant
776
794
  onboarding steps already being finished.
@@ -783,20 +801,14 @@ await loginClient.login(
783
801
  ```
784
802
 
785
803
  #### Full API request
786
- Request sent for the usage example above:
804
+ Request sent for the full payload usage example above:
787
805
 
788
806
  ```json
789
807
  {
790
808
  "Data": {
791
- "FirstName": "",
792
- "LastName": "",
793
809
  "Email": "john.smith@example.com",
794
810
  "Password": "ExamplePassword123!",
795
- "TenantID": "test-tenant",
796
- "AppPoolID": "",
797
- "GoogleIdToken": "",
798
- "AppleIdToken": "",
799
- "AppleCode": ""
811
+ "TenantID": "test-tenant"
800
812
  }
801
813
  }
802
814
  ```
@@ -817,12 +829,15 @@ Status:
817
829
  "AccessToken": "eyJ_access_token_example",
818
830
  "IDToken": "eyJ_id_token_example",
819
831
  "EHR": "fhir",
832
+ "ErrorMessage": null,
820
833
  "HasInsurance": false,
821
834
  "HasIDCard": false,
822
835
  "HasSelfie": false,
823
836
  "Attributes": {
824
- "EHR": "fhir"
837
+ "EHR": "fhir",
838
+ "Type": "PATIENT"
825
839
  },
840
+ "ID": "john.smith@example.com",
826
841
  "TenantID": "test-tenant",
827
842
  "Expiration": "2030-01-01T00:00:00.000Z",
828
843
  "Type": 0
@@ -836,21 +851,23 @@ Status:
836
851
 
837
852
  ### Reset Password
838
853
 
839
- Public signature: `loginClient.resetPassword(email, isPasswordResetWithOTP?)`
854
+ `resetPassword` supports both OTP-based and link-based reset initiation
855
+ flows.
856
+
857
+ `IsPasswordResetWithOTP` is optional. It is included in the request body only
858
+ when `isPasswordResetWithOTP` is `true`. When `false` or omitted, the field is
859
+ not sent at all and `false` is not serialized into the payload.
840
860
 
841
- `TenantID` is injected automatically from `configure(...)`.
842
- If an ID token is already available, the client may also include an
843
- `Authorization` header.
861
+ #### OTP-based password reset initiation
862
+
863
+ Use this when the password reset flow should be handled through an OTP code.
864
+ In this case, `IsPasswordResetWithOTP` should be `true`.
844
865
 
845
866
  ```ts
846
- await loginClient.resetPassword(
847
- "john.smith@example.com",
848
- true
849
- );
867
+ await loginClient.resetPassword("john.smith@example.com", true);
850
868
  ```
851
869
 
852
870
  #### Full API request
853
- Request sent for the usage example above:
854
871
 
855
872
  ```json
856
873
  {
@@ -862,6 +879,27 @@ Request sent for the usage example above:
862
879
  }
863
880
  ```
864
881
 
882
+ #### Link-based password reset initiation
883
+
884
+ Use this when the password reset flow should be handled from an email link.
885
+ In this case, `IsPasswordResetWithOTP` should be omitted by passing `false` or
886
+ leaving the second argument out.
887
+
888
+ ```ts
889
+ await loginClient.resetPassword("john.smith@example.com", false);
890
+ ```
891
+
892
+ Effective request body:
893
+
894
+ ```json
895
+ {
896
+ "Data": {
897
+ "Email": "john.smith@example.com",
898
+ "TenantID": "test-tenant"
899
+ }
900
+ }
901
+ ```
902
+
865
903
  `Authorization: Bearer eyJ_id_token_example` may also be included when an ID token
866
904
  is already stored.
867
905
 
@@ -885,23 +923,32 @@ Status:
885
923
 
886
924
  ### Reset Password Confirm
887
925
 
888
- Public signature: `loginClient.resetPasswordConfirm(email, password, code, isPasswordResetWithOTP?)`
926
+ `resetPasswordConfirm` supports both OTP-based and link-based confirmation
927
+ flows.
928
+
929
+ If `IsPasswordResetWithOTP` is `true`, `Code` is required. If
930
+ `IsPasswordResetWithOTP` is not `true`, `Token` is required. For the
931
+ link-based flow, the frontend is responsible for taking the token from the
932
+ password reset email link and passing that token in the payload.
933
+
934
+ #### OTP-based password reset confirmation
889
935
 
890
- `TenantID` is injected automatically from `configure(...)`.
891
- If an ID token is already available, the client may also include an
892
- `Authorization` header.
936
+ Use this when the password reset flow was started with OTP. In this case,
937
+ `IsPasswordResetWithOTP` should be `true` and `Code` should contain the final
938
+ reset code.
893
939
 
894
940
  ```ts
895
- await loginClient.resetPasswordConfirm(
896
- "john.smith@example.com",
897
- "ExamplePassword123!",
898
- "123456",
899
- true
900
- );
941
+ await loginClient.resetPasswordConfirm({
942
+ Data: {
943
+ Email: "john.smith@example.com",
944
+ Password: "ExamplePassword123!",
945
+ IsPasswordResetWithOTP: true,
946
+ Code: "123456"
947
+ }
948
+ });
901
949
  ```
902
950
 
903
- #### Full API request
904
- Request sent for the usage example above:
951
+ Request body:
905
952
 
906
953
  ```json
907
954
  {
@@ -909,12 +956,42 @@ Request sent for the usage example above:
909
956
  "Email": "john.smith@example.com",
910
957
  "TenantID": "test-tenant",
911
958
  "Password": "ExamplePassword123!",
912
- "code": "123456",
959
+ "Code": "123456",
913
960
  "IsPasswordResetWithOTP": true
914
961
  }
915
962
  }
916
963
  ```
917
964
 
965
+ #### Link-based password reset confirmation
966
+
967
+ Use this when the password reset flow was started from an email link. In this
968
+ case, `Token` should be included in the payload, the frontend should read the
969
+ token value from the password reset email link and send that token in the
970
+ request payload, and `IsPasswordResetWithOTP` should be omitted or `false`.
971
+
972
+ ```ts
973
+ await loginClient.resetPasswordConfirm({
974
+ Data: {
975
+ Email: "john.smith@example.com",
976
+ Password: "ExamplePassword123!",
977
+ Token: "token-from-email-link"
978
+ }
979
+ });
980
+ ```
981
+
982
+ Effective request body:
983
+
984
+ ```json
985
+ {
986
+ "Data": {
987
+ "Email": "john.smith@example.com",
988
+ "TenantID": "test-tenant",
989
+ "Password": "ExamplePassword123!",
990
+ "Token": "token-from-email-link"
991
+ }
992
+ }
993
+ ```
994
+
918
995
  `Authorization: Bearer eyJ_id_token_example` may also be included when an ID token
919
996
  is already stored.
920
997
 
@@ -940,8 +1017,8 @@ Status:
940
1017
 
941
1018
  Public signature: `loginClient.refreshToken()`
942
1019
 
943
- `refreshToken()` requires a successful prior login and an available refresh token.
944
- The client sends the stored refresh token, and stores the returned token set in
1020
+ `refreshToken()` requires a previous successful login and a stored refresh token.
1021
+ The client sends the stored refresh token and stores the returned token set in
945
1022
  memory.
946
1023
 
947
1024
  ```ts
@@ -975,6 +1052,13 @@ Status:
975
1052
  "RefreshToken": "eyJ_refresh_token_example",
976
1053
  "AccessToken": "eyJ_access_token_example",
977
1054
  "IDToken": "eyJ_id_token_example",
1055
+ "EHR": null,
1056
+ "ErrorMessage": null,
1057
+ "HasInsurance": false,
1058
+ "HasIDCard": false,
1059
+ "HasSelfie": false,
1060
+ "Attributes": null,
1061
+ "ID": null,
978
1062
  "TenantID": "test-tenant",
979
1063
  "Expiration": "2030-01-01T00:00:00.000Z",
980
1064
  "Type": 0
@@ -1014,16 +1098,16 @@ The usage example above reads the value from local state.
1014
1098
  }
1015
1099
  ```
1016
1100
 
1101
+ If an API key has been configured through setApiKey(...), the returned header object also includes the configured API key header.
1102
+
1017
1103
  ---
1018
1104
 
1019
1105
  ### Get User Info
1020
1106
 
1021
1107
  Public signature: `loginClient.getUserInfo()`
1022
1108
 
1023
- The current implementation calls the patient header endpoint and returns the raw
1024
- server response.
1025
- It requires a stored ID token, and it currently targets the same endpoint as
1026
- `getHeader()`.
1109
+ Calls the patient header endpoint and returns the raw server response.
1110
+ It requires a stored ID token.
1027
1111
 
1028
1112
  ```ts
1029
1113
  const userInfo = await loginClient.getUserInfo();
@@ -1089,78 +1173,6 @@ Status:
1089
1173
 
1090
1174
  ---
1091
1175
 
1092
- ### Get Header
1093
-
1094
- Public signature: `loginClient.getHeader()`
1095
-
1096
- The current implementation also calls the patient header endpoint.
1097
- It requires a stored ID token, and the response shape is effectively the same as
1098
- `getUserInfo()`.
1099
-
1100
- ```ts
1101
- await loginClient.getHeader();
1102
- ```
1103
-
1104
- #### Full API request
1105
- `getHeader()` does not send a request body.
1106
-
1107
- #### API response
1108
-
1109
- Status:
1110
-
1111
- ```txt
1112
- 200
1113
- ```
1114
-
1115
- ```json
1116
- {
1117
- "Data": {
1118
- "Record": {
1119
- "ID": "record-id-example",
1120
- "TenantID": "test-tenant",
1121
- "FirstName": "John",
1122
- "LastName": "Smith",
1123
- "Email": "john.smith@example.com",
1124
- "Phone": "+15555550123",
1125
- "BirthDate": "1990-01-01T00:00:00",
1126
- "Gender": "male",
1127
- "Sex": "Male",
1128
- "Race": "White",
1129
- "Ethnicity": "Not Hispanic or Latino",
1130
- "HasInsurance": false,
1131
- "HasIDCard": false,
1132
- "HasSelfie": false,
1133
- "Address": {
1134
- "StreetAndNumber": "123 Test St",
1135
- "Extension": null,
1136
- "City": "Springfield",
1137
- "State": "CA",
1138
- "PostalCode": "90210",
1139
- "Country": "US"
1140
- },
1141
- "Attributes": {
1142
- "FHIRPatientID": "patient-id-example",
1143
- "CompositeID": "composite-id-example",
1144
- "VERIFY_EMAIL_CODE": "true"
1145
- },
1146
- "CompositeID": "composite-id-example",
1147
- "FHIRID": "fhir-id-example"
1148
- },
1149
- "Encounters": null,
1150
- "EHR": "fhir",
1151
- "PendingActions": [
1152
- "ADD_INSURANCE",
1153
- "ADD_ID",
1154
- "IMPORT_VITALS"
1155
- ]
1156
- },
1157
- "ErrorMessage": null,
1158
- "IsOK": true
1159
- }
1160
- ```
1161
-
1162
- ---
1163
-
1164
1176
  ### Get Access Token
1165
1177
 
1166
1178
  Public signature: `loginClient.getAccessToken()`
@@ -1218,8 +1230,8 @@ eyJ_id_token_example
1218
1230
  - Call `register(...)` if the patient account needs to be created.
1219
1231
  - Use `submitOnboardingStep(...)` or the onboarding helper methods to complete required onboarding steps.
1220
1232
  - Call `login(...)` to authenticate and store the returned access, refresh, and ID tokens in memory.
1221
- - Use `refreshToken()` to replace the current token set when needed.
1222
- - Use `getAuthHeader()`, `getAccessToken()`, `getIDToken()`, `getUserInfo()`, and `getHeader()` for authenticated flows after login.
1233
+ - Use `refreshToken()` to replace the current token set when a stored refresh token is available.
1234
+ - Use `getAuthHeader()`, `getAccessToken()`, `getIDToken()`, and `getUserInfo()` for authenticated flows after login.
1223
1235
  - Other Healthcheck connectors can consume `getAuthHeader()` instead of managing auth tokens directly.
1224
1236
 
1225
1237
 
@@ -1229,25 +1241,8 @@ eyJ_id_token_example
1229
1241
  - `TenantID` is injected by the client into tenant-bound register, onboarding, login, refresh, and password requests.
1230
1242
  - `register()`, `verifyEmail()`, and `resendEmailVerify()` all follow the same string-based `User.Attributes.VERIFY_EMAIL_CODE` pattern for OTP email verification flows.
1231
1243
  - `saveAddress()` accepts an `Address`.
1232
- - `login()` and `refreshToken()` both store returned tokens internally for later helper calls.
1233
- - `getUserInfo()` and `getHeader()` both currently call the patient header endpoint.
1244
+ - `login()` stores the initial token set internally, and `refreshToken()` updates that stored token set when a refresh token is available.
1245
+ - `refreshToken()` does not require a current ID token. It uses the stored refresh token from the previous successful login.
1246
+ - `getUserInfo()` calls the patient header endpoint.
1234
1247
  - `getAuthHeader()`, `getAccessToken()`, `getIDToken()`, `getBaseUrl()`, and `getTenantId()` return local values and do not perform HTTP requests.
1235
1248
  - This connector is intended to be reused by other Healthcheck SDK connectors built on the same HTTP layer.
1236
-
1237
-
1238
- ## API Key
1239
-
1240
- All outgoing requests from `HCLoginClient` can include an optional API key header.
1241
-
1242
- ```ts
1243
- const apiKey = process.env.HEALTHCLOUD_API_KEY;
1244
-
1245
- if (apiKey) {
1246
- loginClient.setApiKey("x-api-key", apiKey);
1247
- }
1248
- ```
1249
-
1250
- - Header name should be `x-api-key`.
1251
- - API key is optional unless required by the backend.
1252
- - If not set, behavior remains unchanged and the header is omitted.
1253
- - The header is applied to registration, onboarding, login, token refresh, password reset, and authenticated patient header requests.
package/dist/index.cjs CHANGED
@@ -63,17 +63,31 @@ var HCLoginClient = class {
63
63
  this.http = httpClient;
64
64
  }
65
65
  configure(tenantID, environment, region) {
66
- if (!tenantID) throw new ConfigError("tenantID is required");
66
+ const trimmedTenantID = tenantID == null ? void 0 : tenantID.trim();
67
+ if (!trimmedTenantID) {
68
+ throw new ConfigError("tenantID is required.");
69
+ }
70
+ if (!ENV_PREFIX[environment]) {
71
+ throw new ConfigError("Invalid environment.");
72
+ }
67
73
  this.config = {
68
- tenantID,
74
+ tenantID: trimmedTenantID,
69
75
  environment,
70
76
  region,
71
- baseUrl: buildBaseUrl(tenantID, environment, region)
77
+ baseUrl: buildBaseUrl(trimmedTenantID, environment, region)
72
78
  };
73
79
  }
74
80
  setApiKey(headerName, value) {
75
- this.apiKeyHeaderName = headerName;
76
- this.apiKeyValue = value;
81
+ const trimmedHeaderName = headerName == null ? void 0 : headerName.trim();
82
+ const trimmedValue = value == null ? void 0 : value.trim();
83
+ if (!trimmedHeaderName) {
84
+ throw new ConfigError("API key header name is required.");
85
+ }
86
+ if (!trimmedValue) {
87
+ throw new ConfigError("API key value is required.");
88
+ }
89
+ this.apiKeyHeaderName = trimmedHeaderName;
90
+ this.apiKeyValue = trimmedValue;
77
91
  }
78
92
  async register(email, password, firstName = "Unknown", lastName = "Unknown", options = {}) {
79
93
  var _a, _b;
@@ -219,15 +233,9 @@ var HCLoginClient = class {
219
233
  this.ensureConfigured();
220
234
  const requestPayload = {
221
235
  Data: {
222
- FirstName: "",
223
- LastName: "",
224
236
  Email: email,
225
237
  Password: password,
226
- TenantID: this.config.tenantID,
227
- AppPoolID: "",
228
- GoogleIdToken: "",
229
- AppleIdToken: "",
230
- AppleCode: ""
238
+ TenantID: this.config.tenantID
231
239
  }
232
240
  };
233
241
  const resp = await this.http.post(
@@ -263,7 +271,10 @@ var HCLoginClient = class {
263
271
  const resp = await this.http.post(
264
272
  `${this.config.baseUrl}/patient/refresh`,
265
273
  requestPayload,
266
- this.getAuthHeader()
274
+ {
275
+ "X-Tenant-ID": this.config.tenantID,
276
+ ...this.getApiKeyHeader()
277
+ }
267
278
  );
268
279
  const data = (_b = resp.Data) != null ? _b : resp;
269
280
  const tokens = {
@@ -275,14 +286,14 @@ var HCLoginClient = class {
275
286
  this.tokens = tokens;
276
287
  return tokens;
277
288
  }
278
- async resetPassword(email, isPasswordResetWithOTP = true) {
289
+ async resetPassword(email, isPasswordResetWithOTP = false) {
279
290
  var _a;
280
291
  this.ensureConfigured();
281
292
  const requestPayload = {
282
293
  Data: {
283
294
  Email: email,
284
295
  TenantID: this.config.tenantID,
285
- IsPasswordResetWithOTP: isPasswordResetWithOTP
296
+ ...isPasswordResetWithOTP === true ? { IsPasswordResetWithOTP: true } : {}
286
297
  }
287
298
  };
288
299
  await this.http.post(
@@ -296,21 +307,24 @@ var HCLoginClient = class {
296
307
  }
297
308
  );
298
309
  }
299
- async resetPasswordConfirm(email, password, code, isPasswordResetWithOTP = true) {
310
+ async resetPasswordConfirm(payload) {
300
311
  var _a;
301
312
  this.ensureConfigured();
302
- const requestPayload = {
303
- Data: {
304
- Email: email,
305
- TenantID: this.config.tenantID,
306
- Password: password,
307
- code,
308
- IsPasswordResetWithOTP: isPasswordResetWithOTP
309
- }
310
- };
313
+ const isOtpFlow = payload.Data.IsPasswordResetWithOTP === true;
314
+ if (isOtpFlow && !payload.Data.Code) {
315
+ throw new ConfigError("Code is required for OTP password reset confirmation.");
316
+ }
317
+ if (!isOtpFlow && !payload.Data.Token) {
318
+ throw new ConfigError("Token is required for link-based password reset confirmation.");
319
+ }
311
320
  await this.http.post(
312
321
  `${this.config.baseUrl}/patient/password`,
313
- requestPayload,
322
+ {
323
+ Data: {
324
+ ...payload.Data,
325
+ TenantID: this.config.tenantID
326
+ }
327
+ },
314
328
  {
315
329
  "Content-Type": "application/json",
316
330
  "X-Tenant-ID": this.config.tenantID,
@@ -437,23 +451,12 @@ var HCLoginClient = class {
437
451
  ...this.getApiKeyHeader()
438
452
  };
439
453
  }
440
- async getHeader() {
441
- var _a;
442
- this.ensureConfigured();
443
- if (!((_a = this.tokens) == null ? void 0 : _a.idToken)) {
444
- throw new AuthError("No ID token available");
445
- }
446
- return this.http.get(
447
- `${this.config.baseUrl}/patient/header`,
448
- this.getAuthHeader()
449
- );
450
- }
451
454
  getApiKeyHeader() {
452
455
  if (!this.apiKeyHeaderName || !this.apiKeyValue) {
453
456
  return {};
454
457
  }
455
458
  return {
456
- "x-api-key": this.apiKeyValue
459
+ [this.apiKeyHeaderName]: this.apiKeyValue
457
460
  };
458
461
  }
459
462
  getBaseUrl() {
package/dist/index.d.cts CHANGED
@@ -39,17 +39,26 @@ interface VerifyEmailOptions {
39
39
  attributes?: Record<string, string>;
40
40
  }
41
41
  interface LoginBody {
42
- FirstName: string;
43
- LastName: string;
42
+ FirstName?: string;
43
+ LastName?: string;
44
44
  Email: string;
45
+ UserName?: string;
45
46
  Password: string;
46
- TenantID: string;
47
- AppPoolID: string;
48
- GoogleIdToken: string;
49
- AppleIdToken: string;
50
- AppleCode: string;
47
+ PoolID?: string;
48
+ AppPoolID?: string;
49
+ AppClientID?: string;
50
+ TenantID?: string;
51
+ Token?: string;
52
+ Type?: number;
53
+ AppleIdToken?: string;
54
+ AppleCode?: string;
55
+ GoogleIdToken?: string;
56
+ IsPasswordResetWithOTP?: boolean;
57
+ Code?: string;
58
+ Language?: string;
51
59
  }
52
60
  type LoginRequest = ApiRequest<LoginBody>;
61
+ type LoginPayload = LoginRequest;
53
62
  interface RefreshBody {
54
63
  RefreshToken: string;
55
64
  TenantID: string;
@@ -58,17 +67,24 @@ type RefreshRequest = ApiRequest<RefreshBody>;
58
67
  interface ResetBody {
59
68
  Email: string;
60
69
  TenantID: string;
61
- IsPasswordResetWithOTP: boolean;
70
+ IsPasswordResetWithOTP?: boolean;
62
71
  }
63
72
  type ResetRequest = ApiRequest<ResetBody>;
64
- interface ResetConfirmBody {
73
+ type ResetConfirmBody = {
65
74
  Email: string;
66
- TenantID: string;
67
75
  Password: string;
68
- code: string;
69
- IsPasswordResetWithOTP: boolean;
70
- }
76
+ IsPasswordResetWithOTP: true;
77
+ Code: string;
78
+ Token?: string;
79
+ } | {
80
+ Email: string;
81
+ Password: string;
82
+ Token: string;
83
+ IsPasswordResetWithOTP?: false;
84
+ Code?: string;
85
+ };
71
86
  type ResetConfirmRequest = ApiRequest<ResetConfirmBody>;
87
+ type ResetPasswordConfirmPayload = ResetConfirmRequest;
72
88
  interface RegisterCredentials {
73
89
  Email: string;
74
90
  Password: string;
@@ -204,7 +220,7 @@ declare class HCLoginClient {
204
220
  login(email: string, password: string): Promise<AuthTokens>;
205
221
  refreshToken(): Promise<AuthTokens>;
206
222
  resetPassword(email: string, isPasswordResetWithOTP?: boolean): Promise<void>;
207
- resetPasswordConfirm(email: string, password: string, code: string, isPasswordResetWithOTP?: boolean): Promise<void>;
223
+ resetPasswordConfirm(payload: ResetPasswordConfirmPayload): Promise<void>;
208
224
  getAccessToken(): string | undefined;
209
225
  getIDToken(): string | undefined;
210
226
  getUserInfo(): Promise<unknown>;
@@ -217,7 +233,6 @@ declare class HCLoginClient {
217
233
  Authorization: string;
218
234
  "X-Tenant-ID": string;
219
235
  };
220
- getHeader(): Promise<any>;
221
236
  private getApiKeyHeader;
222
237
  getBaseUrl(): string;
223
238
  getTenantId(): string;
@@ -234,4 +249,4 @@ declare class HttpError extends Error {
234
249
  constructor(status: number, message: string);
235
250
  }
236
251
 
237
- export { type Address, type ApiRequest, AuthError, type AuthTokens, ConfigError, type Environment, HCLoginClient, type HealthProfile, HttpError, type LoginBody, type LoginConfig, type LoginRequest, type OnboardBody, type OnboardInput, type OnboardRequest, type OnboardUser, type OnboardingStep, type RefreshBody, type RefreshRequest, type Region, type RegisterAttributes, type RegisterBody, type RegisterCredentials, type RegisterFullBody, type RegisterFullOptions, type RegisterFullRequest, type RegisterFullUser, type RegisterOptions, type RegisterOpts, type RegisterRequest, type RegisterUser, type ResetBody, type ResetConfirmBody, type ResetConfirmRequest, type ResetRequest, type SmsData, type UserInfo, type VerifyEmailOptions };
252
+ export { type Address, type ApiRequest, AuthError, type AuthTokens, ConfigError, type Environment, HCLoginClient, type HealthProfile, HttpError, type LoginBody, type LoginConfig, type LoginPayload, type LoginRequest, type OnboardBody, type OnboardInput, type OnboardRequest, type OnboardUser, type OnboardingStep, type RefreshBody, type RefreshRequest, type Region, type RegisterAttributes, type RegisterBody, type RegisterCredentials, type RegisterFullBody, type RegisterFullOptions, type RegisterFullRequest, type RegisterFullUser, type RegisterOptions, type RegisterOpts, type RegisterRequest, type RegisterUser, type ResetBody, type ResetConfirmBody, type ResetConfirmRequest, type ResetPasswordConfirmPayload, type ResetRequest, type SmsData, type UserInfo, type VerifyEmailOptions };
package/dist/index.d.ts CHANGED
@@ -39,17 +39,26 @@ interface VerifyEmailOptions {
39
39
  attributes?: Record<string, string>;
40
40
  }
41
41
  interface LoginBody {
42
- FirstName: string;
43
- LastName: string;
42
+ FirstName?: string;
43
+ LastName?: string;
44
44
  Email: string;
45
+ UserName?: string;
45
46
  Password: string;
46
- TenantID: string;
47
- AppPoolID: string;
48
- GoogleIdToken: string;
49
- AppleIdToken: string;
50
- AppleCode: string;
47
+ PoolID?: string;
48
+ AppPoolID?: string;
49
+ AppClientID?: string;
50
+ TenantID?: string;
51
+ Token?: string;
52
+ Type?: number;
53
+ AppleIdToken?: string;
54
+ AppleCode?: string;
55
+ GoogleIdToken?: string;
56
+ IsPasswordResetWithOTP?: boolean;
57
+ Code?: string;
58
+ Language?: string;
51
59
  }
52
60
  type LoginRequest = ApiRequest<LoginBody>;
61
+ type LoginPayload = LoginRequest;
53
62
  interface RefreshBody {
54
63
  RefreshToken: string;
55
64
  TenantID: string;
@@ -58,17 +67,24 @@ type RefreshRequest = ApiRequest<RefreshBody>;
58
67
  interface ResetBody {
59
68
  Email: string;
60
69
  TenantID: string;
61
- IsPasswordResetWithOTP: boolean;
70
+ IsPasswordResetWithOTP?: boolean;
62
71
  }
63
72
  type ResetRequest = ApiRequest<ResetBody>;
64
- interface ResetConfirmBody {
73
+ type ResetConfirmBody = {
65
74
  Email: string;
66
- TenantID: string;
67
75
  Password: string;
68
- code: string;
69
- IsPasswordResetWithOTP: boolean;
70
- }
76
+ IsPasswordResetWithOTP: true;
77
+ Code: string;
78
+ Token?: string;
79
+ } | {
80
+ Email: string;
81
+ Password: string;
82
+ Token: string;
83
+ IsPasswordResetWithOTP?: false;
84
+ Code?: string;
85
+ };
71
86
  type ResetConfirmRequest = ApiRequest<ResetConfirmBody>;
87
+ type ResetPasswordConfirmPayload = ResetConfirmRequest;
72
88
  interface RegisterCredentials {
73
89
  Email: string;
74
90
  Password: string;
@@ -204,7 +220,7 @@ declare class HCLoginClient {
204
220
  login(email: string, password: string): Promise<AuthTokens>;
205
221
  refreshToken(): Promise<AuthTokens>;
206
222
  resetPassword(email: string, isPasswordResetWithOTP?: boolean): Promise<void>;
207
- resetPasswordConfirm(email: string, password: string, code: string, isPasswordResetWithOTP?: boolean): Promise<void>;
223
+ resetPasswordConfirm(payload: ResetPasswordConfirmPayload): Promise<void>;
208
224
  getAccessToken(): string | undefined;
209
225
  getIDToken(): string | undefined;
210
226
  getUserInfo(): Promise<unknown>;
@@ -217,7 +233,6 @@ declare class HCLoginClient {
217
233
  Authorization: string;
218
234
  "X-Tenant-ID": string;
219
235
  };
220
- getHeader(): Promise<any>;
221
236
  private getApiKeyHeader;
222
237
  getBaseUrl(): string;
223
238
  getTenantId(): string;
@@ -234,4 +249,4 @@ declare class HttpError extends Error {
234
249
  constructor(status: number, message: string);
235
250
  }
236
251
 
237
- export { type Address, type ApiRequest, AuthError, type AuthTokens, ConfigError, type Environment, HCLoginClient, type HealthProfile, HttpError, type LoginBody, type LoginConfig, type LoginRequest, type OnboardBody, type OnboardInput, type OnboardRequest, type OnboardUser, type OnboardingStep, type RefreshBody, type RefreshRequest, type Region, type RegisterAttributes, type RegisterBody, type RegisterCredentials, type RegisterFullBody, type RegisterFullOptions, type RegisterFullRequest, type RegisterFullUser, type RegisterOptions, type RegisterOpts, type RegisterRequest, type RegisterUser, type ResetBody, type ResetConfirmBody, type ResetConfirmRequest, type ResetRequest, type SmsData, type UserInfo, type VerifyEmailOptions };
252
+ export { type Address, type ApiRequest, AuthError, type AuthTokens, ConfigError, type Environment, HCLoginClient, type HealthProfile, HttpError, type LoginBody, type LoginConfig, type LoginPayload, type LoginRequest, type OnboardBody, type OnboardInput, type OnboardRequest, type OnboardUser, type OnboardingStep, type RefreshBody, type RefreshRequest, type Region, type RegisterAttributes, type RegisterBody, type RegisterCredentials, type RegisterFullBody, type RegisterFullOptions, type RegisterFullRequest, type RegisterFullUser, type RegisterOptions, type RegisterOpts, type RegisterRequest, type RegisterUser, type ResetBody, type ResetConfirmBody, type ResetConfirmRequest, type ResetPasswordConfirmPayload, type ResetRequest, type SmsData, type UserInfo, type VerifyEmailOptions };
package/dist/index.js CHANGED
@@ -34,17 +34,31 @@ var HCLoginClient = class {
34
34
  this.http = httpClient;
35
35
  }
36
36
  configure(tenantID, environment, region) {
37
- if (!tenantID) throw new ConfigError("tenantID is required");
37
+ const trimmedTenantID = tenantID == null ? void 0 : tenantID.trim();
38
+ if (!trimmedTenantID) {
39
+ throw new ConfigError("tenantID is required.");
40
+ }
41
+ if (!ENV_PREFIX[environment]) {
42
+ throw new ConfigError("Invalid environment.");
43
+ }
38
44
  this.config = {
39
- tenantID,
45
+ tenantID: trimmedTenantID,
40
46
  environment,
41
47
  region,
42
- baseUrl: buildBaseUrl(tenantID, environment, region)
48
+ baseUrl: buildBaseUrl(trimmedTenantID, environment, region)
43
49
  };
44
50
  }
45
51
  setApiKey(headerName, value) {
46
- this.apiKeyHeaderName = headerName;
47
- this.apiKeyValue = value;
52
+ const trimmedHeaderName = headerName == null ? void 0 : headerName.trim();
53
+ const trimmedValue = value == null ? void 0 : value.trim();
54
+ if (!trimmedHeaderName) {
55
+ throw new ConfigError("API key header name is required.");
56
+ }
57
+ if (!trimmedValue) {
58
+ throw new ConfigError("API key value is required.");
59
+ }
60
+ this.apiKeyHeaderName = trimmedHeaderName;
61
+ this.apiKeyValue = trimmedValue;
48
62
  }
49
63
  async register(email, password, firstName = "Unknown", lastName = "Unknown", options = {}) {
50
64
  var _a, _b;
@@ -190,15 +204,9 @@ var HCLoginClient = class {
190
204
  this.ensureConfigured();
191
205
  const requestPayload = {
192
206
  Data: {
193
- FirstName: "",
194
- LastName: "",
195
207
  Email: email,
196
208
  Password: password,
197
- TenantID: this.config.tenantID,
198
- AppPoolID: "",
199
- GoogleIdToken: "",
200
- AppleIdToken: "",
201
- AppleCode: ""
209
+ TenantID: this.config.tenantID
202
210
  }
203
211
  };
204
212
  const resp = await this.http.post(
@@ -234,7 +242,10 @@ var HCLoginClient = class {
234
242
  const resp = await this.http.post(
235
243
  `${this.config.baseUrl}/patient/refresh`,
236
244
  requestPayload,
237
- this.getAuthHeader()
245
+ {
246
+ "X-Tenant-ID": this.config.tenantID,
247
+ ...this.getApiKeyHeader()
248
+ }
238
249
  );
239
250
  const data = (_b = resp.Data) != null ? _b : resp;
240
251
  const tokens = {
@@ -246,14 +257,14 @@ var HCLoginClient = class {
246
257
  this.tokens = tokens;
247
258
  return tokens;
248
259
  }
249
- async resetPassword(email, isPasswordResetWithOTP = true) {
260
+ async resetPassword(email, isPasswordResetWithOTP = false) {
250
261
  var _a;
251
262
  this.ensureConfigured();
252
263
  const requestPayload = {
253
264
  Data: {
254
265
  Email: email,
255
266
  TenantID: this.config.tenantID,
256
- IsPasswordResetWithOTP: isPasswordResetWithOTP
267
+ ...isPasswordResetWithOTP === true ? { IsPasswordResetWithOTP: true } : {}
257
268
  }
258
269
  };
259
270
  await this.http.post(
@@ -267,21 +278,24 @@ var HCLoginClient = class {
267
278
  }
268
279
  );
269
280
  }
270
- async resetPasswordConfirm(email, password, code, isPasswordResetWithOTP = true) {
281
+ async resetPasswordConfirm(payload) {
271
282
  var _a;
272
283
  this.ensureConfigured();
273
- const requestPayload = {
274
- Data: {
275
- Email: email,
276
- TenantID: this.config.tenantID,
277
- Password: password,
278
- code,
279
- IsPasswordResetWithOTP: isPasswordResetWithOTP
280
- }
281
- };
284
+ const isOtpFlow = payload.Data.IsPasswordResetWithOTP === true;
285
+ if (isOtpFlow && !payload.Data.Code) {
286
+ throw new ConfigError("Code is required for OTP password reset confirmation.");
287
+ }
288
+ if (!isOtpFlow && !payload.Data.Token) {
289
+ throw new ConfigError("Token is required for link-based password reset confirmation.");
290
+ }
282
291
  await this.http.post(
283
292
  `${this.config.baseUrl}/patient/password`,
284
- requestPayload,
293
+ {
294
+ Data: {
295
+ ...payload.Data,
296
+ TenantID: this.config.tenantID
297
+ }
298
+ },
285
299
  {
286
300
  "Content-Type": "application/json",
287
301
  "X-Tenant-ID": this.config.tenantID,
@@ -408,23 +422,12 @@ var HCLoginClient = class {
408
422
  ...this.getApiKeyHeader()
409
423
  };
410
424
  }
411
- async getHeader() {
412
- var _a;
413
- this.ensureConfigured();
414
- if (!((_a = this.tokens) == null ? void 0 : _a.idToken)) {
415
- throw new AuthError("No ID token available");
416
- }
417
- return this.http.get(
418
- `${this.config.baseUrl}/patient/header`,
419
- this.getAuthHeader()
420
- );
421
- }
422
425
  getApiKeyHeader() {
423
426
  if (!this.apiKeyHeaderName || !this.apiKeyValue) {
424
427
  return {};
425
428
  }
426
429
  return {
427
- "x-api-key": this.apiKeyValue
430
+ [this.apiKeyHeaderName]: this.apiKeyValue
428
431
  };
429
432
  }
430
433
  getBaseUrl() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@healthcloudai/hc-login-connector",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "Healthcheck Login authentication SDK with TypeScrip and token refresh",
5
5
  "author": "Healthcheck Systems Inc",
6
6
  "license": "MIT",