create-windy 0.3.4 → 0.3.5
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/README.md +20 -3
- package/dist/cli.js +582 -109
- package/package.json +1 -1
- package/template/.windy-template.json +2 -2
- package/template/AGENTS.md +4 -0
- package/template/README.md +18 -11
- package/template/apps/server/src/application-services.ts +16 -0
- package/template/apps/server/src/data-governance/export/authorization-port.test.ts +5 -1
- package/template/apps/server/src/data-governance/export/drizzle-repository.integration.test.ts +2 -0
- package/template/apps/server/src/data-governance/export/drizzle-repository.ts +1 -0
- package/template/apps/server/src/data-governance/export/job-runtime.test.ts +3 -1
- package/template/apps/server/src/data-governance/export/job-runtime.ts +53 -14
- package/template/apps/server/src/data-governance/export/ndjson-stream.ts +8 -0
- package/template/apps/server/src/data-governance/export/postgres-recovery.integration.test.ts +2 -0
- package/template/apps/server/src/data-governance/export/renderer-job-runtime.test.ts +235 -0
- package/template/apps/server/src/data-governance/export/renderer-runtime.ts +293 -0
- package/template/apps/server/src/data-governance/export/renderer-selection.test.ts +67 -0
- package/template/apps/server/src/data-governance/export/repository.test.ts +2 -0
- package/template/apps/server/src/data-governance/export/request-fingerprint.test.ts +13 -0
- package/template/apps/server/src/data-governance/export/request-fingerprint.ts +2 -0
- package/template/apps/server/src/data-governance/export/routes.ts +11 -1
- package/template/apps/server/src/data-governance/export/service-support.ts +61 -4
- package/template/apps/server/src/data-governance/export/service.ts +8 -2
- package/template/apps/server/src/data-governance/export/types.ts +27 -0
- package/template/apps/server/src/index.ts +1 -0
- package/template/apps/server/src/jobs/artifact-service.test.ts +14 -2
- package/template/apps/server/src/jobs/artifact-service.ts +10 -0
- package/template/apps/server/src/jobs/drizzle-execution-repository.ts +17 -18
- package/template/apps/server/src/jobs/drizzle-execution.integration.test.ts +19 -1
- package/template/apps/server/src/jobs/drizzle-mappers.ts +3 -1
- package/template/apps/server/src/jobs/drizzle-recovery-repository.ts +49 -2
- package/template/apps/server/src/jobs/execution-repository.ts +17 -0
- package/template/apps/server/src/jobs/in-memory-control.ts +135 -0
- package/template/apps/server/src/jobs/in-memory-execution.ts +34 -65
- package/template/apps/server/src/jobs/worker.ts +27 -3
- package/template/apps/server/src/module-host/governed-export-route-support.ts +24 -5
- package/template/apps/server/src/module-host/governed-export-routes.test.ts +5 -1
- package/template/apps/server/src/module-host/governed-export-routes.ts +1 -2
- package/template/apps/server/src/module-host/governed-renderer-registration.test.ts +247 -0
- package/template/apps/server/src/module-host/governed-resources.test.ts +1 -0
- package/template/apps/server/src/module-host/governed-resources.ts +56 -0
- package/template/apps/server/src/module-host/http-runtime.ts +3 -0
- package/template/apps/server/src/module-host/job-port.test.ts +262 -0
- package/template/apps/server/src/module-host/job-port.ts +334 -0
- package/template/apps/server/src/module-host/request-context.ts +14 -26
- package/template/apps/server/src/module-host/route-installer.ts +11 -0
- package/template/apps/web/src/app/business-routes.ts +22 -0
- package/template/apps/web/src/components/common/AccessSnapshotBoundary.vue +112 -0
- package/template/apps/web/src/components/common/AccessSnapshotBoundary.webtest.ts +130 -0
- package/template/apps/web/src/components/common/AccessSnapshotNotice.vue +117 -0
- package/template/apps/web/src/composables/access-snapshot-change.ts +131 -0
- package/template/apps/web/src/composables/access-snapshot-change.webtest.ts +103 -0
- package/template/apps/web/src/composables/useAccessSnapshot.ts +48 -2
- package/template/apps/web/src/composables/useAccessSnapshot.webtest.ts +54 -0
- package/template/apps/web/src/composables/useAccessSnapshotMonitor.ts +42 -0
- package/template/apps/web/src/layout/AppShell.vue +28 -25
- package/template/apps/web/src/layout/AppShell.webtest.ts +1 -0
- package/template/apps/web/src/router/business-routes.ts +68 -0
- package/template/apps/web/src/router/business-routes.webtest.ts +85 -0
- package/template/apps/web/src/router/index.ts +7 -0
- package/template/apps/web/src/router/shared-scaffold-neutrality.webtest.ts +12 -0
- package/template/apps/web/src/services/access-api.ts +5 -1
- package/template/apps/web/src/services/access-api.webtest.ts +35 -0
- package/template/docs/architecture/ai-egress.md +12 -9
- package/template/docs/architecture/durable-jobs.md +7 -1
- package/template/docs/architecture/foundation-infrastructure.md +163 -0
- package/template/docs/architecture/module-host.md +115 -0
- package/template/docs/architecture/server-module-interface.md +39 -0
- package/template/docs/architecture/web-access-snapshot-resilience.md +60 -0
- package/template/docs/development/business-web-routes.md +66 -0
- package/template/docs/development/custom-login-page.md +3 -3
- package/template/docs/development/module-lifecycle.md +71 -0
- package/template/docs/operations/observability.md +5 -1
- package/template/docs/platform/agent-runtime.md +6 -6
- package/template/docs/platform/agent-tool-sandbox.md +58 -0
- package/template/docs/platform/document-ai-runtime.md +204 -0
- package/template/docs/platform/governed-export-renderers.md +132 -0
- package/template/docs/platform/navigation-registry.md +5 -0
- package/template/docs/platform/organization-membership.md +2 -1
- package/template/docs/platform/speech-ai-runtime.md +156 -0
- package/template/docs/platform/system-crud-api.md +7 -1
- package/template/docs/platform/vision-ai-runtime.md +97 -0
- package/template/docs/platform/web-system-crud.md +6 -0
- package/template/packages/config/package.json +1 -1
- package/template/packages/database/drizzle/0042_puzzling_rumiko_fujikawa.sql +27 -0
- package/template/packages/database/drizzle/meta/0042_snapshot.json +8541 -0
- package/template/packages/database/drizzle/meta/_journal.json +7 -0
- package/template/packages/database/package.json +1 -1
- package/template/packages/database/src/schema/durable-jobs.ts +1 -0
- package/template/packages/database/src/schema/governed-exports.ts +15 -0
- package/template/packages/database/src/schema-governed-exports.test.ts +21 -1
- package/template/packages/jobs/package.json +1 -1
- package/template/packages/jobs/src/handlers.ts +1 -0
- package/template/packages/jobs/src/types.ts +1 -0
- package/template/packages/modules/package.json +1 -1
- package/template/packages/server-sdk/index.ts +11 -0
- package/template/packages/server-sdk/package.json +1 -1
- package/template/packages/server-sdk/src/data-governance-registration.ts +46 -0
- package/template/packages/server-sdk/src/jobs-port.ts +69 -0
- package/template/packages/server-sdk/src/request-context.ts +2 -2
- package/template/packages/shared/package.json +1 -1
|
@@ -295,6 +295,13 @@
|
|
|
295
295
|
"when": 1785102272102,
|
|
296
296
|
"tag": "0041_yummy_prowler",
|
|
297
297
|
"breakpoints": true
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
"idx": 42,
|
|
301
|
+
"version": "7",
|
|
302
|
+
"when": 1785151819729,
|
|
303
|
+
"tag": "0042_puzzling_rumiko_fujikawa",
|
|
304
|
+
"breakpoints": true
|
|
298
305
|
}
|
|
299
306
|
]
|
|
300
307
|
}
|
|
@@ -205,6 +205,7 @@ export const durableJobArtifacts = pgTable(
|
|
|
205
205
|
byteSize: integer("byte_size").notNull(),
|
|
206
206
|
sha256: varchar("sha256", { length: 64 }).notNull(),
|
|
207
207
|
ownerId: varchar("owner_id", { length: 64 }).notNull(),
|
|
208
|
+
metadata: jsonb("metadata").$type<Record<string, unknown>>(),
|
|
208
209
|
expiresAt: timestamp("expires_at", { withTimezone: true }),
|
|
209
210
|
createdAt: timestamp("created_at", { withTimezone: true })
|
|
210
211
|
.notNull()
|
|
@@ -17,6 +17,18 @@ export interface GovernedExportQuerySnapshot {
|
|
|
17
17
|
readonly [key: string]: JsonValue | undefined;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
export interface GovernedExportRendererSnapshot {
|
|
21
|
+
formatKey: string;
|
|
22
|
+
templateKey: string;
|
|
23
|
+
templateVersion: string;
|
|
24
|
+
inputSchemaKey: string;
|
|
25
|
+
contentType: string;
|
|
26
|
+
filenameExtension: string;
|
|
27
|
+
maxRecords: number;
|
|
28
|
+
maxOutputBytes: number;
|
|
29
|
+
timeoutSeconds: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
20
32
|
export const governedExportRequests = pgTable(
|
|
21
33
|
"governed_export_requests",
|
|
22
34
|
{
|
|
@@ -39,6 +51,9 @@ export const governedExportRequests = pgTable(
|
|
|
39
51
|
querySnapshot: jsonb("query_snapshot")
|
|
40
52
|
.$type<GovernedExportQuerySnapshot>()
|
|
41
53
|
.notNull(),
|
|
54
|
+
renderer: jsonb("renderer")
|
|
55
|
+
.$type<GovernedExportRendererSnapshot>()
|
|
56
|
+
.notNull(),
|
|
42
57
|
status: varchar("status", { length: 32 }).notNull(),
|
|
43
58
|
approvalRequired: boolean("approval_required").notNull(),
|
|
44
59
|
approvalId: varchar("approval_id", { length: 64 }),
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
import { getTableConfig } from "drizzle-orm/pg-core";
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
durableJobArtifacts,
|
|
5
|
+
governedExportRequests,
|
|
6
|
+
} from "./schema/index.js";
|
|
4
7
|
|
|
5
8
|
describe("governed export schema", () => {
|
|
6
9
|
test("申请以 owner/resource/idempotency 唯一并受 Durable Job 外键约束", async () => {
|
|
@@ -9,6 +12,7 @@ describe("governed export schema", () => {
|
|
|
9
12
|
expect(config.name).toBe("governed_export_requests");
|
|
10
13
|
expect(governedExportRequests.scopeSnapshot.notNull).toBe(true);
|
|
11
14
|
expect(governedExportRequests.requestFingerprint.notNull).toBe(true);
|
|
15
|
+
expect(governedExportRequests.renderer.notNull).toBe(true);
|
|
12
16
|
expect(governedExportRequests.durableJobId.notNull).toBe(false);
|
|
13
17
|
expect(config.foreignKeys[0]?.onDelete).toBe("restrict");
|
|
14
18
|
expect(
|
|
@@ -45,5 +49,21 @@ describe("governed export schema", () => {
|
|
|
45
49
|
expect(constraintMigration).toContain(
|
|
46
50
|
'VALIDATE CONSTRAINT "ck_governed_exports_approval_job_state"',
|
|
47
51
|
);
|
|
52
|
+
const rendererMigration = await Bun.file(
|
|
53
|
+
new URL(
|
|
54
|
+
"../drizzle/0042_puzzling_rumiko_fujikawa.sql",
|
|
55
|
+
import.meta.url,
|
|
56
|
+
),
|
|
57
|
+
).text();
|
|
58
|
+
expect(rendererMigration).toContain(
|
|
59
|
+
'UPDATE "governed_export_requests"',
|
|
60
|
+
);
|
|
61
|
+
expect(rendererMigration).toContain(
|
|
62
|
+
'ALTER COLUMN "renderer" SET NOT NULL',
|
|
63
|
+
);
|
|
64
|
+
expect(rendererMigration).toContain(
|
|
65
|
+
'UPDATE "durable_job_artifacts" AS artifact',
|
|
66
|
+
);
|
|
67
|
+
expect(durableJobArtifacts.metadata.notNull).toBe(false);
|
|
48
68
|
});
|
|
49
69
|
});
|
|
@@ -23,20 +23,31 @@ export type {
|
|
|
23
23
|
ModuleAuditTarget,
|
|
24
24
|
} from "./src/audit-port.js";
|
|
25
25
|
export type {
|
|
26
|
+
ModuleJobCancelInput,
|
|
27
|
+
ModuleJobControlErrorCode,
|
|
28
|
+
ModuleJobPort,
|
|
29
|
+
ModuleJobProgressView,
|
|
30
|
+
ModuleJobRecoverInput,
|
|
31
|
+
ModuleJobStatus,
|
|
26
32
|
ModuleJobSubmitter,
|
|
27
33
|
ModuleJobSubmitInput,
|
|
28
34
|
ModuleJobSubmitResult,
|
|
35
|
+
ModuleJobView,
|
|
29
36
|
} from "./src/jobs-port.js";
|
|
37
|
+
export { ModuleJobControlError } from "./src/jobs-port.js";
|
|
30
38
|
export type {
|
|
31
39
|
ModuleDurableHandlerContext,
|
|
32
40
|
ModuleDurableHandlerDefinition,
|
|
33
41
|
ModuleDurableStoragePort,
|
|
34
42
|
} from "./src/durable-handler.js";
|
|
35
43
|
export type {
|
|
44
|
+
GovernedExportRenderedArtifact,
|
|
45
|
+
GovernedExportWatermarkContext,
|
|
36
46
|
ModuleGovernedExportPage,
|
|
37
47
|
ModuleGovernedExportPageInput,
|
|
38
48
|
ModuleGovernedExportQuery,
|
|
39
49
|
ModuleGovernedExportRegistration,
|
|
50
|
+
ModuleGovernedExportRendererRegistration,
|
|
40
51
|
ModuleGovernedRecord,
|
|
41
52
|
ModuleGovernedResourceContext,
|
|
42
53
|
ModuleGovernedResourceRegistration,
|
|
@@ -30,6 +30,47 @@ export interface ModuleGovernedExportPage {
|
|
|
30
30
|
readonly nextCursor?: string;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export interface GovernedExportWatermarkContext {
|
|
34
|
+
readonly actorId: string;
|
|
35
|
+
readonly generatedAt: string;
|
|
36
|
+
readonly scopeHash: string;
|
|
37
|
+
readonly jobId: string;
|
|
38
|
+
readonly requestId: string;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface GovernedExportRenderedArtifact {
|
|
42
|
+
readonly body: ReadableStream<Uint8Array>;
|
|
43
|
+
/** 不得包含记录原文或敏感字段,仅用于受控 artifact 元数据与审计。 */
|
|
44
|
+
readonly contentMetadata?: Readonly<Record<string, JsonValue>>;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export interface ModuleGovernedExportRendererRegistration {
|
|
48
|
+
readonly formatKey: string;
|
|
49
|
+
readonly templateKey: string;
|
|
50
|
+
readonly templateVersion: string;
|
|
51
|
+
readonly inputSchemaKey: string;
|
|
52
|
+
readonly contentType: string;
|
|
53
|
+
/** 不含点号,例如 pdf、docx、xlsx。 */
|
|
54
|
+
readonly filenameExtension: string;
|
|
55
|
+
readonly limits: {
|
|
56
|
+
readonly maxRecords: number;
|
|
57
|
+
readonly maxOutputBytes: number;
|
|
58
|
+
readonly timeoutSeconds: number;
|
|
59
|
+
};
|
|
60
|
+
render(
|
|
61
|
+
input: {
|
|
62
|
+
readonly records: AsyncIterable<Readonly<Record<string, JsonValue>>>;
|
|
63
|
+
readonly watermark: GovernedExportWatermarkContext;
|
|
64
|
+
},
|
|
65
|
+
context: {
|
|
66
|
+
readonly signal: AbortSignal;
|
|
67
|
+
readonly heartbeat: () => Promise<void>;
|
|
68
|
+
},
|
|
69
|
+
):
|
|
70
|
+
| Promise<GovernedExportRenderedArtifact>
|
|
71
|
+
| GovernedExportRenderedArtifact;
|
|
72
|
+
}
|
|
73
|
+
|
|
33
74
|
export interface ModuleGovernedExportRegistration {
|
|
34
75
|
/** 四个导出端点的基路径,例如 /api/people/persons/exports。 */
|
|
35
76
|
readonly basePath: string;
|
|
@@ -37,6 +78,11 @@ export interface ModuleGovernedExportRegistration {
|
|
|
37
78
|
readonly approvalRequired?: boolean;
|
|
38
79
|
/** 产物保留时间;宿主还会施加平台上限。 */
|
|
39
80
|
readonly retentionSeconds?: number;
|
|
81
|
+
/**
|
|
82
|
+
* 服务端受治理 Renderer。声明后请求必须显式选择已注册 formatKey;
|
|
83
|
+
* 未声明时保持既有 NDJSON 行为。
|
|
84
|
+
*/
|
|
85
|
+
readonly renderers?: readonly ModuleGovernedExportRendererRegistration[];
|
|
40
86
|
validateQuery(query: unknown): ModuleGovernedExportQuery;
|
|
41
87
|
readPage(
|
|
42
88
|
input: ModuleGovernedExportPageInput,
|
|
@@ -22,3 +22,72 @@ export interface ModuleJobSubmitResult {
|
|
|
22
22
|
export interface ModuleJobSubmitter {
|
|
23
23
|
submit(input: ModuleJobSubmitInput): Promise<ModuleJobSubmitResult>;
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
export type ModuleJobStatus =
|
|
27
|
+
| "queued"
|
|
28
|
+
| "running"
|
|
29
|
+
| "succeeded"
|
|
30
|
+
| "failed"
|
|
31
|
+
| "cancelled";
|
|
32
|
+
|
|
33
|
+
export interface ModuleJobProgressView {
|
|
34
|
+
readonly completedUnits: number;
|
|
35
|
+
readonly totalUnits?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ModuleJobView {
|
|
39
|
+
readonly jobId: string;
|
|
40
|
+
readonly handlerKey: string;
|
|
41
|
+
readonly status: ModuleJobStatus;
|
|
42
|
+
readonly progress?: ModuleJobProgressView;
|
|
43
|
+
readonly attempt: number;
|
|
44
|
+
readonly maxAttempts: number;
|
|
45
|
+
readonly createdAt: string;
|
|
46
|
+
readonly startedAt?: string;
|
|
47
|
+
readonly finishedAt?: string;
|
|
48
|
+
readonly failureCode?: string;
|
|
49
|
+
readonly canCancel: boolean;
|
|
50
|
+
readonly canRecover: boolean;
|
|
51
|
+
/** 当前持久化版本;控制操作必须回传该值以执行 CAS。 */
|
|
52
|
+
readonly version: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export interface ModuleJobCancelInput {
|
|
56
|
+
readonly jobId: string;
|
|
57
|
+
readonly reason: string;
|
|
58
|
+
readonly expectedStatus?: ModuleJobStatus;
|
|
59
|
+
readonly expectedVersion?: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export interface ModuleJobRecoverInput {
|
|
63
|
+
readonly jobId: string;
|
|
64
|
+
readonly reason: string;
|
|
65
|
+
readonly expectedAttempt: number;
|
|
66
|
+
readonly expectedStatus: ModuleJobStatus;
|
|
67
|
+
readonly expectedVersion: string;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type ModuleJobControlErrorCode =
|
|
71
|
+
| "JOB_NOT_AVAILABLE"
|
|
72
|
+
| "JOB_STATE_CONFLICT"
|
|
73
|
+
| "JOB_CONTROL_UNAVAILABLE"
|
|
74
|
+
| "JOB_REASON_INVALID";
|
|
75
|
+
|
|
76
|
+
export class ModuleJobControlError extends Error {
|
|
77
|
+
constructor(
|
|
78
|
+
readonly code: ModuleJobControlErrorCode,
|
|
79
|
+
message: string,
|
|
80
|
+
) {
|
|
81
|
+
super(message);
|
|
82
|
+
this.name = "ModuleJobControlError";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 宿主绑定 Module、Queue、Actor 与授权范围的 Durable Job 受限控制 Port。
|
|
88
|
+
*/
|
|
89
|
+
export interface ModuleJobPort extends ModuleJobSubmitter {
|
|
90
|
+
get(jobId: string): Promise<ModuleJobView | undefined>;
|
|
91
|
+
cancel(input: ModuleJobCancelInput): Promise<ModuleJobView>;
|
|
92
|
+
recover(input: ModuleJobRecoverInput): Promise<ModuleJobView>;
|
|
93
|
+
}
|
|
@@ -2,7 +2,7 @@ import type { ModuleActor } from "./actor.js";
|
|
|
2
2
|
import type { ModuleAuditEmitter } from "./audit-port.js";
|
|
3
3
|
import type { ModuleAiArtifactPort } from "./ai-artifact-port.js";
|
|
4
4
|
import type { ModuleAiOperationPort } from "./ai-operation-port.js";
|
|
5
|
-
import type {
|
|
5
|
+
import type { ModuleJobPort } from "./jobs-port.js";
|
|
6
6
|
import type { ModuleStoragePort } from "./storage-port.js";
|
|
7
7
|
import type { ModuleUserDirectoryPort } from "./user-directory-port.js";
|
|
8
8
|
|
|
@@ -21,7 +21,7 @@ export interface ModuleRequestContext {
|
|
|
21
21
|
readonly audit: ModuleAuditEmitter;
|
|
22
22
|
readonly aiArtifacts: ModuleAiArtifactPort;
|
|
23
23
|
readonly aiOperations: ModuleAiOperationPort;
|
|
24
|
-
readonly jobs:
|
|
24
|
+
readonly jobs: ModuleJobPort;
|
|
25
25
|
readonly storage: ModuleStoragePort;
|
|
26
26
|
readonly userDirectory: ModuleUserDirectoryPort;
|
|
27
27
|
}
|