Skip to content

Commit d5efffa

Browse files
committed
added desktopDirect session
1 parent 49a4974 commit d5efffa

9 files changed

Lines changed: 246 additions & 39 deletions

File tree

‎.gitignore‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
dist
3+
.msal-cache.json

‎.vscode/launch.json‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
"name": "Current TS File",
66
"type": "node",
77
"request": "launch",
8+
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/tsx",
89
"args": ["${relativeFile}"],
9-
"runtimeArgs": ["-r", "ts-node/register"],
10-
"cwd": "${workspaceRoot}",
10+
"cwd": "${workspaceFolder}",
1111
"protocol": "inspector",
1212
"internalConsoleOptions": "openOnSessionStart",
1313
"sourceMaps": true,
1414
"outputCapture": "std"
15-
}
15+
}
1616
]
1717
}

‎README.md‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,83 @@
11
# TypeScript examples for the LSEG Data Library
22

3+
## Getting started
4+
5+
### Prerequisites
6+
7+
- Node.js and npm installed on your machine.
8+
- Access to the LSEG data service required by the example and session type you select.
9+
10+
### Install the dependencies
11+
12+
Run these commands from the repository root:
13+
14+
```bash
15+
npm install
16+
npm install @lsegroup/data
17+
```
18+
19+
The examples use `tsx` to run TypeScript files directly. It is installed by the first command as a development dependency.
20+
21+
### Configure a session
22+
23+
Open [`session.config.json`](session.config.json) and replace the placeholder values with your credentials. Set `sessions.default` to the session type you want to use:
24+
25+
```json
26+
{
27+
"sessions": {
28+
"default": "platform"
29+
}
30+
}
31+
```
32+
33+
The supported session types are:
34+
35+
- `platform`: machine account credentials, including `ldpUser`, `ldpPassword`, and `appKey`.
36+
- `desktop`: Workspace Desktop must be running and the configuration must contain a valid application key.
37+
- `container`: browser Workspace environment with a valid container application key.
38+
- `desktopDirect`: Microsoft Entra authentication through an `entraAppId` that has previously been onboarded to LSEG.
39+
40+
Keep `session.config.json` private and do not commit real credentials or application keys.
41+
42+
### Test the session
43+
44+
Before running the other examples, test that the configured default session can be opened and closed successfully:
45+
46+
```bash
47+
npm run example src/1.QuickStart/testSession.ts
48+
```
49+
50+
This example uses `sessions.default` from `session.config.json`. It reports whether the session opened successfully and then closes it.
51+
52+
### Run an example with npm
53+
54+
Run the command from the repository root and provide the path to the example TypeScript file:
55+
56+
```bash
57+
npm run example src/2.Content/2.8-Fundamental/fundamental-reference.ts
58+
```
59+
60+
You can replace the file path with any example in the repository. Most examples use the session configured in `sessions.default`.
61+
62+
### Run an example with the VS Code debugger
63+
64+
1. Open the repository root as the VS Code workspace.
65+
2. Open the example TypeScript file you want to run.
66+
3. Select **Current TS File** in the Run and Debug view.
67+
4. Press **F5** or select **Start Debugging**.
68+
69+
The launch configuration runs the currently open TypeScript file with `tsx` and uses the workspace root as its working directory. The debugger uses the session configured in `sessions.default`.
70+
71+
### Build the examples
72+
73+
To type-check and compile the project, run:
74+
75+
```bash
76+
npm run build
77+
```
78+
79+
Some examples require a live LSEG connection and valid credentials, so a successful build does not guarantee that an example can connect to the selected service.
80+
381
## Summary
482

583
The following series of examples demonstrate how to programmatically access content residing within the LSEG Data Platform using a single, ease of use API called the LSEG Data Library for TypeScript. The platform refers to the layer of data services providing both streaming and non-streaming content serving different clients, from the simple desktop interface to the enterprise application.

