@grasp-labs/ds-microfrontends-integration 0.10.1 → 0.11.1

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 CHANGED
@@ -220,7 +220,7 @@ npm install
220
220
 
221
221
  ### Dev auth middleware
222
222
 
223
- `devAuthMiddleware` adds a quick login screen to your local Express setup and reuses the returned token for every backend call. Mount it before anything that proxies to your APIs so outbound requests get `Authorization: Bearer <token>` automatically.
223
+ `devAuthMiddleware` provides an optional login page for local development and injects `Authorization: Bearer <token>` for backend calls when a token is available. Mount it before anything that proxies to your APIs so outbound requests receive the token automatically.
224
224
 
225
225
  ```ts
226
226
  import express from "express";
@@ -229,11 +229,20 @@ import { devAuthMiddleware } from "@grasp-labs/ds-microfrontends-integration/dev
229
229
  const app = express();
230
230
 
231
231
  app.use(devAuthMiddleware());
232
+
233
+ // Or with custom options:
234
+ app.use(
235
+ devAuthMiddleware({
236
+ loginPagePath: "/__login", // Path for the login page
237
+ afterLoginRedirectPath: "/", // Where to redirect after login
238
+ authServerLoginUrl: "https://auth-dev.grasp-daas.com/rest-auth/login/", // Auth server endpoint
239
+ }),
240
+ );
232
241
  ```
233
242
 
234
- Skip the form entirely by setting `DEV_AUTH_TOKEN` (env var or `.env` file) before starting the server. Need a token? Call the dev auth endpoint with your usual credentials and copy the `access_token`.
243
+ The login page is available at `/__login` (configurable via `loginPagePath`). Navigate there manually when you need to authenticate. Alternatively, set `DEV_AUTH_TOKEN` (env var or `.env` file) before starting the server to skip the login form entirely.
235
244
 
236
- After a successful login, the middleware redirects to `process.env.VITE_BASE_PATH` when set, otherwise `/` (override via `redirectAfterLoginPathTo` if needed).
245
+ After a successful login, the middleware redirects to `process.env.VITE_BASE_PATH` when set, otherwise `/` (override via `afterLoginRedirectPath` if needed).
237
246
 
238
247
  ### Scripts
239
248
 
@@ -1,22 +1,22 @@
1
1
  import { Request, Response, NextFunction } from 'express';
2
2
  export type DevLoginOptions = {
3
3
  /**
4
- * Path segment or absolute path for the login page. Values are trimmed and
5
- * automatically prefixed with "/" when missing (e.g. "__login" => "/__login").
4
+ * Path segment or absolute path for the login page. Automatically prefixed
5
+ * with "/" when missing (e.g. "__login" => "/__login").
6
6
  * @default "/__login"
7
7
  */
8
- loginPath?: string;
8
+ loginPagePath?: string;
9
9
  /**
10
10
  * Location to redirect to after successful authentication. The same
11
- * normalization rules apply as for {@link loginPath}.
11
+ * normalization rules apply as for {@link loginPagePath}.
12
12
  * @default process.env.VITE_BASE_PATH || "/"
13
13
  */
14
- redirectAfterLoginPathTo?: string;
14
+ afterLoginRedirectPath?: string;
15
15
  /**
16
- * Fully qualified URL of the backend dev auth login endpoint.
16
+ * Fully qualified URL of the auth server login endpoint.
17
17
  * @default "https://auth-dev.grasp-daas.com/rest-auth/login/"
18
18
  */
19
- authEndpoint?: string;
19
+ authServerLoginUrl?: string;
20
20
  };
21
21
  /**
22
22
  * Simple Express middleware that forces a one-page dev login and then injects
@@ -37,7 +37,7 @@ export type DevLoginOptions = {
37
37
  * app.use(devAuthMiddleware());
38
38
  * ```
39
39
  */
