@zauru-sdk/common 6.13.0 → 6.14.0
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/CHANGELOG.md +11 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/sessionReauth.js +65 -0
- package/dist/index.d.ts +1 -0
- package/dist/sessionReauth.d.ts +21 -0
- package/package.json +3 -3
- package/src/index.ts +1 -0
- package/src/sessionReauth.test.ts +50 -0
- package/src/sessionReauth.ts +95 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [6.14.0](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/common@6.13.0...@zauru-sdk/common@6.14.0) (2026-10-30)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* preservar estado local al reautenticar webapps ([e1f76e6](https://github.com/intuitiva/zauru-typescript-sdk/commit/e1f76e6fe06a76c9dc183b0d1af91439f4cadea7))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
6
17
|
# [6.13.0](https://github.com/intuitiva/zauru-typescript-sdk/compare/@zauru-sdk/common@6.12.0...@zauru-sdk/common@6.13.0) (2026-10-29)
|
|
7
18
|
|
|
8
19
|
|
package/dist/esm/index.js
CHANGED
|
@@ -21,3 +21,4 @@ __exportStar(require("./oauthErrors.js"), exports);
|
|
|
21
21
|
__exportStar(require("./providerRestrictions.js"), exports);
|
|
22
22
|
__exportStar(require("./providerReceptionMatrix.js"), exports);
|
|
23
23
|
__exportStar(require("./rejectionPercentageAdjustment.js"), exports);
|
|
24
|
+
__exportStar(require("./sessionReauth.js"), exports);
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isZauruSessionReauthPayload = exports.createZauruSessionReauthPayload = exports.hasZauruOauthReauthCookie = exports.isZauruSessionExpiredError = exports.ZAURU_OAUTH_REAUTH_COOKIE = exports.ZAURU_SESSION_REAUTH_URL = void 0;
|
|
4
|
+
exports.ZAURU_SESSION_REAUTH_URL = "/logout?reauth=1";
|
|
5
|
+
exports.ZAURU_OAUTH_REAUTH_COOKIE = "zauru_oauth_reauth";
|
|
6
|
+
const errorText = (value) => {
|
|
7
|
+
if (value instanceof Error)
|
|
8
|
+
return value.message;
|
|
9
|
+
if (typeof value === "string")
|
|
10
|
+
return value;
|
|
11
|
+
if (value == null)
|
|
12
|
+
return "";
|
|
13
|
+
try {
|
|
14
|
+
return JSON.stringify(value);
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return String(value);
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
const hasUnauthorizedStatus = (value) => {
|
|
21
|
+
if (!value || typeof value !== "object" || !("status" in value)) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return Number(value.status) === 401;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Detects the HTTP 401 response Zauru emits when the API token stored in the
|
|
28
|
+
* Remix session expires. It accepts direct Response-like values and nested
|
|
29
|
+
* messages produced by handlePossibleAxiosErrors.
|
|
30
|
+
*/
|
|
31
|
+
const isZauruSessionExpiredError = (...values) => {
|
|
32
|
+
for (const value of values) {
|
|
33
|
+
if (hasUnauthorizedStatus(value))
|
|
34
|
+
return true;
|
|
35
|
+
const text = errorText(value);
|
|
36
|
+
const isUnauthorized = /HTTP\s*401/i.test(text) ||
|
|
37
|
+
/status(?:\s+code)?[\s:=]+401/i.test(text) ||
|
|
38
|
+
/401\s+Unauthorized/i.test(text);
|
|
39
|
+
const isFromZauru = /zauru/i.test(text) ||
|
|
40
|
+
/\/apps\/webapp_tables\//i.test(text) ||
|
|
41
|
+
/your session expired/i.test(text);
|
|
42
|
+
if (isUnauthorized && isFromZauru)
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
return false;
|
|
46
|
+
};
|
|
47
|
+
exports.isZauruSessionExpiredError = isZauruSessionExpiredError;
|
|
48
|
+
const hasZauruOauthReauthCookie = (cookieHeader) => (cookieHeader ?? "")
|
|
49
|
+
.split(";")
|
|
50
|
+
.some((part) => part.trim() === `${exports.ZAURU_OAUTH_REAUTH_COOKIE}=1`);
|
|
51
|
+
exports.hasZauruOauthReauthCookie = hasZauruOauthReauthCookie;
|
|
52
|
+
const createZauruSessionReauthPayload = (overrides = {}) => ({
|
|
53
|
+
error: true,
|
|
54
|
+
reauthRequired: true,
|
|
55
|
+
reauthUrl: overrides.reauthUrl ?? exports.ZAURU_SESSION_REAUTH_URL,
|
|
56
|
+
title: overrides.title ?? "La sesión venció",
|
|
57
|
+
type: overrides.type ?? "info",
|
|
58
|
+
description: overrides.description ??
|
|
59
|
+
"Inicie sesión nuevamente para continuar con la operación.",
|
|
60
|
+
});
|
|
61
|
+
exports.createZauruSessionReauthPayload = createZauruSessionReauthPayload;
|
|
62
|
+
const isZauruSessionReauthPayload = (value) => Boolean(value &&
|
|
63
|
+
typeof value === "object" &&
|
|
64
|
+
value.reauthRequired === true);
|
|
65
|
+
exports.isZauruSessionReauthPayload = isZauruSessionReauthPayload;
|
package/dist/index.d.ts
CHANGED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare const ZAURU_SESSION_REAUTH_URL = "/logout?reauth=1";
|
|
2
|
+
export declare const ZAURU_OAUTH_REAUTH_COOKIE = "zauru_oauth_reauth";
|
|
3
|
+
export type ZauruSessionReauthPayload = {
|
|
4
|
+
error: true;
|
|
5
|
+
reauthRequired: true;
|
|
6
|
+
reauthUrl: string;
|
|
7
|
+
title: string;
|
|
8
|
+
type: "info";
|
|
9
|
+
description: string;
|
|
10
|
+
};
|
|
11
|
+
type ZauruSessionReauthPayloadOverrides = Partial<Pick<ZauruSessionReauthPayload, "reauthUrl" | "title" | "type" | "description">>;
|
|
12
|
+
/**
|
|
13
|
+
* Detects the HTTP 401 response Zauru emits when the API token stored in the
|
|
14
|
+
* Remix session expires. It accepts direct Response-like values and nested
|
|
15
|
+
* messages produced by handlePossibleAxiosErrors.
|
|
16
|
+
*/
|
|
17
|
+
export declare const isZauruSessionExpiredError: (...values: unknown[]) => boolean;
|
|
18
|
+
export declare const hasZauruOauthReauthCookie: (cookieHeader?: string | null) => boolean;
|
|
19
|
+
export declare const createZauruSessionReauthPayload: (overrides?: ZauruSessionReauthPayloadOverrides) => ZauruSessionReauthPayload;
|
|
20
|
+
export declare const isZauruSessionReauthPayload: (value: unknown) => value is ZauruSessionReauthPayload;
|
|
21
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zauru-sdk/common",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.14.0",
|
|
4
4
|
"description": "Funciones de uso común en el desarrollo de webapps en Zauru",
|
|
5
5
|
"main": "./dist/esm/index.js",
|
|
6
6
|
"module": "./dist/esm/index.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "npm run build:esm",
|
|
14
14
|
"build:esm": "tsc -p tsconfig.esm.json",
|
|
15
|
-
"test": "tsx --test src/httpClientPolicy.test.ts src/providerRestrictions.test.ts src/providerReceptionMatrix.test.ts src/purchaseOrderFinancials.test.ts"
|
|
15
|
+
"test": "tsx --test src/httpClientPolicy.test.ts src/providerRestrictions.test.ts src/providerReceptionMatrix.test.ts src/purchaseOrderFinancials.test.ts src/sessionReauth.test.ts"
|
|
16
16
|
},
|
|
17
17
|
"author": "Oscar Cuéllar",
|
|
18
18
|
"license": "MIT",
|
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
"moment": "^2.30.1",
|
|
27
27
|
"moment-timezone": "^0.5.45"
|
|
28
28
|
},
|
|
29
|
-
"gitHead": "
|
|
29
|
+
"gitHead": "8e5cb991b0da7d1a5d70cd6275d7bfdc52ee1102"
|
|
30
30
|
}
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import {
|
|
4
|
+
ZAURU_SESSION_REAUTH_URL,
|
|
5
|
+
createZauruSessionReauthPayload,
|
|
6
|
+
hasZauruOauthReauthCookie,
|
|
7
|
+
isZauruSessionExpiredError,
|
|
8
|
+
isZauruSessionReauthPayload,
|
|
9
|
+
} from "./sessionReauth.js";
|
|
10
|
+
|
|
11
|
+
describe("isZauruSessionExpiredError", () => {
|
|
12
|
+
it("When a Zauru webapp table returns HTTP 401, it should detect an expired session", () => {
|
|
13
|
+
const message =
|
|
14
|
+
"Error: HTTP 401 Unauthorized - URI: https://app.zauru.com/apps/webapp_tables/58/webapp_rows.json - <title>Your session expired</title>";
|
|
15
|
+
|
|
16
|
+
assert.equal(isZauruSessionExpiredError(message), true);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("When a Response-like value has status 401, it should detect an expired session", () => {
|
|
20
|
+
assert.equal(isZauruSessionExpiredError({ status: 401 }), true);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("When an unrelated Zauru error occurs, it should not request reauthentication", () => {
|
|
24
|
+
assert.equal(
|
|
25
|
+
isZauruSessionExpiredError(
|
|
26
|
+
"HTTP 500 Internal Server Error - URI: https://app.zauru.com/apps/webapp_tables/58/webapp_rows.json",
|
|
27
|
+
),
|
|
28
|
+
false,
|
|
29
|
+
);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("Zauru session reauthentication", () => {
|
|
34
|
+
it("When the reauth marker cookie is present, it should recognize the refresh flow", () => {
|
|
35
|
+
assert.equal(
|
|
36
|
+
hasZauruOauthReauthCookie("foo=bar; zauru_oauth_reauth=1; theme=dark"),
|
|
37
|
+
true,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("When building a payload, it should keep the standard contract and custom copy", () => {
|
|
42
|
+
const payload = createZauruSessionReauthPayload({
|
|
43
|
+
description: "El registro local se conservará.",
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
assert.equal(payload.reauthUrl, ZAURU_SESSION_REAUTH_URL);
|
|
47
|
+
assert.equal(payload.description, "El registro local se conservará.");
|
|
48
|
+
assert.equal(isZauruSessionReauthPayload(payload), true);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
export const ZAURU_SESSION_REAUTH_URL = "/logout?reauth=1";
|
|
2
|
+
export const ZAURU_OAUTH_REAUTH_COOKIE = "zauru_oauth_reauth";
|
|
3
|
+
|
|
4
|
+
export type ZauruSessionReauthPayload = {
|
|
5
|
+
error: true;
|
|
6
|
+
reauthRequired: true;
|
|
7
|
+
reauthUrl: string;
|
|
8
|
+
title: string;
|
|
9
|
+
type: "info";
|
|
10
|
+
description: string;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
type ZauruSessionReauthPayloadOverrides = Partial<
|
|
14
|
+
Pick<
|
|
15
|
+
ZauruSessionReauthPayload,
|
|
16
|
+
"reauthUrl" | "title" | "type" | "description"
|
|
17
|
+
>
|
|
18
|
+
>;
|
|
19
|
+
|
|
20
|
+
const errorText = (value: unknown): string => {
|
|
21
|
+
if (value instanceof Error) return value.message;
|
|
22
|
+
if (typeof value === "string") return value;
|
|
23
|
+
if (value == null) return "";
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
return JSON.stringify(value);
|
|
27
|
+
} catch {
|
|
28
|
+
return String(value);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const hasUnauthorizedStatus = (value: unknown): boolean => {
|
|
33
|
+
if (!value || typeof value !== "object" || !("status" in value)) {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return Number((value as { status?: unknown }).status) === 401;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Detects the HTTP 401 response Zauru emits when the API token stored in the
|
|
42
|
+
* Remix session expires. It accepts direct Response-like values and nested
|
|
43
|
+
* messages produced by handlePossibleAxiosErrors.
|
|
44
|
+
*/
|
|
45
|
+
export const isZauruSessionExpiredError = (...values: unknown[]): boolean => {
|
|
46
|
+
for (const value of values) {
|
|
47
|
+
if (hasUnauthorizedStatus(value)) return true;
|
|
48
|
+
|
|
49
|
+
const text = errorText(value);
|
|
50
|
+
const isUnauthorized =
|
|
51
|
+
/HTTP\s*401/i.test(text) ||
|
|
52
|
+
/status(?:\s+code)?[\s:=]+401/i.test(text) ||
|
|
53
|
+
/401\s+Unauthorized/i.test(text);
|
|
54
|
+
const isFromZauru =
|
|
55
|
+
/zauru/i.test(text) ||
|
|
56
|
+
/\/apps\/webapp_tables\//i.test(text) ||
|
|
57
|
+
/your session expired/i.test(text);
|
|
58
|
+
|
|
59
|
+
if (isUnauthorized && isFromZauru) return true;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return false;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const hasZauruOauthReauthCookie = (
|
|
66
|
+
cookieHeader?: string | null,
|
|
67
|
+
): boolean =>
|
|
68
|
+
(cookieHeader ?? "")
|
|
69
|
+
.split(";")
|
|
70
|
+
.some(
|
|
71
|
+
(part) =>
|
|
72
|
+
part.trim() === `${ZAURU_OAUTH_REAUTH_COOKIE}=1`,
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
export const createZauruSessionReauthPayload = (
|
|
76
|
+
overrides: ZauruSessionReauthPayloadOverrides = {},
|
|
77
|
+
): ZauruSessionReauthPayload => ({
|
|
78
|
+
error: true,
|
|
79
|
+
reauthRequired: true,
|
|
80
|
+
reauthUrl: overrides.reauthUrl ?? ZAURU_SESSION_REAUTH_URL,
|
|
81
|
+
title: overrides.title ?? "La sesión venció",
|
|
82
|
+
type: overrides.type ?? "info",
|
|
83
|
+
description:
|
|
84
|
+
overrides.description ??
|
|
85
|
+
"Inicie sesión nuevamente para continuar con la operación.",
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
export const isZauruSessionReauthPayload = (
|
|
89
|
+
value: unknown,
|
|
90
|
+
): value is ZauruSessionReauthPayload =>
|
|
91
|
+
Boolean(
|
|
92
|
+
value &&
|
|
93
|
+
typeof value === "object" &&
|
|
94
|
+
(value as { reauthRequired?: unknown }).reauthRequired === true,
|
|
95
|
+
);
|