‎package.json‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "example.datalibrary.typescript",
3+
"version": "1.0.0",
4+
"description": "The following series of examples demonstrate how to programmatically access content residing within the LSEG Data Platform using a single, ease of use API called the LSEG Data Library for TypeScript. The platform refers to the layer of data services providing both streaming and non-streaming content serving different clients, from the simple desktop interface to the enterprise application.",
5+
"homepage": "https://github.com/LSEG-API-Samples/Example.DataLibrary.TypeScript#readme",
6+
"bugs": {
7+
"url": "https://github.com/LSEG-API-Samples/Example.DataLibrary.TypeScript/issues"
8+
},
9+
"repository": {
10+
"type": "git",
11+
"url": "git+https://github.com/LSEG-API-Samples/Example.DataLibrary.TypeScript.git"
12+
},
13+
"license": "ISC",
14+
"author": "",
15+
"type": "commonjs",
16+
"scripts": {
17+
"test": "echo \"Error: no test specified\" && exit 1",
18+
"build": "tsc",
19+
"example": "tsx"
20+
},
21+
"dependencies": {
22+
"@azure/msal-node": "^6.0.1",
23+
"@azure/msal-node-extensions": "^5.5.1",
24+
"open": "^11.0.4"
25+
},
26+
"devDependencies": {
27+
"tsx": "^4.19.2",
28+
"typescript": "^7.0.2"
29+
}
30+
}

‎session.config.json‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@
1414

1515
"container": {
1616
"appKey": "<Application Key>"
17+
},
18+
19+
"desktopDirect": {
20+
"entraAppId": "<Desktop Direct Application Key>"
1721
}
1822
}
1923
}

‎src/1.QuickStart/testSession.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const session = getSession();
1313
//const session = getSession('platform');
1414
//const session = getSession('desktop');
1515
//const session = getSession('container');
16+
//const session = getSession('desktopDirect');
1617

