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.
Files changed (138) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +70 -0
  3. package/dist/auth/auth.api.d.ts +28 -0
  4. package/dist/auth/auth.api.d.ts.map +1 -0
  5. package/dist/auth/auth.api.js +50 -0
  6. package/dist/auth/auth.api.js.map +1 -0
  7. package/dist/core.api.d.ts +68 -0
  8. package/dist/core.api.d.ts.map +1 -0
  9. package/dist/core.api.js +226 -0
  10. package/dist/core.api.js.map +1 -0
  11. package/dist/core.interface.d.ts +36 -0
  12. package/dist/core.interface.d.ts.map +1 -0
  13. package/dist/core.interface.js +46 -0
  14. package/dist/core.interface.js.map +1 -0
  15. package/dist/core.utils.d.ts +19 -0
  16. package/dist/core.utils.d.ts.map +1 -0
  17. package/dist/core.utils.js +86 -0
  18. package/dist/core.utils.js.map +1 -0
  19. package/dist/feed/feed.interface.d.ts +27 -0
  20. package/dist/feed/feed.interface.d.ts.map +1 -0
  21. package/dist/feed/feed.interface.js +17 -0
  22. package/dist/feed/feed.interface.js.map +1 -0
  23. package/dist/file/file-manager.d.ts +24 -0
  24. package/dist/file/file-manager.d.ts.map +1 -0
  25. package/dist/file/file-manager.js +109 -0
  26. package/dist/file/file-manager.js.map +1 -0
  27. package/dist/file/file.api.d.ts +15 -0
  28. package/dist/file/file.api.d.ts.map +1 -0
  29. package/dist/file/file.api.js +30 -0
  30. package/dist/file/file.api.js.map +1 -0
  31. package/dist/file/file.interface.d.ts +25 -0
  32. package/dist/file/file.interface.d.ts.map +1 -0
  33. package/dist/file/file.interface.js +9 -0
  34. package/dist/file/file.interface.js.map +1 -0
  35. package/dist/file-list/file-list.api.d.ts +15 -0
  36. package/dist/file-list/file-list.api.d.ts.map +1 -0
  37. package/dist/file-list/file-list.api.js +54 -0
  38. package/dist/file-list/file-list.api.js.map +1 -0
  39. package/dist/file-list/file-list.interface.d.ts +22 -0
  40. package/dist/file-list/file-list.interface.d.ts.map +1 -0
  41. package/dist/file-list/file-list.interface.js +5 -0
  42. package/dist/file-list/file-list.interface.js.map +1 -0
  43. package/dist/idea/idea.interface.d.ts +25 -0
  44. package/dist/idea/idea.interface.d.ts.map +1 -0
  45. package/dist/idea/idea.interface.js +15 -0
  46. package/dist/idea/idea.interface.js.map +1 -0
  47. package/dist/index.d.ts +33 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +28 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/link/link.interface.d.ts +18 -0
  52. package/dist/link/link.interface.d.ts.map +1 -0
  53. package/dist/link/link.interface.js +6 -0
  54. package/dist/link/link.interface.js.map +1 -0
  55. package/dist/parcel/parcel-manager.d.ts +39 -0
  56. package/dist/parcel/parcel-manager.d.ts.map +1 -0
  57. package/dist/parcel/parcel-manager.js +156 -0
  58. package/dist/parcel/parcel-manager.js.map +1 -0
  59. package/dist/parcel/parcel.interface.d.ts +34 -0
  60. package/dist/parcel/parcel.interface.d.ts.map +1 -0
  61. package/dist/parcel/parcel.interface.js +11 -0
  62. package/dist/parcel/parcel.interface.js.map +1 -0
  63. package/dist/question-list/question-list.api.d.ts +13 -0
  64. package/dist/question-list/question-list.api.d.ts.map +1 -0
  65. package/dist/question-list/question-list.api.js +35 -0
  66. package/dist/question-list/question-list.api.js.map +1 -0
  67. package/dist/question-list/question-list.interface.d.ts +18 -0
  68. package/dist/question-list/question-list.interface.d.ts.map +1 -0
  69. package/dist/question-list/question-list.interface.js +5 -0
  70. package/dist/question-list/question-list.interface.js.map +1 -0
  71. package/dist/review/review.api.d.ts +14 -0
  72. package/dist/review/review.api.d.ts.map +1 -0
  73. package/dist/review/review.api.js +133 -0
  74. package/dist/review/review.api.js.map +1 -0
  75. package/dist/review/review.interface.d.ts +24 -0
  76. package/dist/review/review.interface.d.ts.map +1 -0
  77. package/dist/review/review.interface.js +10 -0
  78. package/dist/review/review.interface.js.map +1 -0
  79. package/dist/review-v2/apis/post-review-setting.api.d.ts +12 -0
  80. package/dist/review-v2/apis/post-review-setting.api.d.ts.map +1 -0
  81. package/dist/review-v2/apis/post-review-setting.api.js +27 -0
  82. package/dist/review-v2/apis/post-review-setting.api.js.map +1 -0
  83. package/dist/review-v2/apis/post-review.api.d.ts +13 -0
  84. package/dist/review-v2/apis/post-review.api.d.ts.map +1 -0
  85. package/dist/review-v2/apis/post-review.api.js +46 -0
  86. package/dist/review-v2/apis/post-review.api.js.map +1 -0
  87. package/dist/review-v2/review-setting.interface.d.ts +23 -0
  88. package/dist/review-v2/review-setting.interface.d.ts.map +1 -0
  89. package/dist/review-v2/review-setting.interface.js +5 -0
  90. package/dist/review-v2/review-setting.interface.js.map +1 -0
  91. package/dist/review-v2/review.interface.d.ts +20 -0
  92. package/dist/review-v2/review.interface.d.ts.map +1 -0
  93. package/dist/review-v2/review.interface.js +5 -0
  94. package/dist/review-v2/review.interface.js.map +1 -0
  95. package/dist/service/api.interface.d.ts +35 -0
  96. package/dist/service/api.interface.d.ts.map +1 -0
  97. package/dist/service/api.interface.js +12 -0
  98. package/dist/service/api.interface.js.map +1 -0
  99. package/dist/service/base.interface.d.ts +83 -0
  100. package/dist/service/base.interface.d.ts.map +1 -0
  101. package/dist/service/base.interface.js +7 -0
  102. package/dist/service/base.interface.js.map +1 -0
  103. package/dist/service/service.interface.d.ts +24 -0
  104. package/dist/service/service.interface.d.ts.map +1 -0
  105. package/dist/service/service.interface.js +11 -0
  106. package/dist/service/service.interface.js.map +1 -0
  107. package/dist/supabase.d.ts +32 -0
  108. package/dist/supabase.d.ts.map +1 -0
  109. package/dist/supabase.js +100 -0
  110. package/dist/supabase.js.map +1 -0
  111. package/package.json +45 -0
  112. package/src/auth/auth.api.ts +85 -0
  113. package/src/core.api.ts +338 -0
  114. package/src/core.interface.ts +74 -0
  115. package/src/core.utils.ts +98 -0
  116. package/src/feed/feed.interface.ts +33 -0
  117. package/src/file/file-manager.ts +145 -0
  118. package/src/file/file.api.ts +43 -0
  119. package/src/file/file.interface.ts +30 -0
  120. package/src/file-list/file-list.api.ts +64 -0
  121. package/src/file-list/file-list.interface.ts +24 -0
  122. package/src/idea/idea.interface.ts +28 -0
  123. package/src/index.ts +50 -0
  124. package/src/link/link.interface.ts +21 -0
  125. package/src/parcel/parcel-manager.ts +209 -0
  126. package/src/parcel/parcel.interface.ts +40 -0
  127. package/src/question-list/question-list.api.ts +42 -0
  128. package/src/question-list/question-list.interface.ts +21 -0
  129. package/src/review/review.api.ts +145 -0
  130. package/src/review/review.interface.ts +26 -0
  131. package/src/review-v2/apis/post-review-setting.api.ts +35 -0
  132. package/src/review-v2/apis/post-review.api.ts +59 -0
  133. package/src/review-v2/review-setting.interface.ts +26 -0
  134. package/src/review-v2/review.interface.ts +23 -0
  135. package/src/service/api.interface.ts +47 -0
  136. package/src/service/base.interface.ts +97 -0
  137. package/src/service/service.interface.ts +27 -0
  138. 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
+ }
@@ -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
+ }