@serialsubscriptions/platform-integration 0.0.8-5.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 +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 +395 -0
- package/lib/SSISubscribedPlanApi.js +567 -0
- package/lib/SubscribedPlanManager.d.ts +400 -0
- package/lib/SubscribedPlanManager.js +319 -0
- package/lib/UsageApi.d.ts +128 -0
- package/lib/UsageApi.js +224 -0
- package/lib/auth.server.d.ts +212 -0
- package/lib/auth.server.js +624 -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/clientConfig.d.ts +42 -0
- package/lib/clientConfig.js +80 -0
- package/lib/frontend/index.d.ts +3 -0
- package/lib/frontend/index.js +12 -0
- package/lib/frontend/session/SessionClient.d.ts +36 -0
- package/lib/frontend/session/SessionClient.js +151 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.js +40 -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/requestConfig.d.ts +60 -0
- package/lib/requestConfig.js +151 -0
- package/lib/session/SessionClient.d.ts +19 -0
- package/lib/session/SessionClient.js +132 -0
- package/lib/session/SessionManager.d.ts +142 -0
- package/lib/session/SessionManager.js +437 -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 +74 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SSICache = void 0;
|
|
4
|
+
const MemoryCacheBackend_1 = require("./backends/MemoryCacheBackend");
|
|
5
|
+
const RedisCacheBackend_1 = require("./backends/RedisCacheBackend");
|
|
6
|
+
function envBool(v) {
|
|
7
|
+
if (v === undefined)
|
|
8
|
+
return undefined;
|
|
9
|
+
return ['1', 'true', 'yes', 'on'].includes(v.toLowerCase());
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Creates a namespaced key according to the required format:
|
|
13
|
+
* container:prefix:key
|
|
14
|
+
*/
|
|
15
|
+
function keyFor(container, prefix, key) {
|
|
16
|
+
const safePrefix = (prefix && prefix.length > 0) ? prefix : '_';
|
|
17
|
+
return `${container}:${safePrefix}:${key}`;
|
|
18
|
+
}
|
|
19
|
+
class SSICache {
|
|
20
|
+
constructor(backend, container, prefix) {
|
|
21
|
+
this.backend = backend;
|
|
22
|
+
this.container = container;
|
|
23
|
+
this.prefix = prefix;
|
|
24
|
+
}
|
|
25
|
+
static fromEnv() {
|
|
26
|
+
if (SSICache.__shared)
|
|
27
|
+
return SSICache.__shared;
|
|
28
|
+
const backend = process.env.SSI_CACHE_BACKEND || 'memory';
|
|
29
|
+
const container = process.env.SSI_CACHE_CONTAINER || 'ssi';
|
|
30
|
+
SSICache.__shared = SSICache.init({
|
|
31
|
+
backend,
|
|
32
|
+
container,
|
|
33
|
+
url: process.env.SSI_CACHE_URL,
|
|
34
|
+
host: process.env.SSI_CACHE_HOST,
|
|
35
|
+
port: process.env.SSI_CACHE_PORT ? Number(process.env.SSI_CACHE_PORT) : undefined,
|
|
36
|
+
user: process.env.SSI_CACHE_USER,
|
|
37
|
+
password: process.env.SSI_CACHE_PASSWORD,
|
|
38
|
+
tls: envBool(process.env.SSI_CACHE_SSL),
|
|
39
|
+
});
|
|
40
|
+
return SSICache.__shared;
|
|
41
|
+
}
|
|
42
|
+
static init(opts) {
|
|
43
|
+
const t = opts.backend || 'memory';
|
|
44
|
+
const container = opts.container;
|
|
45
|
+
let backend;
|
|
46
|
+
if (t === 'memory') {
|
|
47
|
+
backend = new MemoryCacheBackend_1.MemoryCacheBackend();
|
|
48
|
+
}
|
|
49
|
+
else if (t === 'redis') {
|
|
50
|
+
backend = new RedisCacheBackend_1.RedisCacheBackend({
|
|
51
|
+
url: opts.url,
|
|
52
|
+
host: opts.host,
|
|
53
|
+
port: opts.port,
|
|
54
|
+
user: opts.user,
|
|
55
|
+
password: opts.password,
|
|
56
|
+
tls: opts.tls,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
throw new Error(`Unsupported cache backend: ${t}`);
|
|
61
|
+
}
|
|
62
|
+
return new SSICache(backend, container);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Returns a cache instance pinned to a prefix ("jwks", "oidc", "rl", etc.).
|
|
66
|
+
*/
|
|
67
|
+
withPrefix(prefix) {
|
|
68
|
+
return new SSICache(this.backend, this.container, prefix);
|
|
69
|
+
// shares the same backend connection; creates a new namespacer
|
|
70
|
+
}
|
|
71
|
+
k(key) {
|
|
72
|
+
return keyFor(this.container, this.prefix, key);
|
|
73
|
+
}
|
|
74
|
+
async get(key) {
|
|
75
|
+
return this.backend.get(this.k(key));
|
|
76
|
+
}
|
|
77
|
+
async set(key, value, ttlSec) {
|
|
78
|
+
await this.backend.set(this.k(key), value, ttlSec);
|
|
79
|
+
}
|
|
80
|
+
async del(key) {
|
|
81
|
+
await this.backend.del(this.k(key));
|
|
82
|
+
}
|
|
83
|
+
async mget(keys) {
|
|
84
|
+
return this.backend.mget(keys.map((k) => this.k(k)));
|
|
85
|
+
}
|
|
86
|
+
async mset(entries) {
|
|
87
|
+
return this.backend.mset(entries.map((e) => ({ key: this.k(e.key), value: e.value, ttlSec: e.ttlSec })));
|
|
88
|
+
}
|
|
89
|
+
async incrby(key, by, ttlSec) {
|
|
90
|
+
return this.backend.incrby(this.k(key), by, ttlSec);
|
|
91
|
+
}
|
|
92
|
+
async ttl(key) {
|
|
93
|
+
return this.backend.ttl(this.k(key));
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* compute-if-absent: get from cache or compute and cache the value
|
|
97
|
+
*/
|
|
98
|
+
async remember(key, ttlSec, loader) {
|
|
99
|
+
const cached = await this.get(key);
|
|
100
|
+
if (cached !== null)
|
|
101
|
+
return cached;
|
|
102
|
+
const value = await loader();
|
|
103
|
+
await this.set(key, value, ttlSec);
|
|
104
|
+
return value;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Simple distributed lock (best-effort): returns lock token if acquired
|
|
108
|
+
* Only works properly with Redis backend; memory backend returns a naive token
|
|
109
|
+
*/
|
|
110
|
+
async acquireLock(key, ttlMs) {
|
|
111
|
+
const token = Math.random().toString(36).slice(2);
|
|
112
|
+
if (typeof this.backend.tryLock === 'function') {
|
|
113
|
+
const ok = await this.backend.tryLock(this.k(`lock:${key}`), ttlMs, token);
|
|
114
|
+
return ok ? token : null;
|
|
115
|
+
}
|
|
116
|
+
return token; // naive fallback for memory backend
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Release a lock acquired via acquireLock
|
|
120
|
+
*/
|
|
121
|
+
async releaseLock(key, token) {
|
|
122
|
+
if (typeof this.backend.unlock === 'function') {
|
|
123
|
+
await this.backend.unlock(this.k(`lock:${key}`), token);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async close() {
|
|
127
|
+
if (this.prefix)
|
|
128
|
+
return; // only root closes the connection
|
|
129
|
+
if (this.backend.close)
|
|
130
|
+
await this.backend.close();
|
|
131
|
+
SSICache.__shared = undefined;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
exports.SSICache = SSICache;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { CacheBackend } from '../types';
|
|
2
|
+
export declare class MemoryCacheBackend implements CacheBackend {
|
|
3
|
+
private store;
|
|
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
|
+
mget<T = unknown>(keys: string[]): Promise<(T | null)[]>;
|
|
8
|
+
mset<T = unknown>(entries: Array<{
|
|
9
|
+
key: string;
|
|
10
|
+
value: T;
|
|
11
|
+
ttlSec: number;
|
|
12
|
+
}>): Promise<void>;
|
|
13
|
+
incrby(key: string, by?: number, ttlSec?: number): Promise<number>;
|
|
14
|
+
ttl(key: string): Promise<number | null>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.MemoryCacheBackend = void 0;
|
|
4
|
+
class MemoryCacheBackend {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.store = new Map();
|
|
7
|
+
}
|
|
8
|
+
async get(key) {
|
|
9
|
+
const it = this.store.get(key);
|
|
10
|
+
if (!it)
|
|
11
|
+
return null;
|
|
12
|
+
if (Date.now() > it.exp) {
|
|
13
|
+
this.store.delete(key);
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
return it.v;
|
|
17
|
+
}
|
|
18
|
+
async set(key, value, ttlSec) {
|
|
19
|
+
this.store.set(key, { v: value, exp: Date.now() + ttlSec * 1000 });
|
|
20
|
+
}
|
|
21
|
+
async del(key) {
|
|
22
|
+
this.store.delete(key);
|
|
23
|
+
}
|
|
24
|
+
async mget(keys) {
|
|
25
|
+
return Promise.all(keys.map((k) => this.get(k)));
|
|
26
|
+
}
|
|
27
|
+
async mset(entries) {
|
|
28
|
+
for (const e of entries) {
|
|
29
|
+
await this.set(e.key, e.value, e.ttlSec);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async incrby(key, by = 1, ttlSec) {
|
|
33
|
+
const cur = (await this.get(key)) ?? 0;
|
|
34
|
+
const next = cur + by;
|
|
35
|
+
await this.set(key, next, ttlSec ?? 60);
|
|
36
|
+
return next;
|
|
37
|
+
}
|
|
38
|
+
async ttl(key) {
|
|
39
|
+
const it = this.store.get(key);
|
|
40
|
+
if (!it)
|
|
41
|
+
return null;
|
|
42
|
+
const ms = it.exp - Date.now();
|
|
43
|
+
return ms > 0 ? Math.ceil(ms / 1000) : null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.MemoryCacheBackend = MemoryCacheBackend;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CacheBackend } from '../types';
|
|
2
|
+
export declare class RedisCacheBackend implements CacheBackend {
|
|
3
|
+
private client;
|
|
4
|
+
constructor(opts: {
|
|
5
|
+
url?: string;
|
|
6
|
+
host?: string;
|
|
7
|
+
port?: number;
|
|
8
|
+
user?: string;
|
|
9
|
+
password?: string;
|
|
10
|
+
tls?: boolean;
|
|
11
|
+
});
|
|
12
|
+
private ensure;
|
|
13
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
14
|
+
set<T = unknown>(key: string, value: T, ttlSec: number): Promise<void>;
|
|
15
|
+
del(key: string): Promise<void>;
|
|
16
|
+
mget<T = unknown>(keys: string[]): Promise<(T | null)[]>;
|
|
17
|
+
mset<T = unknown>(entries: Array<{
|
|
18
|
+
key: string;
|
|
19
|
+
value: T;
|
|
20
|
+
ttlSec: number;
|
|
21
|
+
}>): Promise<void>;
|
|
22
|
+
incrby(key: string, by?: number, ttlSec?: number): Promise<number>;
|
|
23
|
+
ttl(key: string): Promise<number | null>;
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
tryLock(key: string, ttlMs: number, token: string): Promise<boolean>;
|
|
26
|
+
unlock(key: string, token: string): Promise<void>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RedisCacheBackend = void 0;
|
|
4
|
+
const ioredis_1 = require("ioredis");
|
|
5
|
+
class RedisCacheBackend {
|
|
6
|
+
constructor(opts) {
|
|
7
|
+
if (opts.url) {
|
|
8
|
+
this.client = new ioredis_1.Redis(opts.url, { lazyConnect: true });
|
|
9
|
+
}
|
|
10
|
+
else {
|
|
11
|
+
this.client = new ioredis_1.Redis({
|
|
12
|
+
host: opts.host ?? 'localhost',
|
|
13
|
+
port: opts.port ?? 6379,
|
|
14
|
+
username: opts.user,
|
|
15
|
+
password: opts.password,
|
|
16
|
+
tls: opts.tls ? {} : undefined,
|
|
17
|
+
lazyConnect: true,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async ensure() {
|
|
22
|
+
if (this.client.status === 'wait')
|
|
23
|
+
await this.client.connect();
|
|
24
|
+
}
|
|
25
|
+
async get(key) {
|
|
26
|
+
await this.ensure();
|
|
27
|
+
const s = await this.client.get(key);
|
|
28
|
+
return s ? JSON.parse(s) : null;
|
|
29
|
+
}
|
|
30
|
+
async set(key, value, ttlSec) {
|
|
31
|
+
await this.ensure();
|
|
32
|
+
await this.client.set(key, JSON.stringify(value), 'EX', ttlSec);
|
|
33
|
+
}
|
|
34
|
+
async del(key) {
|
|
35
|
+
await this.ensure();
|
|
36
|
+
await this.client.del(key);
|
|
37
|
+
}
|
|
38
|
+
async mget(keys) {
|
|
39
|
+
await this.ensure();
|
|
40
|
+
if (!keys.length)
|
|
41
|
+
return [];
|
|
42
|
+
const res = await this.client.mget(...keys);
|
|
43
|
+
return res.map((s) => (s ? JSON.parse(s) : null));
|
|
44
|
+
}
|
|
45
|
+
async mset(entries) {
|
|
46
|
+
await this.ensure();
|
|
47
|
+
// Use pipeline to preserve per-key TTLs
|
|
48
|
+
const p = this.client.pipeline();
|
|
49
|
+
for (const e of entries) {
|
|
50
|
+
p.set(e.key, JSON.stringify(e.value), 'EX', e.ttlSec);
|
|
51
|
+
}
|
|
52
|
+
await p.exec();
|
|
53
|
+
}
|
|
54
|
+
async incrby(key, by = 1, ttlSec) {
|
|
55
|
+
await this.ensure();
|
|
56
|
+
const p = this.client.pipeline();
|
|
57
|
+
p.incrby(key, by);
|
|
58
|
+
if (ttlSec)
|
|
59
|
+
p.expire(key, ttlSec);
|
|
60
|
+
const results = await p.exec();
|
|
61
|
+
if (!results || results.length === 0) {
|
|
62
|
+
throw new Error('Pipeline exec failed');
|
|
63
|
+
}
|
|
64
|
+
const [error, val] = results[0];
|
|
65
|
+
if (error) {
|
|
66
|
+
throw error;
|
|
67
|
+
}
|
|
68
|
+
return val;
|
|
69
|
+
}
|
|
70
|
+
async ttl(key) {
|
|
71
|
+
await this.ensure();
|
|
72
|
+
const t = await this.client.ttl(key);
|
|
73
|
+
return t >= 0 ? t : null;
|
|
74
|
+
}
|
|
75
|
+
async close() {
|
|
76
|
+
await this.client.quit();
|
|
77
|
+
}
|
|
78
|
+
// Simple locks (SET NX PX)
|
|
79
|
+
async tryLock(key, ttlMs, token) {
|
|
80
|
+
await this.ensure();
|
|
81
|
+
const r = await this.client.set(key, token, 'PX', ttlMs, 'NX');
|
|
82
|
+
return r === 'OK';
|
|
83
|
+
}
|
|
84
|
+
async unlock(key, token) {
|
|
85
|
+
await this.ensure();
|
|
86
|
+
// Lua compare-and-del
|
|
87
|
+
const lua = `
|
|
88
|
+
if redis.call("get", KEYS[1]) == ARGV[1] then
|
|
89
|
+
return redis.call("del", KEYS[1])
|
|
90
|
+
else return 0 end
|
|
91
|
+
`;
|
|
92
|
+
await this.client.eval(lua, 1, key, token);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
exports.RedisCacheBackend = RedisCacheBackend;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TTL_JWKS = exports.TTL_LONG = exports.TTL_DEFAULT = exports.TTL_SHORT = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Recommended default TTLs for cache operations
|
|
6
|
+
*/
|
|
7
|
+
exports.TTL_SHORT = 60; // rate-limit buckets, nonces
|
|
8
|
+
exports.TTL_DEFAULT = 300; // API responses
|
|
9
|
+
exports.TTL_LONG = 3600; // discovery docs
|
|
10
|
+
exports.TTL_JWKS = 43200; // 12h; rotate if kid miss
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export type CacheBackendType = 'memory' | 'redis';
|
|
2
|
+
export interface CacheInitOpts {
|
|
3
|
+
backend?: CacheBackendType;
|
|
4
|
+
container: string;
|
|
5
|
+
url?: string;
|
|
6
|
+
host?: string;
|
|
7
|
+
port?: number;
|
|
8
|
+
user?: string;
|
|
9
|
+
password?: string;
|
|
10
|
+
tls?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface CacheBackend {
|
|
13
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
14
|
+
set<T = unknown>(key: string, value: T, ttlSec: number): Promise<void>;
|
|
15
|
+
del(key: string): Promise<void>;
|
|
16
|
+
mget<T = unknown>(keys: string[]): Promise<(T | null)[]>;
|
|
17
|
+
mset<T = unknown>(entries: Array<{
|
|
18
|
+
key: string;
|
|
19
|
+
value: T;
|
|
20
|
+
ttlSec: number;
|
|
21
|
+
}>): Promise<void>;
|
|
22
|
+
incrby(key: string, by?: number, ttlSec?: number): Promise<number>;
|
|
23
|
+
ttl(key: string): Promise<number | null>;
|
|
24
|
+
close?(): Promise<void>;
|
|
25
|
+
tryLock?(key: string, ttlMs: number, token: string): Promise<boolean>;
|
|
26
|
+
unlock?(key: string, token: string): Promise<void>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config shape that host apps use in the browser (e.g. from getClientConfig()).
|
|
3
|
+
*
|
|
4
|
+
* Derived from public env (NEXT_PUBLIC_*) and optionally window.location.
|
|
5
|
+
* Use this type for the return value of your client config helper so SessionClient
|
|
6
|
+
* and other client code stay typed.
|
|
7
|
+
*
|
|
8
|
+
* - **baseUrl**: App origin (e.g. window.location.origin or NEXT_PUBLIC_APP_URL).
|
|
9
|
+
* - **apiUrl**: App API base; where your app's routes live (e.g. /api/v1/auth/session).
|
|
10
|
+
* Pass to SessionClient.getSessionClient(config.apiUrl ?? config.baseUrl).
|
|
11
|
+
* - **ssiApiUrl**: SSI Platform API base (for links, account portal, etc.).
|
|
12
|
+
* - **ssiIssuerBaseUrl**: SSI issuer URL (often same as ssiApiUrl; e.g. for /pricing links).
|
|
13
|
+
*/
|
|
14
|
+
export type SSIClientConfig = {
|
|
15
|
+
baseUrl: string | null;
|
|
16
|
+
apiUrl?: string | null;
|
|
17
|
+
ssiApiUrl?: string | null;
|
|
18
|
+
ssiIssuerBaseUrl?: string | null;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Base app URL (client): NEXT_PUBLIC_APP_URL or (in browser) window.location.origin.
|
|
22
|
+
*/
|
|
23
|
+
export declare function getClientBaseUrl(): string | null;
|
|
24
|
+
/**
|
|
25
|
+
* App API base URL (client): NEXT_PUBLIC_API_URL or baseUrl.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getClientApiUrl(baseUrl: string | null): string | null;
|
|
28
|
+
/**
|
|
29
|
+
* SSI Platform API base URL (client): NEXT_PUBLIC_SSI_API_BASE_URL or derived from baseUrl
|
|
30
|
+
* hostname (e.g. https://<subdomain>.cerealstackdev.com on known domains).
|
|
31
|
+
*/
|
|
32
|
+
export declare function getClientSsiApiUrl(baseUrl: string | null): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Build SSIClientConfig from public env and (in browser) window.location.
|
|
35
|
+
* Use in client components; for SessionClient pass the result to getSessionClient(config).
|
|
36
|
+
*/
|
|
37
|
+
export declare function getClientConfig(): SSIClientConfig;
|
|
38
|
+
/**
|
|
39
|
+
* Returns the URL to pass to SessionClient (app base so it can call the app's session endpoint).
|
|
40
|
+
* Prefers apiUrl so the session route is resolved correctly when app and API differ.
|
|
41
|
+
*/
|
|
42
|
+
export declare function getSessionClientBaseUrl(config: SSIClientConfig | undefined | null): string | undefined;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.getClientBaseUrl = getClientBaseUrl;
|
|
5
|
+
exports.getClientApiUrl = getClientApiUrl;
|
|
6
|
+
exports.getClientSsiApiUrl = getClientSsiApiUrl;
|
|
7
|
+
exports.getClientConfig = getClientConfig;
|
|
8
|
+
exports.getSessionClientBaseUrl = getSessionClientBaseUrl;
|
|
9
|
+
function trimTrailingSlash(url) {
|
|
10
|
+
return url.replace(/\/$/, "");
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Base app URL (client): NEXT_PUBLIC_APP_URL or (in browser) window.location.origin.
|
|
14
|
+
*/
|
|
15
|
+
function getClientBaseUrl() {
|
|
16
|
+
const baseUrl = process.env.NEXT_PUBLIC_APP_URL ||
|
|
17
|
+
(typeof window !== "undefined" ? window.location.origin : null);
|
|
18
|
+
return baseUrl ? trimTrailingSlash(baseUrl) : null;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* App API base URL (client): NEXT_PUBLIC_API_URL or baseUrl.
|
|
22
|
+
*/
|
|
23
|
+
function getClientApiUrl(baseUrl) {
|
|
24
|
+
const apiUrl = process.env.NEXT_PUBLIC_API_URL || (baseUrl ?? null);
|
|
25
|
+
return apiUrl ? trimTrailingSlash(apiUrl) : null;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* SSI Platform API base URL (client): NEXT_PUBLIC_SSI_API_BASE_URL or derived from baseUrl
|
|
29
|
+
* hostname (e.g. https://<subdomain>.cerealstackdev.com on known domains).
|
|
30
|
+
*/
|
|
31
|
+
function getClientSsiApiUrl(baseUrl) {
|
|
32
|
+
if (!baseUrl)
|
|
33
|
+
return null;
|
|
34
|
+
if (process.env.NEXT_PUBLIC_SSI_API_BASE_URL) {
|
|
35
|
+
return trimTrailingSlash(process.env.NEXT_PUBLIC_SSI_API_BASE_URL);
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const url = new URL(baseUrl);
|
|
39
|
+
const hostname = url.hostname;
|
|
40
|
+
const validDomain = hostname.endsWith(".cerealstackdev.com") ||
|
|
41
|
+
hostname.endsWith(".cerealstackqa.com") ||
|
|
42
|
+
hostname.endsWith(".cerealstack.com");
|
|
43
|
+
if (!validDomain)
|
|
44
|
+
return null;
|
|
45
|
+
const parts = hostname.split(".");
|
|
46
|
+
if (parts.length < 3)
|
|
47
|
+
return null;
|
|
48
|
+
const subdomain = parts[parts.length - 3];
|
|
49
|
+
const domain = parts.slice(-2).join(".");
|
|
50
|
+
return `https://${subdomain}.${domain}`;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return null;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Build SSIClientConfig from public env and (in browser) window.location.
|
|
58
|
+
* Use in client components; for SessionClient pass the result to getSessionClient(config).
|
|
59
|
+
*/
|
|
60
|
+
function getClientConfig() {
|
|
61
|
+
const baseUrl = getClientBaseUrl();
|
|
62
|
+
const apiUrl = getClientApiUrl(baseUrl);
|
|
63
|
+
const ssiApiUrl = getClientSsiApiUrl(baseUrl);
|
|
64
|
+
return {
|
|
65
|
+
baseUrl,
|
|
66
|
+
apiUrl,
|
|
67
|
+
ssiApiUrl,
|
|
68
|
+
ssiIssuerBaseUrl: ssiApiUrl,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Returns the URL to pass to SessionClient (app base so it can call the app's session endpoint).
|
|
73
|
+
* Prefers apiUrl so the session route is resolved correctly when app and API differ.
|
|
74
|
+
*/
|
|
75
|
+
function getSessionClientBaseUrl(config) {
|
|
76
|
+
if (config == null)
|
|
77
|
+
return undefined;
|
|
78
|
+
const url = config.apiUrl ?? config.baseUrl;
|
|
79
|
+
return url != null && url !== "" ? url : undefined;
|
|
80
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getClientSsiApiUrl = exports.getClientApiUrl = exports.getClientBaseUrl = exports.getSessionClientBaseUrl = exports.getClientConfig = exports.SessionClient = void 0;
|
|
4
|
+
// Browser/middleware-safe exports only (no auth.server / requestConfig)
|
|
5
|
+
var SessionClient_1 = require("./session/SessionClient");
|
|
6
|
+
Object.defineProperty(exports, "SessionClient", { enumerable: true, get: function () { return SessionClient_1.SessionClient; } });
|
|
7
|
+
var clientConfig_1 = require("../clientConfig");
|
|
8
|
+
Object.defineProperty(exports, "getClientConfig", { enumerable: true, get: function () { return clientConfig_1.getClientConfig; } });
|
|
9
|
+
Object.defineProperty(exports, "getSessionClientBaseUrl", { enumerable: true, get: function () { return clientConfig_1.getSessionClientBaseUrl; } });
|
|
10
|
+
Object.defineProperty(exports, "getClientBaseUrl", { enumerable: true, get: function () { return clientConfig_1.getClientBaseUrl; } });
|
|
11
|
+
Object.defineProperty(exports, "getClientApiUrl", { enumerable: true, get: function () { return clientConfig_1.getClientApiUrl; } });
|
|
12
|
+
Object.defineProperty(exports, "getClientSsiApiUrl", { enumerable: true, get: function () { return clientConfig_1.getClientSsiApiUrl; } });
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { type SSIClientConfig } from '../../clientConfig';
|
|
2
|
+
export declare class SessionClient {
|
|
3
|
+
private readonly cookieHeader?;
|
|
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
|
+
/**
|
|
11
|
+
* Returns a new SessionClient for this request. Call once per request (or per user
|
|
12
|
+
* context) so session is not shared across requests.
|
|
13
|
+
*
|
|
14
|
+
* Accepts a base URL string or an SSIClientConfig (e.g. from getClientConfig());
|
|
15
|
+
* when given config, uses config.apiUrl ?? config.baseUrl.
|
|
16
|
+
*
|
|
17
|
+
* In Next.js server components/route handlers you can omit cookieHeader: the client
|
|
18
|
+
* will automatically use the current request's session cookie (via next/headers).
|
|
19
|
+
* In other server contexts (e.g. middleware, non-Next), pass the request's Cookie
|
|
20
|
+
* header so this client is bound to that request's session.
|
|
21
|
+
*/
|
|
22
|
+
static getSessionClient(baseUrlOrConfig?: string | SSIClientConfig, cookieHeader?: string | null): SessionClient;
|
|
23
|
+
isLoggedIn(): Promise<boolean>;
|
|
24
|
+
warmup(): void;
|
|
25
|
+
getTtl(): Promise<number | null>;
|
|
26
|
+
get(claimName: string): Promise<unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Get a specific claim from the session.
|
|
29
|
+
* Alias for `get()` method for consistency with SessionManager.
|
|
30
|
+
*/
|
|
31
|
+
getClaim(claimName: string): Promise<unknown>;
|
|
32
|
+
getAll(): Promise<unknown | null>;
|
|
33
|
+
private withSession;
|
|
34
|
+
private loadClaims;
|
|
35
|
+
}
|
|
36
|
+
export default SessionClient;
|