Skip to content

Commit ee60add

Browse files
committed
Add reminder system: computeReminders, duration utils, lastEventContent
- ISO 8601 duration parser (durationToSeconds, durationToLabel) - computeReminders() with cooldown, expectedInterval, relativeTo support - Multi-source merge with importance escalation - ReminderConfig type + reminder getter on HDSItemDef - lastEventContent on ReminderStatus for displaying last values - 17 unit tests covering all reminder statuses and sorting
1 parent 6d814e6 commit ee60add

25 files changed

Lines changed: 948 additions & 216 deletions

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ node_modules
22
coverage
33
dist
44
.gcd
5+
.DS_Store

README.md

Lines changed: 21 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -3,223 +3,38 @@
33
[![CI](https://github.com/healthdatasafe/hds-lib-js/actions/workflows/ci.yml/badge.svg)](https://github.com/healthdatasafe/hds-lib-js/actions/workflows/ci.yml)
44
[![codecov](https://codecov.io/gh/healthdatasafe/hds-lib-js/graph/badge.svg)](https://codecov.io/gh/healthdatasafe/hds-lib-js)
55

6-
Generic toolkit for server and web applications.
6+
Generic toolkit for server and web applications[Health Data Safe](https://github.com/healthdatasafe).
77

8-
1. Manages global settings for the lib (servers, localization, logger)
9-
2. Extends orginal Pryv's JS lib to fit HDS needs
10-
3. Based on [HDS data model](https://github.com/healthdatasafe/data-model-draft?tab=readme-ov-file#hds-data-model-drafting-space) exposes methods to facilitate app development.
11-
- load data model and exposes it as a singleton
12-
- retrieve definitions
13-
- provides helper for stream creation and authorizations requests
14-
4. Provide app templates to create new applications for
15-
- Requesting and managing consents - And collecting data
16-
- Approving requests and sharing data
17-
5. Other tools to facilitate app developments
8+
**Full documentation: [healthdatasafe.github.io/hds-lib-js](https://healthdatasafe.github.io/hds-lib-js/)**
189

10+
## Features
1911

20-
## Components
12+
1. **Settings** — Configure service endpoints and localization
13+
2. **Pryv extensions** — Extends [Pryv JS lib](https://github.com/pryv/lib-js) with Socket.io and Monitor support
14+
3. **HDS Data Model** — Load and query the [HDS data model](https://github.com/healthdatasafe/data-model-draft): items, streams, authorizations, event types, datasources
15+
4. **App Templates** — Consent-based data collection and sharing (Manager, Collector, Invite, Client flows)
16+
5. **Toolkit** — Stream auto-creation, reminders, duration parsing
2117

22-
### settings
23-
24-
#### settings.setServiceInfoURL(url)
25-
Set the default service for `HDSModel` and `HDSService`
26-
27-
#### settings.setPreferredLocales(Array of locales)
28-
Change the order of pereferred localization codes
29-
30-
### HDSService
31-
Is an extension of `pryv.Service` which uses the default service set with `settings.setServiceInfoURL(url)``
32-
33-
### pryv
34-
Patched version of [pryv's javacript library](https://github.com/pryv/lib-js) including supports for [Socket.io](https://github.com/pryv/lib-js/tree/master/components/pryv-socket.io) and [Monitors](https://github.com/pryv/lib-js/tree/master/components/pryv-monitor)
35-
36-
### localizeText (alias "l")
37-
Handles localization of text. The choice of locales can be set with `settings.setPreferredLocales()`
38-
39-
### HDSModel
40-
41-
an instance of HDSModel loads the definitions from a json file, usually `https://model.datasafe.dev/pack.json`. This may be overridden with:
42-
43-
**Load your own model**
44-
45-
```javascript
46-
const model = new HDSLib.HDSModel('https://model.datasafe.dev/pack.json');
47-
await model.load();
48-
```
49-
50-
**Per service auto loading.** (preferred way)
51-
0. (Optional) You may set the defaultService info of the lib with `HDSLib.setServiceInfoURL()`.
52-
1. Initialize model singleton once with `await HDSLib.initHDSModel()`
53-
2. Use model from `HDSLib.getHDSModel()`
54-
55-
#### HDSModel.ItemDef
56-
57-
An `ItemDef` is an object representation of the items from the data Model
58-
59-
- **itemDef.key**: (string) a unique identifier, for example `body-weight`
60-
- **itemDef.data**: (Object) raw data for this item from [HDS data model](https://github.com/healthdatasafe/data-model-draft?tab=readme-ov-file#hds-data-model-drafting-space)
61-
- **itemDef.label**: (string) localized `item.data.label`
62-
- **itemDef.description**: (string) localized `item.data.description`
63-
- **itemDef.eventTypes**: (Array) of supported eventTypes
64-
65-
#### model.itemDefs
66-
Tools to retrieve itemDefinitons
67-
68-
##### model.itemDefs.forKey()
69-
retrieve an itemDef with its key
18+
## Quick start
7019

7120
```javascript
72-
const weight = model.itemDefs.forKey('body-weight');
73-
weight.streamId; // => 'body-weight'
74-
weight.eventTypes; // => ['mass/kg', 'mass/lb']
75-
```
76-
77-
##### model.itemDefs.forKey()
78-
```javascript
79-
// retrieve an itemDef from an event
80-
const anEvent = {
81-
streamIds: ['body-weight', 'dummy'],
82-
type: 'mass/kg'
83-
};
84-
const itemDef = model.itemsDefs.forEvent(anEvent);
85-
itemDef.key // => 'body-weight'
86-
```
21+
const HDSLib = require('hds-lib');
8722

88-
#### HDSModel.Streams
23+
HDSLib.settings.setServiceInfoURL('https://demo.datasafe.dev/reg/service/info');
24+
await HDSLib.initHDSModel();
8925

90-
##### model.streams.getNecessaryListForItems(itemKeys, params)
91-
get the list of streams to be created to store these items
92-
93-
**params**
94-
- **nameProperty**: (string) can be set to 'name' (default), 'defaultName' or 'none' => if you want nothing
95-
- **knowExistingStreamsIds**: (Array of strings) Array of known existing streams' ids
96-
97-
```javascript
98-
const itemKeys = [
99-
'profile-name',
100-
'profile-date-of-birth',
101-
'body-vulva-mucus-stretch',
102-
'profile-surname'
103-
];
104-
const streamsToBeCreated = model.streams.getNecessaryListForItems(itemKeys);
26+
const model = HDSLib.getHDSModel();
27+
const weight = model.itemsDefs.forKey('body-weight');
10528
```
10629

107-
##### model.streams.getDataById(streamId)
108-
retrieve model data related to this stream
109-
110-
##### model.streams.getParentsIds(streamId)
111-
retrieve order list of parents up to this streamId
112-
113-
114-
#### HDSModel.Authorizations
115-
Helpers to generate authorizations from itemKeys
116-
117-
##### model.authorizations.forItemKeys(itemKeys, options);
118-
get the authorization needed to manipulate a set of items
30+
## Dev
11931

120-
**options** (all optional)
121-
- **defaultLevel**: (string, default = 'name' ) - one of'read', 'manage', 'contribue', 'writeOnly'
122-
- **includeDefaultName** (boolean, default = true) - if false does not add defaultNames for streams
123-
- **preRequest** (Array of AuthorizationRequestItem) you may specify a custom set or authorizations
32+
Source code is in TypeScript in `./ts`.
12433

125-
```javascript
126-
const itemKeys = [
127-
'body-vulva-mucus-inspect',
128-
'profile-name',
129-
'profile-date-of-birth',
130-
'body-vulva-mucus-stretch',
131-
'profile-surname'
132-
];
133-
const options = {
134-
preRequest: [ // optional, will be considered in the request
135-
{ streamId: 'profile' },
136-
{ streamId: 'app-test', defaultName: 'App test', level: 'write' }
137-
]
138-
};
139-
const authorizationSet = model.authorizations.forItemKeys(itemKeys, options);
140-
// the following object is the result
141-
const expected = [
142-
{ streamId: 'profile', defaultName: 'Profile', level: 'read' },
143-
{ streamId: 'app-test', defaultName: 'App test', level: 'write' },
144-
{
145-
streamId: 'body-vulva-mucus-inspect',
146-
defaultName: 'Vulva Mucus Inspect',
147-
level: 'read'
148-
},
149-
{
150-
streamId: 'body-vulva-mucus-stretch',
151-
defaultName: 'Vulva Mucus Stretch',
152-
level: 'read'
153-
}
154-
];
34+
```bash
35+
npm run build # TypeScript + webpack bundle
36+
npm run test # Node tests
37+
npm run test:coverage # Coverage report
15538
```
15639

157-
### AppTemplates
158-
159-
App templates based on HDS Model, provide frameworks to build applications for HDS.
160-
161-
- **AppManagingAccount**: App which manages Collectors. A "Collector" handles a "Request" and set of "Responses". => With access to some HDS data from other accounts.
162-
- **AppClientAccount**: Handles requests from `AppManagingAccount` and corresponding responses (agree, refuse, revoke).
163-
164-
Details and examples for theses App templates can be found in [AppTemplates.md]
165-
166-
167-
### toolkit
168-
Misc. tools
169-
170-
#### toolkit.StreamsAutoCreate
171-
helper to be attached to a `Connection` to facilitate auto creation of streams when needed.
172-
173-
Exemple:
174-
```javascript
175-
// done at initialization of connection (a pryv.Connection)
176-
toolkit.StreamsAutoCreate.attachToConnection(connection)
177-
178-
// later
179-
await connection.streamsAutoCreate.ensureExistsForItems(['body-weight', 'profile-name']);
180-
```
181-
182-
## Usage Browser
183-
184-
```html
185-
<head>
186-
<script src="../dist/hds-lib.js"></script>
187-
<script>
188-
HDSLib.settings.setServiceInfoURL('https://demo.datasafe.dev/reg/service/info');
189-
HDSLib.settings.setPreferredLocales(['fr', 'en']); // ordered
190-
191-
// init model in async code
192-
(async () => {
193-
await HDSLib.initHDSModel(); // need just one
194-
// from now on an in all your code you use HDSLib.getHDSModel()
195-
196-
// you may create new HDSService with:
197-
const service = new HDSService();
198-
199-
})();
200-
</script>
201-
</head>
202-
```
203-
204-
# Dev
205-
206-
Source code is in TypeScript in `./ts` directory.
207-
208-
## Build
209-
210-
`npm run build` remove ts anotations and put js code in `./js` and publish the code in `./dist`
211-
212-
## Tests
213-
214-
## Node
215-
- all tests: `npm run test`
216-
- specific test: `npm run test -- --grep=<string>`
217-
- coverage: `npm run test:coverage`
218-
219-
## Browser
220-
Test suite is accessible in `dist/`
221-
run `npx backloop.dev ./dist` and open `https://whatever.backloop.dev:4443/tests.html`
222-
223-
224-
225-
40+
Browser test suite: build then run `npx backloop.dev ./dist` and open `https://l.backloop.dev:4443/tests.html`

js/HDSModel/HDSItemDef.d.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
1+
export interface ReminderConfig {
2+
cooldown?: string;
3+
expectedInterval?: {
4+
min?: string;
5+
max?: string;
6+
};
7+
relativeTo?: string;
8+
relativeDays?: number[];
9+
importance?: 'may' | 'should' | 'must';
10+
}
111
export declare class HDSItemDef {
212
#private;
313
constructor(key: string, definitionData: any);
414
get eventTypes(): string[];
515
get key(): string;
616
get data(): any;
717
get repeatable(): string;
18+
get reminder(): ReminderConfig | null;
819
/** label Localized */
920
get label(): string;
1021
/** description Localized */

js/HDSModel/HDSItemDef.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/HDSModel/HDSItemDef.js

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/HDSModel/HDSItemDef.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/HDSModel/reminders.d.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import type { ReminderConfig } from './HDSItemDef';
2+
export interface ReminderSource {
3+
origin: 'default' | 'collector' | 'user';
4+
collectorId?: string;
5+
reminder: ReminderConfig;
6+
}
7+
export interface ReminderStatus {
8+
itemKey: string;
9+
status: 'cooldown' | 'ok' | 'upcoming' | 'due' | 'overdue';
10+
importance: 'may' | 'should' | 'must';
11+
lastEntry?: number;
12+
lastEventContent?: any;
13+
dueDate?: number;
14+
sources: ReminderSource[];
15+
}
16+
interface ItemDefLike {
17+
key: string;
18+
eventTypes: string[];
19+
reminder: ReminderConfig | null;
20+
data: {
21+
streamId: string;
22+
};
23+
}
24+
interface EventLike {
25+
type: string;
26+
streamId?: string;
27+
streamIds?: string[];
28+
time: number;
29+
content?: any;
30+
}
31+
/**
32+
* Compute reminder statuses for a set of items given their events and optional overrides.
33+
*
34+
* @param itemDefs - array of item definitions (must have .key, .eventTypes, .reminder, .data.streamId)
35+
* @param events - all events to search for last entries
36+
* @param overrides - optional collector/user overrides (matched by itemKey in the ReminderSource)
37+
* @param now - current time in unix seconds (defaults to Date.now()/1000)
38+
*/
39+
export declare function computeReminders(itemDefs: ItemDefLike[], events: EventLike[], overrides?: Record<string, ReminderSource[]>, now?: number): ReminderStatus[];
40+
export {};
41+
//# sourceMappingURL=reminders.d.ts.map

js/HDSModel/reminders.d.ts.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)