Skip to content

Commit f01579a

Browse files
committed
chore: adds platform client and updates more docs
Signed-off-by: Eugene Yakhnenko <[email protected]>
1 parent 5593ac9 commit f01579a

File tree

6 files changed

+128
-9
lines changed

6 files changed

+128
-9
lines changed

lib/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
"build:watch": "tsc --watch",
7070
"clean": "rm -rf {build,coverage,dist,tests/mocha/dist}",
7171
"coverage:merge": "for x in mocha wtr; do cp coverage/$x/coverage-final.json coverage/$x.json; done; nyc report --reporter text --reporter lcov -t coverage --lines 75 --statements 75 --branches 70 --functions 65 --check-coverage >coverage/coverage.txt",
72-
"doc": "typedoc --out dist/docs src/index.ts",
72+
"doc": "typedoc --out dist/docs src/index.ts --customCss ./typedoc-theme.css",
7373
"doc:md": "typedoc --plugin typedoc-plugin-markdown --out dist/docs-md src/index.ts",
7474
"format": "prettier --write \"{src,tdf3,tests}/**/*.ts\"",
7575
"license-check": "license-checker-rseidelsohn --production --onlyAllow 'Apache-2.0; BSD; CC-BY-4.0; ISC; MIT'",

lib/src/auth/oidc-refreshtoken-provider.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,20 @@ import { ConfigurationError } from '../errors.js';
22
import { type AuthProvider, type HttpRequest } from './auth.js';
33
import { AccessToken, type RefreshTokenCredentials } from './oidc.js';
44

