openxiangda 2.0.0-alpha.2 → 2.0.0-alpha.21
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/bin/run.js +6 -1
- package/dist/browser/AuthoritativeSelector.d.ts.map +1 -1
- package/dist/browser/AuthoritativeSelector.js +4 -2
- package/dist/browser/AuthoritativeSelector.js.map +1 -1
- package/dist/browser/Shell.d.ts.map +1 -1
- package/dist/browser/Shell.js +213 -56
- package/dist/browser/Shell.js.map +1 -1
- package/dist/browser/admin-contributions.d.ts +66 -0
- package/dist/browser/admin-contributions.d.ts.map +1 -0
- package/dist/browser/admin-contributions.js +196 -0
- package/dist/browser/admin-contributions.js.map +1 -0
- package/dist/browser/application.d.ts +7 -1
- package/dist/browser/application.d.ts.map +1 -1
- package/dist/browser/application.js +68 -23
- package/dist/browser/application.js.map +1 -1
- package/dist/browser/components/platform-fields/SubtableField.js +3 -3
- package/dist/browser/components/platform-fields/SubtableField.js.map +1 -1
- package/dist/browser/components/platform-fields/resource-query.d.ts +0 -1
- package/dist/browser/components/platform-fields/resource-query.d.ts.map +1 -1
- package/dist/browser/components/platform-fields/resource-query.js +7 -8
- package/dist/browser/components/platform-fields/resource-query.js.map +1 -1
- package/dist/browser/components/resource/GeneratedResourceCrud.d.ts.map +1 -1
- package/dist/browser/components/resource/GeneratedResourceCrud.js +134 -46
- package/dist/browser/components/resource/GeneratedResourceCrud.js.map +1 -1
- package/dist/browser/components/resource/StandardResourcePages.d.ts +3 -2
- package/dist/browser/components/resource/StandardResourcePages.d.ts.map +1 -1
- package/dist/browser/components/resource/StandardResourcePages.js +13 -13
- package/dist/browser/components/resource/StandardResourcePages.js.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.d.ts.map +1 -1
- package/dist/browser/components/resource/SurfaceFields.js +6 -2
- package/dist/browser/components/resource/SurfaceFields.js.map +1 -1
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts +13 -0
- package/dist/browser/components/workflow/StandardWorkflowPages.d.ts.map +1 -0
- package/dist/browser/components/workflow/StandardWorkflowPages.js +407 -0
- package/dist/browser/components/workflow/StandardWorkflowPages.js.map +1 -0
- package/dist/browser/platform-client.d.ts +41 -2
- package/dist/browser/platform-client.d.ts.map +1 -1
- package/dist/browser/platform-client.js +117 -10
- package/dist/browser/platform-client.js.map +1 -1
- package/dist/browser/runtime-meta.d.ts +2 -0
- package/dist/browser/runtime-meta.d.ts.map +1 -1
- package/dist/browser/runtime-meta.js +12 -0
- package/dist/browser/runtime-meta.js.map +1 -1
- package/dist/browser/runtime.d.ts +8 -1
- package/dist/browser/runtime.d.ts.map +1 -1
- package/dist/browser/runtime.js +61 -13
- package/dist/browser/runtime.js.map +1 -1
- package/dist/browser/selector-copy.d.ts +6 -0
- package/dist/browser/selector-copy.d.ts.map +1 -0
- package/dist/browser/selector-copy.js +13 -0
- package/dist/browser/selector-copy.js.map +1 -0
- package/dist/browser/styles.css +449 -15
- package/dist/browser/workflow-definitions.d.ts +25 -0
- package/dist/browser/workflow-definitions.d.ts.map +1 -0
- package/dist/browser/workflow-definitions.js +32 -0
- package/dist/browser/workflow-definitions.js.map +1 -0
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/internal/web-build-verifier.d.ts +8 -0
- package/dist/internal/web-build-verifier.d.ts.map +1 -0
- package/dist/internal/web-build-verifier.js +55 -0
- package/dist/internal/web-build-verifier.js.map +1 -0
- package/dist/nest.d.ts +3 -4
- package/dist/nest.d.ts.map +1 -1
- package/dist/nest.js +2 -3
- package/dist/nest.js.map +1 -1
- package/dist/react.d.ts +3 -0
- package/dist/react.d.ts.map +1 -1
- package/dist/react.js +3 -0
- package/dist/react.js.map +1 -1
- package/dist/testing.d.ts +1 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +1 -0
- package/dist/testing.js.map +1 -1
- package/package.json +7 -7
- package/skills/manifest.json +1 -1
- package/skills/openxiangda-v2/SKILL.md +18 -14
- package/skills/openxiangda-v2/references/appspec.md +67 -0
- package/skills/openxiangda-v2/references/backend.md +58 -9
- package/skills/openxiangda-v2/references/commands.md +21 -0
- package/skills/openxiangda-v2/references/data-authz.md +39 -5
- package/skills/openxiangda-v2/references/delivery.md +17 -1
- package/skills/openxiangda-v2/references/frontend.md +47 -1
- package/skills/openxiangda-v2/references/testing.md +46 -2
- package/skills/openxiangda-v2/references/{workflow-notification.md → workflow-events.md} +6 -3
- package/skills/openxiangda-v2/references/workspace.md +9 -5
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { gzipSync } from 'node:zlib';
|
|
5
|
+
const MAX_ASSET_FILES = 512;
|
|
6
|
+
const MAX_HTML_BYTES = 100_000;
|
|
7
|
+
const MAX_INITIAL_JAVASCRIPT_GZIP_BYTES = 2_000_000;
|
|
8
|
+
export function verifyOpenXiangdaWebBuild(distInput) {
|
|
9
|
+
const dist = resolve(typeof distInput === 'string' ? distInput : fileURLToPath(distInput));
|
|
10
|
+
const assets = join(dist, 'assets');
|
|
11
|
+
const entries = readdirSync(assets, { withFileTypes: true });
|
|
12
|
+
if (entries.length > MAX_ASSET_FILES) {
|
|
13
|
+
throw new Error(`WEB_ASSET_FILE_COUNT_EXCEEDED:${entries.length}>${MAX_ASSET_FILES}`);
|
|
14
|
+
}
|
|
15
|
+
if (entries.some(entry => !entry.isFile())) {
|
|
16
|
+
throw new Error('WEB_ASSET_TREE_INVALID');
|
|
17
|
+
}
|
|
18
|
+
const names = entries.map(entry => entry.name);
|
|
19
|
+
const files = names.map(name => join(assets, name));
|
|
20
|
+
const sizes = files.map(file => statSync(file).size);
|
|
21
|
+
const totalBytes = sizes.reduce((total, size) => total + size, 0);
|
|
22
|
+
if (names.some(name => name.endsWith('.map'))) {
|
|
23
|
+
throw new Error('WEB_SOURCE_MAP_FORBIDDEN');
|
|
24
|
+
}
|
|
25
|
+
const javascript = files.filter(file => file.endsWith('.js'));
|
|
26
|
+
const totalJavaScriptGzipBytes = javascript.reduce((total, file) => total + gzipSync(readFileSync(file), { level: 9 }).byteLength, 0);
|
|
27
|
+
const htmlPath = join(dist, 'index.html');
|
|
28
|
+
const htmlBytes = statSync(htmlPath).size;
|
|
29
|
+
if (htmlBytes > MAX_HTML_BYTES) {
|
|
30
|
+
throw new Error(`WEB_HTML_BUDGET_EXCEEDED:${htmlBytes}>${MAX_HTML_BYTES}`);
|
|
31
|
+
}
|
|
32
|
+
const html = readFileSync(htmlPath, 'utf8');
|
|
33
|
+
if (!html.includes('<div id="root"></div>')) {
|
|
34
|
+
throw new Error('WEB_ROOT_MISSING');
|
|
35
|
+
}
|
|
36
|
+
const initialNames = [
|
|
37
|
+
...html.matchAll(/(?:src|href)="\.\/assets\/([^"]+\.js)"/g),
|
|
38
|
+
].map(match => match[1]);
|
|
39
|
+
const initialJavaScriptGzipBytes = [...new Set(initialNames)].reduce((total, name) => {
|
|
40
|
+
if (!names.includes(name))
|
|
41
|
+
throw new Error(`WEB_INITIAL_ASSET_MISSING:${name}`);
|
|
42
|
+
return (total +
|
|
43
|
+
gzipSync(readFileSync(join(assets, name)), { level: 9 }).byteLength);
|
|
44
|
+
}, 0);
|
|
45
|
+
if (initialJavaScriptGzipBytes > MAX_INITIAL_JAVASCRIPT_GZIP_BYTES) {
|
|
46
|
+
throw new Error(`WEB_INITIAL_JS_GZIP_BUDGET_EXCEEDED:${initialJavaScriptGzipBytes}>${MAX_INITIAL_JAVASCRIPT_GZIP_BYTES}`);
|
|
47
|
+
}
|
|
48
|
+
return {
|
|
49
|
+
assetFiles: entries.length,
|
|
50
|
+
totalBytes,
|
|
51
|
+
totalJavaScriptGzipBytes,
|
|
52
|
+
initialJavaScriptGzipBytes,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=web-build-verifier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web-build-verifier.js","sourceRoot":"","sources":["../../src/internal/web-build-verifier.ts"],"names":[],"mappings":"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"}
|
package/dist/nest.d.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Application-facing NestJS surface for OpenXiangda 2.0.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* low-level transport clients. Applications receive only current-user-union,
|
|
4
|
+
* Applications receive only current-user-union, Perspective read projection,
|
|
6
5
|
* application-principal, Data API, runtime, event and bounded operation APIs.
|
|
7
6
|
*/
|
|
8
|
-
export { bootstrapOpenXiangdaApplication, OpenXiangdaModule, OpenXiangdaAuthzGuard, RequireCapability, OpenXiangdaOperation, CurrentPrincipal, CurrentUser, currentUserFromVerifiedContext, currentUserFromPrincipal, CurrentApplicationPrincipal, OpenXiangdaDataApiService, OpenXiangdaApplicationDataApiService, OpenXiangdaApplicationCredentials, OpenXiangdaRuntimeLeaseService, OpenXiangdaRuntimeSecrets, OpenXiangdaStandardOperations, OpenXiangdaEventContext, OpenXiangdaEventHandler, OpenXiangdaEventRegistry, OpenXiangdaEventRetryableError, OpenXiangdaEventDeterministicError, eventSigningSecretsFromEnvironment, assertValidTimeInterval, idempotentTransaction, } from 'openxiangda-nest';
|
|
9
|
-
export type { OpenXiangdaApplicationBootstrapOptions, OpenXiangdaModuleOptions, OpenXiangdaOAuthClientOptions, OpenXiangdaFetch, OpenXiangdaCurrentUser, OpenXiangdaServicePrincipal, OpenXiangdaConnectedDevelopmentStatus, OpenXiangdaDomainEventEmitInput, OpenXiangdaDomainEventEmitResult, OpenXiangdaRuntimeLeaseState, OpenXiangdaEventHandlerContext, OpenXiangdaEventHandlerDeclaration, OpenXiangdaEventConsumer, TimeInterval, MeetingReservationOperationInput, CourseSelectionOperationInput, VisitorReservationOperationInput, } from 'openxiangda-nest';
|
|
7
|
+
export { bootstrapOpenXiangdaApplication, OpenXiangdaModule, OpenXiangdaAuthzGuard, RequireCapability, OpenXiangdaOperation, CurrentPrincipal, CurrentUser, CurrentPerspective, currentUserFromVerifiedContext, currentUserFromPrincipal, CurrentApplicationPrincipal, OpenXiangdaDataApiService, OpenXiangdaBusinessDataApiService, OpenXiangdaApplicationDataApiService, OpenXiangdaApplicationCredentials, OpenXiangdaRuntimeLeaseService, OpenXiangdaRuntimeSecrets, OpenXiangdaStandardOperations, OpenXiangdaEventContext, OpenXiangdaEventHandler, OpenXiangdaEventRegistry, OpenXiangdaEventRetryableError, OpenXiangdaEventDeterministicError, eventSigningSecretsFromEnvironment, assertValidTimeInterval, idempotentTransaction, } from 'openxiangda-nest';
|
|
8
|
+
export type { OpenXiangdaApplicationBootstrapOptions, OpenXiangdaModuleOptions, OpenXiangdaOAuthClientOptions, OpenXiangdaFetch, OpenXiangdaCurrentUser, OpenXiangdaServicePrincipal, OpenXiangdaConnectedDevelopmentStatus, OpenXiangdaDomainEventEmitInput, OpenXiangdaDomainEventEmitResult, OpenXiangdaBusinessActionContext, OpenXiangdaRuntimeLeaseState, OpenXiangdaEventHandlerContext, OpenXiangdaEventHandlerDeclaration, OpenXiangdaEventConsumer, TimeInterval, MeetingReservationOperationInput, CourseSelectionOperationInput, VisitorReservationOperationInput, } from 'openxiangda-nest';
|
|
10
9
|
//# sourceMappingURL=nest.d.ts.map
|
package/dist/nest.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest.d.ts","sourceRoot":"","sources":["../src/nest.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"nest.d.ts","sourceRoot":"","sources":["../src/nest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,+BAA+B,EAC/B,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,8BAA8B,EAC9B,wBAAwB,EACxB,2BAA2B,EAC3B,yBAAyB,EACzB,iCAAiC,EACjC,oCAAoC,EACpC,iCAAiC,EACjC,8BAA8B,EAC9B,yBAAyB,EACzB,6BAA6B,EAC7B,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,8BAA8B,EAC9B,kCAAkC,EAClC,kCAAkC,EAClC,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAE1B,YAAY,EACV,sCAAsC,EACtC,wBAAwB,EACxB,6BAA6B,EAC7B,gBAAgB,EAChB,sBAAsB,EACtB,2BAA2B,EAC3B,qCAAqC,EACrC,+BAA+B,EAC/B,gCAAgC,EAChC,gCAAgC,EAChC,4BAA4B,EAC5B,8BAA8B,EAC9B,kCAAkC,EAClC,wBAAwB,EACxB,YAAY,EACZ,gCAAgC,EAChC,6BAA6B,EAC7B,gCAAgC,GACjC,MAAM,kBAAkB,CAAC"}
|
package/dist/nest.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Application-facing NestJS surface for OpenXiangda 2.0.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* low-level transport clients. Applications receive only current-user-union,
|
|
4
|
+
* Applications receive only current-user-union, Perspective read projection,
|
|
6
5
|
* application-principal, Data API, runtime, event and bounded operation APIs.
|
|
7
6
|
*/
|
|
8
|
-
export { bootstrapOpenXiangdaApplication, OpenXiangdaModule, OpenXiangdaAuthzGuard, RequireCapability, OpenXiangdaOperation, CurrentPrincipal, CurrentUser, currentUserFromVerifiedContext, currentUserFromPrincipal, CurrentApplicationPrincipal, OpenXiangdaDataApiService, OpenXiangdaApplicationDataApiService, OpenXiangdaApplicationCredentials, OpenXiangdaRuntimeLeaseService, OpenXiangdaRuntimeSecrets, OpenXiangdaStandardOperations, OpenXiangdaEventContext, OpenXiangdaEventHandler, OpenXiangdaEventRegistry, OpenXiangdaEventRetryableError, OpenXiangdaEventDeterministicError, eventSigningSecretsFromEnvironment, assertValidTimeInterval, idempotentTransaction, } from 'openxiangda-nest';
|
|
7
|
+
export { bootstrapOpenXiangdaApplication, OpenXiangdaModule, OpenXiangdaAuthzGuard, RequireCapability, OpenXiangdaOperation, CurrentPrincipal, CurrentUser, CurrentPerspective, currentUserFromVerifiedContext, currentUserFromPrincipal, CurrentApplicationPrincipal, OpenXiangdaDataApiService, OpenXiangdaBusinessDataApiService, OpenXiangdaApplicationDataApiService, OpenXiangdaApplicationCredentials, OpenXiangdaRuntimeLeaseService, OpenXiangdaRuntimeSecrets, OpenXiangdaStandardOperations, OpenXiangdaEventContext, OpenXiangdaEventHandler, OpenXiangdaEventRegistry, OpenXiangdaEventRetryableError, OpenXiangdaEventDeterministicError, eventSigningSecretsFromEnvironment, assertValidTimeInterval, idempotentTransaction, } from 'openxiangda-nest';
|
|
9
8
|
//# sourceMappingURL=nest.js.map
|
package/dist/nest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nest.js","sourceRoot":"","sources":["../src/nest.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"nest.js","sourceRoot":"","sources":["../src/nest.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACL,+BAA+B,EAC/B,iBAAiB,EACjB,qBAAqB,EACrB,iBAAiB,EACjB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,kBAAkB,EAClB,8BAA8B,EAC9B,wBAAwB,EACxB,2BAA2B,EAC3B,yBAAyB,EACzB,iCAAiC,EACjC,oCAAoC,EACpC,iCAAiC,EACjC,8BAA8B,EAC9B,yBAAyB,EACzB,6BAA6B,EAC7B,uBAAuB,EACvB,uBAAuB,EACvB,wBAAwB,EACxB,8BAA8B,EAC9B,kCAAkC,EAClC,kCAAkC,EAClC,uBAAuB,EACvB,qBAAqB,GACtB,MAAM,kBAAkB,CAAC"}
|
package/dist/react.d.ts
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
export * from './browser/application';
|
|
2
|
+
export * from './browser/admin-contributions';
|
|
2
3
|
export * from './browser/appearance';
|
|
3
4
|
export * from './browser/data-provider';
|
|
4
5
|
export * from './browser/FilePreviewPage';
|
|
5
6
|
export * from './browser/runtime';
|
|
6
7
|
export * from './browser/Shell';
|
|
7
8
|
export * from './browser/resource-definitions';
|
|
9
|
+
export * from './browser/workflow-definitions';
|
|
8
10
|
export * from './browser/components/resource/GeneratedResourceCrud';
|
|
9
11
|
export * from './browser/components/resource/ResourceBatchActions';
|
|
10
12
|
export * from './browser/components/resource/StandardResourcePages';
|
|
13
|
+
export * from './browser/components/workflow/StandardWorkflowPages';
|
|
11
14
|
export type * from './browser/components/resource/generated-resource-definition';
|
|
12
15
|
//# sourceMappingURL=react.d.ts.map
|
package/dist/react.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qDAAqD,CAAC;AACpE,cAAc,oDAAoD,CAAC;AACnE,cAAc,qDAAqD,CAAC;AACpE,mBAAmB,6DAA6D,CAAC"}
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qDAAqD,CAAC;AACpE,cAAc,oDAAoD,CAAC;AACnE,cAAc,qDAAqD,CAAC;AACpE,cAAc,qDAAqD,CAAC;AACpE,mBAAmB,6DAA6D,CAAC"}
|
package/dist/react.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
export * from './browser/application';
|
|
2
|
+
export * from './browser/admin-contributions';
|
|
2
3
|
export * from './browser/appearance';
|
|
3
4
|
export * from './browser/data-provider';
|
|
4
5
|
export * from './browser/FilePreviewPage';
|
|
5
6
|
export * from './browser/runtime';
|
|
6
7
|
export * from './browser/Shell';
|
|
7
8
|
export * from './browser/resource-definitions';
|
|
9
|
+
export * from './browser/workflow-definitions';
|
|
8
10
|
export * from './browser/components/resource/GeneratedResourceCrud';
|
|
9
11
|
export * from './browser/components/resource/ResourceBatchActions';
|
|
10
12
|
export * from './browser/components/resource/StandardResourcePages';
|
|
13
|
+
export * from './browser/components/workflow/StandardWorkflowPages';
|
|
11
14
|
//# sourceMappingURL=react.js.map
|
package/dist/react.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qDAAqD,CAAC;AACpE,cAAc,oDAAoD,CAAC;AACnE,cAAc,qDAAqD,CAAC"}
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../src/react.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,qDAAqD,CAAC;AACpE,cAAc,oDAAoD,CAAC;AACnE,cAAc,qDAAqD,CAAC;AACpE,cAAc,qDAAqD,CAAC"}
|
package/dist/testing.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from 'openxiangda-devkit-core/testing';
|
|
2
2
|
export { OpenXiangdaApplicationServices, verifySealedAppPackage, } from 'openxiangda-devkit-core';
|
|
3
3
|
export { sha256Digest } from 'openxiangda-contracts';
|
|
4
|
+
export { verifyOpenXiangdaWebBuild, type OpenXiangdaWebBuildVerification, } from './internal/web-build-verifier.js';
|
|
4
5
|
//# sourceMappingURL=testing.d.ts.map
|
package/dist/testing.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,OAAO,EACL,8BAA8B,EAC9B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,OAAO,EACL,8BAA8B,EAC9B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EACL,yBAAyB,EACzB,KAAK,+BAA+B,GACrC,MAAM,kCAAkC,CAAC"}
|
package/dist/testing.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export * from 'openxiangda-devkit-core/testing';
|
|
2
2
|
export { OpenXiangdaApplicationServices, verifySealedAppPackage, } from 'openxiangda-devkit-core';
|
|
3
3
|
export { sha256Digest } from 'openxiangda-contracts';
|
|
4
|
+
export { verifyOpenXiangdaWebBuild, } from './internal/web-build-verifier.js';
|
|
4
5
|
//# sourceMappingURL=testing.js.map
|
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,OAAO,EACL,8BAA8B,EAC9B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"testing.js","sourceRoot":"","sources":["../src/testing.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,OAAO,EACL,8BAA8B,EAC9B,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EACL,yBAAyB,GAE1B,MAAM,kCAAkC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.21",
|
|
4
4
|
"description": "Unified OpenXiangda 2.0 CLI, SDK, React runtime, NestJS integration and AI skill distribution.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -49,12 +49,12 @@
|
|
|
49
49
|
"dependencies": {
|
|
50
50
|
"dayjs": "1.11.18",
|
|
51
51
|
"docx-preview": "0.3.7",
|
|
52
|
-
"openxiangda-cli": "2.0.0-alpha.
|
|
53
|
-
"openxiangda-contracts": "2.0.0-alpha.
|
|
54
|
-
"openxiangda-devkit-core": "2.0.0-alpha.
|
|
55
|
-
"openxiangda-mcp": "2.0.0-alpha.
|
|
56
|
-
"openxiangda-nest": "2.0.0-alpha.
|
|
57
|
-
"openxiangda-skill-kit": "2.0.0-alpha.
|
|
52
|
+
"openxiangda-cli": "2.0.0-alpha.108",
|
|
53
|
+
"openxiangda-contracts": "2.0.0-alpha.50",
|
|
54
|
+
"openxiangda-devkit-core": "2.0.0-alpha.67",
|
|
55
|
+
"openxiangda-mcp": "2.0.0-alpha.67",
|
|
56
|
+
"openxiangda-nest": "2.0.0-alpha.61",
|
|
57
|
+
"openxiangda-skill-kit": "2.0.0-alpha.85",
|
|
58
58
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
|
59
59
|
},
|
|
60
60
|
"peerDependencies": {
|
package/skills/manifest.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
{
|
|
5
5
|
"name": "openxiangda-v2",
|
|
6
6
|
"description": "Use when researching, designing, building, testing, or delivering a complete OpenXiangda 2.0 application.",
|
|
7
|
-
"sha256": "
|
|
7
|
+
"sha256": "4e79de2626b4fe8ec1049cba8354db8447b2d93160957237df8ba6a3d547bc93"
|
|
8
8
|
}
|
|
9
9
|
]
|
|
10
10
|
}
|
|
@@ -5,30 +5,32 @@ description: Use when researching, designing, building, testing, or delivering a
|
|
|
5
5
|
|
|
6
6
|
# OpenXiangda 2.0
|
|
7
7
|
|
|
8
|
-
Treat requirement discovery, architecture, authorization, development, testing and delivery as one evidence-backed application lifecycle. OpenXiangda 2.0 has no compatibility surface: replace an incorrect alpha contract directly and never add aliases, migration branches, 1.x SDD, Umi, ProComponents, Function CRUD, application
|
|
8
|
+
Treat requirement discovery, architecture, authorization, development, testing and delivery as one evidence-backed application lifecycle. OpenXiangda 2.0 has no compatibility surface: replace an incorrect alpha contract directly and never add aliases, migration branches, 1.x SDD, Umi, ProComponents, Function CRUD, application-owned identity switching or another identity path.
|
|
9
9
|
|
|
10
10
|
Before a workspace exists, use this Skill's exact npm version:
|
|
11
11
|
|
|
12
12
|
```bash
|
|
13
|
-
pnpm dlx openxiangda@2.0.0-alpha.
|
|
14
|
-
pnpm dlx openxiangda@2.0.0-alpha.
|
|
13
|
+
pnpm dlx openxiangda@2.0.0-alpha.21 login --base-url <platform>
|
|
14
|
+
pnpm dlx openxiangda@2.0.0-alpha.21 create <directory>
|
|
15
15
|
```
|
|
16
16
|
|
|
17
17
|
Inside an application, use only its locked executable through `pnpm openxiangda`. Never invoke a bare global `openxiangda`, because that executable may belong to stable 1.x. Moving tags such as `latest` and `alpha` are forbidden. To install or refresh this same Skill from the package, run:
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
pnpm dlx openxiangda@2.0.0-alpha.
|
|
20
|
+
pnpm dlx openxiangda@2.0.0-alpha.21 skill install --force
|
|
21
21
|
```
|
|
22
22
|
|
|
23
23
|
Use this order:
|
|
24
24
|
|
|
25
|
-
1. Read [
|
|
26
|
-
2. Read [
|
|
27
|
-
3.
|
|
28
|
-
4. Read [
|
|
29
|
-
5.
|
|
30
|
-
6.
|
|
31
|
-
7.
|
|
25
|
+
1. Read [Commands](references/commands.md) when selecting a CLI operation. It is generated from the executable registry. `create` owns application binding and initialization, while `check`, `deploy` and `status` expose the current workspace and deployment facts.
|
|
26
|
+
2. Read [Discovery](references/discovery.md), turn the request into actors, scenarios, data, permissions, constraints and acceptance evidence, and identify every unresolved choice.
|
|
27
|
+
3. If the workspace contains `appspec/`, the user asks to maintain requirements, or the task changes observable behavior, read [AppSpec](references/appspec.md), load the bounded index with `pnpm openxiangda spec context --json`, then select only the relevant stable ID. AppSpec is optional and never a release gate; L0 changes create no record.
|
|
28
|
+
4. Read [Architecture](references/architecture.md), assign one owner to each capability and keep ordinary CRUD on platform Data API.
|
|
29
|
+
5. For every resource or permission change, read [Data and authorization](references/data-authz.md) before editing `openxiangda.config.ts`.
|
|
30
|
+
6. Read [Frontend](references/frontend.md) for pages or fields and [Backend actions](references/backend.md) only for a real business action.
|
|
31
|
+
7. When the application explicitly enables standard approval, application events or notifications, read [Workflow, Events and Notification Hub](references/workflow-events.md). Keep them optional and out of ordinary CRUD.
|
|
32
|
+
8. Run the connected loop with `pnpm openxiangda dev`, then follow [Testing](references/testing.md) and `pnpm openxiangda check`.
|
|
33
|
+
9. Follow [Delivery](references/delivery.md): deploy preproduction first, inspect status/logs, then promote the exact successful version to production.
|
|
32
34
|
|
|
33
35
|
For an AI-native client, start the workspace protocol through the same pinned executable:
|
|
34
36
|
|
|
@@ -36,19 +38,21 @@ For an AI-native client, start the workspace protocol through the same pinned ex
|
|
|
36
38
|
pnpm exec openxiangda --mcp-stdio --cwd <workspace>
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
Read `openxiangda://workspace/contracts` or call `contract_describe`. Require `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. Never create an application MCP server, Catalog file, preview store or AI authorization path.
|
|
41
|
+
Read `openxiangda://workspace/contracts` or call `contract_describe`. When AppSpec is enabled, read `openxiangda://workspace/appspec` or call `appspec_context`; treat it as advisory context, never as deployment authority. Require `aiCatalog` and `aiCatalogDigest` to match the normal compiler output. Never create an application MCP server, Catalog file, preview store or AI authorization path.
|
|
40
42
|
|
|
41
|
-
The browser uses the current logged-in user's complete application-role union. The platform is authoritative for capabilities, fields, rows and RLS. Application code does not
|
|
43
|
+
The browser uses the current logged-in user's complete application-role union. The platform is authoritative for capabilities, fields, rows and RLS. A declared Perspective is only a read projection over that union: it may narrow pages, rows and readable fields, but never create/update/delete, workflow or custom-action authorization. Omitted Perspective means the complete union. Application code does not replace the authenticated identity, persist a platform token, construct an authorization result or keep a second permission state.
|
|
42
44
|
|
|
43
45
|
Read only the references needed for the current change, except the mandatory discovery and Data/authorization rules above:
|
|
44
46
|
|
|
45
47
|
- [Discovery](references/discovery.md)
|
|
48
|
+
- [AppSpec](references/appspec.md)
|
|
49
|
+
- [Commands](references/commands.md)
|
|
46
50
|
- [Architecture](references/architecture.md)
|
|
47
51
|
- [Workspace agent contract](references/workspace.md)
|
|
48
52
|
- [Backend actions](references/backend.md)
|
|
49
53
|
- [Data and authorization](references/data-authz.md)
|
|
50
54
|
- [Frontend](references/frontend.md)
|
|
51
|
-
- [Workflow and Notification Hub](references/workflow-
|
|
55
|
+
- [Workflow, Events and Notification Hub](references/workflow-events.md)
|
|
52
56
|
- [Testing](references/testing.md)
|
|
53
57
|
- [Delivery](references/delivery.md)
|
|
54
58
|
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# AppSpec
|
|
2
|
+
|
|
3
|
+
AppSpec 是 OpenXiangda 2.0 应用仓库中的可选业务意图层。它帮助 AI 理解“为什么做、应当表现成
|
|
4
|
+
什么、这次改变什么”,但不复制 `openxiangda.config.ts`、编译合同、代码、测试或部署状态,也
|
|
5
|
+
不是发布门禁。
|
|
6
|
+
|
|
7
|
+
AppSpec 只使用 2.0 的 `appspec/`、文档 schema v1 与 context v2。绝不读取、识别、导入或迁移
|
|
8
|
+
1.x 的 `openspec/`、SDD、表单、页面、函数和发布材料。
|
|
9
|
+
|
|
10
|
+
## 何时读取
|
|
11
|
+
|
|
12
|
+
- 工作区存在 `appspec/` 时,在分析需求或修改行为前运行 `pnpm openxiangda spec context --json`,先读取
|
|
13
|
+
有界索引。
|
|
14
|
+
- 从索引选择相关变更、能力、ADR 或历史变更 ID,再运行例如
|
|
15
|
+
`pnpm openxiangda spec context booking-window --json` 读取正文。
|
|
16
|
+
- AI-native 客户端可读取 `openxiangda://workspace/appspec` 或调用 `appspec_context`。
|
|
17
|
+
- 默认不加载全部正文;历史变更只在追查原因时用稳定 ID 按需读取。
|
|
18
|
+
|
|
19
|
+
## 何时维护
|
|
20
|
+
|
|
21
|
+
| 风险 | 典型变化 | 最小维护量 |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| L0 | 重构、格式、无行为变化 | 不创建 ChangeSpec |
|
|
24
|
+
| L1 | 文案、单字段、局部规则 | 一份短 ChangeSpec |
|
|
25
|
+
| L2 | 跨资源、权限、状态变化 | 加正反验收、数据与回滚 |
|
|
26
|
+
| L3 | 身份、迁移、并发、外部副作用 | 加失败/幂等、资源边界和 ADR |
|
|
27
|
+
|
|
28
|
+
用户没有要求且变更是 L0 时,不要为了“流程完整”创建文档。小应用可以长期只维护 `app.md`。
|
|
29
|
+
|
|
30
|
+
## 标准操作
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pnpm openxiangda spec init
|
|
34
|
+
pnpm openxiangda spec add-capability CAP-BOOKING --title "预约管理" --resources bookings
|
|
35
|
+
pnpm openxiangda spec new booking-window --title "限制可预约时段" --risk L1 \
|
|
36
|
+
--capabilities CAP-BOOKING --resources bookings
|
|
37
|
+
pnpm openxiangda spec context booking-window --json
|
|
38
|
+
pnpm openxiangda spec check
|
|
39
|
+
pnpm openxiangda spec close booking-window --current-spec merged \
|
|
40
|
+
--summary "已通过真实角色验收"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`spec check` 是用户主动选择的严格检查;普通 `check/dev/deploy` 只给 advisory,不因 AppSpec
|
|
44
|
+
缺失或不完整而失败。
|
|
45
|
+
|
|
46
|
+
新 ChangeSpec 的 `currentSpec` 固定从 `pending` 开始。关闭前先把长期有效结果合入 `app.md` 或相关
|
|
47
|
+
CapabilitySpec,再由用户确认 `merged`;不改变长期规格时由用户确认 `not-applicable`。AI 可以列出
|
|
48
|
+
未合入差异,但不能自行选择这两个值。稳定 REQ/AC 未进入当前规格、L2/L3 必需章节为空或保留默认
|
|
49
|
+
占位内容时,`spec close` 不移动文件。
|
|
50
|
+
|
|
51
|
+
## 写作边界
|
|
52
|
+
|
|
53
|
+
- `app.md` 记录长期目标、角色、范围、术语和跨能力约束。
|
|
54
|
+
- `capabilities/CAP-*.md` 记录当前有效需求,使用稳定 `REQ-*` 和可证伪 `AC-*`。
|
|
55
|
+
- `changes/active/*.md` 只记录本次 delta、风险、影响范围与验收;关闭前把仍有效的结论合入能力规格,
|
|
56
|
+
并由用户确认 `currentSpec`。
|
|
57
|
+
- `decisions/ADR-*.md` 只用于架构显著决定,不为普通小改创建。
|
|
58
|
+
- 引用真实 2.0 resource/action code,不抄字段定义和权限矩阵的机器事实。
|
|
59
|
+
- AI 可以创建 `draft`、指出未确认问题和建议更新,不能自行把需求标记为 `confirmed`。
|
|
60
|
+
- 不因 AppSpec 与实现冲突就静默修改其中一方;明确指出冲突,由用户决定业务意图,技术事实以实时
|
|
61
|
+
编译合同为准。
|
|
62
|
+
|
|
63
|
+
## 可迁移程度
|
|
64
|
+
|
|
65
|
+
完整 AppSpec 能显著提高另一个新项目复现业务逻辑的概率,但最终文档本身不等于可执行应用。
|
|
66
|
+
需要接近原应用时,应同时提供 AppSpec、`openxiangda.config.ts`、必要自定义动作、测试和外部接口
|
|
67
|
+
合同;历史 ChangeSpec 不是必需输入。
|
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
# OpenXiangda 2.0 Backend
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Read [Architecture](architecture.md) and [Data and authorization](data-authz.md)
|
|
4
|
+
before adding a backend. Finish with [Testing](testing.md).
|
|
5
|
+
|
|
6
|
+
Keep normal record CRUD in the platform Data API. Use `apps/server` only for typed business actions that need server-side logic. For an interactive request, the platform gateway supplies the verified current user, complete application-role union and capabilities. Controllers bind operations and capabilities through `openxiangda/nest`; workers continue to use their explicit application identity.
|
|
7
|
+
|
|
8
|
+
Every interactive business action uses `@OpenXiangdaOperation(operation)`. The
|
|
9
|
+
guard checks `operation.requiredCapability` once at App API ingress. Inside that
|
|
10
|
+
declared action, inject `OpenXiangdaBusinessDataApiService` or use
|
|
11
|
+
`OpenXiangdaStandardOperations`: Native Data then runs as the trusted backend
|
|
12
|
+
for this exact application, environment, version and operation. Do not forward
|
|
13
|
+
the caller's resource, row or field permissions into that internal Data call,
|
|
14
|
+
and do not author an `authorizationJSON` permission mirror. The platform still
|
|
15
|
+
records the initiating user and action code in records, files, events and audit.
|
|
16
|
+
|
|
17
|
+
`OpenXiangdaDataApiService` deliberately retains ordinary current-user Data
|
|
18
|
+
authorization and automatically inherits the request Perspective for reads.
|
|
19
|
+
Its writes still authorize against the complete role union. Do not use it to
|
|
20
|
+
implement a declared business action. The
|
|
21
|
+
business facade also rejects routes without immutable `OpenXiangdaOperation`
|
|
22
|
+
metadata, so a controller cannot silently gain trusted Data access.
|
|
23
|
+
|
|
24
|
+
If a custom controller bypasses the standard Data API and reads Nest-owned SQL,
|
|
25
|
+
an external service or another datastore, inject `@CurrentPerspective()` and
|
|
26
|
+
apply the declared role-based read projection explicitly. Perspective is not a
|
|
27
|
+
credential and must never change mutation authorization. Prefer moving ordinary
|
|
28
|
+
reads back to `OpenXiangdaDataApiService`, where the platform owns the contract.
|
|
4
29
|
|
|
5
30
|
Do not duplicate resource persistence in controllers. Keep actions bounded and side-effect behavior explicit. Run `pnpm openxiangda dev` for the connected loop and `pnpm openxiangda check` before delivery.
|
|
6
31
|
|
|
@@ -16,15 +41,25 @@ Every constructor dependency in a `@Controller` or `@Injectable` class uses an
|
|
|
16
41
|
explicit token:
|
|
17
42
|
|
|
18
43
|
```ts
|
|
19
|
-
import { Controller, Inject } from '@nestjs/common';
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
|
|
44
|
+
import { Controller, Inject, Post } from '@nestjs/common';
|
|
45
|
+
import { appOperations } from '@app/contracts';
|
|
46
|
+
import {
|
|
47
|
+
OpenXiangdaBusinessDataApiService,
|
|
48
|
+
OpenXiangdaOperation,
|
|
49
|
+
} from 'openxiangda/nest';
|
|
50
|
+
|
|
51
|
+
@Controller()
|
|
23
52
|
export class VisitorReservationsController {
|
|
24
53
|
constructor(
|
|
25
|
-
@Inject(
|
|
26
|
-
private readonly
|
|
54
|
+
@Inject(OpenXiangdaBusinessDataApiService)
|
|
55
|
+
private readonly data: OpenXiangdaBusinessDataApiService,
|
|
27
56
|
) {}
|
|
57
|
+
|
|
58
|
+
@Post('/api/reservations/enroll')
|
|
59
|
+
@OpenXiangdaOperation(appOperations.reservationEnroll)
|
|
60
|
+
async enroll() {
|
|
61
|
+
return await this.data.create('visitor-reservations', { status: 'pending' });
|
|
62
|
+
}
|
|
28
63
|
}
|
|
29
64
|
```
|
|
30
65
|
|
|
@@ -33,14 +68,28 @@ Do not silence that diagnostic or replace the connected-development compiler.
|
|
|
33
68
|
|
|
34
69
|
Backend routes are private to the application unless their operation declaration contains an explicit `ai` block. Never infer AI exposure or risk from the HTTP method. A write action declares its touched resources and non-empty side effects, for example:
|
|
35
70
|
|
|
71
|
+
Build operation request and response schemas through
|
|
72
|
+
`resourceRecordSchema`, `schemaRef` and `composeAppOperationSchemas` from
|
|
73
|
+
`openxiangda/config`. These helpers project canonical field value protocols
|
|
74
|
+
from the same Resource declaration and prevent repeated user, department,
|
|
75
|
+
resource-reference or managed-file shapes. Do not import a physical toolchain
|
|
76
|
+
package or copy the JSON protocol by hand.
|
|
77
|
+
|
|
36
78
|
```ts
|
|
37
79
|
{
|
|
38
80
|
code: 'reservation.enroll',
|
|
39
81
|
method: 'POST',
|
|
40
82
|
path: '/api/reservations/enroll',
|
|
41
83
|
capability: 'app:visitor-app:reservation:enroll',
|
|
42
|
-
|
|
43
|
-
|
|
84
|
+
...composeAppOperationSchemas({
|
|
85
|
+
request: resourceRecordSchema(visitorReservations, {
|
|
86
|
+
fields: ['visitorName', 'visitDate', 'startTime'],
|
|
87
|
+
}),
|
|
88
|
+
response: schemaRef('ReservationRecord'),
|
|
89
|
+
definitions: {
|
|
90
|
+
ReservationRecord: resourceRecordSchema(visitorReservations),
|
|
91
|
+
},
|
|
92
|
+
}),
|
|
44
93
|
ai: {
|
|
45
94
|
name: '预约访客',
|
|
46
95
|
description: '校验预约规则并创建访客预约',
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# OpenXiangda 2.0 Commands
|
|
2
|
+
|
|
3
|
+
> Generated from `DEVKIT_COMMANDS`. Do not edit manually.
|
|
4
|
+
|
|
5
|
+
| Command | Risk | Purpose |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| `pnpm openxiangda create` | deploy | 创建、绑定并初始化应用 |
|
|
8
|
+
| `pnpm openxiangda dev` | write-local | 连接平台测试数据启动本地 Web 与 Nest |
|
|
9
|
+
| `pnpm openxiangda check` | write-local | 生成契约并执行检查、测试和构建 |
|
|
10
|
+
| `pnpm openxiangda accept` | deploy | 按计划准备可选的真实预发验收身份 |
|
|
11
|
+
| `pnpm openxiangda deploy` | deploy | 部署测试环境或显式复用测试版本部署生产 |
|
|
12
|
+
| `pnpm openxiangda status` | read | 查询最近或指定部署状态 |
|
|
13
|
+
| `pnpm openxiangda logs` | read | 查询最近或指定部署日志 |
|
|
14
|
+
| `pnpm openxiangda cancel` | deploy | 幂等取消尚未提交激活的部署 |
|
|
15
|
+
| `pnpm openxiangda retry` | deploy | 显式重试可恢复的失败部署 |
|
|
16
|
+
| `pnpm openxiangda start` | deploy | 从当前不可变版本启动应用环境 |
|
|
17
|
+
| `pnpm openxiangda stop` | deploy | 将应用环境缩容为零并保留数据 |
|
|
18
|
+
| `pnpm openxiangda rollback` | deploy | 回滚测试或生产环境 |
|
|
19
|
+
| `pnpm openxiangda login` | write-local | 通过平台浏览器授权登录 |
|
|
20
|
+
| `pnpm openxiangda skill` | write-local | 安装当前版本的 AI Skill |
|
|
21
|
+
| `pnpm openxiangda spec` | write-local | 维护可选的 AppSpec 需求与变更辅助 |
|
|
@@ -39,7 +39,7 @@ const visitorReservations = {
|
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
code: 'attachments', type: 'file', label: '附件',
|
|
42
|
-
file: {
|
|
42
|
+
file: { maxCount: 5, maxSizeMb: 20, accept: ['image/*', '.pdf'] },
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
code: 'internalNote', type: 'text.long', label: '内部备注',
|
|
@@ -56,14 +56,46 @@ Put it in `data: { resources: [visitorReservations] }`. Resource CRUD
|
|
|
56
56
|
capabilities are derived by `resourceCapabilityCodes`; grant the needed values
|
|
57
57
|
to roles. Directory-backed roles also require
|
|
58
58
|
`app:<app-code>:directory:read`. Explicit field `access` capability codes are
|
|
59
|
-
also granted only to the intended roles.
|
|
59
|
+
also granted only to the intended roles. They are owned and exported by the
|
|
60
|
+
generated field policy, so do not repeat them in `authz.capabilities`.
|
|
61
|
+
`authz.capabilities` contains only explicit `backend` or `ui` capabilities.
|
|
62
|
+
|
|
63
|
+
Declare optional work Perspectives once at the application root. A Perspective
|
|
64
|
+
references existing role codes; the compiler derives its readable capability
|
|
65
|
+
projection, so never hand-author `capabilityCodes` or duplicate row filters:
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
export default defineOpenXiangdaApp({
|
|
69
|
+
// ...identity, authz and data...
|
|
70
|
+
perspectives: [
|
|
71
|
+
{
|
|
72
|
+
code: 'reception-desk',
|
|
73
|
+
name: '接待人员视角',
|
|
74
|
+
roleCodes: ['reception_staff'],
|
|
75
|
+
default: true,
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
code: 'visitor-admin',
|
|
79
|
+
name: '访客管理员视角',
|
|
80
|
+
roleCodes: ['visitor_admin'],
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
});
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
The runtime offers only Perspectives whose `roleCodes` intersect the current
|
|
87
|
+
user's actual application-role union. Selecting one sends
|
|
88
|
+
`X-OpenXiangda-Perspective` on standard reads. Native Data intersects the
|
|
89
|
+
normal authorized role union with that Perspective before capability, field,
|
|
90
|
+
row-policy and RLS evaluation. Omit the header for the complete union. Never
|
|
91
|
+
use Perspective to guard writes, workflows or custom actions.
|
|
60
92
|
|
|
61
93
|
`required: true` owns both storage nullability and form validation. A field
|
|
62
94
|
without `access` inherits the resource read/create/update capability. Each
|
|
63
95
|
access array is all-of; `false` is explicit deny. The same arrays drive the
|
|
64
96
|
generated UI and platform field policies.
|
|
65
97
|
|
|
66
|
-
Field types are semantic, not PostgreSQL storage aliases. Use the catalog in the generated `AGENTS.md`: for example `text.short`, `number.integer`, `user.single`, `department.multiple`, `resource-ref.single`, `file`, `address` and `subtable`. The compiler alone chooses storage columns and constraints. Reference fields store
|
|
98
|
+
Field types are semantic, not PostgreSQL storage aliases. Use the catalog in the generated `AGENTS.md`: for example `text.short`, `number.integer`, `user.single`, `department.multiple`, `resource-ref.single`, `file`, `address` and `subtable`. The compiler alone chooses storage columns and constraints. Reference fields store JSON display values. For `resource-ref.*`, `resourceCode`, `value`, `label`, optional `description` and optional `snapshot` are convenient historical display data only: the target resource remains authoritative, the platform does not create a foreign key or refresh/check the stored JSON, and business actions that need current target state must query it by `resourceCode` plus `value`. A resource source `labelField` must point to `text.short` or `text.long`; a `serial-number` field can be listed in `searchFields`, `descriptionFields` or `snapshotFields`, but it is not a display label. File limits exist only under `file`; `maxCount` owns the single/multiple bound and `maxSizeMb` owns the per-file size bound. There is no `file.multiple` key.
|
|
67
99
|
|
|
68
100
|
Do not author raw schema or storage words as field types. `string`, `text`,
|
|
69
101
|
`integer`, `decimal`, `boolean`, `date`, `datetime`, `uuid`, `json` and `file`
|
|
@@ -80,7 +112,7 @@ currentUserDataPolicy({
|
|
|
80
112
|
code: 'reservation-host',
|
|
81
113
|
name: '接待人员仅查看本人预约',
|
|
82
114
|
resourceCode: 'visitor-reservations',
|
|
83
|
-
field: 'hostUserId
|
|
115
|
+
field: 'hostUserId',
|
|
84
116
|
roleCodes: ['reception_staff'],
|
|
85
117
|
unrestrictedRoleCodes: ['visitor_admin'],
|
|
86
118
|
})
|
|
@@ -88,6 +120,8 @@ currentUserDataPolicy({
|
|
|
88
120
|
|
|
89
121
|
Put that value in `authz.dataPolicies`, declare both roles, and set the
|
|
90
122
|
resource `dataPolicyCode` to the same code. Do not invent `operator`, `value`,
|
|
91
|
-
`current_user: true`, lowercase match modes,
|
|
123
|
+
`current_user: true`, lowercase match modes, a dotted value path, or
|
|
124
|
+
policy-level `roleCodes`. The compiler and platform know that `user.*` fields
|
|
125
|
+
compare their stable `value`; `field` remains the declared field root code.
|
|
92
126
|
|
|
93
127
|
Run `pnpm openxiangda check` after every declaration or permission change.
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
# OpenXiangda 2.0 Delivery
|
|
2
2
|
|
|
3
|
-
Run `pnpm openxiangda check`; it owns generation, static checks, tests
|
|
3
|
+
Run `pnpm openxiangda check --json`; it owns generation, static checks, tests
|
|
4
|
+
and production builds but deliberately does not seal an AppPackage. Its
|
|
5
|
+
`data.sealedArtifact` object and `.openxiangda/build/seal-status.json` make that
|
|
6
|
+
state explicit even when an older `app-package.json` remains on disk. Deploy to
|
|
7
|
+
test with the returned `openxiangda deploy` next command. Deploy owns the
|
|
8
|
+
official application Dockerfile and platform-provided repository target,
|
|
9
|
+
builds and pushes the Nest image, then writes a `sealed` status tied to the new
|
|
10
|
+
immutable package digest. Never ask the developer for an image tag, digest,
|
|
11
|
+
registry password, Docker configuration, or another public build command. If
|
|
12
|
+
Docker, Buildx, repository configuration, or registry login is missing,
|
|
13
|
+
preserve the stable machine error and retry with the same
|
|
14
|
+
`pnpm openxiangda deploy` command after fixing that prerequisite.
|
|
15
|
+
|
|
16
|
+
`pnpm openxiangda accept --plan <file>` is an optional manual preproduction
|
|
17
|
+
test helper. It prepares expiring real identities but does not deploy, seal,
|
|
18
|
+
promote or satisfy any release gate. Use it only when the requested acceptance
|
|
19
|
+
needs real role membership and browser login.
|
|
4
20
|
|
|
5
21
|
Use `pnpm openxiangda status` and `pnpm openxiangda logs` without an ID for the most recent run, or pass an explicit run ID.
|
|
6
22
|
|