40
- export declare function devAuthMiddleware(options?: DevLoginOptions): (req: Request, res: Response, next: NextFunction) => Promise<any>;
40
+ export declare function devAuthMiddleware(options?: DevLoginOptions): (req: Request, res: Response, next: NextFunction) => Promise<void | Response<any, Record<string, any>>>;
41
41
  /**
42
42
  * Simple in-memory token store backed by process.env.
43
43
  * Preloading `DEV_AUTH_TOKEN` (e.g. via a `.env` file or shell env var) skips the login flow entirely.
@@ -45,5 +45,4 @@ export declare function devAuthMiddleware(options?: DevLoginOptions): (req: Requ
45
45
  export declare const DEV_AUTH_TOKEN: {
46
46
  readonly get: () => string | undefined;
47
47
  readonly set: (token: string) => void;
48
- readonly exists: () => boolean;
49
48
  };
@@ -1,6 +1,6 @@
1
- import { urlencoded as b } from "express";
2
- function w(e) {
3
- const t = e.loginPath, r = e.errorMessage ?? "", n = y(r);
1
+ import { urlencoded as g } from "express";
2
+ function m(e) {
3
+ const o = e.loginPath, r = e.errorMessage ?? "", n = f(r);
4
4
  return `<!DOCTYPE html>
5
5
  <html lang="en">
6
6
  <head>
@@ -99,7 +99,7 @@ function w(e) {
99
99
  <p>Provide credentials to unlock the dev server</p>
100
100
  </div>
101
101
 
102
- <form method="POST" action="${t}">
102
+ <form method="POST" action="${o}">
103
103
  <input type="text" placeholder="Email" name="email" required />
104
104
  <input
105
105
  type="password"
@@ -116,9 +116,9 @@ function w(e) {
116
116
  </body>
117
117
  </html>`;
118
118
  }
119
- function y(e) {
120
- return e.replace(/[&<>"']/g, (t) => {
121
- switch (t) {
119
+ function f(e) {
120
+ return e.replace(/[&<>"']/g, (o) => {
121
+ switch (o) {
122
122
  case "&":
123
123
  return "&amp;";
124
124
  case "<":
@@ -130,72 +130,79 @@ function y(e) {
130
130
  case "'":
131
131
  return "&#39;";
132
132
  default:
133
- return t;
133
+ return o;
134
134
  }
135
135
  });
136
136
  }
137
- function v(e = {}) {
138
- const {
139
- loginPath: t = "/__login",
140
- redirectAfterLoginPathTo: r = process.env.VITE_BASE_PATH || "/",
141
- authEndpoint: n = "https://auth-dev.grasp-daas.com/rest-auth/login/"
142
- } = e, o = g(t, "loginPath"), c = g(
143
- r,
144
- "redirectAfterLoginPathTo"
145
- ), m = k();
146
- return async (s, i, p) => {
147
- if (l.exists())
148
- return s.path === o ? i.redirect(c) : (s.headers.authorization = `Bearer ${l.get()}`, p());
149
- if (s.path !== o)
150
- return i.redirect(o);
151
- if (s.method === "GET")
152
- return d(i, o);
153
- if (s.method === "POST") {
154
- try {
155
- await m(s, i);
156
- } catch (a) {
157
- return p(a);
158
- }
159
- const { email: u, password: h } = s.body ?? {};
160
- if (!u || !h)
161
- return d(i, o, "Email and password are required.");
162
- try {
163
- const { access_token: a } = await x({
164
- email: u,
165
- password: h,
166
- authEndpoint: n
167
- });
168
- return l.set(a), i.redirect(303, c);
169
- } catch (a) {
170
- const f = `${a instanceof Error ? a.message : String(a)}`;
171
- return d(i, o, f);
172
- }
173
- }
174
- return i.status(405).send("Method Not Allowed");
175
- };
137
+ function T(e = {}) {
138
+ const o = b(e);
139
+ return k(o), async (r, n, t) => r.path === o.loginPagePath ? r.method === "GET" ? d(n, o.loginPagePath) : r.method === "POST" ? y(o, r, n, t) : n.status(405).send("Method Not Allowed") : P(r, t);
176
140
  }
177
- function g(e, t) {
178
- const r = e.trim();
179
- if (!r)
180
- throw new Error(
181
- `devAuthMiddleware ${t} must be a non-empty string`
182
- );
183
- return r.startsWith("/") ? r : `/${r}`;
141
+ function b(e) {
142
+ const o = (r) => r.startsWith("/") ? r : `/${r}`;
143
+ return {
144
+ loginPagePath: o(e.loginPagePath ?? "/__login"),
145
+ afterLoginRedirectPath: o(
146
+ e.afterLoginRedirectPath ?? process.env.VITE_BASE_PATH ?? "/"
147
+ ),
148
+ authServerLoginUrl: e.authServerLoginUrl ?? "https://auth-dev.grasp-daas.com/rest-auth/login/"
149
+ };
184
150
  }
185
- function d(e, t, r) {
151
+ function d(e, o, r) {
186
152
  return e.type("html").send(
187
- w({
188
- loginPath: t,
153
+ m({
154
+ loginPath: o,
189
155
  errorMessage: r
190
156
  })
191
157
  );
192
158
  }
193
- function k() {
194
- const e = b({ extended: !0 });
195
- return (t, r) => new Promise((n, o) => {
196
- e(t, r, (c) => {
197
- if (c) {
198
- o(c);
159
+ function k({ loginPagePath: e }) {
160
+ const o = "\x1B[33m", r = "\x1B[34m", n = "\x1B[2m", t = "\x1B[0m", a = "─".repeat(50), s = `${o}┌${a}┐${t}`, c = `${o}└${a}┘${t}`, i = process.env.HOST ?? "localhost", l = process.env.PORT ?? "XXXX", p = `${r}http://${i}:${l}${e}${t}`, h = [
161
+ s,
162
+ "",
163
+ " 🔐 Dev Auth Middleware Active",
164
+ "",
165
+ ` Login: ${p}`,
166
+ "",
167
+ ` ${n}Tip: Set DEV_AUTH_TOKEN env var to skip login${t}`,
168
+ "",
169
+ c
170
+ ];
171
+ console.log(h.join(`
172
+ `));
173
+ }
174
+ async function y({
175
+ authServerLoginUrl: e,
176
+ loginPagePath: o,
177
+ afterLoginRedirectPath: r
178
+ }, n, t, a) {
179
+ try {
180
+ await w(n, t);
181
+ } catch (i) {
182
+ return a(i);
183
+ }
184
+ const { email: s, password: c } = n.body ?? {};
185
+ if (!s || !c)
186
+ return d(t, o, "Email and password are required.");
187
+ try {
188
+ const { access_token: i } = await x({
189
+ email: s,
190
+ password: c,
191
+ authServerLoginUrl: e
192
+ });
193
+ return u.set(i), t.redirect(303, r);
194
+ } catch (i) {
195
+ const l = `${i instanceof Error ? i.message : String(i)}`;
196
+ return d(t, o, l);
197
+ }
198
+ }
199
+ const w = v();
200
+ function v() {
201
+ const e = g({ extended: !0 });
202
+ return (o, r) => new Promise((n, t) => {
203
+ e(o, r, (a) => {
204
+ if (a) {
205
+ t(a);
199
206
  return;
200
207
  }
201
208
  n();
@@ -204,8 +211,8 @@ function k() {
204
211
  }
205
212
  async function x({
206
213
  email: e,
207
- password: t,
208
- authEndpoint: r
214
+ password: o,
215
+ authServerLoginUrl: r
209
216
  }) {
210
217
  const n = await fetch(r, {
211
218
  method: "POST",
@@ -214,7 +221,7 @@ async function x({
214
221
  },
215
222
  body: JSON.stringify({
216
223
  email: e,
217
- password: t,
224
+ password: o,
218
225
  remember_me: !0
219
226
  })
220
227
  });
@@ -222,21 +229,28 @@ async function x({
222
229
  throw new Error(
223
230
  `Authentication failed with status ${n.status} and response: ${await n.text()}`
224
231
  );
225
- const o = await n.json();
226
- if (!("access_token" in o && "refresh_token" in o))
232
+ const t = await n.json();
233
+ if (!("access_token" in t && "refresh_token" in t))
227
234
  throw new Error(
228
- `Authentication response is missing access_token or refresh_token: ${JSON.stringify(o, null, 2)}`
235
+ `Authentication response is missing access_token or refresh_token: ${JSON.stringify(t, null, 2)}`
229
236
  );
230
- return o;
237
+ return t;
231
238
  }
232
- const l = {
233
- get: () => process.env.DEV_AUTH_TOKEN,
239
+ const u = {
240
+ get: () => {
241
+ const e = process.env.DEV_AUTH_TOKEN?.trim();
242
+ if (e && e.length > 0)
243
+ return e;
244
+ },
234
245
  set: (e) => {
235
246
  process.env.DEV_AUTH_TOKEN = e;
236
- },
237
- exists: () => typeof process.env.DEV_AUTH_TOKEN == "string" && process.env.DEV_AUTH_TOKEN.length > 0
247
+ }
238
248
  };
249
+ async function P(e, o) {
250
+ const r = u.get();
251
+ return r && (e.headers.authorization = `Bearer ${r}`), o();
252
+ }
239
253
  export {
240
- l as DEV_AUTH_TOKEN,
241
- v as devAuthMiddleware
254
+ u as DEV_AUTH_TOKEN,
255
+ T as devAuthMiddleware
242
256
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@grasp-labs/ds-microfrontends-integration",
3
- "version": "0.10.1",
3
+ "version": "0.11.1",
4
4
  "private": false,
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",