@addn/sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/storage.d.ts +25 -0
- package/dist/auth/storage.d.ts.map +1 -0
- package/dist/auth/storage.js +72 -0
- package/dist/auth/storage.js.map +1 -0
- package/dist/auth/token-manager.d.ts +39 -0
- package/dist/auth/token-manager.d.ts.map +1 -0
- package/dist/auth/token-manager.js +98 -0
- package/dist/auth/token-manager.js.map +1 -0
- package/dist/client.d.ts +31 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +39 -0
- package/dist/client.js.map +1 -0
- package/dist/http/errors.d.ts +51 -0
- package/dist/http/errors.d.ts.map +1 -0
- package/dist/http/errors.js +92 -0
- package/dist/http/errors.js.map +1 -0
- package/dist/http/http-client.d.ts +18 -0
- package/dist/http/http-client.d.ts.map +1 -0
- package/dist/http/http-client.js +221 -0
- package/dist/http/http-client.js.map +1 -0
- package/dist/http/types.d.ts +27 -0
- package/dist/http/types.d.ts.map +1 -0
- package/dist/http/types.js +3 -0
- package/dist/http/types.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +36 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/accounts.module.d.ts +15 -0
- package/dist/modules/accounts.module.d.ts.map +1 -0
- package/dist/modules/accounts.module.js +57 -0
- package/dist/modules/accounts.module.js.map +1 -0
- package/dist/modules/analytics.module.d.ts +14 -0
- package/dist/modules/analytics.module.d.ts.map +1 -0
- package/dist/modules/analytics.module.js +24 -0
- package/dist/modules/analytics.module.js.map +1 -0
- package/dist/modules/auth.module.d.ts +18 -0
- package/dist/modules/auth.module.d.ts.map +1 -0
- package/dist/modules/auth.module.js +113 -0
- package/dist/modules/auth.module.js.map +1 -0
- package/dist/modules/content-plans.module.d.ts +58 -0
- package/dist/modules/content-plans.module.d.ts.map +1 -0
- package/dist/modules/content-plans.module.js +125 -0
- package/dist/modules/content-plans.module.js.map +1 -0
- package/dist/modules/customers.module.d.ts +12 -0
- package/dist/modules/customers.module.d.ts.map +1 -0
- package/dist/modules/customers.module.js +43 -0
- package/dist/modules/customers.module.js.map +1 -0
- package/dist/modules/notifications.module.d.ts +20 -0
- package/dist/modules/notifications.module.d.ts.map +1 -0
- package/dist/modules/notifications.module.js +37 -0
- package/dist/modules/notifications.module.js.map +1 -0
- package/dist/modules/orgs.module.d.ts +23 -0
- package/dist/modules/orgs.module.d.ts.map +1 -0
- package/dist/modules/orgs.module.js +112 -0
- package/dist/modules/orgs.module.js.map +1 -0
- package/dist/modules/projects.module.d.ts +26 -0
- package/dist/modules/projects.module.d.ts.map +1 -0
- package/dist/modules/projects.module.js +88 -0
- package/dist/modules/projects.module.js.map +1 -0
- package/dist/modules/scheduling.module.d.ts +13 -0
- package/dist/modules/scheduling.module.d.ts.map +1 -0
- package/dist/modules/scheduling.module.js +32 -0
- package/dist/modules/scheduling.module.js.map +1 -0
- package/dist/modules/storage.module.d.ts +36 -0
- package/dist/modules/storage.module.d.ts.map +1 -0
- package/dist/modules/storage.module.js +100 -0
- package/dist/modules/storage.module.js.map +1 -0
- package/dist/modules/subscriptions.module.d.ts +25 -0
- package/dist/modules/subscriptions.module.d.ts.map +1 -0
- package/dist/modules/subscriptions.module.js +62 -0
- package/dist/modules/subscriptions.module.js.map +1 -0
- package/dist/types/account.types.d.ts +17 -0
- package/dist/types/account.types.d.ts.map +1 -0
- package/dist/types/account.types.js +3 -0
- package/dist/types/account.types.js.map +1 -0
- package/dist/types/analytics.types.d.ts +15 -0
- package/dist/types/analytics.types.d.ts.map +1 -0
- package/dist/types/analytics.types.js +3 -0
- package/dist/types/analytics.types.js.map +1 -0
- package/dist/types/api.types.d.ts +20 -0
- package/dist/types/api.types.d.ts.map +1 -0
- package/dist/types/api.types.js +3 -0
- package/dist/types/api.types.js.map +1 -0
- package/dist/types/auth.types.d.ts +40 -0
- package/dist/types/auth.types.d.ts.map +1 -0
- package/dist/types/auth.types.js +3 -0
- package/dist/types/auth.types.js.map +1 -0
- package/dist/types/content-plan.types.d.ts +27 -0
- package/dist/types/content-plan.types.d.ts.map +1 -0
- package/dist/types/content-plan.types.js +3 -0
- package/dist/types/content-plan.types.js.map +1 -0
- package/dist/types/customer.types.d.ts +25 -0
- package/dist/types/customer.types.d.ts.map +1 -0
- package/dist/types/customer.types.js +3 -0
- package/dist/types/customer.types.js.map +1 -0
- package/dist/types/index.d.ts +585 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/notification.types.d.ts +11 -0
- package/dist/types/notification.types.d.ts.map +1 -0
- package/dist/types/notification.types.js +3 -0
- package/dist/types/notification.types.js.map +1 -0
- package/dist/types/org.types.d.ts +25 -0
- package/dist/types/org.types.d.ts.map +1 -0
- package/dist/types/org.types.js +3 -0
- package/dist/types/org.types.js.map +1 -0
- package/dist/types/project.types.d.ts +20 -0
- package/dist/types/project.types.d.ts.map +1 -0
- package/dist/types/project.types.js +3 -0
- package/dist/types/project.types.js.map +1 -0
- package/dist/types/scheduling.types.d.ts +31 -0
- package/dist/types/scheduling.types.d.ts.map +1 -0
- package/dist/types/scheduling.types.js +3 -0
- package/dist/types/scheduling.types.js.map +1 -0
- package/dist/types/storage.types.d.ts +8 -0
- package/dist/types/storage.types.d.ts.map +1 -0
- package/dist/types/storage.types.js +3 -0
- package/dist/types/storage.types.js.map +1 -0
- package/dist/types/subscription.types.d.ts +19 -0
- package/dist/types/subscription.types.d.ts.map +1 -0
- package/dist/types/subscription.types.js +3 -0
- package/dist/types/subscription.types.js.map +1 -0
- package/package.json +27 -0
- package/src/auth/storage.ts +75 -0
- package/src/auth/token-manager.ts +107 -0
- package/src/client.ts +51 -0
- package/src/http/errors.ts +97 -0
- package/src/http/http-client.ts +263 -0
- package/src/http/types.ts +32 -0
- package/src/index.ts +17 -0
- package/src/modules/accounts.module.ts +61 -0
- package/src/modules/analytics.module.ts +26 -0
- package/src/modules/auth.module.ts +129 -0
- package/src/modules/content-plans.module.ts +170 -0
- package/src/modules/customers.module.ts +48 -0
- package/src/modules/notifications.module.ts +41 -0
- package/src/modules/orgs.module.ts +122 -0
- package/src/modules/projects.module.ts +97 -0
- package/src/modules/scheduling.module.ts +35 -0
- package/src/modules/storage.module.ts +121 -0
- package/src/modules/subscriptions.module.ts +82 -0
- package/src/types/account.types.ts +17 -0
- package/src/types/analytics.types.ts +15 -0
- package/src/types/api.types.ts +21 -0
- package/src/types/auth.types.ts +45 -0
- package/src/types/content-plan.types.ts +28 -0
- package/src/types/customer.types.ts +25 -0
- package/src/types/index.ts +682 -0
- package/src/types/notification.types.ts +10 -0
- package/src/types/org.types.ts +27 -0
- package/src/types/project.types.ts +21 -0
- package/src/types/scheduling.types.ts +32 -0
- package/src/types/storage.types.ts +7 -0
- package/src/types/subscription.types.ts +19 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface Project {
|
|
2
|
+
id: string;
|
|
3
|
+
organization_id: string;
|
|
4
|
+
customer_id?: string | null;
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
status: "active" | "archived" | "draft";
|
|
8
|
+
created_by: string;
|
|
9
|
+
created_at: string;
|
|
10
|
+
updated_at: string;
|
|
11
|
+
}
|
|
12
|
+
export interface CreateProjectPayload {
|
|
13
|
+
name: string;
|
|
14
|
+
customer_id?: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface UpdateProjectPayload extends Partial<CreateProjectPayload> {
|
|
18
|
+
status?: "active" | "archived" | "draft";
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=project.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.types.d.ts","sourceRoot":"","sources":["../../src/types/project.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;IACxC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,oBAAqB,SAAQ,OAAO,CAAC,oBAAoB,CAAC;IACzE,MAAM,CAAC,EAAE,QAAQ,GAAG,UAAU,GAAG,OAAO,CAAC;CAC1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.types.js","sourceRoot":"","sources":["../../src/types/project.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface ScheduledPost {
|
|
2
|
+
id: string;
|
|
3
|
+
post_id: string;
|
|
4
|
+
account_id: string;
|
|
5
|
+
platform: "instagram" | "facebook" | "linkedin";
|
|
6
|
+
caption: string;
|
|
7
|
+
media_urls: string[];
|
|
8
|
+
scheduled_time: string;
|
|
9
|
+
status: "scheduled" | "processing" | "published" | "failed";
|
|
10
|
+
error_message?: string;
|
|
11
|
+
approval_token?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface PublicApprovalView {
|
|
14
|
+
token: string;
|
|
15
|
+
project_name: string;
|
|
16
|
+
posts: Array<{
|
|
17
|
+
id: string;
|
|
18
|
+
title: string;
|
|
19
|
+
caption: string;
|
|
20
|
+
media_urls: string[];
|
|
21
|
+
post_type: string;
|
|
22
|
+
status: string;
|
|
23
|
+
}>;
|
|
24
|
+
}
|
|
25
|
+
export interface SubmitApprovalPayload {
|
|
26
|
+
token: string;
|
|
27
|
+
post_id: string;
|
|
28
|
+
action: "approve" | "reject";
|
|
29
|
+
comment?: string;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=scheduling.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduling.types.d.ts","sourceRoot":"","sources":["../../src/types/scheduling.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,WAAW,GAAG,UAAU,GAAG,UAAU,CAAC;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;IACrB,KAAK,EAAE,KAAK,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,EAAE,CAAC;QACrB,SAAS,EAAE,MAAM,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scheduling.types.js","sourceRoot":"","sources":["../../src/types/scheduling.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.types.d.ts","sourceRoot":"","sources":["../../src/types/storage.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"storage.types.js","sourceRoot":"","sources":["../../src/types/storage.types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface SubscriptionPlan {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
price_monthly: number;
|
|
5
|
+
price_yearly: number;
|
|
6
|
+
features: string[];
|
|
7
|
+
max_projects: number;
|
|
8
|
+
max_members: number;
|
|
9
|
+
max_social_accounts: number;
|
|
10
|
+
is_active: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface UserSubscription {
|
|
13
|
+
id: string;
|
|
14
|
+
organization_id: string;
|
|
15
|
+
plan_id: string;
|
|
16
|
+
status: "active" | "canceled" | "past_due" | "trialing";
|
|
17
|
+
current_period_end: string;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=subscription.types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription.types.d.ts","sourceRoot":"","sources":["../../src/types/subscription.types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,QAAQ,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,CAAC;IACxD,kBAAkB,EAAE,MAAM,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription.types.js","sourceRoot":"","sources":["../../src/types/subscription.types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@addn/sdk",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official ADDN Backend TypeScript SDK for Web (frontend3) and Mobile (React Native/Expo)",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"dist",
|
|
9
|
+
"src"
|
|
10
|
+
],
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"require": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"scripts": {
|
|
19
|
+
"build": "tsc",
|
|
20
|
+
"typecheck": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"author": "ADDN Engineering",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"typescript": "^5.0.0"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { StorageAdapter } from "../http/types";
|
|
2
|
+
|
|
3
|
+
export class MemoryStorageAdapter implements StorageAdapter {
|
|
4
|
+
private store: Map<string, string> = new Map();
|
|
5
|
+
|
|
6
|
+
getItem(key: string): string | null {
|
|
7
|
+
return this.store.get(key) ?? null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
setItem(key: string, value: string): void {
|
|
11
|
+
this.store.set(key, value);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
removeItem(key: string): void {
|
|
15
|
+
this.store.delete(key);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export class LocalStorageAdapter implements StorageAdapter {
|
|
20
|
+
getItem(key: string): string | null {
|
|
21
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
22
|
+
return window.localStorage.getItem(key);
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
setItem(key: string, value: string): void {
|
|
28
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
29
|
+
window.localStorage.setItem(key, value);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
removeItem(key: string): void {
|
|
34
|
+
if (typeof window !== "undefined" && window.localStorage) {
|
|
35
|
+
window.localStorage.removeItem(key);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export class SessionStorageAdapter implements StorageAdapter {
|
|
41
|
+
getItem(key: string): string | null {
|
|
42
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
43
|
+
return window.sessionStorage.getItem(key);
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
setItem(key: string, value: string): void {
|
|
49
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
50
|
+
window.sessionStorage.setItem(key, value);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
removeItem(key: string): void {
|
|
55
|
+
if (typeof window !== "undefined" && window.sessionStorage) {
|
|
56
|
+
window.sessionStorage.removeItem(key);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export class CustomStorageAdapter implements StorageAdapter {
|
|
62
|
+
constructor(private readonly storage: StorageAdapter) {}
|
|
63
|
+
|
|
64
|
+
async getItem(key: string): Promise<string | null> {
|
|
65
|
+
return await this.storage.getItem(key);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
async setItem(key: string, value: string): Promise<void> {
|
|
69
|
+
await this.storage.setItem(key, value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async removeItem(key: string): Promise<void> {
|
|
73
|
+
await this.storage.removeItem(key);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { StorageAdapter } from "../http/types";
|
|
2
|
+
import { MemoryStorageAdapter } from "./storage";
|
|
3
|
+
|
|
4
|
+
export interface TokenPair {
|
|
5
|
+
accessToken: string;
|
|
6
|
+
refreshToken?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export class TokenManager {
|
|
10
|
+
private readonly REFRESH_TOKEN_KEY = "addn_refresh_token";
|
|
11
|
+
private readonly USER_KEY = "addn_current_user";
|
|
12
|
+
|
|
13
|
+
private memoryAccessToken: string | null = null;
|
|
14
|
+
private memoryRefreshToken: string | null = null;
|
|
15
|
+
private refreshPromise: Promise<TokenPair | null> | null = null;
|
|
16
|
+
|
|
17
|
+
constructor(
|
|
18
|
+
private readonly storage: StorageAdapter = new MemoryStorageAdapter(),
|
|
19
|
+
private readonly onUnauthenticated?: () => void
|
|
20
|
+
) {}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns the short-lived access token strictly from memory.
|
|
24
|
+
* Access tokens are NEVER stored in persistent browser/disk storage to prevent XSS exfiltration.
|
|
25
|
+
*/
|
|
26
|
+
public async getAccessToken(): Promise<string | null> {
|
|
27
|
+
return this.memoryAccessToken;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Returns the refresh token from memory or secure storage for session restoration.
|
|
32
|
+
*/
|
|
33
|
+
public async getRefreshToken(): Promise<string | null> {
|
|
34
|
+
if (this.memoryRefreshToken) {
|
|
35
|
+
return this.memoryRefreshToken;
|
|
36
|
+
}
|
|
37
|
+
const stored = await this.storage.getItem(this.REFRESH_TOKEN_KEY);
|
|
38
|
+
this.memoryRefreshToken = stored;
|
|
39
|
+
return stored;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Sets access token in memory and persists refresh token securely.
|
|
44
|
+
*/
|
|
45
|
+
public async setTokens(accessToken: string, refreshToken?: string): Promise<void> {
|
|
46
|
+
this.memoryAccessToken = accessToken;
|
|
47
|
+
if (refreshToken) {
|
|
48
|
+
this.memoryRefreshToken = refreshToken;
|
|
49
|
+
await this.storage.setItem(this.REFRESH_TOKEN_KEY, refreshToken);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async setUser(user: any): Promise<void> {
|
|
54
|
+
if (user) {
|
|
55
|
+
await this.storage.setItem(this.USER_KEY, JSON.stringify(user));
|
|
56
|
+
} else {
|
|
57
|
+
await this.storage.removeItem(this.USER_KEY);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
public async getUser<T = any>(): Promise<T | null> {
|
|
62
|
+
const raw = await this.storage.getItem(this.USER_KEY);
|
|
63
|
+
if (!raw) return null;
|
|
64
|
+
try {
|
|
65
|
+
return JSON.parse(raw) as T;
|
|
66
|
+
} catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Clears in-memory tokens and persistent session keys.
|
|
73
|
+
*/
|
|
74
|
+
public async clearTokens(): Promise<void> {
|
|
75
|
+
this.memoryAccessToken = null;
|
|
76
|
+
this.memoryRefreshToken = null;
|
|
77
|
+
await this.storage.removeItem(this.REFRESH_TOKEN_KEY);
|
|
78
|
+
await this.storage.removeItem(this.USER_KEY);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Manages single-flight refresh queue without race conditions.
|
|
83
|
+
*/
|
|
84
|
+
public async handleRefresh(refreshFn: (refreshToken?: string) => Promise<TokenPair>): Promise<TokenPair | null> {
|
|
85
|
+
if (this.refreshPromise) {
|
|
86
|
+
return this.refreshPromise;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const currentRefreshToken = await this.getRefreshToken();
|
|
90
|
+
|
|
91
|
+
this.refreshPromise = (async () => {
|
|
92
|
+
try {
|
|
93
|
+
const newTokens = await refreshFn(currentRefreshToken || undefined);
|
|
94
|
+
await this.setTokens(newTokens.accessToken, newTokens.refreshToken);
|
|
95
|
+
return newTokens;
|
|
96
|
+
} catch (err) {
|
|
97
|
+
await this.clearTokens();
|
|
98
|
+
this.onUnauthenticated?.();
|
|
99
|
+
return null;
|
|
100
|
+
} finally {
|
|
101
|
+
this.refreshPromise = null;
|
|
102
|
+
}
|
|
103
|
+
})();
|
|
104
|
+
|
|
105
|
+
return this.refreshPromise;
|
|
106
|
+
}
|
|
107
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { HttpClient } from "./http/http-client";
|
|
2
|
+
import { AddnClientOptions } from "./http/types";
|
|
3
|
+
import { AuthModule } from "./modules/auth.module";
|
|
4
|
+
import { OrgsModule } from "./modules/orgs.module";
|
|
5
|
+
import { CustomersModule } from "./modules/customers.module";
|
|
6
|
+
import { ProjectsModule } from "./modules/projects.module";
|
|
7
|
+
import { ContentPlansModule } from "./modules/content-plans.module";
|
|
8
|
+
import { SchedulingModule } from "./modules/scheduling.module";
|
|
9
|
+
import { AccountsModule } from "./modules/accounts.module";
|
|
10
|
+
import { AnalyticsModule } from "./modules/analytics.module";
|
|
11
|
+
import { NotificationsModule } from "./modules/notifications.module";
|
|
12
|
+
import { StorageModule } from "./modules/storage.module";
|
|
13
|
+
import { SubscriptionsModule } from "./modules/subscriptions.module";
|
|
14
|
+
|
|
15
|
+
export class AddnClient {
|
|
16
|
+
public readonly http: HttpClient;
|
|
17
|
+
public readonly auth: AuthModule;
|
|
18
|
+
public readonly orgs: OrgsModule;
|
|
19
|
+
public readonly customers: CustomersModule;
|
|
20
|
+
public readonly projects: ProjectsModule;
|
|
21
|
+
public readonly contentPlans: ContentPlansModule;
|
|
22
|
+
public readonly scheduling: SchedulingModule;
|
|
23
|
+
public readonly accounts: AccountsModule;
|
|
24
|
+
public readonly analytics: AnalyticsModule;
|
|
25
|
+
public readonly notifications: NotificationsModule;
|
|
26
|
+
public readonly storage: StorageModule;
|
|
27
|
+
public readonly subscriptions: SubscriptionsModule;
|
|
28
|
+
|
|
29
|
+
constructor(options: AddnClientOptions) {
|
|
30
|
+
this.http = new HttpClient(options);
|
|
31
|
+
this.auth = new AuthModule(this.http);
|
|
32
|
+
this.orgs = new OrgsModule(this.http);
|
|
33
|
+
this.customers = new CustomersModule(this.http);
|
|
34
|
+
this.projects = new ProjectsModule(this.http);
|
|
35
|
+
this.contentPlans = new ContentPlansModule(this.http);
|
|
36
|
+
this.scheduling = new SchedulingModule(this.http);
|
|
37
|
+
this.accounts = new AccountsModule(this.http);
|
|
38
|
+
this.analytics = new AnalyticsModule(this.http);
|
|
39
|
+
this.notifications = new NotificationsModule(this.http);
|
|
40
|
+
this.storage = new StorageModule(this.http);
|
|
41
|
+
this.subscriptions = new SubscriptionsModule(this.http);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
public async setTokens(accessToken: string, refreshToken: string): Promise<void> {
|
|
45
|
+
await this.http.tokenManager.setTokens(accessToken, refreshToken);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public async clearTokens(): Promise<void> {
|
|
49
|
+
await this.http.tokenManager.clearTokens();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { ValidationErrorDetail } from "../types";
|
|
2
|
+
|
|
3
|
+
export abstract class AddnError extends Error {
|
|
4
|
+
public abstract readonly code: string;
|
|
5
|
+
|
|
6
|
+
constructor(message: string, public readonly cause?: unknown) {
|
|
7
|
+
super(message);
|
|
8
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
9
|
+
if ((Error as any).captureStackTrace) {
|
|
10
|
+
(Error as any).captureStackTrace(this, this.constructor);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export class AddnNetworkError extends AddnError {
|
|
16
|
+
public readonly code = "NETWORK_ERROR";
|
|
17
|
+
|
|
18
|
+
constructor(message: string = "Unable to connect to ADDN server. Please check your internet connection.", cause?: unknown) {
|
|
19
|
+
super(message, cause);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class AddnTimeoutError extends AddnError {
|
|
24
|
+
public readonly code = "REQUEST_TIMEOUT";
|
|
25
|
+
|
|
26
|
+
constructor(public readonly timeoutMs: number, message: string = `Request timed out after ${timeoutMs}ms`) {
|
|
27
|
+
super(message);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export class AddnApiError extends AddnError {
|
|
32
|
+
public readonly code: string;
|
|
33
|
+
|
|
34
|
+
constructor(
|
|
35
|
+
message: string,
|
|
36
|
+
public readonly statusCode: number,
|
|
37
|
+
public readonly errorCode: string = "API_ERROR",
|
|
38
|
+
public readonly details: unknown = null,
|
|
39
|
+
public readonly rawResponse?: unknown
|
|
40
|
+
) {
|
|
41
|
+
super(message);
|
|
42
|
+
this.code = errorCode;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export class AddnAuthError extends AddnApiError {
|
|
47
|
+
constructor(message: string = "Authentication failed or token expired.", statusCode: number = 401, errorCode: string = "AUTHENTICATION_FAILED", details?: unknown) {
|
|
48
|
+
super(message, statusCode, errorCode, details);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export class AddnForbiddenError extends AddnApiError {
|
|
53
|
+
constructor(message: string = "You do not have permission to perform this action.", statusCode: number = 403, errorCode: string = "PERMISSION_DENIED", details?: unknown) {
|
|
54
|
+
super(message, statusCode, errorCode, details);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export class AddnNotFoundError extends AddnApiError {
|
|
59
|
+
constructor(message: string = "The requested resource could not be found.", statusCode: number = 404, errorCode: string = "RESOURCE_NOT_FOUND", details?: unknown) {
|
|
60
|
+
super(message, statusCode, errorCode, details);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export class AddnConflictError extends AddnApiError {
|
|
65
|
+
constructor(message: string = "A resource conflict occurred.", statusCode: number = 409, errorCode: string = "DUPLICATE_RESOURCE", details?: unknown) {
|
|
66
|
+
super(message, statusCode, errorCode, details);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export class AddnValidationError extends AddnApiError {
|
|
71
|
+
public readonly validationDetails: ValidationErrorDetail[];
|
|
72
|
+
|
|
73
|
+
constructor(message: string = "Validation failed.", details: ValidationErrorDetail[] = [], rawResponse?: unknown) {
|
|
74
|
+
super(message, 422, "VALIDATION_ERROR", details, rawResponse);
|
|
75
|
+
this.validationDetails = details;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export class AddnRateLimitError extends AddnApiError {
|
|
80
|
+
constructor(message: string = "Too many requests. Please try again later.", public readonly retryAfterSeconds?: number) {
|
|
81
|
+
super(message, 429, "RATE_LIMITED", { retryAfterSeconds });
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export class AddnServerError extends AddnApiError {
|
|
86
|
+
constructor(message: string = "An internal server error occurred. Please try again later.", statusCode: number = 500, errorCode: string = "INTERNAL_SERVER_ERROR", details?: unknown) {
|
|
87
|
+
super(message, statusCode, errorCode, details);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export class AddnUnexpectedError extends AddnError {
|
|
92
|
+
public readonly code = "UNEXPECTED_ERROR";
|
|
93
|
+
|
|
94
|
+
constructor(message: string = "An unexpected error occurred processing the server response.", cause?: unknown) {
|
|
95
|
+
super(message, cause);
|
|
96
|
+
}
|
|
97
|
+
}
|