openxiangda-cli 2.0.0-alpha.99 → 2.0.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 (124) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +4 -8
  3. package/bin/run.js +2 -12
  4. package/dist/base.d.ts +30 -6
  5. package/dist/base.d.ts.map +1 -1
  6. package/dist/base.js +119 -22
  7. package/dist/base.js.map +1 -1
  8. package/dist/commands/accept.d.ts +8 -3
  9. package/dist/commands/accept.d.ts.map +1 -1
  10. package/dist/commands/admin.d.ts +32 -0
  11. package/dist/commands/admin.d.ts.map +1 -0
  12. package/dist/commands/admin.js +27 -0
  13. package/dist/commands/admin.js.map +1 -0
  14. package/dist/commands/auth.d.ts +30 -0
  15. package/dist/commands/auth.d.ts.map +1 -0
  16. package/dist/commands/auth.js +13 -0
  17. package/dist/commands/auth.js.map +1 -0
  18. package/dist/commands/cancel.d.ts +30 -0
  19. package/dist/commands/cancel.d.ts.map +1 -0
  20. package/dist/commands/cancel.js +12 -0
  21. package/dist/commands/cancel.js.map +1 -0
  22. package/dist/commands/check.d.ts +12 -3
  23. package/dist/commands/check.d.ts.map +1 -1
  24. package/dist/commands/check.js +21 -4
  25. package/dist/commands/check.js.map +1 -1
  26. package/dist/commands/context.d.ts +27 -0
  27. package/dist/commands/context.d.ts.map +1 -0
  28. package/dist/commands/context.js +10 -0
  29. package/dist/commands/context.js.map +1 -0
  30. package/dist/commands/create.d.ts +20 -3
  31. package/dist/commands/create.d.ts.map +1 -1
  32. package/dist/commands/create.js +396 -22
  33. package/dist/commands/create.js.map +1 -1
  34. package/dist/commands/deploy.d.ts +13 -3
  35. package/dist/commands/deploy.d.ts.map +1 -1
  36. package/dist/commands/deploy.js +17 -16
  37. package/dist/commands/deploy.js.map +1 -1
  38. package/dist/commands/dev.d.ts +10 -3
  39. package/dist/commands/dev.d.ts.map +1 -1
  40. package/dist/commands/dev.js +7 -4
  41. package/dist/commands/dev.js.map +1 -1
  42. package/dist/commands/docs.d.ts +30 -0
  43. package/dist/commands/docs.d.ts.map +1 -0
  44. package/dist/commands/docs.js +20 -0
  45. package/dist/commands/docs.js.map +1 -0
  46. package/dist/commands/login.d.ts +8 -3
  47. package/dist/commands/login.d.ts.map +1 -1
  48. package/dist/commands/login.js +1 -1
  49. package/dist/commands/login.js.map +1 -1
  50. package/dist/commands/logs.d.ts +10 -3
  51. package/dist/commands/logs.d.ts.map +1 -1
  52. package/dist/commands/logs.js +7 -3
  53. package/dist/commands/logs.js.map +1 -1
  54. package/dist/commands/retry.d.ts +30 -0
  55. package/dist/commands/retry.d.ts.map +1 -0
  56. package/dist/commands/retry.js +12 -0
  57. package/dist/commands/retry.js.map +1 -0
  58. package/dist/commands/rollback.d.ts +11 -3
  59. package/dist/commands/rollback.d.ts.map +1 -1
  60. package/dist/commands/rollback.js +9 -3
  61. package/dist/commands/rollback.js.map +1 -1
  62. package/dist/commands/skill.d.ts +9 -3
  63. package/dist/commands/skill.d.ts.map +1 -1
  64. package/dist/commands/skill.js +9 -2
  65. package/dist/commands/skill.js.map +1 -1
  66. package/dist/commands/spec.d.ts +42 -0
  67. package/dist/commands/spec.d.ts.map +1 -0
  68. package/dist/commands/spec.js +123 -0
  69. package/dist/commands/spec.js.map +1 -0
  70. package/dist/commands/start.d.ts +28 -0
  71. package/dist/commands/start.d.ts.map +1 -0
  72. package/dist/commands/start.js +18 -0
  73. package/dist/commands/start.js.map +1 -0
  74. package/dist/commands/status.d.ts +9 -3
  75. package/dist/commands/status.d.ts.map +1 -1
  76. package/dist/commands/status.js +10 -3
  77. package/dist/commands/status.js.map +1 -1
  78. package/dist/commands/stop.d.ts +28 -0
  79. package/dist/commands/stop.d.ts.map +1 -0
  80. package/dist/commands/stop.js +18 -0
  81. package/dist/commands/stop.js.map +1 -0
  82. package/dist/create-workspace.d.ts +36 -0
  83. package/dist/create-workspace.d.ts.map +1 -1
  84. package/dist/create-workspace.js +366 -8
  85. package/dist/create-workspace.js.map +1 -1
  86. package/dist/studio-events.d.ts +9 -0
  87. package/dist/studio-events.d.ts.map +1 -0
  88. package/dist/studio-events.js +30 -0
  89. package/dist/studio-events.js.map +1 -0
  90. package/package.json +15 -6
  91. package/template/AGENTS.md +25 -21
  92. package/template/README.md +31 -12
  93. package/template/apps/web/e2e/README.md +7 -0
  94. package/template/apps/web/package.json +4 -2
  95. package/template/apps/web/playwright.config.ts +4 -3
  96. package/template/apps/web/src/document.css +5 -0
  97. package/template/apps/web/src/main.tsx +48 -3
  98. package/template/apps/web/src/user-end/tailwind.css +5 -0
  99. package/template/apps/web/test/loopback.test.ts +8 -2
  100. package/template/apps/web/test/standard-user-surfaces.typecheck.tsx +27 -0
  101. package/template/apps/web/vite.config.ts +5 -1
  102. package/template/appspec/app.md +56 -0
  103. package/template/openxiangda.config.ts +50 -25
  104. package/template/package.json +4 -4
  105. package/template/packages/contracts/package.json +1 -1
  106. package/template/packages/contracts/src/generated.ts +143 -2
  107. package/template/apps/server/Dockerfile +0 -20
  108. package/template/apps/server/package.json +0 -27
  109. package/template/apps/server/src/app.module.ts +0 -43
  110. package/template/apps/server/src/main.ts +0 -5
  111. package/template/apps/server/test/smoke.test.ts +0 -16
  112. package/template/apps/server/tsconfig.json +0 -9
  113. package/template/apps/web/data-api-live.e2e.html +0 -15
  114. package/template/apps/web/e2e/client-fixture.ts +0 -5
  115. package/template/apps/web/e2e/data-api-live-fixture.tsx +0 -146
  116. package/template/apps/web/e2e/data-api-live.spec.ts +0 -138
  117. package/template/apps/web/e2e/field-protocol-fixture.tsx +0 -347
  118. package/template/apps/web/e2e/field-protocol.spec.ts +0 -186
  119. package/template/apps/web/e2e/resources.spec.ts +0 -285
  120. package/template/apps/web/e2e/workflow.spec.ts +0 -329
  121. package/template/apps/web/field-protocol.e2e.html +0 -15
  122. package/template/apps/web/scripts/check.mjs +0 -43
  123. package/template/apps/web/test/contracts.test.ts +0 -99
  124. package/template/scripts/verify-template-budget.mjs +0 -49
