@southwind-ai/database 0.1.1 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@southwind-ai/database",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "license": "UNLICENSED",
5
5
  "type": "module",
6
6
  "engines": {
@@ -15,7 +15,7 @@
15
15
  "typecheck": "tsc --noEmit --project tsconfig.json"
16
16
  },
17
17
  "dependencies": {
18
- "@southwind-ai/shared": "0.1.1",
18
+ "@southwind-ai/shared": "0.1.2",
19
19
  "drizzle-orm": "^0.45.2"
20
20
  },
21
21
  "exports": {
package/src/runner.ts CHANGED
@@ -1,16 +1,14 @@
1
- import type {
2
- BundleMigrationDefinition,
3
- DatabaseCompatibilityAdapter,
4
- DatabaseDialect,
5
- MigrationBundle,
6
- MigrationManifestSource,
7
- MigrationStatement,
8
- } from "@southwind-ai/shared";
9
1
  import {
10
2
  normalizeManifestBundles,
11
3
  orderBundleMigrations,
12
4
  validateAndOrderBundles,
13
- } from "./bundle-validation.js";
5
+ type BundleMigrationDefinition,
6
+ type DatabaseCompatibilityAdapter,
7
+ type DatabaseDialect,
8
+ type MigrationBundle,
9
+ type MigrationManifestSource,
10
+ type MigrationStatement,
11
+ } from "@southwind-ai/shared";
14
12
  import { createDialectAdapter } from "./dialects.js";
15
13
  import type { MigrationHistoryEntry, MigrationHistoryStore } from "./store.js";
16
14
 
@@ -2,7 +2,10 @@
2
2
  export {};
3
3
 
4
4
  // @windy-module system.configuration begin
