@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 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
- private _setSession;
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
- var _a;
276
- const isBrowser = typeof window !== "undefined";
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 or localStorage not available. You must pass token manually.");
280
- return Promise.resolve(fn.apply(this, args));
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 = Number(storage.getItem("exp") || "0");
286
- let refreshExp = Number(storage.getItem("refresh_exp") || "0");
287
- if ((!exp || !refreshExp) && storage.getItem("id_token_claims_obj")) {
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(storage.getItem("id_token_claims_obj"));
288
+ const claims = JSON.parse(claimsRaw);
290
289
  if (claims.exp) exp = claims.exp;
291
290
  if (claims.iat && claims.exp) {
292
- const estimatedDuration = claims.exp - claims.iat;
293
- refreshExp = claims.iat + 3 * estimatedDuration;
291
+ const duration = claims.exp - claims.iat;
292
+ refreshExp = claims.iat + 3 * duration;
294
293
  }
295
- } catch (err) {
296
- console.warn("\u26A0\uFE0F Could not parse id_token_claims_obj:", err);
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 || now >= exp) {
300
- if (!refreshToken || now >= refreshExp) {
301
- console.warn("\u26A0\uFE0F Session expired. Please log in again.");
302
- return Promise.resolve(fn.apply(this, args));
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", session.access_token);
315
- storage.setItem("refresh_token", session.refresh_token);
316
- storage.setItem("exp", String(newExp));
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
- token = session.access_token;
319
- } catch (e) {
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
- const result = fn.apply(this, [...args, token]);
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
- // public setSession(session: OidcToken): void {
805
- // const storage = typeof window !== "undefined" ? sessionStorage : global.sessionStorage;
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 (typeof localStorage !== "undefined") {
822
- localStorage.setItem("token", session.access_token);
823
- localStorage.setItem("refresh_token", session.refresh_token);
824
- localStorage.setItem("exp", String(now + session.expires_in));
825
- localStorage.setItem("refresh_exp", String(now + session.refresh_expires_in));
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("\u26A0\uFE0F Local Storage not available. You will need to pass tokens manually.");
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._setSession(resp);
840
+ this.setSession(resp);
834
841
  return resp;
835
842
  }
836
843
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@singularlogic/coreplatts",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [