@serialsubscriptions/platform-integration 0.0.79
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 +1 -0
- package/lib/SSIProject.d.ts +343 -0
- package/lib/SSIProject.js +429 -0
- package/lib/SSIProjectApi.d.ts +384 -0
- package/lib/SSIProjectApi.js +534 -0
- package/lib/SSISubscribedFeatureApi.d.ts +387 -0
- package/lib/SSISubscribedFeatureApi.js +511 -0
- package/lib/SSISubscribedLimitApi.d.ts +384 -0
- package/lib/SSISubscribedLimitApi.js +534 -0
- package/lib/SSISubscribedPlanApi.d.ts +384 -0
- package/lib/SSISubscribedPlanApi.js +537 -0
- package/lib/SubscribedPlanManager.d.ts +380 -0
- package/lib/SubscribedPlanManager.js +288 -0
- package/lib/UsageApi.d.ts +128 -0
- package/lib/UsageApi.js +224 -0
- package/lib/auth.server.d.ts +192 -0
- package/lib/auth.server.js +579 -0
- package/lib/cache/SSICache.d.ts +40 -0
- package/lib/cache/SSICache.js +134 -0
- package/lib/cache/backends/MemoryCacheBackend.d.ts +15 -0
- package/lib/cache/backends/MemoryCacheBackend.js +46 -0
- package/lib/cache/backends/RedisCacheBackend.d.ts +27 -0
- package/lib/cache/backends/RedisCacheBackend.js +95 -0
- package/lib/cache/constants.d.ts +7 -0
- package/lib/cache/constants.js +10 -0
- package/lib/cache/types.d.ts +27 -0
- package/lib/cache/types.js +2 -0
- package/lib/frontend/index.d.ts +1 -0
- package/lib/frontend/index.js +6 -0
- package/lib/frontend/session/SessionClient.d.ts +24 -0
- package/lib/frontend/session/SessionClient.js +145 -0
- package/lib/index.d.ts +15 -0
- package/lib/index.js +38 -0
- package/lib/lib/session/SessionClient.d.ts +11 -0
- package/lib/lib/session/SessionClient.js +47 -0
- package/lib/lib/session/index.d.ts +3 -0
- package/lib/lib/session/index.js +3 -0
- package/lib/lib/session/stores/MemoryStore.d.ts +7 -0
- package/lib/lib/session/stores/MemoryStore.js +23 -0
- package/lib/lib/session/stores/index.d.ts +1 -0
- package/lib/lib/session/stores/index.js +1 -0
- package/lib/lib/session/types.d.ts +37 -0
- package/lib/lib/session/types.js +1 -0
- package/lib/session/SessionClient.d.ts +19 -0
- package/lib/session/SessionClient.js +132 -0
- package/lib/session/SessionManager.d.ts +139 -0
- package/lib/session/SessionManager.js +443 -0
- package/lib/stateStore.d.ts +5 -0
- package/lib/stateStore.js +9 -0
- package/lib/storage/SSIStorage.d.ts +24 -0
- package/lib/storage/SSIStorage.js +117 -0
- package/lib/storage/backends/MemoryBackend.d.ts +10 -0
- package/lib/storage/backends/MemoryBackend.js +44 -0
- package/lib/storage/backends/PostgresBackend.d.ts +24 -0
- package/lib/storage/backends/PostgresBackend.js +106 -0
- package/lib/storage/backends/RedisBackend.d.ts +19 -0
- package/lib/storage/backends/RedisBackend.js +78 -0
- package/lib/storage/types.d.ts +27 -0
- package/lib/storage/types.js +2 -0
- package/package.json +71 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { SessionStore } from '../types';
|
|
2
|
+
export declare class MemoryStore implements SessionStore {
|
|
3
|
+
private map;
|
|
4
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
5
|
+
set<T = unknown>(key: string, value: T, ttlSec?: number): Promise<void>;
|
|
6
|
+
del(key: string): Promise<void>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export class MemoryStore {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.map = new Map();
|
|
4
|
+
}
|
|
5
|
+
async get(key) {
|
|
6
|
+
const now = Date.now();
|
|
7
|
+
const hit = this.map.get(key);
|
|
8
|
+
if (!hit)
|
|
9
|
+
return null;
|
|
10
|
+
if (hit.expiresAt !== undefined && hit.expiresAt <= now) {
|
|
11
|
+
this.map.delete(key);
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
return hit.value;
|
|
15
|
+
}
|
|
16
|
+
async set(key, value, ttlSec) {
|
|
17
|
+
const expiresAt = ttlSec !== undefined && ttlSec > 0 ? Date.now() + ttlSec * 1000 : undefined;
|
|
18
|
+
this.map.set(key, { value, expiresAt });
|
|
19
|
+
}
|
|
20
|
+
async del(key) {
|
|
21
|
+
this.map.delete(key);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MemoryStore } from './MemoryStore';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MemoryStore } from './MemoryStore';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export interface SessionStore {
|
|
2
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
3
|
+
set<T = unknown>(key: string, value: T, ttlSec?: number): Promise<void>;
|
|
4
|
+
del(key: string): Promise<void>;
|
|
5
|
+
}
|
|
6
|
+
export type SameSite = 'lax' | 'strict' | 'none';
|
|
7
|
+
export interface JWKSOptions {
|
|
8
|
+
issuer: string;
|
|
9
|
+
jwksUri: string;
|
|
10
|
+
cacheTtlSec?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface RequiredClaims {
|
|
13
|
+
sub: string;
|
|
14
|
+
organization_id?: number | string;
|
|
15
|
+
role?: string;
|
|
16
|
+
[k: string]: unknown;
|
|
17
|
+
}
|
|
18
|
+
export interface SessionClientInit {
|
|
19
|
+
store: SessionStore;
|
|
20
|
+
refresh?: {
|
|
21
|
+
endpoint: string;
|
|
22
|
+
graceSec?: number;
|
|
23
|
+
defaultTtlSec?: number;
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export interface TokenBundle {
|
|
27
|
+
id_token: string;
|
|
28
|
+
access_token: string;
|
|
29
|
+
refresh_token?: string;
|
|
30
|
+
ttlSec?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface SessionSnapshot {
|
|
33
|
+
claims: unknown | null;
|
|
34
|
+
access_token: string | null;
|
|
35
|
+
id_token: string | null;
|
|
36
|
+
refresh_token: string | null;
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare class SessionClient {
|
|
2
|
+
private readonly cookieHeader?;
|
|
3
|
+
private static readonly instances;
|
|
4
|
+
private readonly baseUrl;
|
|
5
|
+
private claims;
|
|
6
|
+
private ttl;
|
|
7
|
+
private initPromise;
|
|
8
|
+
private static normalizeBaseUrl;
|
|
9
|
+
constructor(baseUrl?: string, cookieHeader?: string | null | undefined);
|
|
10
|
+
static getSessionManager(baseUrl?: string): SessionClient;
|
|
11
|
+
isLoggedIn(): Promise<boolean>;
|
|
12
|
+
warmup(): void;
|
|
13
|
+
getTtl(): Promise<number | null>;
|
|
14
|
+
get(claimName: string): Promise<unknown>;
|
|
15
|
+
getAll(): Promise<unknown | null>;
|
|
16
|
+
private withSession;
|
|
17
|
+
private loadClaims;
|
|
18
|
+
}
|
|
19
|
+
export default SessionClient;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
export class SessionClient {
|
|
2
|
+
static normalizeBaseUrl(baseUrl) {
|
|
3
|
+
if (!baseUrl) {
|
|
4
|
+
return "";
|
|
5
|
+
}
|
|
6
|
+
try {
|
|
7
|
+
const url = new URL(baseUrl);
|
|
8
|
+
// Remove trailing slash and default ports
|
|
9
|
+
url.pathname = url.pathname.replace(/\/$/, "");
|
|
10
|
+
if ((url.protocol === "https:" && url.port === "443") || (url.protocol === "http:" && url.port === "80")) {
|
|
11
|
+
url.port = "";
|
|
12
|
+
}
|
|
13
|
+
return url.toString().replace(/\/$/, "");
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return baseUrl;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
constructor(baseUrl, cookieHeader) {
|
|
20
|
+
this.cookieHeader = cookieHeader;
|
|
21
|
+
this.claims = null;
|
|
22
|
+
this.ttl = null;
|
|
23
|
+
const resolvedBaseUrl = baseUrl ?? process.env.NEXT_PUBLIC_BASE_URL ?? "";
|
|
24
|
+
this.baseUrl = SessionClient.normalizeBaseUrl(resolvedBaseUrl);
|
|
25
|
+
if (!this.baseUrl || !this.baseUrl.startsWith("http://") && !this.baseUrl.startsWith("https://")) {
|
|
26
|
+
console.error(`You must set baseUrl to SessionClient or you must set env variable NEXT_PUBLIC_BASE_URL. Incorrect value \`${resolvedBaseUrl}\``);
|
|
27
|
+
}
|
|
28
|
+
this.initPromise = this.loadClaims();
|
|
29
|
+
}
|
|
30
|
+
static getSessionManager(baseUrl) {
|
|
31
|
+
const resolvedBaseUrl = baseUrl ?? process.env.NEXT_PUBLIC_BASE_URL ?? "";
|
|
32
|
+
const normalizedBaseUrl = SessionClient.normalizeBaseUrl(resolvedBaseUrl);
|
|
33
|
+
if (!normalizedBaseUrl || !normalizedBaseUrl.startsWith("http://") && !normalizedBaseUrl.startsWith("https://")) {
|
|
34
|
+
console.error(`You must set baseUrl to SessionClient or you must set env variable NEXT_PUBLIC_BASE_URL. Incorrect value \`${resolvedBaseUrl}\``);
|
|
35
|
+
}
|
|
36
|
+
if (!SessionClient.instances.has(normalizedBaseUrl)) {
|
|
37
|
+
SessionClient.instances.set(normalizedBaseUrl, new SessionClient(baseUrl));
|
|
38
|
+
}
|
|
39
|
+
return SessionClient.instances.get(normalizedBaseUrl);
|
|
40
|
+
}
|
|
41
|
+
async isLoggedIn() {
|
|
42
|
+
await this.initPromise;
|
|
43
|
+
return this.claims != null;
|
|
44
|
+
}
|
|
45
|
+
// Non-awaiting stub to ensure initialization happens without blocking
|
|
46
|
+
warmup() {
|
|
47
|
+
void this.initPromise;
|
|
48
|
+
}
|
|
49
|
+
async getTtl() {
|
|
50
|
+
await this.initPromise;
|
|
51
|
+
return this.ttl;
|
|
52
|
+
}
|
|
53
|
+
async get(claimName) {
|
|
54
|
+
await this.initPromise;
|
|
55
|
+
if (this.claims && typeof this.claims === "object") {
|
|
56
|
+
const record = this.claims;
|
|
57
|
+
return record[claimName];
|
|
58
|
+
}
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
async getAll() {
|
|
62
|
+
await this.initPromise;
|
|
63
|
+
return this.claims;
|
|
64
|
+
}
|
|
65
|
+
async withSession(init = {}) {
|
|
66
|
+
if (this.cookieHeader) {
|
|
67
|
+
const headers = new Headers(init.headers ?? {});
|
|
68
|
+
if (!headers.has("Cookie")) {
|
|
69
|
+
headers.set("Cookie", this.cookieHeader);
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
...init,
|
|
73
|
+
headers,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (typeof window !== "undefined") {
|
|
77
|
+
return init;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const { cookies } = await import("next/headers");
|
|
81
|
+
const cookieStore = await cookies();
|
|
82
|
+
const serializedCookies = cookieStore
|
|
83
|
+
.getAll()
|
|
84
|
+
.map(({ name, value }) => `${name}=${value}`)
|
|
85
|
+
.join("; ");
|
|
86
|
+
if (!serializedCookies) {
|
|
87
|
+
return init;
|
|
88
|
+
}
|
|
89
|
+
const headers = new Headers(init.headers ?? {});
|
|
90
|
+
if (!headers.has("Cookie")) {
|
|
91
|
+
headers.set("Cookie", serializedCookies);
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
...init,
|
|
95
|
+
headers,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return init;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async loadClaims() {
|
|
103
|
+
try {
|
|
104
|
+
const url = new URL("/api/v1/auth/session", this.baseUrl).toString();
|
|
105
|
+
const response = await fetch(url, await this.withSession({
|
|
106
|
+
method: "GET",
|
|
107
|
+
headers: { accept: "application/json" },
|
|
108
|
+
credentials: "include",
|
|
109
|
+
}));
|
|
110
|
+
if (!response.ok) {
|
|
111
|
+
this.claims = null;
|
|
112
|
+
this.ttl = null;
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
const data = (await response.json());
|
|
116
|
+
if (data.ok) {
|
|
117
|
+
this.claims = data.claims ?? null;
|
|
118
|
+
this.ttl = typeof data.ttl_seconds === "number" ? data.ttl_seconds : null;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
this.claims = null;
|
|
122
|
+
this.ttl = null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (_err) {
|
|
126
|
+
this.claims = null;
|
|
127
|
+
this.ttl = null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
SessionClient.instances = new Map();
|
|
132
|
+
export default SessionClient;
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { SSIStorage } from '../storage/SSIStorage';
|
|
2
|
+
import type { KVValue } from '../storage/types';
|
|
3
|
+
import { AuthServer, type TokenResponse, type AuthConfig } from '../auth.server';
|
|
4
|
+
export declare const sessionRoles: {
|
|
5
|
+
allRoles: string[];
|
|
6
|
+
adminRoles: string[];
|
|
7
|
+
userRoles: string[];
|
|
8
|
+
userAdminRoles: string[];
|
|
9
|
+
};
|
|
10
|
+
export type SessionDataKey = 'claims' | 'id_token' | 'access_token' | 'refresh_token';
|
|
11
|
+
export interface SetSessionInput {
|
|
12
|
+
sessionId?: string;
|
|
13
|
+
id_token: string;
|
|
14
|
+
access_token: string;
|
|
15
|
+
refresh_token: string;
|
|
16
|
+
/**
|
|
17
|
+
* TTL for the refresh token (seconds). Defaults to 7 days.
|
|
18
|
+
* id_token/access_token inherit the same TTL unless you pass token-specific values.
|
|
19
|
+
*/
|
|
20
|
+
refreshTtlSeconds?: number;
|
|
21
|
+
idTokenTtlSeconds?: number;
|
|
22
|
+
accessTokenTtlSeconds?: number;
|
|
23
|
+
/**
|
|
24
|
+
* Cookie overrides. If omitted, sensible defaults are used.
|
|
25
|
+
*/
|
|
26
|
+
cookie?: Partial<CookieOptions>;
|
|
27
|
+
}
|
|
28
|
+
export interface CookieOptions {
|
|
29
|
+
name: string;
|
|
30
|
+
domain?: string;
|
|
31
|
+
path: string;
|
|
32
|
+
sameSite: 'Lax' | 'Strict' | 'None';
|
|
33
|
+
secure: boolean;
|
|
34
|
+
httpOnly: boolean;
|
|
35
|
+
/** seconds */
|
|
36
|
+
maxAge: number;
|
|
37
|
+
}
|
|
38
|
+
export declare class SessionManager {
|
|
39
|
+
private storage;
|
|
40
|
+
private auth?;
|
|
41
|
+
private _sessionId?;
|
|
42
|
+
private authConfig?;
|
|
43
|
+
private static inFlightRefresh;
|
|
44
|
+
private freshnessOnce;
|
|
45
|
+
constructor(storage: SSIStorage, authConfig?: AuthConfig);
|
|
46
|
+
static fromEnv(): SessionManager;
|
|
47
|
+
static fromEnv(cookieHeader: string | null, authConfig?: AuthConfig): SessionManager;
|
|
48
|
+
static fromEnv(request: Request, authConfig?: AuthConfig): SessionManager;
|
|
49
|
+
static fromEnv(authConfig: AuthConfig): SessionManager;
|
|
50
|
+
/**
|
|
51
|
+
* Async version that attempts to auto-detect the cookie header from Next.js context
|
|
52
|
+
* when called with no arguments. Falls back gracefully if not in a Next.js context.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* // In Next.js server components or route handlers without Request object
|
|
56
|
+
* const session = await SessionManager.fromEnvAsync();
|
|
57
|
+
*
|
|
58
|
+
* // Still supports explicit cookie header or Request object
|
|
59
|
+
* const session = await SessionManager.fromEnvAsync(request);
|
|
60
|
+
* const session = await SessionManager.fromEnvAsync(cookieHeader);
|
|
61
|
+
*
|
|
62
|
+
* // With AuthConfig
|
|
63
|
+
* const session = await SessionManager.fromEnvAsync({ clientId: 'my-client-id' });
|
|
64
|
+
* const session = await SessionManager.fromEnvAsync(request, { clientId: 'my-client-id' });
|
|
65
|
+
*/
|
|
66
|
+
static fromEnvAsync(): Promise<SessionManager>;
|
|
67
|
+
static fromEnvAsync(cookieHeader: string | null, authConfig?: AuthConfig): Promise<SessionManager>;
|
|
68
|
+
static fromEnvAsync(request: Request, authConfig?: AuthConfig): Promise<SessionManager>;
|
|
69
|
+
static fromEnvAsync(authConfig: AuthConfig): Promise<SessionManager>;
|
|
70
|
+
private parseCookies;
|
|
71
|
+
get sessionId(): string | undefined;
|
|
72
|
+
/** Cryptographically strong, URL-safe session id */
|
|
73
|
+
generateSessionId(): string;
|
|
74
|
+
/**
|
|
75
|
+
* Store tokens from AuthServer TokenResponse and return { sessionId, setCookieHeader }.
|
|
76
|
+
* Keys: id_token, access_token, refresh_token
|
|
77
|
+
*/
|
|
78
|
+
setSession(auth: AuthServer, tokenResponse: TokenResponse, options?: {
|
|
79
|
+
sessionId?: string;
|
|
80
|
+
refreshTtlSeconds?: number;
|
|
81
|
+
idTokenTtlSeconds?: number;
|
|
82
|
+
accessTokenTtlSeconds?: number;
|
|
83
|
+
cookie?: Partial<CookieOptions>;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
sessionId: string;
|
|
86
|
+
setCookieHeader: string;
|
|
87
|
+
}>;
|
|
88
|
+
/** Convenience overload that reads the last TokenResponse from AuthServer */
|
|
89
|
+
setSession(auth: AuthServer, options?: {
|
|
90
|
+
sessionId?: string;
|
|
91
|
+
refreshTtlSeconds?: number;
|
|
92
|
+
idTokenTtlSeconds?: number;
|
|
93
|
+
accessTokenTtlSeconds?: number;
|
|
94
|
+
cookie?: Partial<CookieOptions>;
|
|
95
|
+
}): Promise<{
|
|
96
|
+
sessionId: string;
|
|
97
|
+
setCookieHeader: string;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Store tokens and return { sessionId, setCookieHeader }.
|
|
101
|
+
* Keys: id_token, access_token, refresh_token
|
|
102
|
+
*/
|
|
103
|
+
setSession(input: SetSessionInput): Promise<{
|
|
104
|
+
sessionId: string;
|
|
105
|
+
setCookieHeader: string;
|
|
106
|
+
}>;
|
|
107
|
+
/** Build a single Set-Cookie header string for the session id */
|
|
108
|
+
buildSessionCookie(sessionId: string, overrides?: Partial<CookieOptions>): string;
|
|
109
|
+
/**
|
|
110
|
+
* Get session data by key. For 'claims', decodes the id_token payload
|
|
111
|
+
* WITHOUT verification (use your verifier upstream for security).
|
|
112
|
+
*/
|
|
113
|
+
getSessionData(sessionId: string, dataKey: SessionDataKey): Promise<KVValue | null>;
|
|
114
|
+
private ensureFreshOnce;
|
|
115
|
+
/**
|
|
116
|
+
* Delete all keys under this session object (id/access/refresh).
|
|
117
|
+
*/
|
|
118
|
+
clearSession(sessionId: string): Promise<string>;
|
|
119
|
+
/**
|
|
120
|
+
* Refresh session (stub): you’ll likely:
|
|
121
|
+
* 1) read refresh_token
|
|
122
|
+
* 2) call your token endpoint
|
|
123
|
+
* 3) update stored tokens + extend TTL
|
|
124
|
+
* 4) optionally rotate session id & cookie
|
|
125
|
+
*/
|
|
126
|
+
refreshSession(_sessionId: string): Promise<never>;
|
|
127
|
+
/** Returns remaining TTL in seconds for this session's id_token, or null if none */
|
|
128
|
+
getSessionTtlSeconds(sessionId: string): Promise<number | null>;
|
|
129
|
+
private getVerifiedClaims;
|
|
130
|
+
private getRoles;
|
|
131
|
+
hasRole(roleName: string): Promise<boolean>;
|
|
132
|
+
hasRoleOneOf(roleNames: string[]): Promise<boolean>;
|
|
133
|
+
/**
|
|
134
|
+
* Get a specific claim from the session's ID token.
|
|
135
|
+
* Requires `sessionId` to be set (via `fromEnv()` with cookies).
|
|
136
|
+
*/
|
|
137
|
+
getClaim(claimName: string): Promise<unknown>;
|
|
138
|
+
private getAuth;
|
|
139
|
+
}
|