5
- import type { ModuleConfigDiffEntry, ModuleConfigValues } from "@southwind-ai/shared";
5
+ import type {
6
+ ModuleConfigDiffEntry,
7
+ ModuleConfigValues,
8
+ } from "@southwind-ai/shared";
6
9
  import {
7
10
  index,
8
11
  integer,
@@ -15,6 +18,7 @@ import {
15
18
  // @windy-module system.configuration end
16
19
  // @windy-module system.settings begin
17
20
  import {
21
+ boolean,
18
22
  pgTable as settingsTable,
19
23
  text,
20
24
  varchar as settingsVarchar,
@@ -33,6 +37,17 @@ export const platformBrandingSettings = settingsTable(
33
37
  ...auditColumns,
34
38
  },
35
39
  );
40
+
41
+ export const platformWatermarkPolicies = settingsTable(
42
+ "platform_watermark_policies",
43
+ {
44
+ id: settingsVarchar("id", { length: 64 }).primaryKey(),
45
+ enabled: boolean("enabled").notNull(),
46
+ businessPagesEnabled: boolean("business_pages_enabled").notNull(),
47
+ customContent: settingsVarchar("custom_content", { length: 80 }).notNull(),
48
+ ...auditColumns,
49
+ },
50
+ );
36
51
  // @windy-module system.settings end
37
52
 
38
53
  // @windy-module system.configuration begin
@@ -1,218 +0,0 @@
1
- import {
2
- MIGRATION_BUNDLE_FORMAT_VERSION,
3
- type BundleMigrationDefinition,
4
- type MigrationBundle,
5
- type MigrationDefinition,
6
- type MigrationManifestSource,
7
- } from "@southwind-ai/shared";
8
-
9
- export function normalizeManifestBundles(
10
- modules: readonly MigrationManifestSource[],
11
- ): MigrationBundle[] {
12
- return modules.map((manifest) => {
13
- const bundle =
14
- manifest.migrationBundle ||
15
- legacyManifestBundle(manifest, manifest.migrations);
16
- if (bundle.module !== manifest.name) {
17
- throw new Error(
18
- `Migration Bundle ${bundle.module} 与 Manifest ${manifest.name} 不一致`,
19
- );
20
- }
21
- if (bundle.version !== manifest.version) {
22
- throw new Error(
23
- `Migration Bundle ${bundle.module} 版本 ${bundle.version} 与 Manifest ${manifest.version} 不一致`,
24
- );
25
- }
26
- assertSameDependencies(manifest, bundle);
27
- assertSameMigrations(manifest, bundle);
28
- assertSchemaMigrationReferences(manifest, bundle);
29
- return bundle;
30
- });
31
- }
32
-
33
- function assertSameDependencies(
34
- manifest: MigrationManifestSource,
35
- bundle: MigrationBundle,
36
- ): void {
37
- const declared = manifest.dependencies || [];
38
- const bundled = bundle.dependencies || [];
39
- if (
40
- declared.length !== bundled.length ||
41
- declared.some((dependency) => !bundled.includes(dependency))
42
- ) {
43
- throw new Error(
44
- `Manifest ${manifest.name} 的 dependencies 必须与 Migration Bundle 一致`,
45
- );
46
- }
47
- }
48
-
49
- function legacyManifestBundle(
50
- manifest: MigrationManifestSource,
51
- migrations: readonly MigrationDefinition[],
52
- ): MigrationBundle {
53
- return {
54
- formatVersion: MIGRATION_BUNDLE_FORMAT_VERSION,
55
- module: manifest.name,
56
- version: manifest.version,
57
- dependencies: manifest.dependencies,
58
- migrations: migrations.map((migration) => ({
59
- ...migration,
60
- checksum:
61
- migration.checksum ||
62
- `legacy:${manifest.name}:${manifest.version}:${migration.id}`,
63
- })),
64
- };
65
- }
66
-
67
- function assertSameMigrations(
68
- manifest: MigrationManifestSource,
69
- bundle: MigrationBundle,
70
- ): void {
71
- const declared = manifest.migrations.map(({ id }) => id);
72
- const bundled = bundle.migrations.map(({ id }) => id);
73
- if (
74
- declared.length !== bundled.length ||
75
- declared.some((id, index) => id !== bundled[index])
76
- ) {
77
- throw new Error(
78
- `Manifest ${manifest.name} 的 migrations 必须与 Migration Bundle 完全一致`,
79
- );
80
- }
81
- }
82
-
83
- function assertSchemaMigrationReferences(
84
- manifest: MigrationManifestSource,
85
- bundle: MigrationBundle,
86
- ): void {
87
- const ids = new Set(bundle.migrations.map(({ id }) => id));
88
- for (const schema of manifest.schemaExports || []) {
89
- for (const migrationId of schema.migrationIds) {
90
- if (!ids.has(migrationId)) {
91
- throw new Error(
92
- `Schema Export ${schema.key} 引用了 Bundle 中不存在的 Migration:${migrationId}`,
93
- );
94
- }
95
- }
96
- }
97
- }
98
-
99
- export function validateAndOrderBundles(
100
- bundles: readonly MigrationBundle[],
101
- ): MigrationBundle[] {
102
- const byModule = new Map<string, MigrationBundle>();
103
- const migrationOwner = new Map<string, string>();
104
- for (const bundle of bundles) {
105
- validateBundle(bundle);
106
- if (byModule.has(bundle.module)) {
107
- throw new Error(`Migration Bundle 模块重复:${bundle.module}`);
108
- }
109
- byModule.set(bundle.module, bundle);
110
- for (const migration of bundle.migrations) {
111
- const owner = migrationOwner.get(migration.id);
112
- if (owner) {
113
- throw new Error(
114
- `Migration ID 重复:${migration.id}(${owner} / ${bundle.module})`,
115
- );
116
- }
117
- migrationOwner.set(migration.id, bundle.module);
118
- }
119
- }
120
- for (const bundle of bundles) {
121
- for (const dependency of bundle.dependencies || []) {
122
- if (!byModule.has(dependency)) {
123
- throw new Error(
124
- `Migration Bundle ${bundle.module} 依赖未安装模块:${dependency}`,
125
- );
126
- }
127
- }
128
- validateMigrationDependencies(bundle, migrationOwner);
129
- }
130
- return topologicalBundles(byModule);
131
- }
132
-
133
- function validateBundle(bundle: MigrationBundle): void {
134
- if (bundle.formatVersion !== MIGRATION_BUNDLE_FORMAT_VERSION) {
135
- throw new Error(
136
- `Migration Bundle ${bundle.module} 格式版本不受支持:${bundle.formatVersion}`,
137
- );
138
- }
139
- if (!bundle.module.trim()) throw new Error("Migration Bundle 缺少 module");
140
- if (!/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(bundle.version)) {
141
- throw new Error(
142
- `Migration Bundle ${bundle.module} 版本无效:${bundle.version}`,
143
- );
144
- }
145
- for (const migration of bundle.migrations) {
146
- if (migration.module !== bundle.module) {
147
- throw new Error(
148
- `Migration ${migration.id} 的模块归属应为 ${bundle.module}`,
149
- );
150
- }
151
- if (!migration.id.trim()) throw new Error("Migration ID 不能为空");
152
- if (!migration.checksum.trim()) {
153
- throw new Error(`Migration ${migration.id} 缺少 checksum`);
154
- }
155
- }
156
- }
157
-
158
- function validateMigrationDependencies(
159
- bundle: MigrationBundle,
160
- owners: ReadonlyMap<string, string>,
161
- ): void {
162
- for (const migration of bundle.migrations) {
163
- for (const dependency of migration.dependsOn || []) {
164
- const owner = owners.get(dependency);
165
- if (!owner) {
166
- throw new Error(`Migration ${migration.id} 依赖不存在:${dependency}`);
167
- }
168
- if (
169
- owner !== bundle.module &&
170
- !(bundle.dependencies || []).includes(owner)
171
- ) {
172
- throw new Error(
173
- `Migration ${migration.id} 跨模块依赖 ${owner},但 Bundle 未声明该模块依赖`,
174
- );
175
- }
176
- }
177
- }
178
- }
179
-
180
- function topologicalBundles(
181
- pendingSource: ReadonlyMap<string, MigrationBundle>,
182
- ): MigrationBundle[] {
183
- const pending = new Map(pendingSource);
184
- const sorted: MigrationBundle[] = [];
185
- while (pending.size > 0) {
186
- const ready = Array.from(pending.values()).find((bundle) =>
187
- (bundle.dependencies || []).every(
188
- (dependency) => !pending.has(dependency),
189
- ),
190
- );
191
- if (!ready) throw new Error("Migration Bundle 模块依赖存在循环");
192
- sorted.push(ready);
193
- pending.delete(ready.module);
194
- }
195
- return sorted;
196
- }
197
-
198
- export function orderBundleMigrations(
199
- bundle: MigrationBundle,
200
- ): BundleMigrationDefinition[] {
201
- const pending = new Map(
202
- bundle.migrations.map((migration) => [migration.id, migration]),
203
- );
204
- const sorted: BundleMigrationDefinition[] = [];
205
- while (pending.size > 0) {
206
- const ready = Array.from(pending.values()).find((migration) =>
207
- (migration.dependsOn || []).every(
208
- (dependency) => !pending.has(dependency),
209
- ),
210
- );
211
- if (!ready) {
212
- throw new Error(`Migration Bundle ${bundle.module} 的迁移依赖存在循环`);
213
- }
214
- sorted.push(ready);
215
- pending.delete(ready.id);
216
- }
217
- return sorted;
218
- }