ts-client-lib 0.0.7
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 +76 -0
- package/auth/TSJWT.d.ts +29 -0
- package/auth/TSJWT.js +44 -0
- package/auth/TSOAuth.d.ts +132 -0
- package/auth/TSOAuth.js +230 -0
- package/devices/TSCordova.d.ts +5 -0
- package/devices/TSCordova.js +52 -0
- package/entities/TSCountries.d.ts +14 -0
- package/entities/TSCountries.js +1188 -0
- package/entities/TSCurrencies.d.ts +35 -0
- package/entities/TSCurrencies.js +604 -0
- package/entities/TSMobilePhones.d.ts +167 -0
- package/entities/TSMobilePhones.js +206 -0
- package/entities/TSMoney.d.ts +149 -0
- package/entities/TSMoney.js +311 -0
- package/entities/currency-amount.d.ts +13 -0
- package/entities/currency-amount.js +43 -0
- package/finance/TSBonus.d.ts +197 -0
- package/finance/TSBonus.js +530 -0
- package/finance/TSKYC.d.ts +563 -0
- package/finance/TSKYC.js +1066 -0
- package/finance/TSTax.d.ts +49 -0
- package/finance/TSTax.js +106 -0
- package/finance/bonus-money.d.ts +41 -0
- package/finance/bonus-money.js +61 -0
- package/games/TSBetSlip.d.ts +72 -0
- package/games/TSBetSlip.js +179 -0
- package/games/TSBetSystem.d.ts +4 -0
- package/games/TSBetSystem.js +48 -0
- package/games/TSLotto.d.ts +35 -0
- package/games/TSLotto.js +205 -0
- package/games/TSPool.d.ts +28 -0
- package/games/TSPool.js +88 -0
- package/package.json +93 -0
- package/utils/TSArray.d.ts +9 -0
- package/utils/TSArray.js +87 -0
- package/utils/TSBoolean.d.ts +4 -0
- package/utils/TSBoolean.js +24 -0
- package/utils/TSCache.d.ts +167 -0
- package/utils/TSCache.js +531 -0
- package/utils/TSDate.d.ts +8 -0
- package/utils/TSDate.js +67 -0
- package/utils/TSHeuristic.d.ts +20 -0
- package/utils/TSHeuristic.js +197 -0
- package/utils/TSLZS.d.ts +42 -0
- package/utils/TSLZS.js +343 -0
- package/utils/TSLog.d.ts +40 -0
- package/utils/TSLog.js +110 -0
- package/utils/TSNumber.d.ts +6 -0
- package/utils/TSNumber.js +68 -0
- package/utils/TSObject.d.ts +29 -0
- package/utils/TSObject.js +312 -0
- package/utils/TSPagination.d.ts +282 -0
- package/utils/TSPagination.js +425 -0
- package/utils/TSPaginationMulti.d.ts +77 -0
- package/utils/TSPaginationMulti.js +356 -0
- package/utils/TSString.d.ts +10 -0
- package/utils/TSString.js +107 -0
- package/utils/TSValidator.d.ts +16 -0
- package/utils/TSValidator.js +74 -0
- package/utils/TSWorker.d.ts +3 -0
- package/utils/TSWorker.js +32 -0
- package/utils/diacritics-removal-map.d.ts +5 -0
- package/utils/diacritics-removal-map.js +341 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# ts-client-lib
|
|
2
|
+
|
|
3
|
+
TypeScript utilities for **browser and Node**: auth (JWT decode, OAuth URL helpers), **finance** (bonus eligibility, KYC limits), **entities**, **games**, and **shared helpers** (pagination, strings, compression, etc.). No framework or database dependencies in the core modules—safe to use from React, microservices, or scripts.
|
|
4
|
+
|
|
5
|
+
**npm:** [`ts-client-lib`](https://www.npmjs.com/package/ts-client-lib) · **source:** [github.com/onalbi/ts-client-lib](https://github.com/onalbi/ts-client-lib)
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install ts-client-lib
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Peer: **`reflect-metadata`** (required by some decorators; add if your bundler does not inject it).
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
Imports are **explicit module paths** (no single barrel).
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
// JWT (client-safe decode; verify only on the server)
|
|
25
|
+
import { decodeJWT, isExpired } from 'ts-client-lib/auth/TSJWT';
|
|
26
|
+
|
|
27
|
+
// OAuth: login/connect URLs, callback helpers
|
|
28
|
+
import { buildLoginRedirectUrl, OAUTH2_PROVIDER_IDS } from 'ts-client-lib/auth/TSOAuth';
|
|
29
|
+
|
|
30
|
+
// Bonus & KYC eligibility (same rules as your API can enforce server-side)
|
|
31
|
+
import { BonusEligibility } from 'ts-client-lib/finance/TSBonus';
|
|
32
|
+
import { KYCEligibility } from 'ts-client-lib/finance/TSKYC';
|
|
33
|
+
|
|
34
|
+
// Cursor pagination UI helpers
|
|
35
|
+
import { TSPagination } from 'ts-client-lib/utils/TSPagination';
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
See each file’s JSDoc for types and examples.
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
## Scripts
|
|
43
|
+
|
|
44
|
+
| Command | Purpose |
|
|
45
|
+
|--------|---------|
|
|
46
|
+
| `npm run build` | `tsc --declaration` — emit `.js` / `.d.ts` next to sources |
|
|
47
|
+
| `npm run clean` | `clean:artifacts` then `clean:deps` (see `package.json`) |
|
|
48
|
+
| `npm run lint` | ESLint (`eslint.config.cjs`) |
|
|
49
|
+
| `npm test` | Build, then Vitest (`vitest` config in `package.json`) |
|
|
50
|
+
| `npm run test:coverage` | Vitest with coverage |
|
|
51
|
+
|
|
52
|
+
Vitest options live under **`package.json` → `"vitest"`**.
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Testing
|
|
57
|
+
|
|
58
|
+
- **Unit tests** live in **`test/**/*.spec.ts`** (Vitest). Examples: `BonusEligibility.spec.ts`, `KYCEligibility.spec.ts`, `TSOAuth.spec.ts`, `TSPagination.spec.ts`, plus entity/helper specs (`Money`, `BetSlip`, etc.).
|
|
59
|
+
- **Platform integration** (e.g. bonus-service + GraphQL + live templates, Mongo `paginateCollection`, kyc-service engine) belongs in **your application repo**, not here—keep this package free of service URLs and secrets.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Publish
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
npm run build
|
|
67
|
+
npm publish
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`prepublishOnly` runs the build; `postpublish` runs `clean:artifacts` (see `package.json`).
|
|
71
|
+
|
|
72
|
+
---
|
|
73
|
+
|
|
74
|
+
## License
|
|
75
|
+
|
|
76
|
+
MIT © [Albion Liçi](mailto:lici.albion@gmail.com)
|
package/auth/TSJWT.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JWT utilities (client-safe, read-only)
|
|
3
|
+
*
|
|
4
|
+
* Decode JWT payload without verification. For use in browser/client to read
|
|
5
|
+
* claims (e.g. exp for proactive refresh). Verification must be done server-side.
|
|
6
|
+
*
|
|
7
|
+
* No Node.js or crypto dependencies - uses atob and JSON.parse only.
|
|
8
|
+
*/
|
|
9
|
+
export interface JwtPayload {
|
|
10
|
+
exp?: number;
|
|
11
|
+
iat?: number;
|
|
12
|
+
sub?: string;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Decode JWT token without verification (client-side only, for reading claims).
|
|
17
|
+
*
|
|
18
|
+
* @param token - Raw JWT string (header.payload.signature)
|
|
19
|
+
* @returns Decoded payload or null if invalid/not a JWT
|
|
20
|
+
*/
|
|
21
|
+
export declare function decodeJWT(token: string): JwtPayload | null;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a decoded JWT payload is expired (exp claim in seconds since epoch).
|
|
24
|
+
*
|
|
25
|
+
* @param payload - Result of decodeJWT(token)
|
|
26
|
+
* @param nowMs - Optional current time in ms (default: Date.now())
|
|
27
|
+
* @returns true if exp is set and in the past
|
|
28
|
+
*/
|
|
29
|
+
export declare function isExpired(payload: JwtPayload | null, nowMs?: number): boolean;
|
package/auth/TSJWT.js
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* JWT utilities (client-safe, read-only)
|
|
4
|
+
*
|
|
5
|
+
* Decode JWT payload without verification. For use in browser/client to read
|
|
6
|
+
* claims (e.g. exp for proactive refresh). Verification must be done server-side.
|
|
7
|
+
*
|
|
8
|
+
* No Node.js or crypto dependencies - uses atob and JSON.parse only.
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.decodeJWT = decodeJWT;
|
|
12
|
+
exports.isExpired = isExpired;
|
|
13
|
+
/**
|
|
14
|
+
* Decode JWT token without verification (client-side only, for reading claims).
|
|
15
|
+
*
|
|
16
|
+
* @param token - Raw JWT string (header.payload.signature)
|
|
17
|
+
* @returns Decoded payload or null if invalid/not a JWT
|
|
18
|
+
*/
|
|
19
|
+
function decodeJWT(token) {
|
|
20
|
+
try {
|
|
21
|
+
var parts = token.split('.');
|
|
22
|
+
if (parts.length !== 3)
|
|
23
|
+
return null;
|
|
24
|
+
var payload = parts[1];
|
|
25
|
+
var decoded = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/')));
|
|
26
|
+
return decoded;
|
|
27
|
+
}
|
|
28
|
+
catch (_a) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Check if a decoded JWT payload is expired (exp claim in seconds since epoch).
|
|
34
|
+
*
|
|
35
|
+
* @param payload - Result of decodeJWT(token)
|
|
36
|
+
* @param nowMs - Optional current time in ms (default: Date.now())
|
|
37
|
+
* @returns true if exp is set and in the past
|
|
38
|
+
*/
|
|
39
|
+
function isExpired(payload, nowMs) {
|
|
40
|
+
if (nowMs === void 0) { nowMs = Date.now(); }
|
|
41
|
+
if (!(payload === null || payload === void 0 ? void 0 : payload.exp))
|
|
42
|
+
return false;
|
|
43
|
+
return payload.exp * 1000 < nowMs;
|
|
44
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Framework-agnostic OAuth client helpers for login, connect, and callback.
|
|
3
|
+
*
|
|
4
|
+
* Use from any client (React, Vue, mobile, etc.): build URLs, parse callback params,
|
|
5
|
+
* and classify providers (OAuth2 vs OAuth1 vs custom). Auth-service is the source of
|
|
6
|
+
* truth for provider registry; this module mirrors path conventions so any framework
|
|
7
|
+
* can drive login, callback, connect, and link flows without duplicating logic.
|
|
8
|
+
*
|
|
9
|
+
* @see docs/social-service.md §7.5 Client application: login and connect (any framework)
|
|
10
|
+
*/
|
|
11
|
+
/** OAuth2 provider ids: path segment /auth/oauth2/{id}. */
|
|
12
|
+
export declare const OAUTH2_PROVIDER_IDS: readonly ["google", "meta", "twitter", "linkedin", "reddit", "tiktok", "pinterest", "discord", "mastodon", "medium", "github", "whatsapp-meta", "tumblr", "yahoo", "snapchat", "snapchat-public-profile", "dribbble", "behance", "notion", "substack", "deviantart", "figma", "twitch", "ghost", "webflow"];
|
|
13
|
+
/** OAuth1 provider ids: path segment /auth/oauth1/{id}. */
|
|
14
|
+
export declare const OAUTH1_PROVIDER_IDS: readonly ["wordpress", "twitter-oauth1", "tumblr-oauth1"];
|
|
15
|
+
/** Custom providers: app shows /login/{id} (e.g. Telegram, Bluesky, WhatsApp); auth may still issue connect URL. */
|
|
16
|
+
export declare const CUSTOM_PROVIDER_IDS: readonly ["telegram", "bluesky", "whatsapp"];
|
|
17
|
+
export type OAuth2ProviderId = (typeof OAUTH2_PROVIDER_IDS)[number];
|
|
18
|
+
export type OAuth1ProviderId = (typeof OAUTH1_PROVIDER_IDS)[number];
|
|
19
|
+
export type CustomProviderId = (typeof CUSTOM_PROVIDER_IDS)[number];
|
|
20
|
+
/** URL param keys that indicate OAuth error; clients should clear them from the URL after showing the message. */
|
|
21
|
+
export declare const OAUTH_ERROR_PARAM_KEYS: readonly ["error", "provider"];
|
|
22
|
+
/** OAuth error code values (auth-service redirects with ?error=...). Single source of truth for app and auth. */
|
|
23
|
+
export declare const OAUTH_ERROR_AUTH_FAILED: "auth_failed";
|
|
24
|
+
export declare const OAUTH_ERROR_INVALID_USER: "invalid_user";
|
|
25
|
+
/** Snapchat: businessapi `public_profiles/my_profile` returned HTTP 403 (allowlisting / API not enabled). */
|
|
26
|
+
export declare const OAUTH_ERROR_SNAP_PUBLIC_PROFILE_FORBIDDEN: "snap_public_profile_forbidden";
|
|
27
|
+
export declare const OAUTH_ERROR_CODES: readonly ["auth_failed", "invalid_user", "snap_public_profile_forbidden"];
|
|
28
|
+
export type OAuthErrorCode = (typeof OAUTH_ERROR_CODES)[number];
|
|
29
|
+
export interface BuildLoginRedirectUrlOptions {
|
|
30
|
+
tenantId: string;
|
|
31
|
+
returnTo?: string;
|
|
32
|
+
scopeLayer?: 'minimal' | 'based' | 'full';
|
|
33
|
+
/** Origin of the app (e.g. window.location.origin). Required for custom providers so redirect goes to /login/{id}. */
|
|
34
|
+
appOrigin?: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build the full redirect URL for social login (OAuth2/OAuth1) or the app-relative path for custom providers.
|
|
38
|
+
* For custom providers, if appOrigin is given returns full URL `${appOrigin}/login/${providerId}?...`; otherwise returns path-only `/login/${providerId}?...`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function buildLoginRedirectUrl(authUrl: string, providerId: string, options: BuildLoginRedirectUrlOptions): string;
|
|
41
|
+
export interface BuildConnectUrlRequestOptions {
|
|
42
|
+
tenantId: string;
|
|
43
|
+
workspaceId?: string;
|
|
44
|
+
returnTo?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Passed to GET /auth/connect-url/...; auth-service emits `/auth/connect/oauth2/{id}/{layer}` when set.
|
|
47
|
+
* For social account linking (posting), use `full` so registry `scopeSets.full` applies (e.g. TikTok `video.publish`).
|
|
48
|
+
*/
|
|
49
|
+
scopeLayer?: 'minimal' | 'based' | 'full';
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build the URL for GET /auth/connect-url/:providerId (caller adds Bearer and fetches).
|
|
53
|
+
* Returns the request URL; the response body is JSON { url } or { errorCode }.
|
|
54
|
+
*/
|
|
55
|
+
export declare function buildConnectUrlRequestUrl(authUrl: string, providerId: string, options: BuildConnectUrlRequestOptions): string;
|
|
56
|
+
/** Error response from auth-service connect-url and other auth HTTP APIs. */
|
|
57
|
+
export interface AuthErrorResponse {
|
|
58
|
+
errorCode?: string;
|
|
59
|
+
}
|
|
60
|
+
export interface CallbackParams {
|
|
61
|
+
accessToken?: string | null;
|
|
62
|
+
refreshToken?: string | null;
|
|
63
|
+
userId?: string | null;
|
|
64
|
+
error?: string | null;
|
|
65
|
+
provider?: string | null;
|
|
66
|
+
returnTo?: string | null;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Parse OAuth callback query params (from returnTo after login or connect).
|
|
70
|
+
* Accepts URLSearchParams or search string. Framework-agnostic.
|
|
71
|
+
*/
|
|
72
|
+
export declare function parseCallbackParams(input: URLSearchParams | string): CallbackParams;
|
|
73
|
+
/**
|
|
74
|
+
* Whether the given params contain OAuth error keys (error or provider).
|
|
75
|
+
* Use to decide whether to show an error message and then clear params.
|
|
76
|
+
*/
|
|
77
|
+
export declare function hasOAuthErrorParams(params: URLSearchParams | string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Minimal user identity from callback params + JWT (for fallback when me query fails).
|
|
80
|
+
* Returns { id, tenantId } so any client can map to their User type.
|
|
81
|
+
*/
|
|
82
|
+
export declare function getUserIdFromCallbackParams(params: URLSearchParams | string, accessToken: string): {
|
|
83
|
+
id: string;
|
|
84
|
+
tenantId: string;
|
|
85
|
+
};
|
|
86
|
+
/** Optional labels for the iframe; defaults match the built-in copy. */
|
|
87
|
+
export interface CustomConnectIframeLabels {
|
|
88
|
+
/** Telegram: text above the widget. Default: "Sign in with Telegram." */
|
|
89
|
+
telegramSubtitle?: string;
|
|
90
|
+
/** Bluesky: text above the form. Default: "Handle and app password." */
|
|
91
|
+
blueskySubtitle?: string;
|
|
92
|
+
/** Bluesky: label for handle input. Default: "Handle" */
|
|
93
|
+
blueskyHandle?: string;
|
|
94
|
+
/** Bluesky: label for app password input. Default: "App password" */
|
|
95
|
+
blueskyAppPassword?: string;
|
|
96
|
+
/** Bluesky: submit button. Default: "Sign in" */
|
|
97
|
+
blueskySubmit?: string;
|
|
98
|
+
/** WhatsApp: text above the form. Default: "Phone (with country code)." */
|
|
99
|
+
whatsappSubtitle?: string;
|
|
100
|
+
/** WhatsApp: label for phone input. Default: "Phone" */
|
|
101
|
+
whatsappPhone?: string;
|
|
102
|
+
/** WhatsApp: label for display name input. Default: "Name (optional)" */
|
|
103
|
+
whatsappName?: string;
|
|
104
|
+
/** WhatsApp: submit button. Default: "Sign in" */
|
|
105
|
+
whatsappSubmit?: string;
|
|
106
|
+
}
|
|
107
|
+
export interface BuildCustomConnectIframeUrlOptions {
|
|
108
|
+
/** Auth service URL/path (e.g. /api/auth; forms POST to authUrl/auth/custom/:provider). */
|
|
109
|
+
authUrl: string;
|
|
110
|
+
tenantId: string;
|
|
111
|
+
returnTo?: string;
|
|
112
|
+
state?: string;
|
|
113
|
+
/** When true, form target="_top" so redirect replaces entire page (e.g. close iframe context). */
|
|
114
|
+
embed?: boolean;
|
|
115
|
+
/** Light or dark; applied as data-theme in iframe. */
|
|
116
|
+
theme?: 'light' | 'dark';
|
|
117
|
+
/** Override title text (e.g. "Connect with Telegram"). */
|
|
118
|
+
title?: string;
|
|
119
|
+
/** Telegram bot username (no @); required for Telegram widget. */
|
|
120
|
+
telegramBotUsername?: string;
|
|
121
|
+
/** Override labels in the iframe (blueskyHandle, blueskySubmit, etc.); defaults match built-in copy. */
|
|
122
|
+
labels?: Partial<CustomConnectIframeLabels>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Build the URL for the shared custom-connect iframe page (when you serve the page at iframePageUrl).
|
|
126
|
+
*/
|
|
127
|
+
export declare function buildCustomConnectIframeUrl(iframePageUrl: string, providerId: string, options: BuildCustomConnectIframeUrlOptions): string;
|
|
128
|
+
/**
|
|
129
|
+
* Build the iframe document as an HTML string for use with iframe.srcdoc.
|
|
130
|
+
* Config inlined; minimal styles and script. For same-origin use, serve a page that calls this and document.write().
|
|
131
|
+
*/
|
|
132
|
+
export declare function getCustomConnectIframeSrcdoc(providerId: string, options: BuildCustomConnectIframeUrlOptions): string;
|
package/auth/TSOAuth.js
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Framework-agnostic OAuth client helpers for login, connect, and callback.
|
|
4
|
+
*
|
|
5
|
+
* Use from any client (React, Vue, mobile, etc.): build URLs, parse callback params,
|
|
6
|
+
* and classify providers (OAuth2 vs OAuth1 vs custom). Auth-service is the source of
|
|
7
|
+
* truth for provider registry; this module mirrors path conventions so any framework
|
|
8
|
+
* can drive login, callback, connect, and link flows without duplicating logic.
|
|
9
|
+
*
|
|
10
|
+
* @see docs/social-service.md §7.5 Client application: login and connect (any framework)
|
|
11
|
+
*/
|
|
12
|
+
var __assign = (this && this.__assign) || function () {
|
|
13
|
+
__assign = Object.assign || function(t) {
|
|
14
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
15
|
+
s = arguments[i];
|
|
16
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
17
|
+
t[p] = s[p];
|
|
18
|
+
}
|
|
19
|
+
return t;
|
|
20
|
+
};
|
|
21
|
+
return __assign.apply(this, arguments);
|
|
22
|
+
};
|
|
23
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
24
|
+
exports.OAUTH_ERROR_CODES = exports.OAUTH_ERROR_SNAP_PUBLIC_PROFILE_FORBIDDEN = exports.OAUTH_ERROR_INVALID_USER = exports.OAUTH_ERROR_AUTH_FAILED = exports.OAUTH_ERROR_PARAM_KEYS = exports.CUSTOM_PROVIDER_IDS = exports.OAUTH1_PROVIDER_IDS = exports.OAUTH2_PROVIDER_IDS = void 0;
|
|
25
|
+
exports.buildLoginRedirectUrl = buildLoginRedirectUrl;
|
|
26
|
+
exports.buildConnectUrlRequestUrl = buildConnectUrlRequestUrl;
|
|
27
|
+
exports.parseCallbackParams = parseCallbackParams;
|
|
28
|
+
exports.hasOAuthErrorParams = hasOAuthErrorParams;
|
|
29
|
+
exports.getUserIdFromCallbackParams = getUserIdFromCallbackParams;
|
|
30
|
+
exports.buildCustomConnectIframeUrl = buildCustomConnectIframeUrl;
|
|
31
|
+
exports.getCustomConnectIframeSrcdoc = getCustomConnectIframeSrcdoc;
|
|
32
|
+
var TSJWT_js_1 = require("./TSJWT.js");
|
|
33
|
+
// --- Provider lists (mirror auth-service path conventions) --------------------
|
|
34
|
+
/** OAuth2 provider ids: path segment /auth/oauth2/{id}. */
|
|
35
|
+
exports.OAUTH2_PROVIDER_IDS = [
|
|
36
|
+
'google', 'meta', 'twitter', 'linkedin', 'reddit', 'tiktok', 'pinterest', 'discord',
|
|
37
|
+
'mastodon', 'medium', 'github', 'whatsapp-meta', 'tumblr', 'yahoo', 'snapchat', 'snapchat-public-profile', 'dribbble', 'behance', 'notion',
|
|
38
|
+
'substack', 'deviantart', 'figma', 'twitch', 'ghost', 'webflow'
|
|
39
|
+
];
|
|
40
|
+
/** OAuth1 provider ids: path segment /auth/oauth1/{id}. */
|
|
41
|
+
exports.OAUTH1_PROVIDER_IDS = ['wordpress', 'twitter-oauth1', 'tumblr-oauth1'];
|
|
42
|
+
/** Custom providers: app shows /login/{id} (e.g. Telegram, Bluesky, WhatsApp); auth may still issue connect URL. */
|
|
43
|
+
exports.CUSTOM_PROVIDER_IDS = ['telegram', 'bluesky', 'whatsapp'];
|
|
44
|
+
/** URL param keys that indicate OAuth error; clients should clear them from the URL after showing the message. */
|
|
45
|
+
exports.OAUTH_ERROR_PARAM_KEYS = ['error', 'provider'];
|
|
46
|
+
/** OAuth error code values (auth-service redirects with ?error=...). Single source of truth for app and auth. */
|
|
47
|
+
exports.OAUTH_ERROR_AUTH_FAILED = 'auth_failed';
|
|
48
|
+
exports.OAUTH_ERROR_INVALID_USER = 'invalid_user';
|
|
49
|
+
/** Snapchat: businessapi `public_profiles/my_profile` returned HTTP 403 (allowlisting / API not enabled). */
|
|
50
|
+
exports.OAUTH_ERROR_SNAP_PUBLIC_PROFILE_FORBIDDEN = 'snap_public_profile_forbidden';
|
|
51
|
+
exports.OAUTH_ERROR_CODES = [
|
|
52
|
+
exports.OAUTH_ERROR_AUTH_FAILED,
|
|
53
|
+
exports.OAUTH_ERROR_INVALID_USER,
|
|
54
|
+
exports.OAUTH_ERROR_SNAP_PUBLIC_PROFILE_FORBIDDEN
|
|
55
|
+
];
|
|
56
|
+
/**
|
|
57
|
+
* Build the full redirect URL for social login (OAuth2/OAuth1) or the app-relative path for custom providers.
|
|
58
|
+
* For custom providers, if appOrigin is given returns full URL `${appOrigin}/login/${providerId}?...`; otherwise returns path-only `/login/${providerId}?...`.
|
|
59
|
+
*/
|
|
60
|
+
function buildLoginRedirectUrl(authUrl, providerId, options) {
|
|
61
|
+
var tenantId = options.tenantId, returnTo = options.returnTo, scopeLayer = options.scopeLayer, appOrigin = options.appOrigin;
|
|
62
|
+
var query = new URLSearchParams({ tenantId: tenantId });
|
|
63
|
+
if (returnTo)
|
|
64
|
+
query.set('returnTo', returnTo);
|
|
65
|
+
var qs = query.toString();
|
|
66
|
+
var scopeSeg = scopeLayer === 'minimal' || scopeLayer === 'based' || scopeLayer === 'full' ? "/".concat(scopeLayer) : '';
|
|
67
|
+
if (exports.CUSTOM_PROVIDER_IDS.indexOf(providerId) !== -1) {
|
|
68
|
+
var path = "/login/".concat(providerId, "?").concat(qs);
|
|
69
|
+
return appOrigin ? "".concat(appOrigin.replace(/\/$/, '')).concat(path) : path;
|
|
70
|
+
}
|
|
71
|
+
if (exports.OAUTH1_PROVIDER_IDS.indexOf(providerId) !== -1) {
|
|
72
|
+
return "".concat(authUrl.replace(/\/$/, ''), "/auth/oauth1/").concat(providerId).concat(scopeSeg, "?").concat(qs);
|
|
73
|
+
}
|
|
74
|
+
return "".concat(authUrl.replace(/\/$/, ''), "/auth/oauth2/").concat(providerId).concat(scopeSeg, "?").concat(qs);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Build the URL for GET /auth/connect-url/:providerId (caller adds Bearer and fetches).
|
|
78
|
+
* Returns the request URL; the response body is JSON { url } or { errorCode }.
|
|
79
|
+
*/
|
|
80
|
+
function buildConnectUrlRequestUrl(authUrl, providerId, options) {
|
|
81
|
+
var tenantId = options.tenantId, workspaceId = options.workspaceId, returnTo = options.returnTo, scopeLayer = options.scopeLayer;
|
|
82
|
+
var params = new URLSearchParams({ tenantId: tenantId });
|
|
83
|
+
if (workspaceId)
|
|
84
|
+
params.set('workspaceId', workspaceId);
|
|
85
|
+
if (returnTo)
|
|
86
|
+
params.set('returnTo', returnTo);
|
|
87
|
+
if (scopeLayer)
|
|
88
|
+
params.set('scopeLayer', scopeLayer);
|
|
89
|
+
var base = authUrl.replace(/\/$/, '');
|
|
90
|
+
return "".concat(base, "/auth/connect-url/").concat(encodeURIComponent(providerId), "?").concat(params.toString());
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Parse OAuth callback query params (from returnTo after login or connect).
|
|
94
|
+
* Accepts URLSearchParams or search string. Framework-agnostic.
|
|
95
|
+
*/
|
|
96
|
+
function parseCallbackParams(input) {
|
|
97
|
+
var _a, _b, _c, _d, _e, _f;
|
|
98
|
+
var params = typeof input === 'string' ? new URLSearchParams(input) : input;
|
|
99
|
+
return {
|
|
100
|
+
accessToken: (_a = params.get('accessToken')) !== null && _a !== void 0 ? _a : undefined,
|
|
101
|
+
refreshToken: (_b = params.get('refreshToken')) !== null && _b !== void 0 ? _b : undefined,
|
|
102
|
+
userId: (_c = params.get('userId')) !== null && _c !== void 0 ? _c : undefined,
|
|
103
|
+
error: (_d = params.get('error')) !== null && _d !== void 0 ? _d : undefined,
|
|
104
|
+
provider: (_e = params.get('provider')) !== null && _e !== void 0 ? _e : undefined,
|
|
105
|
+
returnTo: (_f = params.get('returnTo')) !== null && _f !== void 0 ? _f : undefined
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Whether the given params contain OAuth error keys (error or provider).
|
|
110
|
+
* Use to decide whether to show an error message and then clear params.
|
|
111
|
+
*/
|
|
112
|
+
function hasOAuthErrorParams(params) {
|
|
113
|
+
var p = typeof params === 'string' ? new URLSearchParams(params) : params;
|
|
114
|
+
return exports.OAUTH_ERROR_PARAM_KEYS.some(function (key) { return p.has(key); });
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Minimal user identity from callback params + JWT (for fallback when me query fails).
|
|
118
|
+
* Returns { id, tenantId } so any client can map to their User type.
|
|
119
|
+
*/
|
|
120
|
+
function getUserIdFromCallbackParams(params, accessToken) {
|
|
121
|
+
var p = typeof params === 'string' ? new URLSearchParams(params) : params;
|
|
122
|
+
var payload = (0, TSJWT_js_1.decodeJWT)(accessToken);
|
|
123
|
+
var id = p.get('userId') || (payload === null || payload === void 0 ? void 0 : payload.sub) || '';
|
|
124
|
+
var tenantId = (payload === null || payload === void 0 ? void 0 : payload.tid) || p.get('tenantId') || '';
|
|
125
|
+
return { id: id, tenantId: tenantId };
|
|
126
|
+
}
|
|
127
|
+
var DEFAULT_IFRAME_LABELS = {
|
|
128
|
+
telegramSubtitle: 'Sign in with Telegram.',
|
|
129
|
+
blueskySubtitle: 'Handle and app password.',
|
|
130
|
+
blueskyHandle: 'Handle',
|
|
131
|
+
blueskyAppPassword: 'App password',
|
|
132
|
+
blueskySubmit: 'Sign in',
|
|
133
|
+
whatsappSubtitle: 'Phone (with country code).',
|
|
134
|
+
whatsappPhone: 'Phone',
|
|
135
|
+
whatsappName: 'Name (optional)',
|
|
136
|
+
whatsappSubmit: 'Sign in'
|
|
137
|
+
};
|
|
138
|
+
/** Normalized options for custom connect iframe (shared by URL builder and srcdoc builder). */
|
|
139
|
+
function normalizeCustomConnectOptions(providerId, options) {
|
|
140
|
+
var _a, _b, _c, _d, _e, _f;
|
|
141
|
+
return {
|
|
142
|
+
authUrl: options.authUrl.replace(/\/$/, ''),
|
|
143
|
+
tenantId: options.tenantId,
|
|
144
|
+
returnTo: (_a = options.returnTo) !== null && _a !== void 0 ? _a : '',
|
|
145
|
+
state: (_b = options.state) !== null && _b !== void 0 ? _b : '',
|
|
146
|
+
embed: options.embed === true,
|
|
147
|
+
theme: ((_c = options.theme) !== null && _c !== void 0 ? _c : 'light'),
|
|
148
|
+
title: (_d = options.title) !== null && _d !== void 0 ? _d : "Connect with ".concat(providerId.charAt(0).toUpperCase() + providerId.slice(1)),
|
|
149
|
+
telegramBotUsername: (_f = (providerId === 'telegram' ? (_e = options.telegramBotUsername) === null || _e === void 0 ? void 0 : _e.replace(/^@/, '') : '')) !== null && _f !== void 0 ? _f : ''
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Build the URL for the shared custom-connect iframe page (when you serve the page at iframePageUrl).
|
|
154
|
+
*/
|
|
155
|
+
function buildCustomConnectIframeUrl(iframePageUrl, providerId, options) {
|
|
156
|
+
if (exports.CUSTOM_PROVIDER_IDS.indexOf(providerId) === -1) {
|
|
157
|
+
throw new Error("Unknown custom provider: ".concat(providerId, ". Use one of: ").concat(exports.CUSTOM_PROVIDER_IDS.join(', ')));
|
|
158
|
+
}
|
|
159
|
+
var n = normalizeCustomConnectOptions(providerId, options);
|
|
160
|
+
var params = new URLSearchParams();
|
|
161
|
+
params.set('provider', providerId);
|
|
162
|
+
params.set('authUrl', n.authUrl);
|
|
163
|
+
params.set('tenantId', n.tenantId);
|
|
164
|
+
if (n.returnTo)
|
|
165
|
+
params.set('returnTo', n.returnTo);
|
|
166
|
+
if (n.state)
|
|
167
|
+
params.set('state', n.state);
|
|
168
|
+
if (n.embed)
|
|
169
|
+
params.set('embed', '1');
|
|
170
|
+
params.set('theme', n.theme);
|
|
171
|
+
params.set('title', n.title);
|
|
172
|
+
if (n.telegramBotUsername && providerId === 'telegram')
|
|
173
|
+
params.set('telegramBotUsername', n.telegramBotUsername);
|
|
174
|
+
var base = iframePageUrl.replace(/\?.*$/, '').replace(/#.*$/, '');
|
|
175
|
+
return "".concat(base, "?").concat(params.toString());
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Build the iframe document as an HTML string for use with iframe.srcdoc.
|
|
179
|
+
* Config inlined; minimal styles and script. For same-origin use, serve a page that calls this and document.write().
|
|
180
|
+
*/
|
|
181
|
+
function getCustomConnectIframeSrcdoc(providerId, options) {
|
|
182
|
+
if (exports.CUSTOM_PROVIDER_IDS.indexOf(providerId) === -1) {
|
|
183
|
+
throw new Error("Unknown custom provider: ".concat(providerId, ". Use one of: ").concat(exports.CUSTOM_PROVIDER_IDS.join(', ')));
|
|
184
|
+
}
|
|
185
|
+
var n = normalizeCustomConnectOptions(providerId, options);
|
|
186
|
+
var labels = __assign(__assign({}, DEFAULT_IFRAME_LABELS), options.labels);
|
|
187
|
+
var config = {
|
|
188
|
+
providerId: providerId,
|
|
189
|
+
authUrl: n.authUrl,
|
|
190
|
+
tenantId: n.tenantId,
|
|
191
|
+
returnTo: n.returnTo,
|
|
192
|
+
state: n.state,
|
|
193
|
+
embed: n.embed,
|
|
194
|
+
theme: n.theme,
|
|
195
|
+
title: n.title,
|
|
196
|
+
telegramBotUsername: n.telegramBotUsername
|
|
197
|
+
};
|
|
198
|
+
var configJson = JSON.stringify(config).replace(/</g, '\\u003c').replace(/>/g, '\\u003e');
|
|
199
|
+
var buildAction = function (path) {
|
|
200
|
+
var u = n.authUrl + path + '?tenantId=' + encodeURIComponent(n.tenantId);
|
|
201
|
+
if (n.returnTo)
|
|
202
|
+
u += '&returnTo=' + encodeURIComponent(n.returnTo);
|
|
203
|
+
if (n.state)
|
|
204
|
+
u += '&state=' + encodeURIComponent(n.state);
|
|
205
|
+
return u;
|
|
206
|
+
};
|
|
207
|
+
var target = n.embed ? '_top' : '_self';
|
|
208
|
+
var bodyContent = '';
|
|
209
|
+
if (providerId === 'telegram') {
|
|
210
|
+
bodyContent = n.telegramBotUsername
|
|
211
|
+
? "<p>".concat(escapeHtml(labels.telegramSubtitle), "</p><div id=\"w\"></div><script>\nvar c=JSON.parse(document.getElementById(\"cfg\").textContent);\nwindow.onTelegramAuth=function(user){\n var f=document.createElement(\"form\");f.method=\"POST\";f.action=c.authUrl+\"/auth/custom/telegram?tenantId=\"+encodeURIComponent(c.tenantId)+(c.returnTo?\"&returnTo=\"+encodeURIComponent(c.returnTo):\"\")+(c.state?\"&state=\"+encodeURIComponent(c.state):\"\");f.target=\"").concat(target, "\";f.enctype=\"application/x-www-form-urlencoded\";\n [\"id\",\"first_name\",\"last_name\",\"username\",\"photo_url\",\"auth_date\",\"hash\"].forEach(function(k){if(user[k]==null)return;var i=document.createElement(\"input\");i.type=\"hidden\";i.name=k;i.value=String(user[k]);f.appendChild(i);});\n document.body.appendChild(f);f.submit();\n};\nvar s=document.createElement(\"script\");s.src=\"https://telegram.org/js/telegram-widget.js?23\";s.setAttribute(\"data-telegram-login\",\"").concat(n.telegramBotUsername.replace(/"/g, '"'), "\");s.setAttribute(\"data-size\",\"large\");s.setAttribute(\"data-onauth\",\"onTelegramAuth(user)\");s.setAttribute(\"data-request-access\",\"write\");s.async=true;document.getElementById(\"w\").appendChild(s);\n</script>")
|
|
212
|
+
: '<p class="err">Missing telegramBotUsername.</p>';
|
|
213
|
+
}
|
|
214
|
+
else if (providerId === 'bluesky') {
|
|
215
|
+
var action = buildAction('/auth/custom/bluesky');
|
|
216
|
+
bodyContent = "<p>".concat(escapeHtml(labels.blueskySubtitle), "</p><form action=\"").concat(action.replace(/"/g, '"'), "\" method=\"POST\" target=\"").concat(target, "\">\n<label>").concat(escapeHtml(labels.blueskyHandle), "</label><input name=\"identifier\" type=\"text\" placeholder=\"you.bsky.social\" required>\n<label>").concat(escapeHtml(labels.blueskyAppPassword), "</label><input name=\"appPassword\" type=\"password\" placeholder=\"xxxx-xxxx-xxxx\" required>\n<button type=\"submit\">").concat(escapeHtml(labels.blueskySubmit), "</button></form>");
|
|
217
|
+
}
|
|
218
|
+
else if (providerId === 'whatsapp') {
|
|
219
|
+
var action = buildAction('/auth/custom/whatsapp');
|
|
220
|
+
bodyContent = "<p>".concat(escapeHtml(labels.whatsappSubtitle), "</p><form action=\"").concat(action.replace(/"/g, '"'), "\" method=\"POST\" target=\"").concat(target, "\">\n<label>").concat(escapeHtml(labels.whatsappPhone), "</label><input name=\"whatsappId\" type=\"tel\" placeholder=\"+1234567890\" required>\n<label>").concat(escapeHtml(labels.whatsappName), "</label><input name=\"displayName\" type=\"text\">\n<button type=\"submit\">").concat(escapeHtml(labels.whatsappSubmit), "</button></form>");
|
|
221
|
+
}
|
|
222
|
+
return "<!DOCTYPE html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>\nbody{font-family:system-ui,sans-serif;margin:0;padding:12px;min-height:100vh;display:flex;flex-direction:column;align-items:center;justify-content:center;box-sizing:border-box;background:".concat(n.theme === 'dark' ? '#1a1a2e' : '#f8fafc', ";color:").concat(n.theme === 'dark' ? '#e2e8f0' : '#1e293b', ";}\nh1{margin:0 0 8px;font-size:1.1rem;}\np{margin:0 0 12px;font-size:0.85rem;color:#64748b;}\nform{display:flex;flex-direction:column;gap:8px;}\nlabel{font-size:0.85rem;}\ninput{padding:6px 10px;border:1px solid #cbd5e1;border-radius:6px;}\nbutton{padding:8px 12px;border:none;border-radius:6px;background:#1185fe;color:#fff;cursor:pointer;}\n.err{color:#dc2626;}\n</style></head><body><h1>").concat(escapeHtml(n.title), "</h1><script type=\"application/json\" id=\"cfg\">").concat(configJson, "</script>").concat(bodyContent, "</body></html>");
|
|
223
|
+
}
|
|
224
|
+
function escapeHtml(s) {
|
|
225
|
+
return s
|
|
226
|
+
.replace(/&/g, '&')
|
|
227
|
+
.replace(/</g, '<')
|
|
228
|
+
.replace(/>/g, '>')
|
|
229
|
+
.replace(/"/g, '"');
|
|
230
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TSCordova = void 0;
|
|
4
|
+
function _window() {
|
|
5
|
+
return window;
|
|
6
|
+
}
|
|
7
|
+
var TSCordova = /** @class */ (function () {
|
|
8
|
+
function TSCordova() {
|
|
9
|
+
}
|
|
10
|
+
TSCordova.bootstrap = function (closure) {
|
|
11
|
+
if (TSCordova.isCordova()) {
|
|
12
|
+
console.log('Bootstrapped with Cordova');
|
|
13
|
+
var script = document.createElement('script');
|
|
14
|
+
script.type = 'text/javascript';
|
|
15
|
+
script.src = 'cordova.js';
|
|
16
|
+
document.head.appendChild(script);
|
|
17
|
+
var legacyScript_1 = script;
|
|
18
|
+
if (legacyScript_1.readyState) {
|
|
19
|
+
legacyScript_1.onreadystatechange = function () {
|
|
20
|
+
if (legacyScript_1.readyState === 'loaded' || legacyScript_1.readyState === 'complete') {
|
|
21
|
+
document.addEventListener('deviceready', closure, false);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
document.addEventListener('deviceready', closure, false);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
closure();
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
TSCordova.bind = function (plugin, closure) {
|
|
34
|
+
if (typeof cordova !== 'undefined') {
|
|
35
|
+
if (Object.hasOwn(cordova.plugins, plugin)) {
|
|
36
|
+
closure(cordova.plugins[plugin]);
|
|
37
|
+
}
|
|
38
|
+
else if (Object.hasOwn(_window().plugins, plugin)) {
|
|
39
|
+
closure(_window().plugins[plugin]);
|
|
40
|
+
}
|
|
41
|
+
else if (Object.hasOwn(_window(), plugin)) {
|
|
42
|
+
closure(_window()[plugin]);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
TSCordova.isCordova = function () {
|
|
47
|
+
// Global || Local
|
|
48
|
+
return typeof _isCordova !== 'undefined' || (document.URL.indexOf('http://') === -1 && document.URL.indexOf('https://') === -1);
|
|
49
|
+
};
|
|
50
|
+
return TSCordova;
|
|
51
|
+
}());
|
|
52
|
+
exports.TSCordova = TSCordova;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface TSCountry {
|
|
2
|
+
alpha2: string;
|
|
3
|
+
alpha3: string;
|
|
4
|
+
dial: Array<string>;
|
|
5
|
+
currencies: Array<string>;
|
|
6
|
+
emoji?: string;
|
|
7
|
+
ioc: string;
|
|
8
|
+
languages: Array<string>;
|
|
9
|
+
name: string;
|
|
10
|
+
status: string;
|
|
11
|
+
}
|
|
12
|
+
export declare const TSCountries: {
|
|
13
|
+
[k: string]: TSCountry | any;
|
|
14
|
+
};
|