edilkamin 1.6.2 → 1.7.2

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/src/cli.ts CHANGED
@@ -4,7 +4,8 @@ import readline from "readline";
4
4
 
5
5
  import { version } from "../package.json";
6
6
  import { NEW_API_URL, OLD_API_URL } from "./constants";
7
- import { configure, signIn } from "./library";
7
+ import { configure, configureAmplify, getSession, signIn } from "./library";
8
+ import { clearSession, createFileStorage } from "./token-storage";
8
9
 
9
10
  const promptPassword = (): Promise<string> => {
10
11
  const rl = readline.createInterface({
@@ -30,12 +31,16 @@ const promptPassword = (): Promise<string> => {
30
31
 
31
32
  /**
32
33
  * Adds common options (username and password) to a command.
34
+ * Username is optional if a session already exists.
33
35
  * @param command The command to which options should be added.
34
36
  * @returns The command with options added.
35
37
  */
36
38
  const addAuthOptions = (command: Command): Command =>
37
39
  command
38
- .requiredOption("-u, --username <username>", "Username")
40
+ .option(
41
+ "-u, --username <username>",
42
+ "Username (optional if session exists)",
43
+ )
39
44
  .option("-p, --password <password>", "Password");
40
45
 
41
46
  /**
@@ -56,11 +61,12 @@ const addLegacyOption = (command: Command): Command =>
56
61
 
57
62
  /**
58
63
  * Handles common authentication and API initialization logic.
64
+ * Tries to use existing session first, falls back to sign-in if needed.
59
65
  * @param options The options passed from the CLI command.
60
66
  * @returns An object containing the normalized MAC, JWT token, and configured API instance.
61
67
  */
62
68
  const initializeCommand = async (options: {
63
- username: string;
69
+ username?: string;
64
70
  password?: string;
65
71
  mac: string;
66
72
  legacy?: boolean;
@@ -71,8 +77,26 @@ const initializeCommand = async (options: {
71
77
  }> => {
72
78
  const { username, password, mac, legacy = false } = options;
73
79
  const normalizedMac = mac.replace(/:/g, "");
74
- const pwd = password || (await promptPassword());
75
- const jwtToken = await signIn(username, pwd, legacy);
80
+
81
+ // Initialize file storage for session persistence
82
+ const storage = createFileStorage();
83
+ configureAmplify(storage);
84
+
85
+ let jwtToken: string;
86
+ try {
87
+ // Try to get existing session first
88
+ jwtToken = await getSession(false, legacy);
89
+ } catch {
90
+ // No session, need to sign in
91
+ if (!username) {
92
+ throw new Error(
93
+ "No session found. Please provide --username to sign in.",
94
+ );
95
+ }
96
+ const pwd = password || (await promptPassword());
97
+ jwtToken = await signIn(username, pwd, legacy);
98
+ }
99
+
76
100
  const apiUrl = legacy ? OLD_API_URL : NEW_API_URL;
77
101
  const api = configure(apiUrl);
78
102
  return { normalizedMac, jwtToken, api };
@@ -85,7 +109,7 @@ const initializeCommand = async (options: {
85
109
  */
86
110
  const executeGetter = async (
87
111
  options: {
88
- username: string;
112
+ username?: string;
89
113
  password?: string;
90
114
  mac: string;
91
115
  legacy?: boolean;
@@ -93,8 +117,8 @@ const executeGetter = async (
93
117
  getter: (
94
118
  api: ReturnType<typeof configure>,
95
119
  jwtToken: string,
96
- mac: string
97
- ) => Promise<unknown>
120
+ mac: string,
121
+ ) => Promise<unknown>,
98
122
  ): Promise<void> => {
99
123
  const { normalizedMac, jwtToken, api } = await initializeCommand(options);
100
124
  const result = await getter(api, jwtToken, normalizedMac);
@@ -108,7 +132,7 @@ const executeGetter = async (
108
132
  */
109
133
  const executeSetter = async (
110
134
  options: {
111
- username: string;
135
+ username?: string;
112
136
  password?: string;
113
137
  mac: string;
114
138
  value: number;
@@ -118,8 +142,8 @@ const executeSetter = async (
118
142
  api: ReturnType<typeof configure>,
119
143
  jwtToken: string,
120
144
  mac: string,
121
- value: number
122
- ) => Promise<unknown>
145
+ value: number,
146
+ ) => Promise<unknown>,
123
147
  ): Promise<void> => {
124
148
  const { normalizedMac, jwtToken, api } = await initializeCommand(options);
125
149
  const result = await setter(api, jwtToken, normalizedMac, options.value);
@@ -133,14 +157,29 @@ const createProgram = (): Command => {
133
157
  .description("CLI tool for interacting with the Edilkamin API")
134
158
  .version(version);
135
159
  // Command: signIn
136
- addAuthOptions(
137
- program.command("signIn").description("Sign in and retrieve a JWT token")
138
- ).action(async (options) => {
139
- const { username, password } = options;
140
- const pwd = password || (await promptPassword());
141
- const jwtToken = await signIn(username, pwd);
142
- console.log("JWT Token:", jwtToken);
143
- });
160
+ program
161
+ .command("signIn")
162
+ .description("Sign in and retrieve a JWT token")
163
+ .requiredOption("-u, --username <username>", "Username")
164
+ .option("-p, --password <password>", "Password")
165
+ .action(async (options) => {
166
+ const { username, password } = options;
167
+ // Initialize file storage for session persistence
168
+ const storage = createFileStorage();
169
+ configureAmplify(storage);
170
+ const pwd = password || (await promptPassword());
171
+ const jwtToken = await signIn(username, pwd);
172
+ console.log("JWT Token:", jwtToken);
173
+ });
174
+
175
+ // Command: logout
176
+ program
177
+ .command("logout")
178
+ .description("Clear stored session")
179
+ .action(async () => {
180
+ await clearSession();
181
+ console.log("Session cleared successfully");
182
+ });
144
183
  // Generic getter commands
145
184
  [
146
185
  {
@@ -149,7 +188,7 @@ const createProgram = (): Command => {
149
188
  getter: (
150
189
  api: ReturnType<typeof configure>,
151
190
  jwtToken: string,
152
- mac: string
191
+ mac: string,
153
192
  ) => api.deviceInfo(jwtToken, mac),
154
193
  },
155
194
  {
@@ -158,7 +197,7 @@ const createProgram = (): Command => {
158
197
  getter: (
159
198
  api: ReturnType<typeof configure>,
160
199
  jwtToken: string,
161
- mac: string
200
+ mac: string,
162
201
  ) => api.getPower(jwtToken, mac),
163
202
  },
164
203
  {
@@ -167,7 +206,7 @@ const createProgram = (): Command => {
167
206
  getter: (
168
207
  api: ReturnType<typeof configure>,
169
208
  jwtToken: string,
170
- mac: string
209
+ mac: string,
171
210
  ) => api.getEnvironmentTemperature(jwtToken, mac),
172
211
  },
173
212
  {
@@ -176,14 +215,14 @@ const createProgram = (): Command => {
176
215
  getter: (
177
216
  api: ReturnType<typeof configure>,
178
217
  jwtToken: string,
179
- mac: string
218
+ mac: string,
180
219
  ) => api.getTargetTemperature(jwtToken, mac),
181
220
  },
182
221
  ].forEach(({ commandName, description, getter }) => {
183
222
  addLegacyOption(
184
223
  addMacOption(
185
- addAuthOptions(program.command(commandName).description(description))
186
- )
224
+ addAuthOptions(program.command(commandName).description(description)),
225
+ ),
187
226
  ).action((options) => executeGetter(options, getter));
188
227
  });
189
228
  // Generic setter commands
@@ -195,7 +234,7 @@ const createProgram = (): Command => {
195
234
  api: ReturnType<typeof configure>,
196
235
  jwtToken: string,
197
236
  mac: string,
198
- value: number
237
+ value: number,
199
238
  ) => api.setPower(jwtToken, mac, value),
200
239
  },
201
240
  {
@@ -205,16 +244,16 @@ const createProgram = (): Command => {
205
244
  api: ReturnType<typeof configure>,
206
245
  jwtToken: string,
207
246
  mac: string,
208
- value: number
247
+ value: number,
209
248
  ) => api.setTargetTemperature(jwtToken, mac, value),
210
249
  },
211
250
  ].forEach(({ commandName, description, setter }) => {
212
251
  addLegacyOption(
213
252
  addMacOption(
214
253
  addAuthOptions(
215
- program.command(commandName).description(description)
216
- ).requiredOption("-v, --value <number>", "Value to set", parseFloat)
217
- )
254
+ program.command(commandName).description(description),
255
+ ).requiredOption("-v, --value <number>", "Value to set", parseFloat),
256
+ ),
218
257
  ).action((options) => executeSetter(options, setter));
219
258
  });
220
259
 
@@ -223,8 +262,8 @@ const createProgram = (): Command => {
223
262
  addAuthOptions(
224
263
  program
225
264
  .command("register")
226
- .description("Register a device with your account")
227
- )
265
+ .description("Register a device with your account"),
266
+ ),
228
267
  )
229
268
  .requiredOption("-m, --mac <macAddress>", "MAC address of the device")
230
269
  .requiredOption("-s, --serial <serialNumber>", "Device serial number")
@@ -241,8 +280,24 @@ const createProgram = (): Command => {
241
280
  legacy = false,
242
281
  } = options;
243
282
  const normalizedMac = mac.replace(/:/g, "");
244
- const pwd = password || (await promptPassword());
245
- const jwtToken = await signIn(username, pwd, legacy);
283
+
284
+ // Initialize file storage for session persistence
285
+ const storage = createFileStorage();
286
+ configureAmplify(storage);
287
+
288
+ let jwtToken: string;
289
+ try {
290
+ jwtToken = await getSession(false, legacy);
291
+ } catch {
292
+ if (!username) {
293
+ throw new Error(
294
+ "No session found. Please provide --username to sign in.",
295
+ );
296
+ }
297
+ const pwd = password || (await promptPassword());
298
+ jwtToken = await signIn(username, pwd, legacy);
299
+ }
300
+
246
301
  const apiUrl = legacy ? OLD_API_URL : NEW_API_URL;
247
302
  const api = configure(apiUrl);
248
303
  const result = await api.registerDevice(
@@ -250,7 +305,7 @@ const createProgram = (): Command => {
250
305
  normalizedMac,
251
306
  serial,
252
307
  name,
253
- room
308
+ room,
254
309
  );
255
310
  console.log("Device registered successfully:");
256
311
  console.log(JSON.stringify(result, null, 2));
@@ -260,17 +315,35 @@ const createProgram = (): Command => {
260
315
  addLegacyOption(
261
316
  addMacOption(
262
317
  addAuthOptions(
263
- program.command("editDevice").description("Update device name and room")
264
- )
265
- )
318
+ program
319
+ .command("editDevice")
320
+ .description("Update device name and room"),
321
+ ),
322
+ ),
266
323
  )
267
324
  .requiredOption("-n, --name <deviceName>", "Device name")
268
325
  .requiredOption("-r, --room <deviceRoom>", "Room name")
269
326
  .action(async (options) => {
270
327
  const { username, password, mac, name, room, legacy = false } = options;
271
328
  const normalizedMac = mac.replace(/:/g, "");
272
- const pwd = password || (await promptPassword());
273
- const jwtToken = await signIn(username, pwd, legacy);
329
+
330
+ // Initialize file storage for session persistence
331
+ const storage = createFileStorage();
332
+ configureAmplify(storage);
333
+
334
+ let jwtToken: string;
335
+ try {
336
+ jwtToken = await getSession(false, legacy);
337
+ } catch {
338
+ if (!username) {
339
+ throw new Error(
340
+ "No session found. Please provide --username to sign in.",
341
+ );
342
+ }
343
+ const pwd = password || (await promptPassword());
344
+ jwtToken = await signIn(username, pwd, legacy);
345
+ }
346
+
274
347
  const apiUrl = legacy ? OLD_API_URL : NEW_API_URL;
275
348
  const api = configure(apiUrl);
276
349
  const result = await api.editDevice(jwtToken, normalizedMac, name, room);
package/src/index.ts CHANGED
@@ -2,12 +2,13 @@ import { configure } from "./library";
2
2
 
3
3
  export { decompressBuffer, isBuffer, processResponse } from "./buffer-utils";
4
4
  export { API_URL, NEW_API_URL, OLD_API_URL } from "./constants";
5
- export { configure, signIn } from "./library";
5
+ export { configure, getSession, signIn } from "./library";
6
6
  export {
7
7
  serialNumberDisplay,
8
8
  serialNumberFromHex,
9
9
  serialNumberToHex,
10
10
  } from "./serial-utils";
11
+ export { clearSession } from "./token-storage";
11
12
  export {
12
13
  BufferEncodedType,
13
14
  CommandsType,
@@ -1,4 +1,5 @@
1
1
  import { strict as assert } from "assert";
2
+ import * as amplifyAuth from "aws-amplify/auth";
2
3
  import axios from "axios";
3
4
  import pako from "pako";
4
5
  import sinon from "sinon";
@@ -10,7 +11,7 @@ import { API_URL } from "./constants";
10
11
  * Helper to create a gzip-compressed Buffer object for testing.
11
12
  */
12
13
  const createGzippedBuffer = (
13
- data: unknown
14
+ data: unknown,
14
15
  ): { type: "Buffer"; data: number[] } => {
15
16
  const json = JSON.stringify(data);
16
17
  const compressed = pako.gzip(json);
@@ -57,7 +58,7 @@ describe("library", () => {
57
58
  const authService = createAuthService(authStub as any);
58
59
  const token = await authService.signIn(
59
60
  expectedUsername,
60
- expectedPassword
61
+ expectedPassword,
61
62
  );
62
63
  assert.deepEqual(authStub.signOut.args, [[]]);
63
64
  assert.deepEqual(signIn.args, [
@@ -87,7 +88,7 @@ describe("library", () => {
87
88
  const token = await authService.signIn(
88
89
  expectedUsername,
89
90
  expectedPassword,
90
- true // legacy mode
91
+ true, // legacy mode
91
92
  );
92
93
  assert.equal(token, expectedToken);
93
94
  });
@@ -114,8 +115,82 @@ describe("library", () => {
114
115
  {
115
116
  name: "AssertionError",
116
117
  message: "Sign-in failed",
117
- }
118
+ },
119
+ );
120
+ });
121
+ });
122
+
123
+ describe("getSession", () => {
124
+ it("should return idToken by default", async () => {
125
+ const mockAuth = {
126
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
127
+ signOut: sinon.stub().resolves(),
128
+ fetchAuthSession: sinon.stub().resolves({
129
+ tokens: {
130
+ idToken: { toString: () => "mock-id-token" },
131
+ accessToken: { toString: () => "mock-access-token" },
132
+ },
133
+ }),
134
+ };
135
+ const { getSession, signIn } = createAuthService(
136
+ mockAuth as unknown as typeof amplifyAuth,
137
+ );
138
+ await signIn("user", "pass");
139
+ const token = await getSession();
140
+ assert.equal(token, "mock-id-token");
141
+ });
142
+
143
+ it("should return accessToken when legacy=true", async () => {
144
+ const mockAuth = {
145
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
146
+ signOut: sinon.stub().resolves(),
147
+ fetchAuthSession: sinon.stub().resolves({
148
+ tokens: {
149
+ idToken: { toString: () => "mock-id-token" },
150
+ accessToken: { toString: () => "mock-access-token" },
151
+ },
152
+ }),
153
+ };
154
+ const { getSession, signIn } = createAuthService(
155
+ mockAuth as unknown as typeof amplifyAuth,
156
+ );
157
+ await signIn("user", "pass");
158
+ const token = await getSession(false, true);
159
+ assert.equal(token, "mock-access-token");
160
+ });
161
+
162
+ it("should throw error when no session exists", async () => {
163
+ const mockAuth = {
164
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
165
+ signOut: sinon.stub().resolves(),
166
+ fetchAuthSession: sinon.stub().resolves({ tokens: null }),
167
+ };
168
+ const { getSession } = createAuthService(
169
+ mockAuth as unknown as typeof amplifyAuth,
170
+ );
171
+ await assert.rejects(async () => getSession(), {
172
+ name: "AssertionError",
173
+ message: "No session found - please sign in first",
174
+ });
175
+ });
176
+
177
+ it("should pass forceRefresh to fetchAuthSession", async () => {
178
+ const mockAuth = {
179
+ signIn: sinon.stub().resolves({ isSignedIn: true }),
180
+ signOut: sinon.stub().resolves(),
181
+ fetchAuthSession: sinon.stub().resolves({
182
+ tokens: {
183
+ idToken: { toString: () => "mock-id-token" },
184
+ accessToken: { toString: () => "mock-access-token" },
185
+ },
186
+ }),
187
+ };
188
+ const { getSession, signIn } = createAuthService(
189
+ mockAuth as unknown as typeof amplifyAuth,
118
190
  );
191
+ await signIn("user", "pass");
192
+ await getSession(true);
193
+ assert.ok(mockAuth.fetchAuthSession.calledWith({ forceRefresh: true }));
119
194
  });
120
195
  });
121
196
 
@@ -278,7 +353,7 @@ describe("library", () => {
278
353
  api: ReturnType<typeof configure>,
279
354
  token: string,
280
355
  mac: string,
281
- value: number
356
+ value: number,
282
357
  ) => api.setTargetTemperature(token, mac, value),
283
358
  payload: {
284
359
  name: "enviroment_1_temperature",
@@ -298,7 +373,7 @@ describe("library", () => {
298
373
  api,
299
374
  expectedToken,
300
375
  "mockMacAddress",
301
- payload.value
376
+ payload.value,
302
377
  );
303
378
 
304
379
  assert.deepEqual(mockAxios.put.args, [
@@ -339,7 +414,7 @@ describe("library", () => {
339
414
  "AA:BB:CC:DD:EE:FF",
340
415
  "EDK123",
341
416
  "Test Stove",
342
- "Living Room"
417
+ "Living Room",
343
418
  );
344
419
 
345
420
  assert.deepEqual(mockAxios.post.args, [
@@ -407,7 +482,7 @@ describe("library", () => {
407
482
  expectedToken,
408
483
  "AA:BB:CC:DD:EE:FF",
409
484
  "Updated Name",
410
- "Basement"
485
+ "Basement",
411
486
  );
412
487
 
413
488
  assert.deepEqual(mockAxios.put.args, [
@@ -564,7 +639,7 @@ describe("library", () => {
564
639
 
565
640
  const result = await api.getEnvironmentTemperature(
566
641
  expectedToken,
567
- "mockMacAddress"
642
+ "mockMacAddress",
568
643
  );
569
644
 
570
645
  assert.equal(result, 19);
@@ -589,7 +664,7 @@ describe("library", () => {
589
664
 
590
665
  const result = await api.getTargetTemperature(
591
666
  expectedToken,
592
- "mockMacAddress"
667
+ "mockMacAddress",
593
668
  );
594
669
 
595
670
  assert.equal(result, 22);
package/src/library.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { strict as assert } from "assert";
2
2
  import { Amplify } from "aws-amplify";
3
3
  import * as amplifyAuth from "aws-amplify/auth";
4
+ import { cognitoUserPoolsTokenProvider } from "aws-amplify/auth/cognito";
4
5
  import axios, { AxiosInstance } from "axios";
5
6
 
6
7
  import { processResponse } from "./buffer-utils";
@@ -31,10 +32,19 @@ let amplifyConfigured = false;
31
32
  /**
32
33
  * Configures Amplify if not already configured.
33
34
  * Uses a local flag to avoid calling getConfig() which prints a warning.
35
+ * @param {object} [storage] - Optional custom storage adapter for token persistence
34
36
  */
35
- const configureAmplify = () => {
37
+ const configureAmplify = (storage?: {
38
+ setItem: (key: string, value: string) => Promise<void>;
39
+ getItem: (key: string) => Promise<string | null>;
40
+ removeItem: (key: string) => Promise<void>;
41
+ clear: () => Promise<void>;
42
+ }) => {
36
43
  if (amplifyConfigured) return;
37
44
  Amplify.configure(amplifyconfiguration);
45
+ if (storage) {
46
+ cognitoUserPoolsTokenProvider.setKeyValueStorage(storage);
47
+ }
38
48
  amplifyConfigured = true;
39
49
  };
40
50
 
@@ -55,7 +65,7 @@ const createAuthService = (auth: typeof amplifyAuth) => {
55
65
  const signIn = async (
56
66
  username: string,
57
67
  password: string,
58
- legacy: boolean = false
68
+ legacy: boolean = false,
59
69
  ): Promise<string> => {
60
70
  configureAmplify();
61
71
  await auth.signOut(); // Ensure the user is signed out first
@@ -70,11 +80,35 @@ const createAuthService = (auth: typeof amplifyAuth) => {
70
80
  assert.ok(tokens.idToken, "No ID token found");
71
81
  return tokens.idToken.toString();
72
82
  };
73
- return { signIn };
83
+
84
+ /**
85
+ * Retrieves the current session, refreshing tokens if necessary.
86
+ * Requires a prior successful signIn() call.
87
+ * @param {boolean} [forceRefresh=false] - Force token refresh even if valid
88
+ * @param {boolean} [legacy=false] - If true, returns accessToken for legacy API
89
+ * @returns {Promise<string>} - The JWT token (idToken or accessToken)
90
+ * @throws {Error} - If no session exists (user needs to sign in)
91
+ */
92
+ const getSession = async (
93
+ forceRefresh: boolean = false,
94
+ legacy: boolean = false,
95
+ ): Promise<string> => {
96
+ configureAmplify();
97
+ const { tokens } = await auth.fetchAuthSession({ forceRefresh });
98
+ assert.ok(tokens, "No session found - please sign in first");
99
+ if (legacy) {
100
+ assert.ok(tokens.accessToken, "No access token found");
101
+ return tokens.accessToken.toString();
102
+ }
103
+ assert.ok(tokens.idToken, "No ID token found");
104
+ return tokens.idToken.toString();
105
+ };
106
+
107
+ return { signIn, getSession };
74
108
  };
75
109
 
76
110
  // Create the default auth service using amplifyAuth
77
- const { signIn } = createAuthService(amplifyAuth);
111
+ const { signIn, getSession } = createAuthService(amplifyAuth);
78
112
 
79
113
  const deviceInfo =
80
114
  (axiosInstance: AxiosInstance) =>
@@ -91,7 +125,7 @@ const deviceInfo =
91
125
  `device/${macAddress}/info`,
92
126
  {
93
127
  headers: headers(jwtToken),
94
- }
128
+ },
95
129
  );
96
130
  // Process response to decompress any gzipped Buffer fields
97
131
  return processResponse(response.data) as DeviceInfoType;
@@ -104,7 +138,7 @@ const mqttCommand =
104
138
  axiosInstance.put(
105
139
  "mqtt/command",
106
140
  { mac_address: macAddress, ...payload },
107
- { headers: headers(jwtToken) }
141
+ { headers: headers(jwtToken) },
108
142
  );
109
143
 
110
144
  const setPower =
@@ -228,7 +262,7 @@ const registerDevice =
228
262
  macAddress: string,
229
263
  serialNumber: string,
230
264
  deviceName: string = "",
231
- deviceRoom: string = ""
265
+ deviceRoom: string = "",
232
266
  ): Promise<DeviceAssociationResponse> => {
233
267
  const body: DeviceAssociationBody = {
234
268
  macAddress: macAddress.replace(/:/g, ""),
@@ -239,7 +273,7 @@ const registerDevice =
239
273
  const response = await axiosInstance.post<DeviceAssociationResponse>(
240
274
  "device",
241
275
  body,
242
- { headers: headers(jwtToken) }
276
+ { headers: headers(jwtToken) },
243
277
  );
244
278
  return response.data;
245
279
  };
@@ -259,7 +293,7 @@ const editDevice =
259
293
  jwtToken: string,
260
294
  macAddress: string,
261
295
  deviceName: string = "",
262
- deviceRoom: string = ""
296
+ deviceRoom: string = "",
263
297
  ): Promise<DeviceAssociationResponse> => {
264
298
  const normalizedMac = macAddress.replace(/:/g, "");
265
299
  const body: EditDeviceAssociationBody = {
@@ -269,7 +303,7 @@ const editDevice =
269
303
  const response = await axiosInstance.put<DeviceAssociationResponse>(
270
304
  `device/${normalizedMac}`,
271
305
  body,
272
- { headers: headers(jwtToken) }
306
+ { headers: headers(jwtToken) },
273
307
  );
274
308
  return response.data;
275
309
  };
@@ -312,4 +346,11 @@ const configure = (baseURL: string = API_URL) => {
312
346
  };
313
347
  };
314
348
 
315
- export { configure, createAuthService, headers, signIn };
349
+ export {
350
+ configure,
351
+ configureAmplify,
352
+ createAuthService,
353
+ getSession,
354
+ headers,
355
+ signIn,
356
+ };