@pooflabs/core 0.0.39-rc1 → 0.0.40
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/dist/client/config.d.ts +4 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +222 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +222 -7
- package/dist/index.mjs.map +1 -1
- package/dist/utils/core-platform.d.ts +16 -0
- package/dist/utils/rn-session-manager.d.ts +73 -0
- package/dist/utils/web-session-manager.d.ts +5 -0
- package/package.json +1 -1
package/dist/client/config.d.ts
CHANGED
|
@@ -3,7 +3,8 @@ export interface ClientConfig {
|
|
|
3
3
|
name: string;
|
|
4
4
|
logoUrl: string;
|
|
5
5
|
apiKey: string;
|
|
6
|
-
|
|
6
|
+
/** Auth method. 'privy-expo' is client-only — mapped to 'privy' before sending to the backend. */
|
|
7
|
+
authMethod: 'none' | 'privy' | 'privy-expo' | 'wallet' | 'rainbowkit' | 'coinbase-smart-wallet' | 'onboard' | 'phantom' | 'mobile-wallet-adapter';
|
|
7
8
|
wsApiUrl: string;
|
|
8
9
|
apiUrl: string;
|
|
9
10
|
appId: string;
|
|
@@ -36,6 +37,8 @@ export interface ClientConfig {
|
|
|
36
37
|
cluster?: string;
|
|
37
38
|
theme?: 'light' | 'dark';
|
|
38
39
|
};
|
|
40
|
+
/** Pre-created PrivyExpoProvider instance for React Native (required when authMethod is 'privy-expo'). */
|
|
41
|
+
privyExpoProvider?: AuthProvider;
|
|
39
42
|
mockAuth?: boolean;
|
|
40
43
|
}
|
|
41
44
|
export declare let clientConfig: ClientConfig;
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ export { subscribe, closeAllSubscriptions, clearCache, getCachedData, reconnectW
|
|
|
5
5
|
export * from './types';
|
|
6
6
|
export { getIdToken } from './utils/utils';
|
|
7
7
|
export { WebSessionManager } from './utils/web-session-manager';
|
|
8
|
+
export { ReactNativeSessionManager } from './utils/rn-session-manager';
|
|
9
|
+
export type { RNStorageAdapter } from './utils/rn-session-manager';
|
|
8
10
|
export { ServerSessionManager } from './utils/server-session-manager';
|
|
9
11
|
export { createSessionWithPrivy, createSessionWithSignature, refreshSession, signSessionCreateMessage, genAuthNonce } from './utils/auth-api';
|
|
10
12
|
export { Tarobase as Tarobase6 } from './utils/sol/taro6CvKqwrYrDc16ufYgzQ2NZcyyVKStffbtudrhRuDevnet-program';
|
package/dist/index.js
CHANGED
|
@@ -62,7 +62,12 @@ async function createSessionWithSignature(address, message, signature) {
|
|
|
62
62
|
return response.data;
|
|
63
63
|
}
|
|
64
64
|
async function createSessionWithPrivy(authToken, address, privyIdToken) {
|
|
65
|
-
|
|
65
|
+
var _a;
|
|
66
|
+
// Block in true SSR/Node.js. Allow in browser (window exists) and React Native (no window,
|
|
67
|
+
// but not Node — detected via process.versions.node). Node 21+ defines navigator globally,
|
|
68
|
+
// so we can't rely on navigator alone.
|
|
69
|
+
const isNode = typeof process !== 'undefined' && !!((_a = process.versions) === null || _a === void 0 ? void 0 : _a.node);
|
|
70
|
+
if (typeof window === 'undefined' && isNode)
|
|
66
71
|
return;
|
|
67
72
|
const client = await getAxiosAuthClient();
|
|
68
73
|
const config = await getConfig();
|
|
@@ -90,6 +95,19 @@ async function signSessionCreateMessage(_signMessageFunction) {
|
|
|
90
95
|
}
|
|
91
96
|
|
|
92
97
|
class WebSessionManager {
|
|
98
|
+
/**
|
|
99
|
+
* Decode a base64url-encoded string (used by JWT payloads).
|
|
100
|
+
* Normalises base64url → standard base64 before calling browser atob().
|
|
101
|
+
*/
|
|
102
|
+
static decodeBase64Url(input) {
|
|
103
|
+
let b64 = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
104
|
+
const pad = b64.length % 4;
|
|
105
|
+
if (pad === 2)
|
|
106
|
+
b64 += '==';
|
|
107
|
+
else if (pad === 3)
|
|
108
|
+
b64 += '=';
|
|
109
|
+
return atob(b64);
|
|
110
|
+
}
|
|
93
111
|
/* ------------------------------------------------------------------ */
|
|
94
112
|
/* STORE */
|
|
95
113
|
/* ------------------------------------------------------------------ */
|
|
@@ -125,7 +143,7 @@ class WebSessionManager {
|
|
|
125
143
|
/* ---------- check JWT expiration ---------- */
|
|
126
144
|
try {
|
|
127
145
|
const { accessToken } = sessionObj;
|
|
128
|
-
const { exp } = JSON.parse(
|
|
146
|
+
const { exp } = JSON.parse(this.decodeBase64Url(accessToken.split(".")[1]));
|
|
129
147
|
if (Date.now() > exp * 1000) {
|
|
130
148
|
const { refreshToken } = sessionObj;
|
|
131
149
|
if (!refreshToken)
|
|
@@ -3139,6 +3157,41 @@ var serverSessionManager = /*#__PURE__*/Object.freeze({
|
|
|
3139
3157
|
ServerSessionManager: ServerSessionManager
|
|
3140
3158
|
});
|
|
3141
3159
|
|
|
3160
|
+
/**
|
|
3161
|
+
* Safe base64 helpers for tarobase-core.
|
|
3162
|
+
*
|
|
3163
|
+
* Uses the global atob/btoa when available (browser, RN with polyfill),
|
|
3164
|
+
* falls back to the 'buffer' package (Node.js / SSR / RN without polyfill).
|
|
3165
|
+
*
|
|
3166
|
+
* These are used instead of bare `atob()`/`btoa()` so the core package
|
|
3167
|
+
* works in React Native without requiring the consumer to polyfill globals.
|
|
3168
|
+
*/
|
|
3169
|
+
function safeAtob(input) {
|
|
3170
|
+
if (typeof globalThis.atob === 'function') {
|
|
3171
|
+
return globalThis.atob(input);
|
|
3172
|
+
}
|
|
3173
|
+
return bufferExports.Buffer.from(input, 'base64').toString('binary');
|
|
3174
|
+
}
|
|
3175
|
+
function safeBtoa(input) {
|
|
3176
|
+
if (typeof globalThis.btoa === 'function') {
|
|
3177
|
+
return globalThis.btoa(input);
|
|
3178
|
+
}
|
|
3179
|
+
return bufferExports.Buffer.from(input, 'binary').toString('base64');
|
|
3180
|
+
}
|
|
3181
|
+
/**
|
|
3182
|
+
* Decode a base64url-encoded string (used by JWT payloads).
|
|
3183
|
+
* Normalises base64url → standard base64 before decoding.
|
|
3184
|
+
*/
|
|
3185
|
+
function decodeBase64Url(input) {
|
|
3186
|
+
let b64 = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
3187
|
+
const pad = b64.length % 4;
|
|
3188
|
+
if (pad === 2)
|
|
3189
|
+
b64 += '==';
|
|
3190
|
+
else if (pad === 3)
|
|
3191
|
+
b64 += '=';
|
|
3192
|
+
return safeAtob(b64);
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3142
3195
|
async function createBearerToken(isServer) {
|
|
3143
3196
|
if (isServer) {
|
|
3144
3197
|
const sessionMgr = ServerSessionManager.instance;
|
|
@@ -3638,7 +3691,7 @@ async function get(path, opts = {}) {
|
|
|
3638
3691
|
}
|
|
3639
3692
|
else {
|
|
3640
3693
|
const path = encodeURIComponent(normalizedPath);
|
|
3641
|
-
const promptQueryParam = (opts === null || opts === void 0 ? void 0 : opts.prompt) ? `&prompt=${
|
|
3694
|
+
const promptQueryParam = (opts === null || opts === void 0 ? void 0 : opts.prompt) ? `&prompt=${safeBtoa(opts.prompt)}` : "";
|
|
3642
3695
|
const apiPath = `items?path=${path}${promptQueryParam}${includeSubPathsParam}${shapeParam}${limitParam}${cursorParam}`;
|
|
3643
3696
|
response = await makeApiRequest('GET', apiPath, null, opts._overrides);
|
|
3644
3697
|
}
|
|
@@ -4093,7 +4146,7 @@ function getCacheKey(path, prompt, shape, limit, cursor) {
|
|
|
4093
4146
|
}
|
|
4094
4147
|
function isTokenExpired(token) {
|
|
4095
4148
|
try {
|
|
4096
|
-
const payload = JSON.parse(
|
|
4149
|
+
const payload = JSON.parse(decodeBase64Url(token.split('.')[1]));
|
|
4097
4150
|
const expirationTime = payload.exp * 1000;
|
|
4098
4151
|
const currentTime = Date.now();
|
|
4099
4152
|
return currentTime > (expirationTime - 60000); // 60 second buffer
|
|
@@ -4105,7 +4158,7 @@ function isTokenExpired(token) {
|
|
|
4105
4158
|
}
|
|
4106
4159
|
function getTokenExpirationTime(token) {
|
|
4107
4160
|
try {
|
|
4108
|
-
const payload = JSON.parse(
|
|
4161
|
+
const payload = JSON.parse(decodeBase64Url(token.split('.')[1]));
|
|
4109
4162
|
return payload.exp ? payload.exp * 1000 : null;
|
|
4110
4163
|
}
|
|
4111
4164
|
catch (_a) {
|
|
@@ -4433,7 +4486,7 @@ function sendSubscribe(connection, subscription) {
|
|
|
4433
4486
|
type: 'subscribe',
|
|
4434
4487
|
subscriptionId: subscription.subscriptionId,
|
|
4435
4488
|
path: subscription.path,
|
|
4436
|
-
prompt: subscription.prompt ?
|
|
4489
|
+
prompt: subscription.prompt ? safeBtoa(subscription.prompt) : undefined,
|
|
4437
4490
|
includeSubPaths: subscription.includeSubPaths,
|
|
4438
4491
|
shape: subscription.shape && Object.keys(subscription.shape).length > 0
|
|
4439
4492
|
? subscription.shape
|
|
@@ -4759,7 +4812,170 @@ async function reconnectWithNewAuth() {
|
|
|
4759
4812
|
return reconnectWithNewAuthV2();
|
|
4760
4813
|
}
|
|
4761
4814
|
|
|
4815
|
+
let _config = null;
|
|
4816
|
+
class ReactNativeSessionManager {
|
|
4817
|
+
/**
|
|
4818
|
+
* Must be called once before any other method.
|
|
4819
|
+
*
|
|
4820
|
+
* ```ts
|
|
4821
|
+
* import { ReactNativeSessionManager } from '@pooflabs/core';
|
|
4822
|
+
* import { MMKV } from 'react-native-mmkv';
|
|
4823
|
+
* import { decode } from 'base-64';
|
|
4824
|
+
*
|
|
4825
|
+
* const mmkv = new MMKV();
|
|
4826
|
+
* ReactNativeSessionManager.configure({
|
|
4827
|
+
* storage: {
|
|
4828
|
+
* getItem: (k) => mmkv.getString(k) ?? null,
|
|
4829
|
+
* setItem: (k, v) => mmkv.set(k, v),
|
|
4830
|
+
* removeItem: (k) => mmkv.delete(k),
|
|
4831
|
+
* },
|
|
4832
|
+
* atob: decode,
|
|
4833
|
+
* });
|
|
4834
|
+
* ```
|
|
4835
|
+
*/
|
|
4836
|
+
static configure(cfg) {
|
|
4837
|
+
_config = cfg;
|
|
4838
|
+
}
|
|
4839
|
+
static getStorage() {
|
|
4840
|
+
if (!_config) {
|
|
4841
|
+
throw new Error("ReactNativeSessionManager.configure() must be called before using session methods.");
|
|
4842
|
+
}
|
|
4843
|
+
return _config.storage;
|
|
4844
|
+
}
|
|
4845
|
+
static decodeBase64(input) {
|
|
4846
|
+
if (!_config) {
|
|
4847
|
+
throw new Error("ReactNativeSessionManager.configure() must be called before using session methods.");
|
|
4848
|
+
}
|
|
4849
|
+
return _config.atob(input);
|
|
4850
|
+
}
|
|
4851
|
+
/**
|
|
4852
|
+
* Decode a base64url-encoded string (used by JWT payloads).
|
|
4853
|
+
* Normalises base64url → standard base64 before decoding.
|
|
4854
|
+
*/
|
|
4855
|
+
static decodeBase64Url(input) {
|
|
4856
|
+
let b64 = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
4857
|
+
const pad = b64.length % 4;
|
|
4858
|
+
if (pad === 2)
|
|
4859
|
+
b64 += '==';
|
|
4860
|
+
else if (pad === 3)
|
|
4861
|
+
b64 += '=';
|
|
4862
|
+
return this.decodeBase64(b64);
|
|
4863
|
+
}
|
|
4864
|
+
/* ------------------------------------------------------------------ */
|
|
4865
|
+
/* STORE */
|
|
4866
|
+
/* ------------------------------------------------------------------ */
|
|
4867
|
+
static async storeSession(address, accessToken, idToken, refreshToken) {
|
|
4868
|
+
const config = await getConfig();
|
|
4869
|
+
const currentAppId = config.appId;
|
|
4870
|
+
this.getStorage().setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify({
|
|
4871
|
+
address,
|
|
4872
|
+
accessToken,
|
|
4873
|
+
idToken,
|
|
4874
|
+
refreshToken,
|
|
4875
|
+
appId: currentAppId,
|
|
4876
|
+
}));
|
|
4877
|
+
}
|
|
4878
|
+
/* ------------------------------------------------------------------ */
|
|
4879
|
+
/* GET */
|
|
4880
|
+
/* ------------------------------------------------------------------ */
|
|
4881
|
+
static async getSession() {
|
|
4882
|
+
const session = this.getStorage().getItem(this.TAROBASE_SESSION_STORAGE_KEY);
|
|
4883
|
+
if (!session)
|
|
4884
|
+
return null;
|
|
4885
|
+
const sessionObj = JSON.parse(session);
|
|
4886
|
+
/* ---------- validate app-id ---------- */
|
|
4887
|
+
const config = await getConfig();
|
|
4888
|
+
if (sessionObj.appId && sessionObj.appId !== config.appId) {
|
|
4889
|
+
this.clearSession();
|
|
4890
|
+
return null;
|
|
4891
|
+
}
|
|
4892
|
+
/* ---------- check JWT expiration ---------- */
|
|
4893
|
+
try {
|
|
4894
|
+
const { accessToken } = sessionObj;
|
|
4895
|
+
const { exp } = JSON.parse(this.decodeBase64Url(accessToken.split(".")[1]));
|
|
4896
|
+
if (Date.now() > exp * 1000) {
|
|
4897
|
+
const { refreshToken } = sessionObj;
|
|
4898
|
+
if (!refreshToken)
|
|
4899
|
+
return null;
|
|
4900
|
+
const refreshed = await refreshSession(refreshToken);
|
|
4901
|
+
if ((refreshed === null || refreshed === void 0 ? void 0 : refreshed.idToken) && (refreshed === null || refreshed === void 0 ? void 0 : refreshed.accessToken)) {
|
|
4902
|
+
await this.updateIdTokenAndAccessToken(refreshed.idToken, refreshed.accessToken);
|
|
4903
|
+
const newSession = this.getStorage().getItem(this.TAROBASE_SESSION_STORAGE_KEY);
|
|
4904
|
+
if (!newSession)
|
|
4905
|
+
return null;
|
|
4906
|
+
const newObj = JSON.parse(newSession);
|
|
4907
|
+
return { address: newObj.address, session: newObj };
|
|
4908
|
+
}
|
|
4909
|
+
// Refresh failed — clear stale session to prevent retry loops
|
|
4910
|
+
this.clearSession();
|
|
4911
|
+
return null;
|
|
4912
|
+
}
|
|
4913
|
+
}
|
|
4914
|
+
catch (err) {
|
|
4915
|
+
// Token decode or refresh failed — clear stale session to prevent retry loops
|
|
4916
|
+
this.clearSession();
|
|
4917
|
+
return null;
|
|
4918
|
+
}
|
|
4919
|
+
return { address: sessionObj.address, session: sessionObj };
|
|
4920
|
+
}
|
|
4921
|
+
/* ------------------------------------------------------------------ */
|
|
4922
|
+
/* CLEAR */
|
|
4923
|
+
/* ------------------------------------------------------------------ */
|
|
4924
|
+
static clearSession() {
|
|
4925
|
+
this.getStorage().removeItem(this.TAROBASE_SESSION_STORAGE_KEY);
|
|
4926
|
+
}
|
|
4927
|
+
/* ------------------------------------------------------------------ */
|
|
4928
|
+
/* IS-AUTH */
|
|
4929
|
+
/* ------------------------------------------------------------------ */
|
|
4930
|
+
static isAuthenticated() {
|
|
4931
|
+
return !!this.getStorage().getItem(this.TAROBASE_SESSION_STORAGE_KEY);
|
|
4932
|
+
}
|
|
4933
|
+
/* ------------------------------------------------------------------ */
|
|
4934
|
+
/* TOKEN HELPERS */
|
|
4935
|
+
/* ------------------------------------------------------------------ */
|
|
4936
|
+
static getIdToken() {
|
|
4937
|
+
try {
|
|
4938
|
+
const session = this.getStorage().getItem(this.TAROBASE_SESSION_STORAGE_KEY);
|
|
4939
|
+
return session ? JSON.parse(session).idToken : null;
|
|
4940
|
+
}
|
|
4941
|
+
catch (_a) {
|
|
4942
|
+
return null;
|
|
4943
|
+
}
|
|
4944
|
+
}
|
|
4945
|
+
static getRefreshToken() {
|
|
4946
|
+
try {
|
|
4947
|
+
const session = this.getStorage().getItem(this.TAROBASE_SESSION_STORAGE_KEY);
|
|
4948
|
+
return session ? JSON.parse(session).refreshToken : null;
|
|
4949
|
+
}
|
|
4950
|
+
catch (_a) {
|
|
4951
|
+
return null;
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
/* ------------------------------------------------------------------ */
|
|
4955
|
+
/* UPDATE TOKENS */
|
|
4956
|
+
/* ------------------------------------------------------------------ */
|
|
4957
|
+
static async updateIdTokenAndAccessToken(idToken, accessToken) {
|
|
4958
|
+
var _a;
|
|
4959
|
+
const session = this.getStorage().getItem(this.TAROBASE_SESSION_STORAGE_KEY);
|
|
4960
|
+
if (!session)
|
|
4961
|
+
return;
|
|
4962
|
+
const sessionObj = JSON.parse(session);
|
|
4963
|
+
/* ---------- app-id guard ---------- */
|
|
4964
|
+
const config = await getConfig();
|
|
4965
|
+
if (sessionObj.appId && sessionObj.appId !== config.appId) {
|
|
4966
|
+
this.clearSession();
|
|
4967
|
+
return;
|
|
4968
|
+
}
|
|
4969
|
+
sessionObj.idToken = idToken;
|
|
4970
|
+
sessionObj.accessToken = accessToken;
|
|
4971
|
+
(_a = sessionObj.appId) !== null && _a !== void 0 ? _a : (sessionObj.appId = config.appId);
|
|
4972
|
+
this.getStorage().setItem(this.TAROBASE_SESSION_STORAGE_KEY, JSON.stringify(sessionObj));
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4975
|
+
ReactNativeSessionManager.TAROBASE_SESSION_STORAGE_KEY = "tarobase_session_storage";
|
|
4976
|
+
|
|
4762
4977
|
exports.InsufficientBalanceError = InsufficientBalanceError;
|
|
4978
|
+
exports.ReactNativeSessionManager = ReactNativeSessionManager;
|
|
4763
4979
|
exports.ServerSessionManager = ServerSessionManager;
|
|
4764
4980
|
exports.WebSessionManager = WebSessionManager;
|
|
4765
4981
|
exports.aggregate = aggregate;
|