5+
/**
6+
* An AuthProvider that uses an OIDC refresh token to obtain an access token.
7+
* It exchanges the refresh token for an access token and uses that to augment HTTP requests with credentials.
8+
* @example
9+
* ```ts
10+
* import { OIDCRefreshTokenProvider } from '@opentdf/sdk';
11+
* await AuthProviders.refreshAuthProvider({
12+
clientId: 'my-client-id',
13+
exchange: 'refresh',
14+
refreshToken: 'refresh-token-from-oidc-provider',
15+
oidcOrigin: 'https://example.oidc.provider.com',
16+
});
17+
```
18+
*/
519
export class OIDCRefreshTokenProvider implements AuthProvider {
620
oidcAuth: AccessToken;
721
refreshToken?: string;

lib/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export { type AuthProvider, type HttpMethod, HttpRequest, withHeaders } from './
22
export * as AuthProviders from './auth/providers.js';
33
export { attributeFQNsAsValues } from './policy/api.js';
44
export { version, clientType, tdfSpecVersion } from './version.js';
5+
export { PlatformClient, type PlatformClientOptions, type PlatformServices } from './platform.js';
56
export * from './opentdf.js';
67
export * from './seekable.js';
78
export * from '../tdf3/src/models/index.js';

lib/src/opentdf.ts

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -310,19 +310,56 @@ export type TDFReader = {
310310
attributes: () => Promise<string[]>;
311311
};
312312

313-
/** SDK for dealing with OpenTDF data and policy services. */
313+
/**
314+
* The main OpenTDF class that provides methods for creating and reading TDF files.
315+
* It supports both NanoTDF and ZTDF formats.
316+
* It can be used to create new TDF files and read existing ones.
317+
* This class is the entry point for using the OpenTDF SDK.
318+
* It requires an authentication provider to be passed in the constructor.
319+
* It also requires a platform URL to be set, which is used to fetch key access servers and policies.
320+
* @example
321+
* ```
322+
* import { type Chunker, OpenTDF } from '@opentdf/sdk';
323+
*
324+
* const oidcCredentials: RefreshTokenCredentials = {
325+
* clientId: keycloakClientId,
326+
* exchange: 'refresh',
327+
* refreshToken: refreshToken,
328+
* oidcOrigin: keycloakUrl,
329+
* };
330+
* const authProvider = await AuthProviders.refreshAuthProvider(oidcCredentials);
331+
*
332+
* const client = new OpenTDF({
333+
* authProvider,
334+
* platformUrl: 'https://platform.example.com',
335+
* });
336+
*
337+
* const cipherText = await client.createZTDF({
338+
* source: { type: 'stream', location: source },
339+
* autoconfigure: false,
340+
* });
341+
*
342+
* const clearText = await client.read({ type: 'stream', location: cipherText });
343+
* ```
344+
*/
314345
export class OpenTDF {
315-
// Configuration service and more is at this URL/connectRPC endpoint
346+
/** The platform URL */
316347
readonly platformUrl: string;
348+
/** The policy service endpoint */
317349
readonly policyEndpoint: string;
350+
/** The auth provider for the OpenTDF instance. */
318351
readonly authProvider: AuthProvider;
352+
/** If DPoP is enabled for this instance. */
319353
readonly dpopEnabled: boolean;
354+
/** Default options for creating TDF objects. */
320355
defaultCreateOptions: Omit<CreateOptions, 'source'>;
356+
/** Default options for reading TDF objects. */
321357
defaultReadOptions: Omit<ReadOptions, 'source'>;
358+
/** The DPoP keys for this instance, if any. */
322359
readonly dpopKeys: Promise<CryptoKeyPair>;
323-
324-
// Header cache for reading nanotdf collections
360+
/** Cache for rewrapped keys */
325361
private readonly rewrapCache: RewrapCache;
362+
/** The TDF3 client for encrypting and decrypting ZTDF files. */
326363
readonly tdf3Client: TDF3Client;
327364

328365
constructor({
@@ -420,10 +457,7 @@ export class OpenTDF {
420457
return stream;
421458
}
422459

423-
/**
424-
* Opens a TDF file for inspection and decryption.
425-
* @param opts The file to open, and any appropriate configuration options.
426-
*/
460+
/** Opens a TDF file for inspection and decryption. */
427461
open(opts: ReadOptions): TDFReader {
428462
opts = { ...this.defaultReadOptions, ...opts };
429463
return new UnknownTypeReader(this, opts, this.rewrapCache);
@@ -453,6 +487,7 @@ class UnknownTypeReader {
453487
this.delegate = this.resolveType();
454488
}
455489

490+
/** Resolves the TDF type based on the file prefix. */
456491
async resolveType(): Promise<TDFReader> {
457492
if (this.state === 'done') {
458493
throw new ConfigurationError('reader is closed');
@@ -474,21 +509,25 @@ class UnknownTypeReader {
474509
throw new InvalidFileError(`unsupported format; prefix not recognized ${prefix}`);
475510
}
476511

512+
/** Decrypts the TDF file */
477513
async decrypt(): Promise<DecoratedStream> {
478514
const actual = await this.delegate;
479515
return actual.decrypt();
480516
}
481517

518+
/** Returns the attributes of the TDF file */
482519
async attributes(): Promise<string[]> {
483520
const actual = await this.delegate;
484521
return actual.attributes();
485522
}
486523

524+
/** Returns the manifest of the TDF file */
487525
async manifest(): Promise<Manifest> {
488526
const actual = await this.delegate;
489527
return actual.manifest();
490528
}
491529

530+
/** Closes the TDF reader */
492531
async close() {
493532
if (this.state === 'done') {
494533
return;
@@ -534,6 +573,7 @@ class NanoTDFReader {
534573
});
535574
}
536575

576+
/** Decrypts the NanoTDF file and returns a decorated stream. */
537577
async decrypt(): Promise<DecoratedStream> {
538578
const nanotdf = await this.container;
539579
const cachedDEK = this.rewrapCache.get(nanotdf.header.ephemeralPublicKey);
@@ -576,10 +616,12 @@ class NanoTDFReader {
576616

577617
async close() {}
578618

619+
/** Returns blank manifest. NanoTDF has no manifest. */
579620
async manifest(): Promise<Manifest> {
580621
return {} as Manifest;
581622
}
582623

624+
/** Returns the attributes of the NanoTDF file. */
583625
async attributes(): Promise<string[]> {
584626
const nanotdf = await this.container;
585627
if (!nanotdf.header.policy?.content) {
@@ -695,12 +737,16 @@ async function streamify(ab: Promise<ArrayBuffer>): Promise<ReadableStream<Uint8
695737

696738
/** A writer for NanoTDF collections. */
697739
export type NanoTDFCollectionWriter = {
740+
/** The NanoTDF client used for encrypting data in this collection. */
698741
encrypt: (source: Source) => Promise<ReadableStream<Uint8Array>>;
742+
/** Closes the collection and releases any resources. */
699743
close: () => Promise<void>;
700744
};
701745

702746
class Collection {
747+
/** The NanoTDF client used for encrypting data in this collection. */
703748
client?: NanoTDFDatasetClient;
749+
/** Options for encrypting data in this collection. */
704750
encryptOptions?: NanoEncryptOptions;
705751

706752
constructor(authProvider: AuthProvider, opts: CreateNanoTDFCollectionOptions) {
@@ -733,6 +779,7 @@ class Collection {
733779
});
734780
}
735781

782+
/** Encrypts a source into a NanoTDF stream. */
736783
async encrypt(source: Source): Promise<DecoratedStream> {
737784
if (!this.client) {
738785
throw new ConfigurationError('Collection is closed');
@@ -750,6 +797,7 @@ class Collection {
750797
return stream;
751798
}
752799

800+
/** Releases client resources. */
753801
async close() {
754802
delete this.client;
755803
}

lib/src/platform.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,22 @@ export interface PlatformClientOptions {
5050
*
5151
* This client supports authentication via an `AuthProvider` or custom interceptors, which can
5252
* be used to add authentication headers or other custom logic to outgoing requests.
53+
* @example
54+
* ```
55+
* import { AuthProviders, OpenTDF } from '@opentdf/sdk';
56+
* import { PlatformClient } from '@opentdf/sdk/platform';
5357
*
58+
* const authProvider: AuthProvider = await AuthProviders.refreshAuthProvider({...});
59+
* const platform = new PlatformClient({
60+
* authProvider,
61+
* platformUrl: 'https://platform.example.com',
62+
* });
63+
*
64+
* const wellKnownResponse = await platform.v1.wellknown.getWellKnownConfiguration({});
65+
* console.log('Well-known configuration:', wellKnownResponse.configuration);
66+
* ```
5467
*/
68+
5569
export class PlatformClient {
5670
readonly v1: PlatformServices;
5771

lib/typedoc-theme.css

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
body {
2+
line-height: 1.5;
3+
}
4+
pre {
5+
line-height: 1.5;
6+
}
7+
8+
:root {
9+
/* Light */
10+
--light-color-background: #ffffff;
11+
--light-color-background-secondary: #fafafa;
12+
--light-color-background-active: #d6d8da;
13+
--light-color-background-warning: #FFC107;
14+
--light-color-warning-text: #262626;
15+
--light-color-accent: #cfcfcf;
16+
--light-color-text: #262626;
17+
--light-color-contrast-text: #000;
18+
--light-color-link: #004987;
19+
--light-color-ts-keyword: #004987;
20+
--light-color-ts-variable: #004987;
21+
}
22+
23+
:root {
24+
/* Dark */
25+
--dark-color-background: #262626;
26+
--dark-color-background-secondary: #1a1a1a;
27+
--dark-color-background-active: #525252;
28+
--dark-color-background-warning: #FFC107;
29+
--dark-color-warning-text: #262626;
30+
--dark-color-accent: #9096a2;
31+
--dark-color-text: #f5f5f5;
32+
--dark-color-contrast-text: #ffffff;
33+
--dark-color-text-aside: #dddddd;
34+
--dark-color-link: #6AAAE4;
35+
--dark-color-focus-outline: #6AAAE4;
36+
--dark-color-ts-keyword: #6AAAE4;
37+
--dark-color-ts-variable: #6AAAE4;
38+
}
39+
40+
.tsd-toolbar-contents a {
41+
color: var(--color-link);
42+
}

0 commit comments

Comments
 (0)