1718
// rest of the code remains unchanged for each session type
1819
(async () => {

‎src/Common/entra-auth.ts‎

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import {
2+
DataProtectionScope,
3+
FilePersistenceWithDataProtection,
4+
PersistenceCachePlugin,
5+
} from "@azure/msal-node-extensions";
6+
import {
7+
InteractiveRequest,
8+
PublicClientApplication,
9+
InteractionRequiredAuthError,
10+
} from "@azure/msal-node";
11+
import path from "node:path";
12+
import creds from "../../session.config.json";
13+
import open, { apps } from "open";
14+
15+
const filePath = path.join(__dirname, ".msal-cache.json");
16+
const entraAppId = creds.sessions.desktopDirect.entraAppId;
17+
18+
// Open browser to sign user in
19+
const openBrowser = async (url: string) => {
20+
// You can open a browser window with any library or method you wish to use - the 'open' npm package is used here for demonstration purposes.
21+
console.log(`Opening browser to: ${url}`);
22+
await open(url, { app: { name: apps.edge } });
23+
};
24+
25+
const loginRequest: InteractiveRequest = {
26+
scopes: [`${entraAppId}/.default`],
27+
openBrowser,
28+
successTemplate: "Successfully signed in! You can close this window now.",
29+
};
30+
31+
const acquireToken = async () => {
32+
const dataProtectionScope = DataProtectionScope.CurrentUser;
33+
const optionalEntropy = "ThisIsOptionalEntropy"; //specifies password or other additional entropy used to encrypt the data.
34+
const windowsPersistence = await FilePersistenceWithDataProtection.create(
35+
filePath,
36+
dataProtectionScope,
37+
optionalEntropy,
38+
);
39+
// Use the persistence object to initialize an MSAL PublicClientApplication with cachePlugin
40+
const pca = new PublicClientApplication({
41+
auth: {
42+
clientId: entraAppId,
43+
authority: "https://login.microsoftonline.com/organizations",
44+
},
45+
cache: {
46+
cachePlugin: new PersistenceCachePlugin(windowsPersistence),
47+
},
48+
});
49+
50+
const accounts = await pca.getTokenCache().getAllAccounts();
51+
console.log(`Found ${accounts.length} account(s) in the cache.`);
52+
if (accounts.length == 1) {
53+
const silentRequest = {
54+
account: accounts[0],
55+
scopes: [`${entraAppId}/.default`],
56+
};
57+
58+
return pca.acquireTokenSilent(silentRequest).catch((e) => {
59+
if (e instanceof InteractionRequiredAuthError) {
60+
return pca.acquireTokenInteractive(loginRequest);
61+
}
62+
throw e;
63+
});
64+
} else if (accounts.length > 1) {
65+
console.log(`Multiple accounts found in the cache. Resetting cache.`);
66+
for (const account of accounts) {
67+
await pca.getTokenCache().removeAccount(account);
68+
}
69+
return pca.acquireTokenInteractive({
70+
...loginRequest,
71+
prompt: "select_account",
72+
});
73+
} else {
74+
return pca.acquireTokenInteractive(loginRequest);
75+
}
76+
};
77+
78+
export async function getEntraToken() {
79+
const { accessToken } = await acquireToken();
80+
return accessToken;
81+
}

‎src/Common/session.ts‎

Lines changed: 45 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,53 @@
11
// tslint:disable-next-line: no-implicit-dependencies
2-
import { Session } from '@lsegroup/data';
3-
import creds from '../../session.config.json';
4-
2+
import { Session } from "@lsegroup/data";
3+
import creds from "../../session.config.json";
4+
import { getEntraToken } from "./entra-auth";
55

66
const createDesktopSession = () =>
7-
Session.Desktop.Definition({
8-
appKey: creds.sessions.desktop.appKey!,
9-
appName: 'MyApp',
10-
}).getSession();
11-
7+
Session.Desktop.Definition({
8+
appKey: creds.sessions.desktop.appKey!,
9+
appName: "MyApp",
10+
}).getSession();
1211

1312
const createPlatformSession = () =>
14-
Session.Platform.Definition({
15-
appKey: creds.sessions.platform.appKey!,
16-
grant: {
17-
userName: creds.sessions.platform.ldpUser!,
18-
password: creds.sessions.platform.ldpPassword!,
19-
takeSignOnControl: true,
20-
},
21-
appName: 'MyApp'
22-
}).getSession();
23-
13+
Session.Platform.Definition({
14+
appKey: creds.sessions.platform.appKey!,
15+
grant: {
16+
userName: creds.sessions.platform.ldpUser!,
17+
password: creds.sessions.platform.ldpPassword!,
18+
takeSignOnControl: true,
19+
},
20+
appName: "MyApp",
21+
}).getSession();
2422

2523
const createContainerSession = () =>
26-
Session.Container.Definition({
27-
appKey: creds.sessions.container.appKey!,
28-
appName: 'MyApp',
29-
}).getSession();
30-
31-
32-
export function getSession(sessionType?: 'platform' | 'desktop' | 'container'): Session.Session {
33-
const sType = sessionType || creds.sessions.default;
34-
switch(sType) {
35-
case 'platform':
36-
return createPlatformSession();
37-
case 'desktop':
38-
return createDesktopSession();
39-
case 'container':
40-
return createContainerSession();
41-
default:
42-
throw new Error('Invalid Session Type. Should be either - platform or desktop or container');
43-
}
24+
Session.Container.Definition({
25+
appKey: creds.sessions.container.appKey!,
26+
appName: "MyApp",
27+
}).getSession();
28+
29+
const createDesktopDirectSession = () =>
30+
Session.DesktopDirect.Definition({
31+
authenticationProvider: new Session.EntraProvider(getEntraToken),
32+
takeRealTimeControl: false,
33+
}).getSession();
34+
35+
export function getSession(
36+
sessionType?: "platform" | "desktop" | "container" | "desktopDirect",
37+
): Session.Session {
38+
const sType = sessionType || creds.sessions.default;
39+
switch (sType) {
40+
case "platform":
41+
return createPlatformSession();
42+
case "desktop":
43+
return createDesktopSession();
44+
case "container":
45+
return createContainerSession();
46+
case "desktopDirect":
47+
return createDesktopDirectSession();
48+
default:
49+
throw new Error(
50+
"Invalid Session Type. Should be either - platform or desktop or container or desktopDirect",
51+
);
52+
}
4453
}

‎tsconfig.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"compilerOptions": {
33
"outDir": "dist",
4+
"module": "commonjs",
45
"strict": true,
56
"esModuleInterop": true,
67
"noEmitOnError": true,

0 commit comments

Comments
 (0)