lamp-core-lst 2025.11.20 → 2025.12.1

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.
@@ -73,6 +73,10 @@ export declare class Activity {
73
73
  * The tab settings for the activity.
74
74
  */
75
75
  category?: Tab[] | null;
76
+ /**
77
+ * The photo/image URL for the activity (stored in Azure Blob Storage).
78
+ */
79
+ photo?: any;
76
80
  /**
77
81
  * The type of streak for the activity.
78
82
  */
@@ -23,8 +23,15 @@ export declare class ActivityService {
23
23
  /**
24
24
  * Get the set of all activities available to participants of a single study, by study identifier.
25
25
  * @param studyId
26
+ * @param transform
27
+ * @param ignore_binary
28
+ * @param limit Optional limit for pagination
29
+ * @param offset Optional offset for pagination
26
30
  */
27
- allByStudy(studyId: Identifier, transform?: string, ignore_binary?: boolean): Promise<Activity[]>;
31
+ allByStudy(studyId: Identifier, transform?: string, ignore_binary?: boolean, limit?: number, offset?: number): Promise<Activity[] | {
32
+ data: Activity[];
33
+ total: number;
34
+ }>;
28
35
  /**
29
36
  * Get the set of all activities available to participants of a single study, by participant identifier.
30
37
  * @param participantId
@@ -199,13 +199,17 @@ var ActivityService = /** @class */ (function () {
199
199
  /**
200
200
  * Get the set of all activities available to participants of a single study, by study identifier.
201
201
  * @param studyId
202
+ * @param transform
203
+ * @param ignore_binary
204
+ * @param limit Optional limit for pagination
205
+ * @param offset Optional offset for pagination
202
206
  */
203
- ActivityService.prototype.allByStudy = function (studyId, transform, ignore_binary) {
204
- var _a, _b;
207
+ ActivityService.prototype.allByStudy = function (studyId, transform, ignore_binary, limit, offset) {
208
+ var _a;
205
209
  return __awaiter(this, void 0, void 0, function () {
206
- var auth_4, credential, output;
207
- return __generator(this, function (_c) {
208
- switch (_c.label) {
210
+ var auth_4, credential, output, total, paginatedOutput, params, queryString, result, activitiesArray, totalCount, mappedActivities;
211
+ return __generator(this, function (_b) {
212
+ switch (_b.label) {
209
213
  case 0:
210
214
  if (studyId === null || studyId === undefined)
211
215
  throw new Error("Required parameter studyId was null or undefined when calling activityAllByStudy.");
@@ -221,14 +225,53 @@ var ActivityService = /** @class */ (function () {
221
225
  if (Demo_1.Demo.Study.filter(function (x) { return x["id"] === studyId; }).length > 0) {
222
226
  output = (_a = Demo_1.Demo.Activity.filter(function (x) { return x["#parent"] === studyId; })) === null || _a === void 0 ? void 0 : _a.map(function (x) { return Object.assign(new Activity_1.Activity(), x); });
223
227
  output = typeof transform === "string" ? jsonata_1.default(transform).evaluate(output) : output;
228
+ // If pagination is requested, return paginated result with total
229
+ if (typeof limit === 'number' && limit > 0 || typeof offset === 'number' && offset > 0) {
230
+ total = output.length;
231
+ paginatedOutput = limit !== undefined && offset !== undefined
232
+ ? output.slice(offset, offset + limit)
233
+ : output;
234
+ return [2 /*return*/, Promise.resolve({ data: paginatedOutput, total: total })];
235
+ }
224
236
  return [2 /*return*/, Promise.resolve(output)];
225
237
  }
226
238
  else {
227
239
  return [2 /*return*/, Promise.resolve({ error: "404.not-found" })];
228
240
  }
229
241
  }
230
- return [4 /*yield*/, Fetch_1.Fetch.get("/study/" + studyId + "/activity?ignore_binary=" + ignore_binary, this.configuration)];
231
- case 1: return [2 /*return*/, (_b = (_c.sent()).data) === null || _b === void 0 ? void 0 : _b.map(function (x) { return Object.assign(new Activity_1.Activity(), x); })];
242
+ params = new URLSearchParams();
243
+ params.append('ignore_binary', String(ignore_binary));
244
+ if (limit !== undefined && limit !== null) {
245
+ params.append('limit', limit.toString());
246
+ }
247
+ if (offset !== undefined && offset !== null) {
248
+ params.append('offset', offset.toString());
249
+ }
250
+ queryString = params.toString();
251
+ return [4 /*yield*/, Fetch_1.Fetch.get("/study/" + studyId + "/activity?" + queryString, this.configuration)
252
+ // Handle the response structure based on _select function behavior:
253
+ // - With pagination (limit > 0 OR offset >= 0): { data: Activity[], total: number }
254
+ // - Without pagination: { data: Activity[] } (total property is missing)
255
+ ];
256
+ case 1:
257
+ result = _b.sent();
258
+ activitiesArray = [];
259
+ totalCount = 0;
260
+ if (result && result.data && Array.isArray(result.data)) {
261
+ activitiesArray = result.data;
262
+ totalCount = typeof result.total === 'number' ? result.total : activitiesArray.length;
263
+ }
264
+ else if (Array.isArray(result)) {
265
+ // Legacy fallback: if result is directly an array
266
+ activitiesArray = result;
267
+ totalCount = result.length;
268
+ }
269
+ mappedActivities = activitiesArray.map(function (x) { return Object.assign(new Activity_1.Activity(), x); });
270
+ // If pagination was requested, return { data, total }, otherwise return array for backward compatibility
271
+ if (typeof limit === 'number' && limit > 0 || typeof offset === 'number' && offset > 0) {
272
+ return [2 /*return*/, { data: mappedActivities, total: totalCount }];
273
+ }
274
+ return [2 /*return*/, mappedActivities];
232
275
  }
233
276
  });
234
277
  });
@@ -60,24 +60,37 @@ var handleSessionExpiry = function () { return __awaiter(void 0, void 0, void 0,
60
60
  });
61
61
  }); };
62
62
  //If access Token expired then call api for renewing the tokens
63
- var handleRenewToken = function (refreshToken, base) { return __awaiter(void 0, void 0, void 0, function () {
64
- var credService, res, accessToken, error_1;
65
- var _a, _b, _c;
66
- return __generator(this, function (_d) {
67
- switch (_d.label) {
63
+ var handleRenewToken = function (refreshToken, base, configuration) { return __awaiter(void 0, void 0, void 0, function () {
64
+ var credService, res, accessToken, newRefreshToken, LAMP, identityObject, serverAddress, error_1;
65
+ var _a, _b, _c, _d, _e, _f;
66
+ return __generator(this, function (_g) {
67
+ switch (_g.label) {
68
68
  case 0:
69
- _d.trys.push([0, 2, , 3]);
69
+ _g.trys.push([0, 2, , 3]);
70
70
  credService = new Credential_service_1.CredentialService();
71
71
  return [4 /*yield*/, credService.renewToken(refreshToken, base)];
72
72
  case 1:
73
- res = _d.sent();
73
+ res = _g.sent();
74
74
  accessToken = (_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.access_token;
75
75
  if (accessToken) {
76
- sessionStorage.setItem(userTokenKey, JSON.stringify({ accessToken: (_b = res === null || res === void 0 ? void 0 : res.data) === null || _b === void 0 ? void 0 : _b.access_token, refreshToken: (_c = res === null || res === void 0 ? void 0 : res.data) === null || _c === void 0 ? void 0 : _c.refresh_token }));
76
+ newRefreshToken = ((_b = res === null || res === void 0 ? void 0 : res.data) === null || _b === void 0 ? void 0 : _b.refresh_token) || refreshToken;
77
+ sessionStorage.setItem(userTokenKey, JSON.stringify({ accessToken: (_c = res === null || res === void 0 ? void 0 : res.data) === null || _c === void 0 ? void 0 : _c.access_token, refreshToken: newRefreshToken }));
78
+ LAMP = global.LAMP || (typeof window !== "undefined" ? window.LAMP : null);
79
+ if (LAMP && typeof LAMP.dispatchEvent === "function") {
80
+ identityObject = ((_d = LAMP.Auth) === null || _d === void 0 ? void 0 : _d._me) || null;
81
+ serverAddress = (configuration === null || configuration === void 0 ? void 0 : configuration.base) || base || ((_e = LAMP.configuration) === null || _e === void 0 ? void 0 : _e.base);
82
+ LAMP.dispatchEvent("renewToken", {
83
+ authorizationToken: (configuration === null || configuration === void 0 ? void 0 : configuration.authorization) || ((_f = LAMP.configuration) === null || _f === void 0 ? void 0 : _f.authorization),
84
+ identityObject: identityObject,
85
+ serverAddress: serverAddress,
86
+ accessToken: accessToken,
87
+ refreshToken: newRefreshToken,
88
+ });
89
+ }
77
90
  }
78
91
  return [2 /*return*/, accessToken];
79
92
  case 2:
80
- error_1 = _d.sent();
93
+ error_1 = _g.sent();
81
94
  console.log(error_1);
82
95
  return [3 /*break*/, 3];
83
96
  case 3: return [2 /*return*/];
@@ -129,7 +142,7 @@ function _fetch(method, route, configuration, body) {
129
142
  handleSessionExpiry();
130
143
  return [2 /*return*/, { data: [], error: "401.invalid-token" }];
131
144
  }
132
- return [4 /*yield*/, handleRenewToken(refreshToken, configuration.base)];
145
+ return [4 /*yield*/, handleRenewToken(refreshToken, configuration.base, configuration)];
133
146
  case 5:
134
147
  token = _d.sent();
135
148
  if (!token) return [3 /*break*/, 17];
@@ -31,4 +31,66 @@ export declare class ResearcherService {
31
31
  usersList(id: string, filters: any): Promise<any>;
32
32
  activitiesList(id: string, filters: any): Promise<any>;
33
33
  sensorsList(id: string, filters: any): Promise<any>;
34
+ /**
35
+ * Create an activity export job.
36
+ * @param researcherId
37
+ * @param body - { studyIds: string[], specs?: string[], format?: "json" | "ndjson" }
38
+ */
39
+ createActivityExport(researcherId: Identifier, body: {
40
+ studyIds: string[];
41
+ specs?: string[];
42
+ format?: "json" | "ndjson";
43
+ }): Promise<{
44
+ jobId: string;
45
+ status: string;
46
+ }>;
47
+ /**
48
+ * Get activity export job status.
49
+ * @param jobId
50
+ */
51
+ getActivityExportJob(jobId: string): Promise<any>;
52
+ /**
53
+ * Get activity export download URL.
54
+ * @param jobId
55
+ * @param ttl - Time to live in seconds (default: 600)
56
+ */
57
+ getActivityExportDownloadUrl(jobId: string, ttl?: number): Promise<{
58
+ url: string;
59
+ expiresIn: number;
60
+ contentType: string;
61
+ contentLength: number;
62
+ }>;
63
+ /**
64
+ * Create an activity import job.
65
+ * @param researcherId
66
+ * @param body - { studyId: string, format?: "json" | "ndjson" }
67
+ */
68
+ createActivityImport(researcherId: Identifier, body: {
69
+ studyId: string;
70
+ format?: "json" | "ndjson";
71
+ }): Promise<{
72
+ jobId: string;
73
+ status: string;
74
+ }>;
75
+ /**
76
+ * Get activity import job status.
77
+ * @param jobId
78
+ */
79
+ getActivityImportJob(jobId: string): Promise<any>;
80
+ /**
81
+ * Get activity import upload URL.
82
+ * @param jobId
83
+ * @param ttl - Time to live in seconds (default: 600)
84
+ */
85
+ getActivityImportUploadUrl(jobId: string, ttl?: number): Promise<{
86
+ url: string;
87
+ expiresIn: number;
88
+ blobName: string;
89
+ }>;
90
+ /**
91
+ * Complete activity import upload and trigger processing.
92
+ * @param jobId
93
+ * @param blobName
94
+ */
95
+ completeActivityImportUpload(jobId: string, blobName: string): Promise<any>;
34
96
  }
@@ -247,6 +247,174 @@ var ResearcherService = /** @class */ (function () {
247
247
  });
248
248
  });
249
249
  };
250
+ /**
251
+ * Create an activity export job.
252
+ * @param researcherId
253
+ * @param body - { studyIds: string[], specs?: string[], format?: "json" | "ndjson" }
254
+ */
255
+ ResearcherService.prototype.createActivityExport = function (researcherId, body) {
256
+ return __awaiter(this, void 0, void 0, function () {
257
+ var result;
258
+ return __generator(this, function (_a) {
259
+ switch (_a.label) {
260
+ case 0:
261
+ if (researcherId === null || researcherId === undefined)
262
+ throw new Error("Required parameter researcherId was null or undefined when calling createActivityExport.");
263
+ if (this.configuration.base === "https://demo.lamp.digital") {
264
+ return [2 /*return*/, Promise.resolve({ error: "500.demo-restriction" })];
265
+ }
266
+ return [4 /*yield*/, Fetch_1.Fetch.post("/researcher/" + researcherId + "/activity-export", body, this.configuration)];
267
+ case 1:
268
+ result = _a.sent();
269
+ return [2 /*return*/, result.data];
270
+ }
271
+ });
272
+ });
273
+ };
274
+ /**
275
+ * Get activity export job status.
276
+ * @param jobId
277
+ */
278
+ ResearcherService.prototype.getActivityExportJob = function (jobId) {
279
+ return __awaiter(this, void 0, void 0, function () {
280
+ var result;
281
+ return __generator(this, function (_a) {
282
+ switch (_a.label) {
283
+ case 0:
284
+ if (jobId === null || jobId === undefined)
285
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityExportJob.");
286
+ if (this.configuration.base === "https://demo.lamp.digital") {
287
+ return [2 /*return*/, Promise.resolve({ error: "500.demo-restriction" })];
288
+ }
289
+ return [4 /*yield*/, Fetch_1.Fetch.get("/exports/" + jobId, this.configuration)];
290
+ case 1:
291
+ result = _a.sent();
292
+ return [2 /*return*/, result.data];
293
+ }
294
+ });
295
+ });
296
+ };
297
+ /**
298
+ * Get activity export download URL.
299
+ * @param jobId
300
+ * @param ttl - Time to live in seconds (default: 600)
301
+ */
302
+ ResearcherService.prototype.getActivityExportDownloadUrl = function (jobId, ttl) {
303
+ if (ttl === void 0) { ttl = 600; }
304
+ return __awaiter(this, void 0, void 0, function () {
305
+ var result;
306
+ return __generator(this, function (_a) {
307
+ switch (_a.label) {
308
+ case 0:
309
+ if (jobId === null || jobId === undefined)
310
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityExportDownloadUrl.");
311
+ if (this.configuration.base === "https://demo.lamp.digital") {
312
+ return [2 /*return*/, Promise.resolve({ error: "500.demo-restriction" })];
313
+ }
314
+ return [4 /*yield*/, Fetch_1.Fetch.get("/exports/" + jobId + "/download?ttl=" + ttl, this.configuration)];
315
+ case 1:
316
+ result = _a.sent();
317
+ return [2 /*return*/, result.data];
318
+ }
319
+ });
320
+ });
321
+ };
322
+ /**
323
+ * Create an activity import job.
324
+ * @param researcherId
325
+ * @param body - { studyId: string, format?: "json" | "ndjson" }
326
+ */
327
+ ResearcherService.prototype.createActivityImport = function (researcherId, body) {
328
+ return __awaiter(this, void 0, void 0, function () {
329
+ var result;
330
+ return __generator(this, function (_a) {
331
+ switch (_a.label) {
332
+ case 0:
333
+ if (researcherId === null || researcherId === undefined)
334
+ throw new Error("Required parameter researcherId was null or undefined when calling createActivityImport.");
335
+ if (this.configuration.base === "https://demo.lamp.digital") {
336
+ return [2 /*return*/, Promise.resolve({ error: "500.demo-restriction" })];
337
+ }
338
+ return [4 /*yield*/, Fetch_1.Fetch.post("/researcher/" + researcherId + "/activity-import", body, this.configuration)];
339
+ case 1:
340
+ result = _a.sent();
341
+ return [2 /*return*/, result.data];
342
+ }
343
+ });
344
+ });
345
+ };
346
+ /**
347
+ * Get activity import job status.
348
+ * @param jobId
349
+ */
350
+ ResearcherService.prototype.getActivityImportJob = function (jobId) {
351
+ return __awaiter(this, void 0, void 0, function () {
352
+ var result;
353
+ return __generator(this, function (_a) {
354
+ switch (_a.label) {
355
+ case 0:
356
+ if (jobId === null || jobId === undefined)
357
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityImportJob.");
358
+ if (this.configuration.base === "https://demo.lamp.digital") {
359
+ return [2 /*return*/, Promise.resolve({ error: "500.demo-restriction" })];
360
+ }
361
+ return [4 /*yield*/, Fetch_1.Fetch.get("/imports/" + jobId, this.configuration)];
362
+ case 1:
363
+ result = _a.sent();
364
+ return [2 /*return*/, result.data];
365
+ }
366
+ });
367
+ });
368
+ };
369
+ /**
370
+ * Get activity import upload URL.
371
+ * @param jobId
372
+ * @param ttl - Time to live in seconds (default: 600)
373
+ */
374
+ ResearcherService.prototype.getActivityImportUploadUrl = function (jobId, ttl) {
375
+ if (ttl === void 0) { ttl = 600; }
376
+ return __awaiter(this, void 0, void 0, function () {
377
+ var result;
378
+ return __generator(this, function (_a) {
379
+ switch (_a.label) {
380
+ case 0:
381
+ if (jobId === null || jobId === undefined)
382
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityImportUploadUrl.");
383
+ if (this.configuration.base === "https://demo.lamp.digital") {
384
+ return [2 /*return*/, Promise.resolve({ error: "500.demo-restriction" })];
385
+ }
386
+ return [4 /*yield*/, Fetch_1.Fetch.post("/imports/" + jobId + "/upload-url", { ttl: ttl }, this.configuration)];
387
+ case 1:
388
+ result = _a.sent();
389
+ return [2 /*return*/, result.data];
390
+ }
391
+ });
392
+ });
393
+ };
394
+ /**
395
+ * Complete activity import upload and trigger processing.
396
+ * @param jobId
397
+ * @param blobName
398
+ */
399
+ ResearcherService.prototype.completeActivityImportUpload = function (jobId, blobName) {
400
+ return __awaiter(this, void 0, void 0, function () {
401
+ var result;
402
+ return __generator(this, function (_a) {
403
+ switch (_a.label) {
404
+ case 0:
405
+ if (jobId === null || jobId === undefined)
406
+ throw new Error("Required parameter jobId was null or undefined when calling completeActivityImportUpload.");
407
+ if (this.configuration.base === "https://demo.lamp.digital") {
408
+ return [2 /*return*/, Promise.resolve({ error: "500.demo-restriction" })];
409
+ }
410
+ return [4 /*yield*/, Fetch_1.Fetch.post("/imports/" + jobId + "/complete-upload", { blobName: blobName }, this.configuration)];
411
+ case 1:
412
+ result = _a.sent();
413
+ return [2 /*return*/, result.data];
414
+ }
415
+ });
416
+ });
417
+ };
250
418
  return ResearcherService;
251
419
  }());
252
420
  exports.ResearcherService = ResearcherService;
@@ -0,0 +1,69 @@
1
+ import { Timestamp } from "../model/Type";
2
+ /**
3
+ *
4
+ */
5
+ export declare class ResearcherSettings {
6
+ /**
7
+ * The banner greeting.
8
+ */
9
+ bannerSettings?: string;
10
+ /**
11
+ * The banner heading
12
+ */
13
+ bannerHeading?: string;
14
+ /**
15
+ * The banner sub heading
16
+ */
17
+ bannerSubHeading?: string;
18
+ /**
19
+ * The image icon for banner
20
+ */
21
+ imageBase64?: string;
22
+ /**
23
+ * The selected activity
24
+ */
25
+ selectedActivity?: string;
26
+ /**
27
+ * The selected group
28
+ */
29
+ selectedGroup?: string;
30
+ /**
31
+ * The button text
32
+ */
33
+ buttonText?: string;
34
+ /**
35
+ * The activityId
36
+ */
37
+ activityId?: string;
38
+ /**
39
+ * The favourite activities
40
+ */
41
+ favouriteActivities?: any;
42
+ /**
43
+ * The featured activity
44
+ */
45
+ featuredActivity?: string;
46
+ /**
47
+ * The streak type
48
+ */
49
+ streak?: string;
50
+ /**
51
+ * The Streak title
52
+ */
53
+ streakTitle?: string;
54
+ /**
55
+ * The Streak description
56
+ */
57
+ streakDesc?: string;
58
+ /**
59
+ * The timestamp
60
+ */
61
+ timestamp?: Timestamp;
62
+ /**
63
+ * The deleted flag
64
+ */
65
+ deleted?: boolean;
66
+ }
67
+ export declare type ResearcherBanner = {
68
+ data: ResearcherSettings;
69
+ };
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResearcherSettings = void 0;
4
+ /**
5
+ *
6
+ */
7
+ var ResearcherSettings = /** @class */ (function () {
8
+ function ResearcherSettings() {
9
+ }
10
+ return ResearcherSettings;
11
+ }());
12
+ exports.ResearcherSettings = ResearcherSettings;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lamp-core-lst",
3
- "version": "2025.11.20",
3
+ "version": "2025.12.1",
4
4
  "author": "BIDMC Division of Digital Psychiatry <team@digitalpsych.org>",
5
5
  "description": "The JavaScript and TypeScript API client for the LAMP Platform.",
6
6
  "homepage": "https://docs.lamp.digital/",
@@ -86,6 +86,11 @@ export class Activity {
86
86
  */
87
87
  category?: Tab[] | null
88
88
 
89
+ /**
90
+ * The photo/image URL for the activity (stored in Azure Blob Storage).
91
+ */
92
+ photo?: any
93
+
89
94
  /**
90
95
  * The type of streak for the activity.
91
96
  */
@@ -142,8 +142,18 @@ export class ActivityService {
142
142
  /**
143
143
  * Get the set of all activities available to participants of a single study, by study identifier.
144
144
  * @param studyId
145
+ * @param transform
146
+ * @param ignore_binary
147
+ * @param limit Optional limit for pagination
148
+ * @param offset Optional offset for pagination
145
149
  */
146
- public async allByStudy(studyId: Identifier, transform?: string, ignore_binary?: boolean): Promise<Activity[]> {
150
+ public async allByStudy(
151
+ studyId: Identifier,
152
+ transform?: string,
153
+ ignore_binary?: boolean,
154
+ limit?: number,
155
+ offset?: number
156
+ ): Promise<Activity[] | { data: Activity[], total: number }> {
147
157
  if (studyId === null || studyId === undefined)
148
158
  throw new Error("Required parameter studyId was null or undefined when calling activityAllByStudy.")
149
159
  if (ignore_binary === null || ignore_binary === undefined) ignore_binary = false
@@ -157,14 +167,58 @@ export class ActivityService {
157
167
  if (Demo.Study.filter((x) => x["id"] === studyId).length > 0) {
158
168
  let output = Demo.Activity.filter((x) => x["#parent"] === studyId)?.map((x) => Object.assign(new Activity(), x))
159
169
  output = typeof transform === "string" ? jsonata(transform).evaluate(output) : output
170
+ // If pagination is requested, return paginated result with total
171
+ if (typeof limit === 'number' && limit > 0 || typeof offset === 'number' && offset > 0) {
172
+ const total = output.length
173
+ const paginatedOutput = limit !== undefined && offset !== undefined
174
+ ? output.slice(offset, offset + limit)
175
+ : output
176
+ return Promise.resolve({ data: paginatedOutput, total })
177
+ }
160
178
  return Promise.resolve(output)
161
179
  } else {
162
180
  return Promise.resolve({ error: "404.not-found" } as any)
163
181
  }
164
182
  }
165
- return (
166
- await Fetch.get<{ data: any[] }>(`/study/${studyId}/activity?ignore_binary=${ignore_binary}`, this.configuration)
167
- ).data?.map((x) => Object.assign(new Activity(), x))
183
+
184
+ // Build query string with pagination parameters
185
+ const params = new URLSearchParams()
186
+ params.append('ignore_binary', String(ignore_binary))
187
+ if (limit !== undefined && limit !== null) {
188
+ params.append('limit', limit.toString())
189
+ }
190
+ if (offset !== undefined && offset !== null) {
191
+ params.append('offset', offset.toString())
192
+ }
193
+ const queryString = params.toString()
194
+
195
+ const result: any = await Fetch.get<{ data: Activity[], total?: number }>(
196
+ `/study/${studyId}/activity?${queryString}`,
197
+ this.configuration
198
+ )
199
+
200
+ // Handle the response structure based on _select function behavior:
201
+ // - With pagination (limit > 0 OR offset >= 0): { data: Activity[], total: number }
202
+ // - Without pagination: { data: Activity[] } (total property is missing)
203
+ let activitiesArray: any[] = []
204
+ let totalCount = 0
205
+
206
+ if (result && result.data && Array.isArray(result.data)) {
207
+ activitiesArray = result.data
208
+ totalCount = typeof result.total === 'number' ? result.total : activitiesArray.length
209
+ } else if (Array.isArray(result)) {
210
+ // Legacy fallback: if result is directly an array
211
+ activitiesArray = result
212
+ totalCount = result.length
213
+ }
214
+
215
+ const mappedActivities = activitiesArray.map((x: any) => Object.assign(new Activity(), x))
216
+
217
+ // If pagination was requested, return { data, total }, otherwise return array for backward compatibility
218
+ if (typeof limit === 'number' && limit > 0 || typeof offset === 'number' && offset > 0) {
219
+ return { data: mappedActivities, total: totalCount }
220
+ }
221
+ return mappedActivities
168
222
  }
169
223
  /**
170
224
  * Get the set of all activities available to participants of a single study, by participant identifier.
@@ -38,7 +38,7 @@ const handleSessionExpiry = async () => {
38
38
  }
39
39
 
40
40
  //If access Token expired then call api for renewing the tokens
41
- const handleRenewToken = async (refreshToken: string, base: string) => {
41
+ const handleRenewToken = async (refreshToken: string, base: string, configuration?: Configuration) => {
42
42
  try {
43
43
  const credService = new CredentialService()
44
44
  const res = await credService.renewToken(refreshToken, base)
@@ -46,10 +46,28 @@ const handleRenewToken = async (refreshToken: string, base: string) => {
46
46
  const accessToken = res?.data?.access_token
47
47
 
48
48
  if (accessToken) {
49
+ const newRefreshToken = res?.data?.refresh_token || refreshToken
49
50
  sessionStorage.setItem(
50
51
  userTokenKey,
51
- JSON.stringify({ accessToken: res?.data?.access_token, refreshToken: res?.data?.refresh_token })
52
+ JSON.stringify({ accessToken: res?.data?.access_token, refreshToken: newRefreshToken })
52
53
  )
54
+
55
+ // Dispatch renewToken event similar to LOGIN event
56
+ // Access LAMP from global scope to avoid circular dependency
57
+ const LAMP = (global as any).LAMP || (typeof window !== "undefined" ? (window as any).LAMP : null)
58
+ if (LAMP && typeof LAMP.dispatchEvent === "function") {
59
+ // Get identity object from LAMP.Auth if available
60
+ const identityObject = LAMP.Auth?._me || null
61
+ const serverAddress = configuration?.base || base || LAMP.configuration?.base
62
+
63
+ LAMP.dispatchEvent("renewToken", {
64
+ authorizationToken: configuration?.authorization || LAMP.configuration?.authorization,
65
+ identityObject: identityObject,
66
+ serverAddress: serverAddress,
67
+ accessToken: accessToken,
68
+ refreshToken: newRefreshToken,
69
+ })
70
+ }
53
71
  }
54
72
  return accessToken
55
73
  } catch (error) {
@@ -93,7 +111,7 @@ async function _fetch<ResultType>(
93
111
  ...(configuration!.headers || {}),
94
112
  } as any)
95
113
  ),
96
- credentials: "include",
114
+ credentials: "include",
97
115
  body: body !== undefined ? JSON.stringify(body) : undefined,
98
116
  })
99
117
  if (!response.ok) {
@@ -113,7 +131,7 @@ async function _fetch<ResultType>(
113
131
  handleSessionExpiry()
114
132
  return { data: [], error: "401.invalid-token" } as unknown as ResultType
115
133
  }
116
- const token = await handleRenewToken(refreshToken, configuration.base)
134
+ const token = await handleRenewToken(refreshToken, configuration.base, configuration)
117
135
  if (token) {
118
136
  configuration.authorization = token
119
137
  // retry the same request
@@ -144,4 +144,131 @@ export class ResearcherService {
144
144
  const result = await Fetch.post(`/researcher/sensors/${id}`, filters, this.configuration) as any
145
145
  return result?.data
146
146
  }
147
- }
147
+
148
+ /**
149
+ * Create an activity export job.
150
+ * @param researcherId
151
+ * @param body - { studyIds: string[], specs?: string[], format?: "json" | "ndjson" }
152
+ */
153
+ public async createActivityExport(researcherId: Identifier, body: {
154
+ studyIds: string[]
155
+ specs?: string[]
156
+ format?: "json" | "ndjson"
157
+ }): Promise<{ jobId: string; status: string }> {
158
+ if (researcherId === null || researcherId === undefined)
159
+ throw new Error("Required parameter researcherId was null or undefined when calling createActivityExport.")
160
+ if (this.configuration.base === "https://demo.lamp.digital") {
161
+ return Promise.resolve({ error: "500.demo-restriction" } as any)
162
+ }
163
+ const result = await Fetch.post<{ data: { jobId: string; status: string } }>(
164
+ `/researcher/${researcherId}/activity-export`,
165
+ body,
166
+ this.configuration
167
+ )
168
+ return result.data
169
+ }
170
+
171
+ /**
172
+ * Get activity export job status.
173
+ * @param jobId
174
+ */
175
+ public async getActivityExportJob(jobId: string): Promise<any> {
176
+ if (jobId === null || jobId === undefined)
177
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityExportJob.")
178
+ if (this.configuration.base === "https://demo.lamp.digital") {
179
+ return Promise.resolve({ error: "500.demo-restriction" } as any)
180
+ }
181
+ const result = await Fetch.get<{ data: any }>(`/exports/${jobId}`, this.configuration)
182
+ return result.data
183
+ }
184
+
185
+ /**
186
+ * Get activity export download URL.
187
+ * @param jobId
188
+ * @param ttl - Time to live in seconds (default: 600)
189
+ */
190
+ public async getActivityExportDownloadUrl(jobId: string, ttl: number = 600): Promise<{
191
+ url: string
192
+ expiresIn: number
193
+ contentType: string
194
+ contentLength: number
195
+ }> {
196
+ if (jobId === null || jobId === undefined)
197
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityExportDownloadUrl.")
198
+ if (this.configuration.base === "https://demo.lamp.digital") {
199
+ return Promise.resolve({ error: "500.demo-restriction" } as any)
200
+ }
201
+ const result = await Fetch.get<{ data: any }>(`/exports/${jobId}/download?ttl=${ttl}`, this.configuration)
202
+ return result.data
203
+ }
204
+
205
+ /**
206
+ * Create an activity import job.
207
+ * @param researcherId
208
+ * @param body - { studyId: string, format?: "json" | "ndjson" }
209
+ */
210
+ public async createActivityImport(researcherId: Identifier, body: {
211
+ studyId: string
212
+ format?: "json" | "ndjson"
213
+ }): Promise<{ jobId: string; status: string }> {
214
+ if (researcherId === null || researcherId === undefined)
215
+ throw new Error("Required parameter researcherId was null or undefined when calling createActivityImport.")
216
+ if (this.configuration.base === "https://demo.lamp.digital") {
217
+ return Promise.resolve({ error: "500.demo-restriction" } as any)
218
+ }
219
+ const result = await Fetch.post<{ data: { jobId: string; status: string } }>(
220
+ `/researcher/${researcherId}/activity-import`,
221
+ body,
222
+ this.configuration
223
+ )
224
+ return result.data
225
+ }
226
+
227
+ /**
228
+ * Get activity import job status.
229
+ * @param jobId
230
+ */
231
+ public async getActivityImportJob(jobId: string): Promise<any> {
232
+ if (jobId === null || jobId === undefined)
233
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityImportJob.")
234
+ if (this.configuration.base === "https://demo.lamp.digital") {
235
+ return Promise.resolve({ error: "500.demo-restriction" } as any)
236
+ }
237
+ const result = await Fetch.get<{ data: any }>(`/imports/${jobId}`, this.configuration)
238
+ return result.data
239
+ }
240
+
241
+ /**
242
+ * Get activity import upload URL.
243
+ * @param jobId
244
+ * @param ttl - Time to live in seconds (default: 600)
245
+ */
246
+ public async getActivityImportUploadUrl(jobId: string, ttl: number = 600): Promise<{
247
+ url: string
248
+ expiresIn: number
249
+ blobName: string
250
+ }> {
251
+ if (jobId === null || jobId === undefined)
252
+ throw new Error("Required parameter jobId was null or undefined when calling getActivityImportUploadUrl.")
253
+ if (this.configuration.base === "https://demo.lamp.digital") {
254
+ return Promise.resolve({ error: "500.demo-restriction" } as any)
255
+ }
256
+ const result = await Fetch.post<{ data: any }>(`/imports/${jobId}/upload-url`, { ttl }, this.configuration)
257
+ return result.data
258
+ }
259
+
260
+ /**
261
+ * Complete activity import upload and trigger processing.
262
+ * @param jobId
263
+ * @param blobName
264
+ */
265
+ public async completeActivityImportUpload(jobId: string, blobName: string): Promise<any> {
266
+ if (jobId === null || jobId === undefined)
267
+ throw new Error("Required parameter jobId was null or undefined when calling completeActivityImportUpload.")
268
+ if (this.configuration.base === "https://demo.lamp.digital") {
269
+ return Promise.resolve({ error: "500.demo-restriction" } as any)
270
+ }
271
+ const result = await Fetch.post<{ data: any }>(`/imports/${jobId}/complete-upload`, { blobName }, this.configuration)
272
+ return result.data
273
+ }
274
+ }
@@ -0,0 +1,77 @@
1
+ import { Identifier, Timestamp } from "../model/Type"
2
+
3
+ /**
4
+ *
5
+ */
6
+ export class ResearcherSettings {
7
+ /**
8
+ * The banner greeting.
9
+ */
10
+ bannerSettings?: string
11
+
12
+ /**
13
+ * The banner heading
14
+ */
15
+ bannerHeading?: string
16
+
17
+ /**
18
+ * The banner sub heading
19
+ */
20
+ bannerSubHeading?: string
21
+
22
+ /**
23
+ * The image icon for banner
24
+ */
25
+ imageBase64?: string
26
+
27
+ /**
28
+ * The selected activity
29
+ */
30
+ selectedActivity?: string
31
+
32
+ /**
33
+ * The selected group
34
+ */
35
+ selectedGroup?: string
36
+ /**
37
+ * The button text
38
+ */
39
+ buttonText?: string
40
+ /**
41
+ * The activityId
42
+ */
43
+ activityId?: string
44
+ /**
45
+ * The favourite activities
46
+ */
47
+ favouriteActivities?: any
48
+ /**
49
+ * The featured activity
50
+ */
51
+ featuredActivity?: string
52
+ /**
53
+ * The streak type
54
+ */
55
+ streak?: string
56
+ /**
57
+ * The Streak title
58
+ */
59
+ streakTitle?: string
60
+ /**
61
+ * The Streak description
62
+ */
63
+ streakDesc?: string
64
+ /**
65
+ * The timestamp
66
+ */
67
+ timestamp?: Timestamp
68
+
69
+ /**
70
+ * The deleted flag
71
+ */
72
+ deleted?: boolean
73
+ }
74
+
75
+ export type ResearcherBanner = {
76
+ data: ResearcherSettings
77
+ }