@singularlogic/coreplatts 0.0.4 โ 0.0.6
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/README.md +166 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +56 -49
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# @singularlogic/coreplatts
|
|
2
|
+
|
|
3
|
+
A TypeScript client library to access the **BUILDSPACE** identity and storage APIs.
|
|
4
|
+
Built to work with [Keycloak](https://www.keycloak.org/) and [MinIO](https://min.io/), this library wraps REST endpoints and handles authentication, token refresh, organization and folder management.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## ๐ฆ Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @singularlogic/coreplatts
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## ๐ Getting Started
|
|
17
|
+
|
|
18
|
+
### Create a client
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { Client } from '@singularlogic/coreplatts';
|
|
22
|
+
|
|
23
|
+
const managementURL = 'https://api-buildspace.euinno.eu';
|
|
24
|
+
const accountURL = 'https://account-buildspace.euinno.eu';
|
|
25
|
+
|
|
26
|
+
const client = new Client(managementURL, accountURL);
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## ๐ Authentication
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
const token = await client.login('user@example.com', 'password');
|
|
35
|
+
console.log('Access token:', token.access_token);
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Tokens are stored in `localStorage` or `sessionStorage` and automatically refreshed when expired.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## ๐ค User Management
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
const me = await client.myUser(); // auto-includes access token
|
|
46
|
+
console.log(me.username);
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Register new users:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
await client.register(
|
|
53
|
+
'new@user.com',
|
|
54
|
+
'password123',
|
|
55
|
+
'password123',
|
|
56
|
+
'First',
|
|
57
|
+
'Last'
|
|
58
|
+
);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## ๐งโ๐คโ๐ง Organizations (Groups)
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const orgs = await client.allOrganizations();
|
|
67
|
+
const myOrgs = await client.myOrganizations();
|
|
68
|
+
|
|
69
|
+
const org = await client.organizationByName('MyOrg');
|
|
70
|
+
|
|
71
|
+
await client.createOrganization('MyNewOrg');
|
|
72
|
+
|
|
73
|
+
await client.addToOrganization('MyNewOrg', {
|
|
74
|
+
'user1@example.com': 'MEMBER',
|
|
75
|
+
'admin@example.com': 'ADMIN'
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## ๐ Folder & File Management
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const folder = await client.getFolderByName('project-data');
|
|
85
|
+
console.log(folder.files);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
You can also upload and download files using `Folder` and `File` methods.
|
|
89
|
+
|
|
90
|
+
Example:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const file = await folder.getFileByName('report.pdf');
|
|
94
|
+
await file.download();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## ๐ Automatic Token Handling
|
|
100
|
+
|
|
101
|
+
All token-sensitive methods use a utility that:
|
|
102
|
+
- Checks if the access token is expired
|
|
103
|
+
- Refreshes it using `refresh_token` if needed
|
|
104
|
+
- Uses `localStorage` or `sessionStorage` automatically
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## ๐งช Example in Angular Service
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { Injectable } from '@angular/core';
|
|
112
|
+
import { Client } from '@singularlogic/coreplatts';
|
|
113
|
+
import { environment } from '../environments/environment';
|
|
114
|
+
|
|
115
|
+
@Injectable({ providedIn: 'root' })
|
|
116
|
+
export class AuthService {
|
|
117
|
+
client = new Client(environment.managementURL, environment.accountURL);
|
|
118
|
+
|
|
119
|
+
getCurrentUser() {
|
|
120
|
+
return this.client.myUser();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## ๐งฑ Core Classes
|
|
128
|
+
|
|
129
|
+
### `Client`
|
|
130
|
+
|
|
131
|
+
- Handles auth, session, and proxies to:
|
|
132
|
+
- `UserConsumer`
|
|
133
|
+
- `GroupConsumer`
|
|
134
|
+
- `BucketConsumer`
|
|
135
|
+
- `FolderConsumer`
|
|
136
|
+
|
|
137
|
+
### `Folder`
|
|
138
|
+
|
|
139
|
+
- Can fetch files
|
|
140
|
+
- Can upload files with chunking and concurrency control
|
|
141
|
+
|
|
142
|
+
### `File`
|
|
143
|
+
|
|
144
|
+
- Can be downloaded by ID or name
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## ๐ API Summary
|
|
149
|
+
|
|
150
|
+
| Method | Description |
|
|
151
|
+
|--------|-------------|
|
|
152
|
+
| `login(email, password)` | Authenticate user |
|
|
153
|
+
| `myUser()` | Get current user info |
|
|
154
|
+
| `register(...)` | Create new user |
|
|
155
|
+
| `allOrganizations()` | List all groups |
|
|
156
|
+
| `createOrganization(name)` | Create group + bucket |
|
|
157
|
+
| `addToOrganization(name, users)` | Assign roles |
|
|
158
|
+
| `getFolderByName(name)` | Retrieve folder |
|
|
159
|
+
| `getFolderByID(id)` | Retrieve folder by ID |
|
|
160
|
+
| `removeOrganizationByID(id)` | Delete group and bucket |
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## ๐ License
|
|
165
|
+
|
|
166
|
+
MIT ยฉ [SingularLogic S.A.](https://www.singularlogic.eu)
|
package/dist/index.d.ts
CHANGED
|
@@ -155,7 +155,8 @@ declare class Client implements IClient$1 {
|
|
|
155
155
|
private _bucketConsumer;
|
|
156
156
|
private _folderConsumer;
|
|
157
157
|
constructor(_managementURL: string, _accountURL: string);
|
|
158
|
-
|
|
158
|
+
setSession(session: OidcToken): void;
|
|
159
|
+
getSessionVariable(key: string): string | null;
|
|
159
160
|
login(email: string, password: string): Promise<OidcToken>;
|
|
160
161
|
myUser(token?: string): Promise<User$1>;
|
|
161
162
|
allOrganizations(token?: string): Promise<Group$1[]>;
|
package/dist/index.js
CHANGED
|
@@ -272,34 +272,40 @@ var BucketConsumer = class extends BaseConsumer {
|
|
|
272
272
|
function withValidToken(fn, accountsAPI) {
|
|
273
273
|
return function(...args) {
|
|
274
274
|
return __async(this, null, function* () {
|
|
275
|
-
|
|
276
|
-
const
|
|
277
|
-
const storage = isBrowser ? (_a = window.sessionStorage) != null ? _a : window.localStorage : void 0;
|
|
275
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
276
|
+
const storage = typeof window !== "undefined" ? window.sessionStorage : globalThis.sessionStorage;
|
|
278
277
|
if (!storage) {
|
|
279
|
-
console.warn("\u26A0\uFE0F sessionStorage
|
|
280
|
-
return
|
|
278
|
+
console.warn("\u26A0\uFE0F sessionStorage not available");
|
|
279
|
+
return fn.apply(this, args);
|
|
281
280
|
}
|
|
282
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
283
281
|
let token = storage.getItem("access_token");
|
|
284
282
|
let refreshToken = storage.getItem("refresh_token");
|
|
285
|
-
let exp =
|
|
286
|
-
let refreshExp =
|
|
287
|
-
|
|
283
|
+
let exp = 0;
|
|
284
|
+
let refreshExp = 0;
|
|
285
|
+
const claimsRaw = storage.getItem("id_token_claims_obj");
|
|
286
|
+
if (claimsRaw) {
|
|
288
287
|
try {
|
|
289
|
-
const claims = JSON.parse(
|
|
288
|
+
const claims = JSON.parse(claimsRaw);
|
|
290
289
|
if (claims.exp) exp = claims.exp;
|
|
291
290
|
if (claims.iat && claims.exp) {
|
|
292
|
-
const
|
|
293
|
-
refreshExp = claims.iat + 3 *
|
|
291
|
+
const duration = claims.exp - claims.iat;
|
|
292
|
+
refreshExp = claims.iat + 3 * duration;
|
|
294
293
|
}
|
|
295
|
-
} catch (
|
|
296
|
-
console.warn("\u26A0\uFE0F Could not parse id_token_claims_obj:",
|
|
294
|
+
} catch (e) {
|
|
295
|
+
console.warn("\u26A0\uFE0F Could not parse id_token_claims_obj:", e);
|
|
297
296
|
}
|
|
297
|
+
} else {
|
|
298
|
+
exp = Number(storage.getItem("refresh_expires_in") || "0");
|
|
299
|
+
refreshExp = Number(storage.getItem("refresh_exp") || "0");
|
|
298
300
|
}
|
|
299
|
-
if (!token ||
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
301
|
+
if (!token || !refreshToken) {
|
|
302
|
+
console.warn("\u26A0\uFE0F No tokens found in sessionStorage.");
|
|
303
|
+
return fn.apply(this, args);
|
|
304
|
+
}
|
|
305
|
+
if (now >= exp) {
|
|
306
|
+
if (now >= refreshExp) {
|
|
307
|
+
console.warn("\u26A0\uFE0F Both access and refresh tokens expired.");
|
|
308
|
+
return fn.apply(this, args);
|
|
303
309
|
}
|
|
304
310
|
try {
|
|
305
311
|
const response = yield fetch(`${accountsAPI}/user/refresh`, {
|
|
@@ -309,20 +315,20 @@ function withValidToken(fn, accountsAPI) {
|
|
|
309
315
|
});
|
|
310
316
|
if (!response.ok) throw new Error("Token refresh failed");
|
|
311
317
|
const session = yield response.json();
|
|
318
|
+
token = session.access_token;
|
|
319
|
+
refreshToken = session.refresh_token;
|
|
312
320
|
const newExp = now + session.expires_in;
|
|
313
321
|
const newRefreshExp = now + session.refresh_expires_in;
|
|
314
|
-
storage.setItem("access_token",
|
|
315
|
-
storage.setItem("refresh_token",
|
|
316
|
-
storage.setItem("
|
|
322
|
+
storage.setItem("access_token", token);
|
|
323
|
+
storage.setItem("refresh_token", refreshToken);
|
|
324
|
+
storage.setItem("refresh_expires_in", String(newExp));
|
|
317
325
|
storage.setItem("refresh_exp", String(newRefreshExp));
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
console.error("\u{1F510} Token refresh failed:", e);
|
|
326
|
+
} catch (err) {
|
|
327
|
+
console.error("\u{1F510} Token refresh failed:", err);
|
|
321
328
|
throw new Error("Could not refresh session.");
|
|
322
329
|
}
|
|
323
330
|
}
|
|
324
|
-
|
|
325
|
-
return result instanceof Promise ? result : Promise.resolve(result);
|
|
331
|
+
return yield fn.apply(this, [...args, token]);
|
|
326
332
|
});
|
|
327
333
|
};
|
|
328
334
|
}
|
|
@@ -801,36 +807,37 @@ var Client = class {
|
|
|
801
807
|
this.getFolderByName = withValidToken(this.getFolderByName.bind(this), _accountURL);
|
|
802
808
|
this.getFolderByID = withValidToken(this.getFolderByID.bind(this), _accountURL);
|
|
803
809
|
}
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
// if (storage) {
|
|
807
|
-
// storage.setItem('token', session.access_token);
|
|
808
|
-
// storage.setItem('refresh_token', session.refresh_token);
|
|
809
|
-
// storage.setItem('exp', String(session.expires_in));
|
|
810
|
-
// storage.setItem('refresh_exp', String(session.refresh_expires_in));
|
|
811
|
-
// } else {
|
|
812
|
-
// console.warn("Session storage is not available.");
|
|
813
|
-
// }
|
|
814
|
-
// }
|
|
815
|
-
// public getSessionVariable(key: string): string | null {
|
|
816
|
-
// const storage = typeof window !== "undefined" ? sessionStorage : global.sessionStorage;
|
|
817
|
-
// return storage ? storage.getItem(key) : null;
|
|
818
|
-
// }
|
|
819
|
-
_setSession(session) {
|
|
810
|
+
setSession(session) {
|
|
811
|
+
const storage = typeof window !== "undefined" ? sessionStorage : global.sessionStorage;
|
|
820
812
|
const now = Math.floor(Date.now() / 1e3);
|
|
821
|
-
if (
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
813
|
+
if (storage) {
|
|
814
|
+
storage.setItem("access_token", session.access_token);
|
|
815
|
+
storage.setItem("refresh_token", session.refresh_token);
|
|
816
|
+
storage.setItem("refresh_expires_in", String(now + session.expires_in));
|
|
817
|
+
storage.setItem("refresh_exp", String(now + session.refresh_expires_in));
|
|
826
818
|
} else {
|
|
827
|
-
console.warn("
|
|
819
|
+
console.warn("Session storage is not available.");
|
|
828
820
|
}
|
|
829
821
|
}
|
|
822
|
+
getSessionVariable(key) {
|
|
823
|
+
const storage = typeof window !== "undefined" ? sessionStorage : global.sessionStorage;
|
|
824
|
+
return storage ? storage.getItem(key) : null;
|
|
825
|
+
}
|
|
826
|
+
// private _setSession(session: OidcToken): void {
|
|
827
|
+
// const now = Math.floor(Date.now() / 1000);
|
|
828
|
+
// if (typeof localStorage !== "undefined") {
|
|
829
|
+
// localStorage.setItem('token', session.access_token);
|
|
830
|
+
// localStorage.setItem('refresh_token', session.refresh_token);
|
|
831
|
+
// localStorage.setItem('exp', String(now + session.expires_in));
|
|
832
|
+
// localStorage.setItem('refresh_exp', String(now + session.refresh_expires_in));
|
|
833
|
+
// } else {
|
|
834
|
+
// console.warn("โ ๏ธ Local Storage not available. You will need to pass tokens manually.");
|
|
835
|
+
// }
|
|
836
|
+
// }
|
|
830
837
|
login(email, password) {
|
|
831
838
|
return this._userConsumer.login(email, password).then(
|
|
832
839
|
(resp) => {
|
|
833
|
-
this.
|
|
840
|
+
this.setSession(resp);
|
|
834
841
|
return resp;
|
|
835
842
|
}
|
|
836
843
|
);
|