target-supabase-sdk 0.1.0 → 0.1.2
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/LICENSE +21 -21
- package/README.md +121 -70
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/parcel/parcel-manager.d.ts +2 -2
- package/dist/parcel/parcel-manager.d.ts.map +1 -1
- package/package.json +57 -45
- package/src/auth/auth.api.ts +85 -85
- package/src/core.api.ts +338 -338
- package/src/core.interface.ts +74 -74
- package/src/core.utils.ts +98 -98
- package/src/feed/feed.interface.ts +33 -33
- package/src/file/file.api.ts +43 -43
- package/src/file/file.interface.ts +29 -29
- package/src/file-list/file-list.api.ts +64 -64
- package/src/file-list/file-list.interface.ts +24 -24
- package/src/idea/idea.interface.ts +27 -27
- package/src/index.ts +51 -50
- package/src/link/link.interface.ts +21 -21
- package/src/parcel/parcel-manager.ts +209 -209
- package/src/parcel/parcel.interface.ts +40 -40
- package/src/question-list/question-list.api.ts +42 -42
- package/src/question-list/question-list.interface.ts +21 -21
- package/src/review/review.api.ts +145 -145
- package/src/review/review.interface.ts +26 -26
- package/src/review-v2/apis/post-review-setting.api.ts +35 -35
- package/src/review-v2/apis/post-review.api.ts +59 -59
- package/src/review-v2/review-setting.interface.ts +26 -26
- package/src/review-v2/review.interface.ts +23 -23
- package/src/service/api.interface.ts +47 -47
- package/src/service/base.interface.ts +97 -97
- package/src/service/service.interface.ts +27 -27
- package/src/supabase.ts +143 -143
|
@@ -1,47 +1,47 @@
|
|
|
1
|
-
import { Target } from "../core.interface";
|
|
2
|
-
import { Field, Lifecycle } from "./base.interface";
|
|
3
|
-
|
|
4
|
-
export interface Api extends Target {
|
|
5
|
-
/** "core.post.target.0" 唯一键 领域 + METHOD + content + VERSION */
|
|
6
|
-
value: string;
|
|
7
|
-
category: CategoryApi;
|
|
8
|
-
details: ApiDetails;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export enum CategoryApi {
|
|
12
|
-
API = "api",
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export enum ApiMethod {
|
|
16
|
-
POST = "POST",
|
|
17
|
-
GET = "GET",
|
|
18
|
-
PUT = "PUT",
|
|
19
|
-
DELETE = "DELETE",
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface ApiDetails {
|
|
23
|
-
method: ApiMethod;
|
|
24
|
-
/** /v0/core/target */
|
|
25
|
-
path: string;
|
|
26
|
-
request: {
|
|
27
|
-
query: {
|
|
28
|
-
[key: string]: Field;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
response: {
|
|
32
|
-
"200": { [key: string]: Field };
|
|
33
|
-
};
|
|
34
|
-
manifestVersion: number;
|
|
35
|
-
lifecycle: Lifecycle;
|
|
36
|
-
/** TODO "application/octet-stream" */
|
|
37
|
-
// contentType: string;
|
|
38
|
-
/** TODO "application/json" */
|
|
39
|
-
// responseType: string;
|
|
40
|
-
/** TODO 安全模型/ 风控 / 限制 / 可观测性 & 审计 */
|
|
41
|
-
// auth: unknown;
|
|
42
|
-
// rate_limit: {
|
|
43
|
-
// key: "user_id";
|
|
44
|
-
// limit: 60;
|
|
45
|
-
// window: "1m";
|
|
46
|
-
// };
|
|
47
|
-
}
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
import { Field, Lifecycle } from "./base.interface";
|
|
3
|
+
|
|
4
|
+
export interface Api extends Target {
|
|
5
|
+
/** "core.post.target.0" 唯一键 领域 + METHOD + content + VERSION */
|
|
6
|
+
value: string;
|
|
7
|
+
category: CategoryApi;
|
|
8
|
+
details: ApiDetails;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export enum CategoryApi {
|
|
12
|
+
API = "api",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export enum ApiMethod {
|
|
16
|
+
POST = "POST",
|
|
17
|
+
GET = "GET",
|
|
18
|
+
PUT = "PUT",
|
|
19
|
+
DELETE = "DELETE",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ApiDetails {
|
|
23
|
+
method: ApiMethod;
|
|
24
|
+
/** /v0/core/target */
|
|
25
|
+
path: string;
|
|
26
|
+
request: {
|
|
27
|
+
query: {
|
|
28
|
+
[key: string]: Field;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
response: {
|
|
32
|
+
"200": { [key: string]: Field };
|
|
33
|
+
};
|
|
34
|
+
manifestVersion: number;
|
|
35
|
+
lifecycle: Lifecycle;
|
|
36
|
+
/** TODO "application/octet-stream" */
|
|
37
|
+
// contentType: string;
|
|
38
|
+
/** TODO "application/json" */
|
|
39
|
+
// responseType: string;
|
|
40
|
+
/** TODO 安全模型/ 风控 / 限制 / 可观测性 & 审计 */
|
|
41
|
+
// auth: unknown;
|
|
42
|
+
// rate_limit: {
|
|
43
|
+
// key: "user_id";
|
|
44
|
+
// limit: 60;
|
|
45
|
+
// window: "1m";
|
|
46
|
+
// };
|
|
47
|
+
}
|
|
@@ -1,97 +1,97 @@
|
|
|
1
|
-
import { Target } from "../core.interface";
|
|
2
|
-
|
|
3
|
-
export enum LifecycleStatus {
|
|
4
|
-
ACTIVE = "ACTIVE",
|
|
5
|
-
DEPRECATED = "DEPRECATED",
|
|
6
|
-
SUNSET = "SUNSET",
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export interface Lifecycle {
|
|
10
|
-
status: LifecycleStatus;
|
|
11
|
-
/** YYYY-MM-DD */
|
|
12
|
-
activeSince: string;
|
|
13
|
-
deprecatedAt: string | null;
|
|
14
|
-
sunsetAt: string | null;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type Field =
|
|
18
|
-
| {
|
|
19
|
-
type: "string";
|
|
20
|
-
nullable: boolean;
|
|
21
|
-
required: boolean;
|
|
22
|
-
/** 1 */
|
|
23
|
-
minLength: number;
|
|
24
|
-
/** 64 */
|
|
25
|
-
maxLength: number;
|
|
26
|
-
/** ^[a-z0-9_-]+$ */
|
|
27
|
-
pattern: string;
|
|
28
|
-
}
|
|
29
|
-
| {
|
|
30
|
-
type: "number";
|
|
31
|
-
nullable: boolean;
|
|
32
|
-
required: boolean;
|
|
33
|
-
/** 1 */
|
|
34
|
-
minimum: number;
|
|
35
|
-
/** 64 */
|
|
36
|
-
maximum: number;
|
|
37
|
-
}
|
|
38
|
-
| {
|
|
39
|
-
type: "boolean";
|
|
40
|
-
nullable: boolean;
|
|
41
|
-
required: boolean;
|
|
42
|
-
}
|
|
43
|
-
| {
|
|
44
|
-
type: "enum";
|
|
45
|
-
nullable: boolean;
|
|
46
|
-
required: boolean;
|
|
47
|
-
/** 'core.Gender.0' */
|
|
48
|
-
enumKey: string;
|
|
49
|
-
}
|
|
50
|
-
| {
|
|
51
|
-
type: "array";
|
|
52
|
-
nullable: boolean;
|
|
53
|
-
required: boolean;
|
|
54
|
-
/** 'string'|'number'|'boolean'|'enum.enumKey'|'ref.refKey' */
|
|
55
|
-
itemType: string;
|
|
56
|
-
}
|
|
57
|
-
| {
|
|
58
|
-
/** Object */
|
|
59
|
-
type: "ref";
|
|
60
|
-
nullable: boolean;
|
|
61
|
-
required: boolean;
|
|
62
|
-
/** 'core.QuestionReview.0' */
|
|
63
|
-
refKey: string;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
export interface TargetDescriptor extends Target {
|
|
68
|
-
/** "core.QuestionReview.0" 唯一键 领域 + targetName + VERSION */
|
|
69
|
-
value: string;
|
|
70
|
-
category: 'target-descriptor';
|
|
71
|
-
details: TargetDescriptorDetails;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export interface TargetDescriptorDetails {
|
|
75
|
-
list: Array<{
|
|
76
|
-
name: string;
|
|
77
|
-
} & Field>;
|
|
78
|
-
refMap?: Record<string, TargetDescriptor>;
|
|
79
|
-
enumMap?: Record<string, string[]>;
|
|
80
|
-
manifestVersion: number;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export interface EnumDescriptor extends Target {
|
|
84
|
-
/** "core.Gender.0" 唯一键 领域 + enumName + VERSION */
|
|
85
|
-
value: string;
|
|
86
|
-
category: 'target-descriptor';
|
|
87
|
-
details: EnumDescriptorDetails;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
export interface EnumDescriptorDetails {
|
|
91
|
-
list: Array<{
|
|
92
|
-
key: string;
|
|
93
|
-
value: string;
|
|
94
|
-
}>;
|
|
95
|
-
manifestVersion: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
|
|
3
|
+
export enum LifecycleStatus {
|
|
4
|
+
ACTIVE = "ACTIVE",
|
|
5
|
+
DEPRECATED = "DEPRECATED",
|
|
6
|
+
SUNSET = "SUNSET",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface Lifecycle {
|
|
10
|
+
status: LifecycleStatus;
|
|
11
|
+
/** YYYY-MM-DD */
|
|
12
|
+
activeSince: string;
|
|
13
|
+
deprecatedAt: string | null;
|
|
14
|
+
sunsetAt: string | null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type Field =
|
|
18
|
+
| {
|
|
19
|
+
type: "string";
|
|
20
|
+
nullable: boolean;
|
|
21
|
+
required: boolean;
|
|
22
|
+
/** 1 */
|
|
23
|
+
minLength: number;
|
|
24
|
+
/** 64 */
|
|
25
|
+
maxLength: number;
|
|
26
|
+
/** ^[a-z0-9_-]+$ */
|
|
27
|
+
pattern: string;
|
|
28
|
+
}
|
|
29
|
+
| {
|
|
30
|
+
type: "number";
|
|
31
|
+
nullable: boolean;
|
|
32
|
+
required: boolean;
|
|
33
|
+
/** 1 */
|
|
34
|
+
minimum: number;
|
|
35
|
+
/** 64 */
|
|
36
|
+
maximum: number;
|
|
37
|
+
}
|
|
38
|
+
| {
|
|
39
|
+
type: "boolean";
|
|
40
|
+
nullable: boolean;
|
|
41
|
+
required: boolean;
|
|
42
|
+
}
|
|
43
|
+
| {
|
|
44
|
+
type: "enum";
|
|
45
|
+
nullable: boolean;
|
|
46
|
+
required: boolean;
|
|
47
|
+
/** 'core.Gender.0' */
|
|
48
|
+
enumKey: string;
|
|
49
|
+
}
|
|
50
|
+
| {
|
|
51
|
+
type: "array";
|
|
52
|
+
nullable: boolean;
|
|
53
|
+
required: boolean;
|
|
54
|
+
/** 'string'|'number'|'boolean'|'enum.enumKey'|'ref.refKey' */
|
|
55
|
+
itemType: string;
|
|
56
|
+
}
|
|
57
|
+
| {
|
|
58
|
+
/** Object */
|
|
59
|
+
type: "ref";
|
|
60
|
+
nullable: boolean;
|
|
61
|
+
required: boolean;
|
|
62
|
+
/** 'core.QuestionReview.0' */
|
|
63
|
+
refKey: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
export interface TargetDescriptor extends Target {
|
|
68
|
+
/** "core.QuestionReview.0" 唯一键 领域 + targetName + VERSION */
|
|
69
|
+
value: string;
|
|
70
|
+
category: 'target-descriptor';
|
|
71
|
+
details: TargetDescriptorDetails;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface TargetDescriptorDetails {
|
|
75
|
+
list: Array<{
|
|
76
|
+
name: string;
|
|
77
|
+
} & Field>;
|
|
78
|
+
refMap?: Record<string, TargetDescriptor>;
|
|
79
|
+
enumMap?: Record<string, string[]>;
|
|
80
|
+
manifestVersion: number;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface EnumDescriptor extends Target {
|
|
84
|
+
/** "core.Gender.0" 唯一键 领域 + enumName + VERSION */
|
|
85
|
+
value: string;
|
|
86
|
+
category: 'target-descriptor';
|
|
87
|
+
details: EnumDescriptorDetails;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface EnumDescriptorDetails {
|
|
91
|
+
list: Array<{
|
|
92
|
+
key: string;
|
|
93
|
+
value: string;
|
|
94
|
+
}>;
|
|
95
|
+
manifestVersion: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
@@ -1,27 +1,27 @@
|
|
|
1
|
-
import { Target } from "../core.interface";
|
|
2
|
-
import { Lifecycle } from "./base.interface";
|
|
3
|
-
|
|
4
|
-
export interface Service extends Target {
|
|
5
|
-
/** "storage-service" 唯一键 */
|
|
6
|
-
value: string;
|
|
7
|
-
category: CategoryService;
|
|
8
|
-
details: ServiceDetails;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export enum CategoryService {
|
|
12
|
-
SERVICE = "service",
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export enum ServiceStatus {
|
|
16
|
-
ACTIVE = "ACTIVE",
|
|
17
|
-
DEPRECATED = "DEPRECATED",
|
|
18
|
-
SUNSET = "SUNSET",
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export interface ServiceDetails {
|
|
22
|
-
/** 能力 Api keys */
|
|
23
|
-
apis: string[];
|
|
24
|
-
/** 依赖的服务 Service keys */
|
|
25
|
-
dependencies: string[];
|
|
26
|
-
lifecycle: Lifecycle;
|
|
27
|
-
}
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
import { Lifecycle } from "./base.interface";
|
|
3
|
+
|
|
4
|
+
export interface Service extends Target {
|
|
5
|
+
/** "storage-service" 唯一键 */
|
|
6
|
+
value: string;
|
|
7
|
+
category: CategoryService;
|
|
8
|
+
details: ServiceDetails;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export enum CategoryService {
|
|
12
|
+
SERVICE = "service",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export enum ServiceStatus {
|
|
16
|
+
ACTIVE = "ACTIVE",
|
|
17
|
+
DEPRECATED = "DEPRECATED",
|
|
18
|
+
SUNSET = "SUNSET",
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface ServiceDetails {
|
|
22
|
+
/** 能力 Api keys */
|
|
23
|
+
apis: string[];
|
|
24
|
+
/** 依赖的服务 Service keys */
|
|
25
|
+
dependencies: string[];
|
|
26
|
+
lifecycle: Lifecycle;
|
|
27
|
+
}
|
package/src/supabase.ts
CHANGED
|
@@ -1,143 +1,143 @@
|
|
|
1
|
-
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
-
import { logDev, logDevGroup } from "./core.utils";
|
|
3
|
-
|
|
4
|
-
interface SupabaseConfig {
|
|
5
|
-
main: {
|
|
6
|
-
url: string;
|
|
7
|
-
anonKey: string;
|
|
8
|
-
};
|
|
9
|
-
auth: {
|
|
10
|
-
url: string;
|
|
11
|
-
anonKey: string;
|
|
12
|
-
} | null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface SupabaseInitializerParams {
|
|
16
|
-
supabaseUrl: string;
|
|
17
|
-
supabaseAnonKey: string;
|
|
18
|
-
supabaseNeedAuthUrl?: string;
|
|
19
|
-
supabaseNeedAuthAnonKey?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export class SupabaseInitializer {
|
|
23
|
-
private static instance: SupabaseInitializer;
|
|
24
|
-
private isInitialized = false;
|
|
25
|
-
private _mainClient: SupabaseClient | null = null;
|
|
26
|
-
private _authClient: SupabaseClient | null = null;
|
|
27
|
-
|
|
28
|
-
private constructor() {}
|
|
29
|
-
|
|
30
|
-
static getInstance(): SupabaseInitializer {
|
|
31
|
-
if (!SupabaseInitializer.instance) {
|
|
32
|
-
SupabaseInitializer.instance = new SupabaseInitializer();
|
|
33
|
-
}
|
|
34
|
-
return SupabaseInitializer.instance;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Initialize Supabase clients
|
|
39
|
-
*/
|
|
40
|
-
async initialize(
|
|
41
|
-
params: SupabaseInitializerParams
|
|
42
|
-
): Promise<{ supabase: SupabaseClient; supabaseAuth: SupabaseClient | null }> {
|
|
43
|
-
if (this.isInitialized) {
|
|
44
|
-
logDev("🚫 Supabase already initialized");
|
|
45
|
-
return { supabase: this._mainClient!, supabaseAuth: this._authClient };
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
logDev("🔧 Initializing Supabase...");
|
|
49
|
-
|
|
50
|
-
// Validate and get environment variables
|
|
51
|
-
const config = this.validateEnvironmentVariables(params);
|
|
52
|
-
|
|
53
|
-
// Create main client
|
|
54
|
-
this._mainClient = createClient(config.main.url, config.main.anonKey, {
|
|
55
|
-
// TODO
|
|
56
|
-
// auth: {
|
|
57
|
-
// persistSession: true,
|
|
58
|
-
// autoRefreshToken: true,
|
|
59
|
-
// },
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Create auth client if configured
|
|
63
|
-
if (config.auth) {
|
|
64
|
-
this._authClient = createClient(config.auth.url, config.auth.anonKey, {
|
|
65
|
-
// TODO
|
|
66
|
-
// auth: {
|
|
67
|
-
// persistSession: true,
|
|
68
|
-
// autoRefreshToken: true,
|
|
69
|
-
// },
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Log configuration
|
|
74
|
-
this.logConfiguration(config);
|
|
75
|
-
|
|
76
|
-
this.isInitialized = true;
|
|
77
|
-
logDev("✅ Supabase initialization completed");
|
|
78
|
-
|
|
79
|
-
return { supabase: this._mainClient, supabaseAuth: this._authClient };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
private validateEnvironmentVariables({
|
|
83
|
-
supabaseUrl,
|
|
84
|
-
supabaseAnonKey,
|
|
85
|
-
supabaseNeedAuthUrl,
|
|
86
|
-
supabaseNeedAuthAnonKey,
|
|
87
|
-
}: SupabaseInitializerParams): SupabaseConfig {
|
|
88
|
-
const mainUrl = supabaseUrl;
|
|
89
|
-
const mainAnonKey = supabaseAnonKey;
|
|
90
|
-
const authUrl = supabaseNeedAuthUrl;
|
|
91
|
-
const authAnonKey = supabaseNeedAuthAnonKey;
|
|
92
|
-
|
|
93
|
-
if (!mainUrl || !mainAnonKey) {
|
|
94
|
-
throw new Error("Missing required Supabase environment variables: VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY");
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return {
|
|
98
|
-
main: { url: mainUrl, anonKey: mainAnonKey },
|
|
99
|
-
auth: authUrl && authAnonKey ? { url: authUrl, anonKey: authAnonKey } : null,
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
private logConfiguration(config: SupabaseConfig) {
|
|
104
|
-
logDevGroup("🔧 Supabase Configuration", () => {
|
|
105
|
-
console.log("Main URL:", config.main.url);
|
|
106
|
-
console.log("Auth URL:", config.auth?.url || "Not configured");
|
|
107
|
-
console.log("Clients:", {
|
|
108
|
-
main: !!this._mainClient,
|
|
109
|
-
auth: !!this._authClient,
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
getClients() {
|
|
115
|
-
if (!this.isInitialized) {
|
|
116
|
-
throw new Error("Supabase not initialized. Call initialize() first.");
|
|
117
|
-
}
|
|
118
|
-
return { supabase: this._mainClient!, supabaseAuth: this._authClient };
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
get client(): SupabaseClient {
|
|
122
|
-
if (!this.isInitialized) {
|
|
123
|
-
throw new Error("Supabase not initialized. Call initialize() first.");
|
|
124
|
-
}
|
|
125
|
-
if (!this._mainClient) {
|
|
126
|
-
throw new Error("Main Supabase client is null. Initialization may have failed.");
|
|
127
|
-
}
|
|
128
|
-
return this._mainClient;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
get authClient(): SupabaseClient | null {
|
|
132
|
-
if (!this.isInitialized) {
|
|
133
|
-
throw new Error("Supabase not initialized. Call initialize() first.");
|
|
134
|
-
}
|
|
135
|
-
return this._authClient;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
reset() {
|
|
139
|
-
this.isInitialized = false;
|
|
140
|
-
this._mainClient = null;
|
|
141
|
-
this._authClient = null;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
1
|
+
import { createClient, SupabaseClient } from "@supabase/supabase-js";
|
|
2
|
+
import { logDev, logDevGroup } from "./core.utils";
|
|
3
|
+
|
|
4
|
+
interface SupabaseConfig {
|
|
5
|
+
main: {
|
|
6
|
+
url: string;
|
|
7
|
+
anonKey: string;
|
|
8
|
+
};
|
|
9
|
+
auth: {
|
|
10
|
+
url: string;
|
|
11
|
+
anonKey: string;
|
|
12
|
+
} | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface SupabaseInitializerParams {
|
|
16
|
+
supabaseUrl: string;
|
|
17
|
+
supabaseAnonKey: string;
|
|
18
|
+
supabaseNeedAuthUrl?: string;
|
|
19
|
+
supabaseNeedAuthAnonKey?: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class SupabaseInitializer {
|
|
23
|
+
private static instance: SupabaseInitializer;
|
|
24
|
+
private isInitialized = false;
|
|
25
|
+
private _mainClient: SupabaseClient | null = null;
|
|
26
|
+
private _authClient: SupabaseClient | null = null;
|
|
27
|
+
|
|
28
|
+
private constructor() {}
|
|
29
|
+
|
|
30
|
+
static getInstance(): SupabaseInitializer {
|
|
31
|
+
if (!SupabaseInitializer.instance) {
|
|
32
|
+
SupabaseInitializer.instance = new SupabaseInitializer();
|
|
33
|
+
}
|
|
34
|
+
return SupabaseInitializer.instance;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Initialize Supabase clients
|
|
39
|
+
*/
|
|
40
|
+
async initialize(
|
|
41
|
+
params: SupabaseInitializerParams
|
|
42
|
+
): Promise<{ supabase: SupabaseClient; supabaseAuth: SupabaseClient | null }> {
|
|
43
|
+
if (this.isInitialized) {
|
|
44
|
+
logDev("🚫 Supabase already initialized");
|
|
45
|
+
return { supabase: this._mainClient!, supabaseAuth: this._authClient };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
logDev("🔧 Initializing Supabase...");
|
|
49
|
+
|
|
50
|
+
// Validate and get environment variables
|
|
51
|
+
const config = this.validateEnvironmentVariables(params);
|
|
52
|
+
|
|
53
|
+
// Create main client
|
|
54
|
+
this._mainClient = createClient(config.main.url, config.main.anonKey, {
|
|
55
|
+
// TODO
|
|
56
|
+
// auth: {
|
|
57
|
+
// persistSession: true,
|
|
58
|
+
// autoRefreshToken: true,
|
|
59
|
+
// },
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Create auth client if configured
|
|
63
|
+
if (config.auth) {
|
|
64
|
+
this._authClient = createClient(config.auth.url, config.auth.anonKey, {
|
|
65
|
+
// TODO
|
|
66
|
+
// auth: {
|
|
67
|
+
// persistSession: true,
|
|
68
|
+
// autoRefreshToken: true,
|
|
69
|
+
// },
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Log configuration
|
|
74
|
+
this.logConfiguration(config);
|
|
75
|
+
|
|
76
|
+
this.isInitialized = true;
|
|
77
|
+
logDev("✅ Supabase initialization completed");
|
|
78
|
+
|
|
79
|
+
return { supabase: this._mainClient, supabaseAuth: this._authClient };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private validateEnvironmentVariables({
|
|
83
|
+
supabaseUrl,
|
|
84
|
+
supabaseAnonKey,
|
|
85
|
+
supabaseNeedAuthUrl,
|
|
86
|
+
supabaseNeedAuthAnonKey,
|
|
87
|
+
}: SupabaseInitializerParams): SupabaseConfig {
|
|
88
|
+
const mainUrl = supabaseUrl;
|
|
89
|
+
const mainAnonKey = supabaseAnonKey;
|
|
90
|
+
const authUrl = supabaseNeedAuthUrl;
|
|
91
|
+
const authAnonKey = supabaseNeedAuthAnonKey;
|
|
92
|
+
|
|
93
|
+
if (!mainUrl || !mainAnonKey) {
|
|
94
|
+
throw new Error("Missing required Supabase environment variables: VITE_SUPABASE_URL, VITE_SUPABASE_ANON_KEY");
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return {
|
|
98
|
+
main: { url: mainUrl, anonKey: mainAnonKey },
|
|
99
|
+
auth: authUrl && authAnonKey ? { url: authUrl, anonKey: authAnonKey } : null,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
private logConfiguration(config: SupabaseConfig) {
|
|
104
|
+
logDevGroup("🔧 Supabase Configuration", () => {
|
|
105
|
+
console.log("Main URL:", config.main.url);
|
|
106
|
+
console.log("Auth URL:", config.auth?.url || "Not configured");
|
|
107
|
+
console.log("Clients:", {
|
|
108
|
+
main: !!this._mainClient,
|
|
109
|
+
auth: !!this._authClient,
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
getClients() {
|
|
115
|
+
if (!this.isInitialized) {
|
|
116
|
+
throw new Error("Supabase not initialized. Call initialize() first.");
|
|
117
|
+
}
|
|
118
|
+
return { supabase: this._mainClient!, supabaseAuth: this._authClient };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get client(): SupabaseClient {
|
|
122
|
+
if (!this.isInitialized) {
|
|
123
|
+
throw new Error("Supabase not initialized. Call initialize() first.");
|
|
124
|
+
}
|
|
125
|
+
if (!this._mainClient) {
|
|
126
|
+
throw new Error("Main Supabase client is null. Initialization may have failed.");
|
|
127
|
+
}
|
|
128
|
+
return this._mainClient;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
get authClient(): SupabaseClient | null {
|
|
132
|
+
if (!this.isInitialized) {
|
|
133
|
+
throw new Error("Supabase not initialized. Call initialize() first.");
|
|
134
|
+
}
|
|
135
|
+
return this._authClient;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
reset() {
|
|
139
|
+
this.isInitialized = false;
|
|
140
|
+
this._mainClient = null;
|
|
141
|
+
this._authClient = null;
|
|
142
|
+
}
|
|
143
|
+
}
|