@visiblebase/core 0.2.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 (110) hide show
  1. package/README.md +127 -0
  2. package/bin/core/auth/authenticator.d.ts +68 -0
  3. package/bin/core/auth/authenticator.d.ts.map +1 -0
  4. package/bin/core/auth/authenticator.js +106 -0
  5. package/bin/core/auth/authenticator.js.map +1 -0
  6. package/bin/core/auth/token-signer.d.ts +27 -0
  7. package/bin/core/auth/token-signer.d.ts.map +1 -0
  8. package/bin/core/auth/token-signer.js +116 -0
  9. package/bin/core/auth/token-signer.js.map +1 -0
  10. package/bin/core/auth/types.d.ts +94 -0
  11. package/bin/core/auth/types.d.ts.map +1 -0
  12. package/bin/core/auth/types.js +7 -0
  13. package/bin/core/auth/types.js.map +1 -0
  14. package/bin/core/base/base.d.ts +98 -0
  15. package/bin/core/base/base.d.ts.map +1 -0
  16. package/bin/core/base/base.js +281 -0
  17. package/bin/core/base/base.js.map +1 -0
  18. package/bin/core/runtime.d.ts +112 -0
  19. package/bin/core/runtime.d.ts.map +1 -0
  20. package/bin/core/runtime.js +19 -0
  21. package/bin/core/runtime.js.map +1 -0
  22. package/bin/core/types.d.ts +39 -0
  23. package/bin/core/types.d.ts.map +1 -0
  24. package/bin/core/types.js +7 -0
  25. package/bin/core/types.js.map +1 -0
  26. package/bin/index.d.ts +39 -0
  27. package/bin/index.d.ts.map +1 -0
  28. package/bin/index.js +45 -0
  29. package/bin/index.js.map +1 -0
  30. package/bin/service/ai/ai-service.d.ts +80 -0
  31. package/bin/service/ai/ai-service.d.ts.map +1 -0
  32. package/bin/service/ai/ai-service.js +184 -0
  33. package/bin/service/ai/ai-service.js.map +1 -0
  34. package/bin/service/ai/provider.d.ts +77 -0
  35. package/bin/service/ai/provider.d.ts.map +1 -0
  36. package/bin/service/ai/provider.js +71 -0
  37. package/bin/service/ai/provider.js.map +1 -0
  38. package/bin/service/ai/types.d.ts +72 -0
  39. package/bin/service/ai/types.d.ts.map +1 -0
  40. package/bin/service/ai/types.js +7 -0
  41. package/bin/service/ai/types.js.map +1 -0
  42. package/bin/service/env/env-service.d.ts +14 -0
  43. package/bin/service/env/env-service.d.ts.map +1 -0
  44. package/bin/service/env/env-service.js +42 -0
  45. package/bin/service/env/env-service.js.map +1 -0
  46. package/bin/service/env/env-store.d.ts +15 -0
  47. package/bin/service/env/env-store.d.ts.map +1 -0
  48. package/bin/service/env/env-store.js +35 -0
  49. package/bin/service/env/env-store.js.map +1 -0
  50. package/bin/service/env/schema.d.ts +171 -0
  51. package/bin/service/env/schema.d.ts.map +1 -0
  52. package/bin/service/env/schema.js +52 -0
  53. package/bin/service/env/schema.js.map +1 -0
  54. package/bin/service/env/types.d.ts +37 -0
  55. package/bin/service/env/types.d.ts.map +1 -0
  56. package/bin/service/env/types.js +8 -0
  57. package/bin/service/env/types.js.map +1 -0
  58. package/bin/service/hook.d.ts +20 -0
  59. package/bin/service/hook.d.ts.map +1 -0
  60. package/bin/service/hook.js +52 -0
  61. package/bin/service/hook.js.map +1 -0
  62. package/bin/service/plugin.d.ts +141 -0
  63. package/bin/service/plugin.d.ts.map +1 -0
  64. package/bin/service/plugin.js +124 -0
  65. package/bin/service/plugin.js.map +1 -0
  66. package/bin/service/products/product-store.d.ts +17 -0
  67. package/bin/service/products/product-store.d.ts.map +1 -0
  68. package/bin/service/products/product-store.js +49 -0
  69. package/bin/service/products/product-store.js.map +1 -0
  70. package/bin/service/products/products-service.d.ts +16 -0
  71. package/bin/service/products/products-service.d.ts.map +1 -0
  72. package/bin/service/products/products-service.js +52 -0
  73. package/bin/service/products/products-service.js.map +1 -0
  74. package/bin/service/products/schema.d.ts +207 -0
  75. package/bin/service/products/schema.d.ts.map +1 -0
  76. package/bin/service/products/schema.js +60 -0
  77. package/bin/service/products/schema.js.map +1 -0
  78. package/bin/service/products/types.d.ts +51 -0
  79. package/bin/service/products/types.d.ts.map +1 -0
  80. package/bin/service/products/types.js +7 -0
  81. package/bin/service/products/types.js.map +1 -0
  82. package/bin/service/service.d.ts +118 -0
  83. package/bin/service/service.d.ts.map +1 -0
  84. package/bin/service/service.js +114 -0
  85. package/bin/service/service.js.map +1 -0
  86. package/bin/service/types.d.ts +17 -0
  87. package/bin/service/types.d.ts.map +1 -0
  88. package/bin/service/types.js +5 -0
  89. package/bin/service/types.js.map +1 -0
  90. package/bin/store/db.d.ts +64 -0
  91. package/bin/store/db.d.ts.map +1 -0
  92. package/bin/store/db.js +28 -0
  93. package/bin/store/db.js.map +1 -0
  94. package/bin/store/table-api.d.ts +42 -0
  95. package/bin/store/table-api.d.ts.map +1 -0
  96. package/bin/store/table-api.js +98 -0
  97. package/bin/store/table-api.js.map +1 -0
  98. package/bin/store/types.d.ts +14 -0
  99. package/bin/store/types.d.ts.map +1 -0
  100. package/bin/store/types.js +7 -0
  101. package/bin/store/types.js.map +1 -0
  102. package/bin/utils/helpers.d.ts +101 -0
  103. package/bin/utils/helpers.d.ts.map +1 -0
  104. package/bin/utils/helpers.js +192 -0
  105. package/bin/utils/helpers.js.map +1 -0
  106. package/bin/utils/validation.d.ts +18 -0
  107. package/bin/utils/validation.d.ts.map +1 -0
  108. package/bin/utils/validation.js +28 -0
  109. package/bin/utils/validation.js.map +1 -0
  110. package/package.json +52 -0
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Product 数据存储。
3
+ *
4
+ * 基于 BaseTableApi,不直接依赖 Drizzle。
5
+ */
6
+ import { randomSecret } from "../../utils/helpers.js";
7
+ export class ProductStore {
8
+ table;
9
+ constructor(table) {
10
+ this.table = table;
11
+ }
12
+ async list() {
13
+ return this.table.select();
14
+ }
15
+ async get(product_id) {
16
+ const rows = await this.table.select({ product_id });
17
+ return rows[0];
18
+ }
19
+ async create(input) {
20
+ const name = String(input.name ?? "").trim();
21
+ if (!name)
22
+ throw new TypeError("Product name is required");
23
+ const now = new Date().toISOString();
24
+ const product = {
25
+ product_id: input.product_id ?? `prod_${randomSecret(12)}`,
26
+ name,
27
+ status: "active",
28
+ created_at: now,
29
+ updated_at: now,
30
+ };
31
+ await this.table.insert(product);
32
+ return product;
33
+ }
34
+ async setStatus(product_id, status) {
35
+ if (status !== "active" && status !== "paused") {
36
+ throw new TypeError(`Invalid product status: ${String(status)}`);
37
+ }
38
+ const existing = await this.get(product_id);
39
+ if (!existing)
40
+ throw new Error(`Unknown product: ${product_id}`);
41
+ const next = { ...existing, status, updated_at: new Date().toISOString() };
42
+ await this.table.update({ where: { product_id }, values: next });
43
+ return next;
44
+ }
45
+ async remove(product_id) {
46
+ await this.table.delete({ product_id });
47
+ }
48
+ }
49
+ //# sourceMappingURL=product-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-store.js","sourceRoot":"","sources":["../../../src/service/products/product-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAItD,MAAM,OAAO,YAAY;IACH;IAApB,YAAoB,KAA4B;QAA5B,UAAK,GAAL,KAAK,CAAuB;IAAG,CAAC;IAEpD,KAAK,CAAC,IAAI;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,UAAkB;QAC1B,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,EAAsB,CAAC,CAAC;QACzE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,KAAyB;QACpC,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,IAAI;YAAE,MAAM,IAAI,SAAS,CAAC,0BAA0B,CAAC,CAAC;QAC3D,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,OAAO,GAAY;YACvB,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,QAAQ,YAAY,CAAC,EAAE,CAAC,EAAE;YAC1D,IAAI;YACJ,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,UAAkB,EAAE,MAAqB;QACvD,IAAI,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/C,MAAM,IAAI,SAAS,CAAC,2BAA2B,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnE,CAAC;QACD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,QAAQ;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,UAAU,EAAE,CAAC,CAAC;QACjE,MAAM,IAAI,GAAY,EAAE,GAAG,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;QACpF,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,UAAU,EAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACrF,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,UAAkB;QAC7B,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,EAAsB,CAAC,CAAC;IAC9D,CAAC;CACF"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * products 内置服务。
3
+ *
4
+ * 通过 _onInit() 自初始化 ProductStore,Base 不需要知道 ProductStore 的存在。
5
+ */
6
+ import { Service } from "../service.js";
7
+ export declare class ProductsService extends Service {
8
+ private store;
9
+ private auth;
10
+ constructor();
11
+ /**
12
+ * Base 调用,传入 DB 和 Auth。Service 自行创建 Store 并种子数据。
13
+ */
14
+ _onInit(): Promise<void>;
15
+ }
16
+ //# sourceMappingURL=products-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products-service.d.ts","sourceRoot":"","sources":["../../../src/service/products/products-service.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAOxC,qBAAa,eAAgB,SAAQ,OAAO;IAC1C,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,IAAI,CAAiB;;IAmC7B;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAU/B"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * products 内置服务。
3
+ *
4
+ * 通过 _onInit() 自初始化 ProductStore,Base 不需要知道 ProductStore 的存在。
5
+ */
6
+ import { Service } from "../service.js";
7
+ import { ProductStore } from "./product-store.js";
8
+ import { sqliteProducts } from "./schema.js";
9
+ import { TableApi } from "../../store/table-api.js";
10
+ export class ProductsService extends Service {
11
+ store;
12
+ auth;
13
+ constructor() {
14
+ super({ id: "products", name: "Products", tables: { products: sqliteProducts } });
15
+ this.get("/", async () => ({ items: await this.store.list() }), { auth: "admin" });
16
+ this.post("/create", async ({ input }) => {
17
+ return await this.store.create({ name: String(input.name ?? "") });
18
+ }, { auth: "admin" });
19
+ this.post("/pause", async ({ input }) => {
20
+ return await this.store.setStatus(String(input.product_id ?? ""), "paused");
21
+ }, { auth: "admin" });
22
+ this.post("/activate", async ({ input }) => {
23
+ return await this.store.setStatus(String(input.product_id ?? ""), "active");
24
+ }, { auth: "admin" });
25
+ this.post("/remove", async ({ input }) => {
26
+ await this.store.remove(String(input.product_id ?? ""));
27
+ return { success: true };
28
+ }, { auth: "admin" });
29
+ this.post("/tokens/apply", async ({ input }) => {
30
+ const result = await this.auth.createToken({
31
+ product_id: String(input.product_id ?? ""),
32
+ user_id: String(input.user_id ?? ""),
33
+ metadata: input.metadata,
34
+ ttl: input.ttl,
35
+ });
36
+ return { user_token: result.user_token };
37
+ }, { auth: "admin" });
38
+ }
39
+ /**
40
+ * Base 调用,传入 DB 和 Auth。Service 自行创建 Store 并种子数据。
41
+ */
42
+ async _onInit() {
43
+ this.store = new ProductStore(new TableApi(this._db, sqliteProducts));
44
+ this.auth = this._authenticator;
45
+ // 种子默认 Product
46
+ const existing = await this.store.get("prod_visiblebase");
47
+ if (!existing) {
48
+ await this.store.create({ product_id: "prod_visiblebase", name: "VisibleBase" });
49
+ }
50
+ }
51
+ }
52
+ //# sourceMappingURL=products-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products-service.js","sourceRoot":"","sources":["../../../src/service/products/products-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ /**
2
+ * Product 数据库 schema 模块。
3
+ *
4
+ * 定义 VisibleBase 内置的 Product 表结构(SQLite + Postgres)。
5
+ * Product 是 Base 多租户隔离的基本单位。
6
+ */
7
+ /**
8
+ * 默认 SQLite Product 表。
9
+ */
10
+ export declare const sqliteProducts: import("drizzle-orm/sqlite-core").SQLiteTableWithColumns<{
11
+ name: "visiblebase_products";
12
+ schema: undefined;
13
+ columns: {
14
+ product_id: import("drizzle-orm/sqlite-core").SQLiteColumn<{
15
+ name: "product_id";
16
+ tableName: "visiblebase_products";
17
+ dataType: "string";
18
+ columnType: "SQLiteText";
19
+ data: string;
20
+ driverParam: string;
21
+ notNull: true;
22
+ hasDefault: false;
23
+ isPrimaryKey: true;
24
+ isAutoincrement: false;
25
+ hasRuntimeDefault: false;
26
+ enumValues: [string, ...string[]];
27
+ baseColumn: never;
28
+ identity: undefined;
29
+ generated: undefined;
30
+ }, {}, {
31
+ length: number | undefined;
32
+ }>;
33
+ name: import("drizzle-orm/sqlite-core").SQLiteColumn<{
34
+ name: "name";
35
+ tableName: "visiblebase_products";
36
+ dataType: "string";
37
+ columnType: "SQLiteText";
38
+ data: string;
39
+ driverParam: string;
40
+ notNull: true;
41
+ hasDefault: false;
42
+ isPrimaryKey: false;
43
+ isAutoincrement: false;
44
+ hasRuntimeDefault: false;
45
+ enumValues: [string, ...string[]];
46
+ baseColumn: never;
47
+ identity: undefined;
48
+ generated: undefined;
49
+ }, {}, {
50
+ length: number | undefined;
51
+ }>;
52
+ status: import("drizzle-orm/sqlite-core").SQLiteColumn<{
53
+ name: "status";
54
+ tableName: "visiblebase_products";
55
+ dataType: "string";
56
+ columnType: "SQLiteText";
57
+ data: string;
58
+ driverParam: string;
59
+ notNull: true;
60
+ hasDefault: false;
61
+ isPrimaryKey: false;
62
+ isAutoincrement: false;
63
+ hasRuntimeDefault: false;
64
+ enumValues: [string, ...string[]];
65
+ baseColumn: never;
66
+ identity: undefined;
67
+ generated: undefined;
68
+ }, {}, {
69
+ length: number | undefined;
70
+ }>;
71
+ created_at: import("drizzle-orm/sqlite-core").SQLiteColumn<{
72
+ name: "created_at";
73
+ tableName: "visiblebase_products";
74
+ dataType: "string";
75
+ columnType: "SQLiteText";
76
+ data: string;
77
+ driverParam: string;
78
+ notNull: true;
79
+ hasDefault: false;
80
+ isPrimaryKey: false;
81
+ isAutoincrement: false;
82
+ hasRuntimeDefault: false;
83
+ enumValues: [string, ...string[]];
84
+ baseColumn: never;
85
+ identity: undefined;
86
+ generated: undefined;
87
+ }, {}, {
88
+ length: number | undefined;
89
+ }>;
90
+ updated_at: import("drizzle-orm/sqlite-core").SQLiteColumn<{
91
+ name: "updated_at";
92
+ tableName: "visiblebase_products";
93
+ dataType: "string";
94
+ columnType: "SQLiteText";
95
+ data: string;
96
+ driverParam: string;
97
+ notNull: true;
98
+ hasDefault: false;
99
+ isPrimaryKey: false;
100
+ isAutoincrement: false;
101
+ hasRuntimeDefault: false;
102
+ enumValues: [string, ...string[]];
103
+ baseColumn: never;
104
+ identity: undefined;
105
+ generated: undefined;
106
+ }, {}, {
107
+ length: number | undefined;
108
+ }>;
109
+ };
110
+ dialect: "sqlite";
111
+ }>;
112
+ /**
113
+ * 默认 Postgres Product 表。
114
+ */
115
+ export declare const pgProducts: import("drizzle-orm/pg-core").PgTableWithColumns<{
116
+ name: "visiblebase_products";
117
+ schema: undefined;
118
+ columns: {
119
+ product_id: import("drizzle-orm/pg-core").PgColumn<{
120
+ name: "product_id";
121
+ tableName: "visiblebase_products";
122
+ dataType: "string";
123
+ columnType: "PgText";
124
+ data: string;
125
+ driverParam: string;
126
+ notNull: true;
127
+ hasDefault: false;
128
+ isPrimaryKey: true;
129
+ isAutoincrement: false;
130
+ hasRuntimeDefault: false;
131
+ enumValues: [string, ...string[]];
132
+ baseColumn: never;
133
+ identity: undefined;
134
+ generated: undefined;
135
+ }, {}, {}>;
136
+ name: import("drizzle-orm/pg-core").PgColumn<{
137
+ name: "name";
138
+ tableName: "visiblebase_products";
139
+ dataType: "string";
140
+ columnType: "PgText";
141
+ data: string;
142
+ driverParam: string;
143
+ notNull: true;
144
+ hasDefault: false;
145
+ isPrimaryKey: false;
146
+ isAutoincrement: false;
147
+ hasRuntimeDefault: false;
148
+ enumValues: [string, ...string[]];
149
+ baseColumn: never;
150
+ identity: undefined;
151
+ generated: undefined;
152
+ }, {}, {}>;
153
+ status: import("drizzle-orm/pg-core").PgColumn<{
154
+ name: "status";
155
+ tableName: "visiblebase_products";
156
+ dataType: "string";
157
+ columnType: "PgText";
158
+ data: string;
159
+ driverParam: string;
160
+ notNull: true;
161
+ hasDefault: false;
162
+ isPrimaryKey: false;
163
+ isAutoincrement: false;
164
+ hasRuntimeDefault: false;
165
+ enumValues: [string, ...string[]];
166
+ baseColumn: never;
167
+ identity: undefined;
168
+ generated: undefined;
169
+ }, {}, {}>;
170
+ created_at: import("drizzle-orm/pg-core").PgColumn<{
171
+ name: "created_at";
172
+ tableName: "visiblebase_products";
173
+ dataType: "string";
174
+ columnType: "PgText";
175
+ data: string;
176
+ driverParam: string;
177
+ notNull: true;
178
+ hasDefault: false;
179
+ isPrimaryKey: false;
180
+ isAutoincrement: false;
181
+ hasRuntimeDefault: false;
182
+ enumValues: [string, ...string[]];
183
+ baseColumn: never;
184
+ identity: undefined;
185
+ generated: undefined;
186
+ }, {}, {}>;
187
+ updated_at: import("drizzle-orm/pg-core").PgColumn<{
188
+ name: "updated_at";
189
+ tableName: "visiblebase_products";
190
+ dataType: "string";
191
+ columnType: "PgText";
192
+ data: string;
193
+ driverParam: string;
194
+ notNull: true;
195
+ hasDefault: false;
196
+ isPrimaryKey: false;
197
+ isAutoincrement: false;
198
+ hasRuntimeDefault: false;
199
+ enumValues: [string, ...string[]];
200
+ baseColumn: never;
201
+ identity: undefined;
202
+ generated: undefined;
203
+ }, {}, {}>;
204
+ };
205
+ dialect: "pg";
206
+ }>;
207
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/service/products/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;GAEG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBzB,CAAC;AAEH;;GAEG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAyBrB,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Product 数据库 schema 模块。
3
+ *
4
+ * 定义 VisibleBase 内置的 Product 表结构(SQLite + Postgres)。
5
+ * Product 是 Base 多租户隔离的基本单位。
6
+ */
7
+ import { pgTable, text as pgText } from "drizzle-orm/pg-core";
8
+ import { sqliteTable, text as sqliteText } from "drizzle-orm/sqlite-core";
9
+ const DEFAULT_PRODUCT_TABLE = "visiblebase_products";
10
+ /**
11
+ * 默认 SQLite Product 表。
12
+ */
13
+ export const sqliteProducts = sqliteTable(DEFAULT_PRODUCT_TABLE, {
14
+ /**
15
+ * Product ID。
16
+ */
17
+ product_id: sqliteText("product_id").primaryKey(),
18
+ /**
19
+ * Product 名称。
20
+ */
21
+ name: sqliteText("name").notNull(),
22
+ /**
23
+ * Product 状态。
24
+ */
25
+ status: sqliteText("status").notNull(),
26
+ /**
27
+ * Product 创建时间。
28
+ */
29
+ created_at: sqliteText("created_at").notNull(),
30
+ /**
31
+ * Product 更新时间。
32
+ */
33
+ updated_at: sqliteText("updated_at").notNull(),
34
+ });
35
+ /**
36
+ * 默认 Postgres Product 表。
37
+ */
38
+ export const pgProducts = pgTable(DEFAULT_PRODUCT_TABLE, {
39
+ /**
40
+ * Product ID。
41
+ */
42
+ product_id: pgText("product_id").primaryKey(),
43
+ /**
44
+ * Product 名称。
45
+ */
46
+ name: pgText("name").notNull(),
47
+ /**
48
+ * Product 状态。
49
+ */
50
+ status: pgText("status").notNull(),
51
+ /**
52
+ * Product 创建时间。
53
+ */
54
+ created_at: pgText("created_at").notNull(),
55
+ /**
56
+ * Product 更新时间。
57
+ */
58
+ updated_at: pgText("updated_at").notNull(),
59
+ });
60
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/service/products/schema.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,IAAI,IAAI,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE1E,MAAM,qBAAqB,GAAG,sBAAsB,CAAC;AAErD;;GAEG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC,qBAAqB,EAAE;IAC/D;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,UAAU,EAAE;IAEjD;;OAEG;IACH,IAAI,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;IAElC;;OAEG;IACH,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;IAEtC;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAE9C;;OAEG;IACH,UAAU,EAAE,UAAU,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;CAC/C,CAAC,CAAC;AAEH;;GAEG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC,qBAAqB,EAAE;IACvD;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,UAAU,EAAE;IAE7C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE;IAE9B;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE;IAElC;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;IAE1C;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE;CAC3C,CAAC,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Product 层公共类型。
3
+ *
4
+ * Product 是 Base 多租户隔离的基本单位,每个 API 调用都绑定到一个 Product。
5
+ */
6
+ /**
7
+ * Product 当前状态。
8
+ */
9
+ export type ProductStatus = "active" | "paused";
10
+ /**
11
+ * Base 中的 Product 记录。
12
+ */
13
+ export interface Product extends Record<string, unknown> {
14
+ /**
15
+ * Product 的唯一 ID。
16
+ */
17
+ product_id: string;
18
+ /**
19
+ * Product 展示名称。
20
+ */
21
+ name: string;
22
+ /**
23
+ * Product 当前状态。
24
+ */
25
+ status: ProductStatus;
26
+ /**
27
+ * Product 创建时间。
28
+ */
29
+ created_at: string;
30
+ /**
31
+ * Product 最后更新时间。
32
+ */
33
+ updated_at: string;
34
+ }
35
+ /**
36
+ * 创建 Product 时的输入。
37
+ */
38
+ export interface ProductCreateInput {
39
+ /**
40
+ * Product 展示名称。
41
+ */
42
+ name: string;
43
+ /**
44
+ * 自定义 Product ID。
45
+ *
46
+ * 未传入时由 Base 自动生成 `prod_${randomSecret(12)}` 格式的 ID。
47
+ * 传入时直接采用该值,便于在种子场景中使用固定 ID。
48
+ */
49
+ product_id?: string;
50
+ }
51
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/service/products/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,OAAQ,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACtD;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,MAAM,EAAE,aAAa,CAAC;IAEtB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Product 层公共类型。
3
+ *
4
+ * Product 是 Base 多租户隔离的基本单位,每个 API 调用都绑定到一个 Product。
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/service/products/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Service — SDK 核心单元。
3
+ *
4
+ * 每个 Service = 路由 + 数据库表 + hook + 自初始化。
5
+ * 只有一个 Context 类型,所有 handler 共用。
6
+ * Service 需要的基础设施(DB、Auth、Env)由 Base 直接设为属性。
7
+ */
8
+ import type { AnySQLiteTable } from "drizzle-orm/sqlite-core";
9
+ import type { AnyPgTable } from "drizzle-orm/pg-core";
10
+ import { Hook } from "./hook.js";
11
+ import type { BaseTableApi } from "../store/table-api.js";
12
+ import type { Database, DbClient } from "../store/db.js";
13
+ import type { RuntimeUser } from "../core/auth/types.js";
14
+ import type { Authenticator } from "../core/auth/authenticator.js";
15
+ export type RouteAuth = "public" | "user" | "admin";
16
+ export interface Context {
17
+ input: Record<string, unknown>;
18
+ db: Record<string, BaseTableApi>;
19
+ user?: RuntimeUser;
20
+ product?: {
21
+ product_id: string;
22
+ status: string;
23
+ };
24
+ request: Request;
25
+ env(key: string): string | undefined;
26
+ /** AI 模型信息(AIService 设置,其他 Service 为 undefined) */
27
+ model?: {
28
+ id: string;
29
+ name: string;
30
+ };
31
+ }
32
+ export type Handler = (ctx: Context) => unknown | Response | Promise<unknown | Response>;
33
+ export interface EnvRequirement {
34
+ key: string;
35
+ description: string;
36
+ required: boolean;
37
+ }
38
+ type HttpMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
39
+ interface RouteDef {
40
+ method: HttpMethod;
41
+ path: string;
42
+ auth: RouteAuth;
43
+ handler(ctx: RouteContext): Promise<Response> | Response;
44
+ }
45
+ /** 内部桥接上下文(Base 构造,wrapHandler 消费,不对外导出) */
46
+ export interface RouteContext {
47
+ request: Request;
48
+ url: URL;
49
+ service_id: string;
50
+ route: RouteDef;
51
+ user?: RuntimeUser;
52
+ product?: {
53
+ product_id: string;
54
+ status: string;
55
+ };
56
+ json<T extends object = Record<string, unknown>>(): Promise<T>;
57
+ text(): Promise<string>;
58
+ jsonResponse(body: unknown, status?: number): Response;
59
+ table(name: string): Promise<BaseTableApi>;
60
+ env(key: string): string | undefined;
61
+ }
62
+ export declare class Service {
63
+ readonly id: string;
64
+ readonly name: string;
65
+ readonly hook: Hook;
66
+ readonly tables?: Record<string, AnySQLiteTable | AnyPgTable>;
67
+ readonly env?: EnvRequirement[];
68
+ /**
69
+ * 数据库查询接口(Base 初始化后设置)。
70
+ */
71
+ _db?: Database;
72
+ /** 数据库底层连接,用于 DDL(Base 初始化后设置) */
73
+ _client?: {
74
+ $client: DbClient;
75
+ };
76
+ /**
77
+ * 鉴权器(Base 初始化后设置)。
78
+ */
79
+ _authenticator?: Authenticator;
80
+ /**
81
+ * Runtime 环境变量(Base 初始化后设置)。
82
+ */
83
+ _env?: {
84
+ get(key: string): string | undefined;
85
+ };
86
+ private routes;
87
+ constructor(options: {
88
+ id: string;
89
+ name?: string;
90
+ tables?: Record<string, AnySQLiteTable | AnyPgTable>;
91
+ env?: EnvRequirement[];
92
+ });
93
+ /**
94
+ * 初始化回调(可选)。Base 在设置 _database/_client/_authenticator/_env 后调用。
95
+ * Service 在此创建自己的 Store、种子数据等。默认空实现。
96
+ */
97
+ _onInit(): Promise<void>;
98
+ get(path: string, handler: Handler, opts?: {
99
+ auth?: RouteAuth;
100
+ }): this;
101
+ post(path: string, handler: Handler, opts?: {
102
+ auth?: RouteAuth;
103
+ }): this;
104
+ put(path: string, handler: Handler, opts?: {
105
+ auth?: RouteAuth;
106
+ }): this;
107
+ patch(path: string, handler: Handler, opts?: {
108
+ auth?: RouteAuth;
109
+ }): this;
110
+ delete(path: string, handler: Handler, opts?: {
111
+ auth?: RouteAuth;
112
+ }): this;
113
+ _listRoutes(): RouteDef[];
114
+ private _add;
115
+ }
116
+ export declare function serviceRouteFullPath(serviceId: string, route: RouteDef): string;
117
+ export {};
118
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../src/service/service.ts"],"names":[],"mappings":"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"}