target-supabase-sdk 0.1.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/LICENSE +21 -0
- package/README.md +70 -0
- package/dist/auth/auth.api.d.ts +28 -0
- package/dist/auth/auth.api.d.ts.map +1 -0
- package/dist/auth/auth.api.js +50 -0
- package/dist/auth/auth.api.js.map +1 -0
- package/dist/core.api.d.ts +68 -0
- package/dist/core.api.d.ts.map +1 -0
- package/dist/core.api.js +226 -0
- package/dist/core.api.js.map +1 -0
- package/dist/core.interface.d.ts +36 -0
- package/dist/core.interface.d.ts.map +1 -0
- package/dist/core.interface.js +46 -0
- package/dist/core.interface.js.map +1 -0
- package/dist/core.utils.d.ts +19 -0
- package/dist/core.utils.d.ts.map +1 -0
- package/dist/core.utils.js +86 -0
- package/dist/core.utils.js.map +1 -0
- package/dist/feed/feed.interface.d.ts +27 -0
- package/dist/feed/feed.interface.d.ts.map +1 -0
- package/dist/feed/feed.interface.js +17 -0
- package/dist/feed/feed.interface.js.map +1 -0
- package/dist/file/file-manager.d.ts +24 -0
- package/dist/file/file-manager.d.ts.map +1 -0
- package/dist/file/file-manager.js +109 -0
- package/dist/file/file-manager.js.map +1 -0
- package/dist/file/file.api.d.ts +15 -0
- package/dist/file/file.api.d.ts.map +1 -0
- package/dist/file/file.api.js +30 -0
- package/dist/file/file.api.js.map +1 -0
- package/dist/file/file.interface.d.ts +25 -0
- package/dist/file/file.interface.d.ts.map +1 -0
- package/dist/file/file.interface.js +9 -0
- package/dist/file/file.interface.js.map +1 -0
- package/dist/file-list/file-list.api.d.ts +15 -0
- package/dist/file-list/file-list.api.d.ts.map +1 -0
- package/dist/file-list/file-list.api.js +54 -0
- package/dist/file-list/file-list.api.js.map +1 -0
- package/dist/file-list/file-list.interface.d.ts +22 -0
- package/dist/file-list/file-list.interface.d.ts.map +1 -0
- package/dist/file-list/file-list.interface.js +5 -0
- package/dist/file-list/file-list.interface.js.map +1 -0
- package/dist/idea/idea.interface.d.ts +25 -0
- package/dist/idea/idea.interface.d.ts.map +1 -0
- package/dist/idea/idea.interface.js +15 -0
- package/dist/idea/idea.interface.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/link/link.interface.d.ts +18 -0
- package/dist/link/link.interface.d.ts.map +1 -0
- package/dist/link/link.interface.js +6 -0
- package/dist/link/link.interface.js.map +1 -0
- package/dist/parcel/parcel-manager.d.ts +39 -0
- package/dist/parcel/parcel-manager.d.ts.map +1 -0
- package/dist/parcel/parcel-manager.js +156 -0
- package/dist/parcel/parcel-manager.js.map +1 -0
- package/dist/parcel/parcel.interface.d.ts +34 -0
- package/dist/parcel/parcel.interface.d.ts.map +1 -0
- package/dist/parcel/parcel.interface.js +11 -0
- package/dist/parcel/parcel.interface.js.map +1 -0
- package/dist/question-list/question-list.api.d.ts +13 -0
- package/dist/question-list/question-list.api.d.ts.map +1 -0
- package/dist/question-list/question-list.api.js +35 -0
- package/dist/question-list/question-list.api.js.map +1 -0
- package/dist/question-list/question-list.interface.d.ts +18 -0
- package/dist/question-list/question-list.interface.d.ts.map +1 -0
- package/dist/question-list/question-list.interface.js +5 -0
- package/dist/question-list/question-list.interface.js.map +1 -0
- package/dist/review/review.api.d.ts +14 -0
- package/dist/review/review.api.d.ts.map +1 -0
- package/dist/review/review.api.js +133 -0
- package/dist/review/review.api.js.map +1 -0
- package/dist/review/review.interface.d.ts +24 -0
- package/dist/review/review.interface.d.ts.map +1 -0
- package/dist/review/review.interface.js +10 -0
- package/dist/review/review.interface.js.map +1 -0
- package/dist/review-v2/apis/post-review-setting.api.d.ts +12 -0
- package/dist/review-v2/apis/post-review-setting.api.d.ts.map +1 -0
- package/dist/review-v2/apis/post-review-setting.api.js +27 -0
- package/dist/review-v2/apis/post-review-setting.api.js.map +1 -0
- package/dist/review-v2/apis/post-review.api.d.ts +13 -0
- package/dist/review-v2/apis/post-review.api.d.ts.map +1 -0
- package/dist/review-v2/apis/post-review.api.js +46 -0
- package/dist/review-v2/apis/post-review.api.js.map +1 -0
- package/dist/review-v2/review-setting.interface.d.ts +23 -0
- package/dist/review-v2/review-setting.interface.d.ts.map +1 -0
- package/dist/review-v2/review-setting.interface.js +5 -0
- package/dist/review-v2/review-setting.interface.js.map +1 -0
- package/dist/review-v2/review.interface.d.ts +20 -0
- package/dist/review-v2/review.interface.d.ts.map +1 -0
- package/dist/review-v2/review.interface.js +5 -0
- package/dist/review-v2/review.interface.js.map +1 -0
- package/dist/service/api.interface.d.ts +35 -0
- package/dist/service/api.interface.d.ts.map +1 -0
- package/dist/service/api.interface.js +12 -0
- package/dist/service/api.interface.js.map +1 -0
- package/dist/service/base.interface.d.ts +83 -0
- package/dist/service/base.interface.d.ts.map +1 -0
- package/dist/service/base.interface.js +7 -0
- package/dist/service/base.interface.js.map +1 -0
- package/dist/service/service.interface.d.ts +24 -0
- package/dist/service/service.interface.d.ts.map +1 -0
- package/dist/service/service.interface.js +11 -0
- package/dist/service/service.interface.js.map +1 -0
- package/dist/supabase.d.ts +32 -0
- package/dist/supabase.d.ts.map +1 -0
- package/dist/supabase.js +100 -0
- package/dist/supabase.js.map +1 -0
- package/package.json +45 -0
- package/src/auth/auth.api.ts +85 -0
- package/src/core.api.ts +338 -0
- package/src/core.interface.ts +74 -0
- package/src/core.utils.ts +98 -0
- package/src/feed/feed.interface.ts +33 -0
- package/src/file/file-manager.ts +145 -0
- package/src/file/file.api.ts +43 -0
- package/src/file/file.interface.ts +30 -0
- package/src/file-list/file-list.api.ts +64 -0
- package/src/file-list/file-list.interface.ts +24 -0
- package/src/idea/idea.interface.ts +28 -0
- package/src/index.ts +50 -0
- package/src/link/link.interface.ts +21 -0
- package/src/parcel/parcel-manager.ts +209 -0
- package/src/parcel/parcel.interface.ts +40 -0
- package/src/question-list/question-list.api.ts +42 -0
- package/src/question-list/question-list.interface.ts +21 -0
- package/src/review/review.api.ts +145 -0
- package/src/review/review.interface.ts +26 -0
- package/src/review-v2/apis/post-review-setting.api.ts +35 -0
- package/src/review-v2/apis/post-review.api.ts +59 -0
- package/src/review-v2/review-setting.interface.ts +26 -0
- package/src/review-v2/review.interface.ts +23 -0
- package/src/service/api.interface.ts +47 -0
- package/src/service/base.interface.ts +97 -0
- package/src/service/service.interface.ts +27 -0
- package/src/supabase.ts +143 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { createTarget } from "../core.api";
|
|
2
|
+
import { BaseValidator } from "../core.utils";
|
|
3
|
+
import { QuestionList, CategoryQuestionList, QuestionListDetails } from "./question-list.interface";
|
|
4
|
+
|
|
5
|
+
export class PostCreateQuestionListValidator extends BaseValidator<PostCreateQuestionListPayload> {
|
|
6
|
+
protected requiredFields: (keyof PostCreateQuestionListPayload)[] = ["name", "list"];
|
|
7
|
+
protected optionalFields: (keyof PostCreateQuestionListPayload)[] = [];
|
|
8
|
+
|
|
9
|
+
constructor() {
|
|
10
|
+
super();
|
|
11
|
+
// Add custom
|
|
12
|
+
this.addValidator((val) => {
|
|
13
|
+
return true;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface PostCreateQuestionListPayload {
|
|
19
|
+
name: QuestionListDetails["name"];
|
|
20
|
+
list: QuestionListDetails["list"];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const postCreateQuestionList = async (payload: PostCreateQuestionListPayload) => {
|
|
24
|
+
return createTarget<QuestionList, PostCreateQuestionListPayload>({
|
|
25
|
+
payload: payload,
|
|
26
|
+
validator: PostCreateQuestionListValidator,
|
|
27
|
+
createFn: (validPayload) => {
|
|
28
|
+
const { name, list } = validPayload;
|
|
29
|
+
const details: QuestionListDetails = {
|
|
30
|
+
name,
|
|
31
|
+
list,
|
|
32
|
+
};
|
|
33
|
+
return {
|
|
34
|
+
name: validPayload.name,
|
|
35
|
+
category: CategoryQuestionList.QUESTION_LIST,
|
|
36
|
+
value: "",
|
|
37
|
+
tagList: [],
|
|
38
|
+
details,
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
|
|
3
|
+
export interface Question {
|
|
4
|
+
ans: string;
|
|
5
|
+
reminder: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type QuestionListDetails = {
|
|
9
|
+
/** Human readable name, should be same to Target.name */
|
|
10
|
+
name: string;
|
|
11
|
+
list: Question[];
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export enum CategoryQuestionList {
|
|
15
|
+
QUESTION_LIST = "question-list",
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface QuestionList extends Target {
|
|
19
|
+
category: CategoryQuestionList;
|
|
20
|
+
details: QuestionListDetails;
|
|
21
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { cloneDeep } from "lodash-es";
|
|
2
|
+
import { createTarget, getPossibleTarget, updateTargetDetails } from "../core.api";
|
|
3
|
+
import { createResponse } from "../core.interface";
|
|
4
|
+
import { BaseValidator } from "../core.utils";
|
|
5
|
+
import { CategoryReview, Review, ReviewDetails } from "./review.interface";
|
|
6
|
+
|
|
7
|
+
class PatchUpsertReviewValidator extends BaseValidator<ReviewDetails> {
|
|
8
|
+
protected requiredFields: (keyof ReviewDetails)[] = ["reviewTargetId", "reviewDomain", "reviewResult"];
|
|
9
|
+
protected optionalFields: (keyof ReviewDetails)[] = [];
|
|
10
|
+
protected ignoredFields: (keyof ReviewDetails)[] = ["reviewCount", "lastUpdated"];
|
|
11
|
+
|
|
12
|
+
constructor() {
|
|
13
|
+
super();
|
|
14
|
+
// Add custom
|
|
15
|
+
this.addValidator((val) => {
|
|
16
|
+
if (val.reviewResult == null || Object.values(val.reviewResult).some((v) => typeof v !== "number")) {
|
|
17
|
+
return "[Check reviewResult] reviewResult invalid";
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const patchUpsertReview = async (payload: ReviewDetails) => {
|
|
25
|
+
const validPayload = new PatchUpsertReviewValidator().validate(payload);
|
|
26
|
+
const { reviewTargetId, reviewDomain } = validPayload;
|
|
27
|
+
|
|
28
|
+
// Check redundancy
|
|
29
|
+
const { data: possibleReview } = await getPossibleTarget({
|
|
30
|
+
filterList: [
|
|
31
|
+
{
|
|
32
|
+
field: "category",
|
|
33
|
+
operator: "eq",
|
|
34
|
+
value: CategoryReview.REVIEW,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
field: "details->>reviewTargetId",
|
|
38
|
+
operator: "eq",
|
|
39
|
+
value: reviewTargetId,
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
field: "details->>reviewDomain",
|
|
43
|
+
operator: "eq",
|
|
44
|
+
value: reviewDomain,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (possibleReview != null) {
|
|
50
|
+
const existingReview = possibleReview as Review;
|
|
51
|
+
const id = existingReview.id;
|
|
52
|
+
// Update
|
|
53
|
+
const data = await updateTargetDetails<Review, ReviewDetails>({
|
|
54
|
+
id,
|
|
55
|
+
updateFn: (details) => {
|
|
56
|
+
const incrementResult = validPayload.reviewResult;
|
|
57
|
+
if (incrementResult != null) {
|
|
58
|
+
const updatedResult = details.reviewResult != null ? cloneDeep(details.reviewResult) : {};
|
|
59
|
+
Object.entries(incrementResult).forEach(([key, value]) => {
|
|
60
|
+
updatedResult[key] = (updatedResult[key] ?? 0) + value;
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
...details,
|
|
64
|
+
reviewResult: updatedResult,
|
|
65
|
+
reviewCount: (details.reviewCount ?? 0) + 1,
|
|
66
|
+
lastUpdated: Date.now(),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
return details;
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
return createResponse.success<Review>(data);
|
|
73
|
+
}
|
|
74
|
+
// Create
|
|
75
|
+
const { data: newReview } = await postReview({
|
|
76
|
+
reviewTargetId,
|
|
77
|
+
reviewDomain,
|
|
78
|
+
});
|
|
79
|
+
if (newReview == null) {
|
|
80
|
+
const msg = "[patchUpsertReview] Unable to create Review";
|
|
81
|
+
console.error(msg);
|
|
82
|
+
throw new Error(msg);
|
|
83
|
+
}
|
|
84
|
+
return createResponse.success<Review>(newReview);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
export interface PostReviewPayload {
|
|
88
|
+
reviewTargetId: ReviewDetails["reviewTargetId"];
|
|
89
|
+
reviewDomain: ReviewDetails["reviewDomain"];
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export class PostReviewValidator extends BaseValidator<PostReviewPayload> {
|
|
93
|
+
protected requiredFields: (keyof PostReviewPayload)[] = ["reviewTargetId", "reviewDomain"];
|
|
94
|
+
protected optionalFields: (keyof PostReviewPayload)[] = [];
|
|
95
|
+
|
|
96
|
+
constructor() {
|
|
97
|
+
super();
|
|
98
|
+
// Add custom
|
|
99
|
+
this.addValidator((val) => {
|
|
100
|
+
return true;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export const postReview = async (payload: PostReviewPayload) => {
|
|
106
|
+
return createTarget<Review, PostReviewPayload>({
|
|
107
|
+
payload: payload,
|
|
108
|
+
validator: PostReviewValidator,
|
|
109
|
+
checkRedundancyFilterList: [
|
|
110
|
+
{
|
|
111
|
+
field: "category",
|
|
112
|
+
operator: "eq",
|
|
113
|
+
value: CategoryReview.REVIEW,
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
field: "details->>reviewTargetId",
|
|
117
|
+
operator: "eq",
|
|
118
|
+
value: payload.reviewTargetId,
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
field: "details->>reviewDomain",
|
|
122
|
+
operator: "eq",
|
|
123
|
+
value: payload.reviewDomain,
|
|
124
|
+
},
|
|
125
|
+
],
|
|
126
|
+
createFn: (validPayload) => {
|
|
127
|
+
const { reviewTargetId, reviewDomain } = validPayload;
|
|
128
|
+
const details: ReviewDetails = {
|
|
129
|
+
reviewTargetId,
|
|
130
|
+
reviewDomain,
|
|
131
|
+
lastUpdated: Date.now(),
|
|
132
|
+
reviewCount: 0,
|
|
133
|
+
reviewResult: {},
|
|
134
|
+
};
|
|
135
|
+
const reviewStr = `Review ${reviewTargetId} ${reviewDomain}`;
|
|
136
|
+
return {
|
|
137
|
+
name: reviewStr,
|
|
138
|
+
category: CategoryReview.REVIEW,
|
|
139
|
+
value: "",
|
|
140
|
+
tagList: [],
|
|
141
|
+
details,
|
|
142
|
+
};
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
|
|
3
|
+
export enum ReviewDomain {
|
|
4
|
+
/** the larger the number, the more popular it is */
|
|
5
|
+
LIKES = "likes",
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type ReviewDetails = {
|
|
9
|
+
reviewTargetId: string;
|
|
10
|
+
lastUpdated: number;
|
|
11
|
+
reviewDomain: ReviewDomain;
|
|
12
|
+
/** Auto increment */
|
|
13
|
+
reviewCount?: number;
|
|
14
|
+
reviewResult?: {
|
|
15
|
+
/** reviewDomain */
|
|
16
|
+
[name: string]: number;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export enum CategoryReview {
|
|
21
|
+
REVIEW = "review",
|
|
22
|
+
}
|
|
23
|
+
export interface Review extends Target {
|
|
24
|
+
category: CategoryReview;
|
|
25
|
+
details: ReviewDetails;
|
|
26
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { createTarget, validateWith } from "../../core.api";
|
|
2
|
+
import { BaseValidator } from "../../core.utils";
|
|
3
|
+
import { ReviewSettingDetails, ReviewSetting, CategoryReviewSetting } from "../review-setting.interface";
|
|
4
|
+
|
|
5
|
+
export interface PostReviewSettingPayload {
|
|
6
|
+
name: ReviewSettingDetails["name"];
|
|
7
|
+
questionList: ReviewSettingDetails["questionList"];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class PostReviewSettingValidator extends BaseValidator<PostReviewSettingPayload> {
|
|
11
|
+
protected requiredFields: (keyof PostReviewSettingPayload)[] = ["name", "questionList"];
|
|
12
|
+
protected optionalFields: (keyof PostReviewSettingPayload)[] = [];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export const postReviewSetting = validateWith<PostReviewSettingPayload, PostReviewSettingValidator>(
|
|
16
|
+
PostReviewSettingValidator
|
|
17
|
+
)(async (validPayload) => {
|
|
18
|
+
return createTarget<ReviewSetting, PostReviewSettingPayload>({
|
|
19
|
+
payload: validPayload,
|
|
20
|
+
createFn: (validPayload) => {
|
|
21
|
+
const { name, questionList } = validPayload;
|
|
22
|
+
const details: ReviewSettingDetails = {
|
|
23
|
+
name,
|
|
24
|
+
questionList,
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
name,
|
|
28
|
+
category: CategoryReviewSetting.REVIEW_SETTING,
|
|
29
|
+
value: "",
|
|
30
|
+
tagList: [],
|
|
31
|
+
details,
|
|
32
|
+
};
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { createTarget, getTarget, validateWith } from "../../core.api";
|
|
2
|
+
import { BaseValidator } from "../../core.utils";
|
|
3
|
+
import { CategoryReview, ReviewV2 as Review, ReviewV2Details as ReviewDetails } from "../review.interface";
|
|
4
|
+
import { ReviewSetting } from "../review-setting.interface";
|
|
5
|
+
|
|
6
|
+
export interface PostReviewPayload {
|
|
7
|
+
targetId: ReviewDetails["targetId"];
|
|
8
|
+
settingId: ReviewDetails["settingId"];
|
|
9
|
+
resultList: ReviewDetails["resultList"];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class PostReviewValidator extends BaseValidator<PostReviewPayload> {
|
|
13
|
+
protected requiredFields: (keyof PostReviewPayload)[] = ["targetId", "targetId", "resultList"];
|
|
14
|
+
protected optionalFields: (keyof PostReviewPayload)[] = [];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const postReview = validateWith<PostReviewPayload, PostReviewValidator>(PostReviewValidator)(
|
|
18
|
+
async (validPayload: PostReviewPayload) => {
|
|
19
|
+
const { targetId, settingId, resultList } = validPayload;
|
|
20
|
+
|
|
21
|
+
// Check Target
|
|
22
|
+
if (targetId != null) {
|
|
23
|
+
const { data: possibleTarget } = await getTarget({
|
|
24
|
+
id: targetId,
|
|
25
|
+
});
|
|
26
|
+
// TODO
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Check ReviewSetting
|
|
30
|
+
const { data: _reviewSetting } = await getTarget({
|
|
31
|
+
id: settingId,
|
|
32
|
+
});
|
|
33
|
+
if (_reviewSetting == null) {
|
|
34
|
+
console.error("[postReview] ReviewSetting not found");
|
|
35
|
+
throw new Error("[postReview] ReviewSetting not found");
|
|
36
|
+
}
|
|
37
|
+
const reviewSetting = _reviewSetting as ReviewSetting;
|
|
38
|
+
|
|
39
|
+
return createTarget<Review, PostReviewPayload>({
|
|
40
|
+
payload: validPayload,
|
|
41
|
+
createFn: (validPayload) => {
|
|
42
|
+
const { targetId, settingId, resultList } = validPayload;
|
|
43
|
+
const details: ReviewDetails = {
|
|
44
|
+
targetId,
|
|
45
|
+
settingId,
|
|
46
|
+
resultList,
|
|
47
|
+
};
|
|
48
|
+
const name = `Review on ${reviewSetting?.details?.name}`;
|
|
49
|
+
return {
|
|
50
|
+
name,
|
|
51
|
+
category: CategoryReview.REVIEW,
|
|
52
|
+
value: "",
|
|
53
|
+
tagList: [],
|
|
54
|
+
details,
|
|
55
|
+
};
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
|
|
3
|
+
export interface ReviewSetting extends Target {
|
|
4
|
+
category: CategoryReviewSetting;
|
|
5
|
+
details: ReviewSettingDetails;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export enum CategoryReviewSetting {
|
|
9
|
+
REVIEW_SETTING = "review-setting",
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export type ReviewSettingDetails = {
|
|
13
|
+
name: string;
|
|
14
|
+
questionList: ReviewQuestion[];
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export interface ReviewQuestion {
|
|
18
|
+
title: string;
|
|
19
|
+
/** uuid */
|
|
20
|
+
key: string;
|
|
21
|
+
type: "$boolean" | "$text" | "$number" | "$choice" | "$custom";
|
|
22
|
+
/** To provide data when rendering a question */
|
|
23
|
+
refTargetId?: string;
|
|
24
|
+
/** To render a custom question */
|
|
25
|
+
customTargetId?: string;
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Target } from "../core.interface";
|
|
2
|
+
import { ReviewQuestion } from "./review-setting.interface";
|
|
3
|
+
|
|
4
|
+
/** Instance of ReviewSetting */
|
|
5
|
+
export interface ReviewV2 extends Target {
|
|
6
|
+
category: CategoryReview;
|
|
7
|
+
details: ReviewV2Details;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export enum CategoryReview {
|
|
11
|
+
REVIEW = "review",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ReviewV2Details = {
|
|
15
|
+
targetId: string | null;
|
|
16
|
+
/** How to collect reviews from users and how to parse the results */
|
|
17
|
+
settingId: string;
|
|
18
|
+
resultList: ReviewResult[];
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export interface ReviewResult extends ReviewQuestion {
|
|
22
|
+
answer: unknown;
|
|
23
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
@@ -0,0 +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
|
+
|
|
@@ -0,0 +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
|
+
}
|
package/src/supabase.ts
ADDED
|
@@ -0,0 +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
|
+
}
|