@@ -1,27 +0,0 @@
1
- {
2
- "name": "@app/server",
3
- "version": "0.1.0",
4
- "private": true,
5
- "type": "module",
6
- "scripts": {
7
- "dev": "tsx watch src/main.ts",
8
- "check": "tsc -p tsconfig.json --noEmit",
9
- "test": "tsx --test test/*.test.ts",
10
- "build": "tsc -p tsconfig.json",
11
- "start": "node dist/main.js"
12
- },
13
- "dependencies": {
14
- "@app/contracts": "workspace:*",
15
- "@nestjs/common": "11.1.29",
16
- "@nestjs/core": "11.1.29",
17
- "@nestjs/platform-fastify": "11.1.29",
18
- "openxiangda": "2.0.0-alpha.11",
19
- "reflect-metadata": "0.2.2",
20
- "rxjs": "7.8.2"
21
- },
22
- "devDependencies": {
23
- "@types/node": "24.13.3",
24
- "tsx": "4.23.12",
25
- "typescript": "5.9.3"
26
- }
27
- }
@@ -1,43 +0,0 @@
1
- import { Module } from '@nestjs/common';
2
- import {
3
- eventHandlerManifest,
4
- eventSchemas,
5
- eventSubscriptionCodes,
6
- } from '@app/contracts';
7
- import {
8
- OpenXiangdaModule,
9
- eventSigningSecretsFromEnvironment,
10
- } from 'openxiangda/nest';
11
-
12
- @Module({
13
- imports: [
14
- OpenXiangdaModule.forRoot({
15
- appCode: process.env.OPENXIANGDA_APP_CODE || 'openxiangda-application',
16
- platformBaseUrl:
17
- process.env.OPENXIANGDA_PLATFORM_BASE_URL ||
18
- 'http://127.0.0.1:7001/service',
19
- environmentKey:
20
- process.env.OPENXIANGDA_ENVIRONMENT_KEY || 'preproduction',
21
- environmentId:
22
- process.env.OPENXIANGDA_ENVIRONMENT_ID || 'connected-development',
23
- appVersionId:
24
- process.env.OPENXIANGDA_APP_VERSION_ID || 'connected-development',
25
- deploymentRunId:
26
- process.env.OPENXIANGDA_DEPLOYMENT_RUN_ID || 'connected-development',
27
- environmentHeadRevision: Number(
28
- process.env.OPENXIANGDA_ENVIRONMENT_HEAD_REVISION || 1
29
- ),
30
- backendRevisionId:
31
- process.env.OPENXIANGDA_BACKEND_REVISION_ID || 'connected-development',
32
- version: process.env.OPENXIANGDA_APP_VERSION || '0.1.0-dev',
33
- connectedDevelopment:
34
- process.env.OPENXIANGDA_CONNECTED_DEV === 'true',
35
- eventHandlerManifest,
36
- eventSchemas,
37
- eventSigningSecrets: eventSigningSecretsFromEnvironment(
38
- eventSubscriptionCodes
39
- ),
40
- }),
41
- ],
42
- })
43
- export class AppModule {}
@@ -1,5 +0,0 @@
1
- import 'reflect-metadata';
2
- import { bootstrapOpenXiangdaApplication } from 'openxiangda/nest';
3
- import { AppModule } from './app.module.js';
4
-
5
- await bootstrapOpenXiangdaApplication(AppModule);
@@ -1,16 +0,0 @@
1
- import assert from 'node:assert/strict';
2
- import { readFileSync } from 'node:fs';
3
- import test from 'node:test';
4
-
5
- test('the clean server template only owns platform bootstrap', () => {
6
- const source = readFileSync(new URL('../src/app.module.ts', import.meta.url), 'utf8');
7
- const main = readFileSync(new URL('../src/main.ts', import.meta.url), 'utf8');
8
- assert.match(source, /OpenXiangdaModule\.forRoot/);
9
- assert.match(source, /eventHandlerManifest/);
10
- assert.match(source, /eventSigningSecretsFromEnvironment/);
11
- assert.match(main, /bootstrapOpenXiangdaApplication\(AppModule\)/);
12
- assert.doesNotMatch(main, /NestFactory|FastifyAdapter/);
13
- const legacyMarkers = ['oauth' + 'Client', 'Workflow', 'instrument' + '-context'];
14
- assert.doesNotMatch(source, new RegExp(legacyMarkers.join('|')));
15
- assert.doesNotMatch(source, /createData|updateData|deleteData|queryData/);
16
- });
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src",
6
- "sourceMap": true
7
- },
8
- "include": ["src/**/*.ts"]
9
- }
@@ -1,15 +0,0 @@
1
- <!doctype html>
2
- <html lang="zh-CN">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <meta name="openxiangda-runtime-base" content="/" />
7
- <meta name="openxiangda-app-code" content="native-projection-app" />
8
- <meta name="openxiangda-environment" content="production" />
9
- <title>OpenXiangda Standard Data API Live Acceptance</title>
10
- </head>
11
- <body>
12
- <div id="root"></div>
13
- <script type="module" src="/e2e/data-api-live-fixture.tsx"></script>
14
- </body>
15
- </html>
@@ -1,5 +0,0 @@
1
- export {
2
- requestApplicationApi,
3
- searchDirectory,
4
- searchResource,
5
- } from 'openxiangda/core';
@@ -1,146 +0,0 @@
1
- import { Refine } from '@refinedev/core';
2
- import { App as AntdApp } from 'antd';
3
- import React from 'react';
4
- import ReactDOM from 'react-dom/client';
5
- import { MemoryRouter, Route, Routes } from 'react-router-dom';
6
- import {
7
- AppearanceProvider,
8
- createApplicationProvider,
9
- GeneratedResourcePage,
10
- OpenXiangdaResourceDefinitionsProvider,
11
- RuntimeBoundary,
12
- type GeneratedResourceDefinition,
13
- } from 'openxiangda/react';
14
- import 'openxiangda/react/styles.css';
15
-
16
- const code = 'field-records';
17
- const capabilityBase = `app:native-projection-app:data:${code}`;
18
- const capabilities = {
19
- read: `${capabilityBase}:read`,
20
- create: `${capabilityBase}:create`,
21
- update: `${capabilityBase}:update`,
22
- delete: `${capabilityBase}:delete`,
23
- };
24
-
25
- function fieldCapabilities() {
26
- return {
27
- readCapabilities: [capabilities.read],
28
- createCapabilities: [capabilities.create],
29
- updateCapabilities: [capabilities.update],
30
- };
31
- }
32
-
33
- export const liveDefinition: GeneratedResourceDefinition = {
34
- code,
35
- name: '字段协议记录',
36
- capabilities,
37
- surface: {
38
- generated: true,
39
- fields: {
40
- text_short: {
41
- label: '标题',
42
- type: 'text.short',
43
- widget: 'text',
44
- requiredHint: true,
45
- maxLength: 120,
46
- list: true,
47
- searchable: true,
48
- sortable: true,
49
- ...fieldCapabilities(),
50
- },
51
- option_single: {
52
- label: '单选快照',
53
- type: 'option.single',
54
- widget: 'radio',
55
- options: [
56
- { label: 'Open', value: 'open' },
57
- { label: 'Closed', value: 'closed' },
58
- ],
59
- list: true,
60
- ...fieldCapabilities(),
61
- },
62
- option_multiple: {
63
- label: '多选快照',
64
- type: 'option.multiple',
65
- widget: 'checkbox',
66
- options: [
67
- { label: 'Open', value: 'open' },
68
- { label: 'Urgent', value: 'urgent' },
69
- ],
70
- list: true,
71
- ...fieldCapabilities(),
72
- },
73
- location_value: {
74
- label: '精确定位',
75
- type: 'location',
76
- widget: 'location',
77
- list: true,
78
- ...fieldCapabilities(),
79
- },
80
- },
81
- list: {
82
- defaultPageSize: 20,
83
- searchableFields: ['text_short'],
84
- filterFields: ['option_single'],
85
- defaultSort: { field: 'text_short', order: 'asc' },
86
- },
87
- form: { layout: 'sections' },
88
- detail: { layout: 'sections' },
89
- mobile: { enabled: true },
90
- },
91
- };
92
-
93
- const definitions = { [code]: liveDefinition };
94
- const provider = createApplicationProvider(definitions);
95
- const initialPath =
96
- new URLSearchParams(window.location.search).get('initial') || `/${code}`;
97
-
98
- function resourcePage(mode: 'list' | 'create' | 'edit' | 'detail') {
99
- return (
100
- <GeneratedResourcePage
101
- definition={liveDefinition}
102
- mode={mode}
103
- resourceCode={code}
104
- />
105
- );
106
- }
107
-
108
- ReactDOM.createRoot(document.getElementById('root')!).render(
109
- <React.StrictMode>
110
- <OpenXiangdaResourceDefinitionsProvider definitions={definitions}>
111
- <AppearanceProvider>
112
- <AntdApp>
113
- <RuntimeBoundary>
114
- <MemoryRouter initialEntries={[initialPath]}>
115
- <Refine
116
- dataProvider={provider}
117
- resources={[
118
- {
119
- name: code,
120
- list: `/${code}`,
121
- create: `/${code}/new`,
122
- edit: `/${code}/:id/edit`,
123
- show: `/${code}/:id`,
124
- },
125
- ]}
126
- >
127
- <Routes>
128
- <Route path={`/${code}`} element={resourcePage('list')} />
129
- <Route path={`/${code}/new`} element={resourcePage('create')} />
130
- <Route
131
- path={`/${code}/:id`}
132
- element={resourcePage('detail')}
133
- />
134
- <Route
135
- path={`/${code}/:id/edit`}
136
- element={resourcePage('edit')}
137
- />
138
- </Routes>
139
- </Refine>
140
- </MemoryRouter>
141
- </RuntimeBoundary>
142
- </AntdApp>
143
- </AppearanceProvider>
144
- </OpenXiangdaResourceDefinitionsProvider>
145
- </React.StrictMode>
146
- );
@@ -1,138 +0,0 @@
1
- import { expect, test } from '@playwright/test';
2
-
3
- const liveEnabled = process.env.OPENXIANGDA_LIVE_DATA_API === '1';
4
- const title = 'UI live field record';
5
-
6
- test.describe('@live-data-api standard resource UI', () => {
7
- test.setTimeout(90_000);
8
- test.skip(
9
- !liveEnabled,
10
- 'Requires the disposable PostgreSQL Native Data API acceptance bridge.'
11
- );
12
-
13
- test.beforeEach(async ({ context }) => {
14
- await context.addCookies([
15
- {
16
- name: 'openxiangda-field-ui-role',
17
- value: 'super',
18
- domain: '127.0.0.1',
19
- path: '/',
20
- },
21
- ]);
22
- });
23
-
24
- test('runs create, list, query, get, update, audit and delete through the standard page', async ({
25
- context,
26
- page,
27
- }) => {
28
- await context.grantPermissions(['geolocation']);
29
- await context.setGeolocation({
30
- longitude: 120.123456,
31
- latitude: 30.234567,
32
- accuracy: 4,
33
- });
34
- await page.goto('/data-api-live.e2e.html?initial=/field-records');
35
- await expect(page.locator('.oxa-list-surface')).toBeVisible();
36
-
37
- await page.getByRole('button', { name: '新增字段协议记录' }).click();
38
- await expect(page.getByRole('heading', { name: '新增字段协议记录' })).toBeVisible();
39
- await page.getByLabel('标题').fill(title);
40
- await page.getByRole('radio', { name: 'Open' }).check();
41
- const openCheckbox = page.getByRole('checkbox', { name: 'Open' });
42
- const urgentCheckbox = page.getByRole('checkbox', { name: 'Urgent' });
43
- await openCheckbox.click();
44
- await urgentCheckbox.click();
45
- await expect(openCheckbox).toBeChecked();
46
- await expect(urgentCheckbox).toBeChecked();
47
- await page.getByRole('button', { name: '浏览器定位' }).click();
48
- await expect(page.getByText('120.123456, 30.234567')).toBeVisible();
49
- await page.getByRole('button', { name: /^保\s*存$/ }).click();
50
-
51
- await expect(page.locator('.oxa-list-surface')).toBeVisible();
52
- await page.locator('.oxa-search-panel .ant-select').first().click();
53
- await page.getByText('标题', { exact: true }).last().click();
54
- await page.getByPlaceholder('关键词').fill(title);
55
- await page.getByRole('button', { name: /查询/ }).click();
56
- const createdRow = page.getByRole('row').filter({ hasText: title });
57
- await expect(createdRow).toHaveCount(1);
58
- await expect(createdRow).toContainText('Open');
59
- await expect(createdRow).toContainText('Urgent');
60
- await expect(createdRow).toContainText('120.123456, 30.234567');
61
-
62
- await createdRow.getByRole('button', { name: '查看' }).click();
63
- await expect(page.getByRole('heading', { name: '字段协议记录详情' })).toBeVisible();
64
- await expect(page.getByText(title, { exact: true })).toBeVisible();
65
- await expect(page.getByText(/浏览器定位/)).toBeVisible();
66
- await page.locator('.oxa-audit-collapse .ant-collapse-header').click();
67
- await expect(page.getByText('创建', { exact: true })).toBeVisible();
68
- await page.screenshot({
69
- fullPage: true,
70
- path: 'test-results/data-api-live-detail.png',
71
- });
72
-
73
- await page.getByRole('button', { name: /编辑/ }).click();
74
- await page.getByLabel('标题').fill(`${title} updated`);
75
- await page.getByRole('radio', { name: 'Closed' }).check();
76
- await page.getByRole('checkbox', { name: 'Open' }).click();
77
- await expect(page.getByRole('checkbox', { name: 'Open' })).not.toBeChecked();
78
- await page.getByRole('button', { name: /^保存修改$/ }).click();
79
- await expect(page.getByText(`${title} updated`, { exact: true })).toBeVisible();
80
- await expect(page.getByText('Closed', { exact: true })).toBeVisible();
81
-
82
- await page.getByRole('button', { name: '返回列表' }).click();
83
- const updatedRow = page
84
- .getByRole('row')
85
- .filter({ hasText: `${title} updated` });
86
- await expect(updatedRow).toHaveCount(1);
87
- await updatedRow.getByRole('button', { name: '删除' }).click();
88
- await page.getByRole('button', { name: /^确\s*定$/ }).click();
89
- await expect(updatedRow).toHaveCount(0);
90
- });
91
-
92
- test('applies PostgreSQL row scope to the standard list and query UI', async ({
93
- context,
94
- page,
95
- }) => {
96
- await context.clearCookies();
97
- await context.addCookies([
98
- {
99
- name: 'openxiangda-field-ui-role',
100
- value: 'restricted',
101
- domain: '127.0.0.1',
102
- path: '/',
103
- },
104
- ]);
105
- await page.goto('/data-api-live.e2e.html?initial=/field-records');
106
- await expect(page.locator('.oxa-list-surface')).toBeVisible();
107
- await page.locator('.oxa-search-panel .ant-select').first().click();
108
- await page.getByText('标题', { exact: true }).last().click();
109
- await page.getByPlaceholder('关键词').fill('UI RLS');
110
- await page.getByRole('button', { name: /查询/ }).click();
111
- await expect(page.getByText('UI RLS visible', { exact: true })).toBeVisible();
112
- await expect(page.getByText('UI RLS hidden', { exact: true })).toHaveCount(0);
113
- await page.screenshot({
114
- fullPage: true,
115
- path: 'test-results/data-api-live-rls.png',
116
- });
117
- });
118
-
119
- test('fails closed in the standard page when the role has no read capability', async ({
120
- context,
121
- page,
122
- }) => {
123
- await context.clearCookies();
124
- await context.addCookies([
125
- {
126
- name: 'openxiangda-field-ui-role',
127
- value: 'denied',
128
- domain: '127.0.0.1',
129
- path: '/',
130
- },
131
- ]);
132
- await page.goto('/data-api-live.e2e.html?initial=/field-records');
133
- await expect(
134
- page.getByText('当前平台用户无字段协议记录页面权限', { exact: true })
135
- ).toBeVisible();
136
- await expect(page.locator('.oxa-list-surface')).toHaveCount(0);
137
- });
138
- });