openxiangda-cli 2.0.0-alpha.131 → 2.0.0-alpha.134
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 +5 -5
- package/template/AGENTS.md +1 -0
- package/template/apps/server/package.json +1 -1
- package/template/apps/web/e2e/resource-experience-fixture.tsx +9 -0
- package/template/apps/web/e2e/workflow-experience-fixture.tsx +125 -4
- package/template/apps/web/e2e/workflow.spec.ts +115 -0
- package/template/apps/web/package.json +1 -1
- package/template/apps/web/src/main.tsx +4 -0
- package/template/apps/web/test/contracts.test.ts +1 -0
- package/template/package.json +1 -1
- package/template/packages/contracts/src/generated.ts +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "openxiangda-cli",
|
|
3
|
-
"version": "2.0.0-alpha.
|
|
3
|
+
"version": "2.0.0-alpha.134",
|
|
4
4
|
"description": "Thin application-level CLI for OpenXiangda 2.0.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -21,10 +21,10 @@
|
|
|
21
21
|
],
|
|
22
22
|
"dependencies": {
|
|
23
23
|
"@oclif/core": "4.13.3",
|
|
24
|
-
"openxiangda-contracts": "2.0.0-alpha.
|
|
25
|
-
"openxiangda-devkit-core": "2.0.0-alpha.
|
|
26
|
-
"openxiangda-mcp": "2.0.0-alpha.
|
|
27
|
-
"openxiangda-skill-kit": "2.0.0-alpha.
|
|
24
|
+
"openxiangda-contracts": "2.0.0-alpha.67",
|
|
25
|
+
"openxiangda-devkit-core": "2.0.0-alpha.87",
|
|
26
|
+
"openxiangda-mcp": "2.0.0-alpha.87",
|
|
27
|
+
"openxiangda-skill-kit": "2.0.0-alpha.108"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"tsx": "4.23.12",
|
package/template/AGENTS.md
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
- Use Vite, React Router, Refine Core and Ant Design. Do not add Umi, ProComponents or another admin shell.
|
|
6
6
|
- Bind every generated `appRoutes` entry to its local page with `defineApplicationContributions`; desktop `admin` routes stay inside the platform Shell, while `user` routes render without an admin Shell for independent mobile/user experiences. Generated resource CRUD routes are compiler-owned under `/admin/resources/<resourceCode>...` and `/m/admin/resources/<resourceCode>...`; never recreate root resource paths, aliases or redirects. Explicit routes that have the same canonical shape as another explicit or generated route fail compilation, even when dynamic parameter names differ. Use only the typed `toolbar`, `row` and `detail` resource slots for generated resource actions. Declare the complete editable admin menu with `defineAdminNavigation` and its page/group helpers; the Shell renders only generated `adminNavigation` references and permissions only filter them. Do not create another router, menu store, layout, identity provider, permission store or copied CRUD page; route/action access uses capability or `allOf`/`anyOf`, while Data/App API and Workflow authorization remain server-owned.
|
|
7
7
|
- Application login is optional `frontend.authentication`: existing platform users only, registration rejected, exact desktop `/login` and mobile `/m/login`. Bind generated `authenticationSurfaces` to separate PC/mobile renderers through `defineApplicationContributions`; renderers own only brand visuals and call `ApplicationLoginSurfaceProps`. The platform alone owns passwords, providers, OAuth state/callbacks, secure cookies, current identity and authorization. Never put login in protected `appRoutes`, call a v1 auth route, store tokens, create users/roles, or add another Router/identity provider. Keep QA in generated `platformAuthManifest`, outside the protected route denominator.
|
|
8
|
+
- External users without platform accounts use only an exact static `surface: 'user'` route declared through `frontend.publicAccess`. Declare the one resource, bounded field sets, required operations, draft limits and named duplicate validations; consume only generated `anonymousPublicAccess` and `createAnonymousPublicClient`. `own.list`/`own.read` mean records submitted by the same platform-issued HttpOnly browser credential, not a verified natural person, and another browser or cleared cookie intentionally loses access. Never create a guest role/user, call the general Native Data API, expose an anonymous upload path, store identity locally or derive ownership from IP, user-agent or fingerprint.
|
|
8
9
|
- Declare each resource once in `openxiangda.config.ts` with only `code`, `name`, `fields` and optional `mutationOwner`, generated/list/layout/data-policy settings. Each field owns type, label, required state, Surface flags, reference/file metadata and access. Resource codes are lower kebab-case. Use `native` for direct Data API mutations, `action`, `readonly` or `workflow` for non-Native ownership; never grant or generate Native mutation for a non-Native owner.
|
|
9
10
|
- Never write resource-level `schemaVersion`, `appCode`, `schema`, `surface`, `capabilities`, `fieldPolicies` or `platform/data` modules. The compiler derives the strict DataResource, CRUD capabilities, Surface and AI Schema. The application manifest still starts with its one top-level `schemaVersion: 3`.
|
|
10
11
|
- Ordinary list/get/create/update/delete, filters, export and batch operations use the platform Native Data API. Do not create Function CRUD or NestJS wrappers.
|
|
@@ -95,6 +95,14 @@ const fields: DataResourceSurface['fields'] = {
|
|
|
95
95
|
}),
|
|
96
96
|
};
|
|
97
97
|
|
|
98
|
+
const routeManifest = {
|
|
99
|
+
schemaVersion: 'openxiangda.application-route-manifest/v2',
|
|
100
|
+
appCode: 'openxiangda-application',
|
|
101
|
+
routes: [],
|
|
102
|
+
digest:
|
|
103
|
+
'88831760f6e672a77babbf039b35a6febca7852092f1579c2721c99596a265c4',
|
|
104
|
+
} as const;
|
|
105
|
+
|
|
98
106
|
const surface: DataResourceSurface = {
|
|
99
107
|
mutationOwner: 'native',
|
|
100
108
|
generated: {
|
|
@@ -426,6 +434,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
426
434
|
]}
|
|
427
435
|
contributions={applicationContributions}
|
|
428
436
|
resourceDefinitions={resourceDefinitions}
|
|
437
|
+
routeManifest={routeManifest}
|
|
429
438
|
/>
|
|
430
439
|
</React.StrictMode>
|
|
431
440
|
);
|
|
@@ -128,6 +128,105 @@ const adminPages = [
|
|
|
128
128
|
},
|
|
129
129
|
] as const satisfies AdminPagesInput;
|
|
130
130
|
|
|
131
|
+
const routeManifest = {
|
|
132
|
+
schemaVersion: 'openxiangda.application-route-manifest/v2',
|
|
133
|
+
appCode,
|
|
134
|
+
routes: [
|
|
135
|
+
{
|
|
136
|
+
code: 'application:todo-center',
|
|
137
|
+
kind: 'application-todo-center',
|
|
138
|
+
desktop: {
|
|
139
|
+
routeCode: 'application.todo-center.desktop',
|
|
140
|
+
path: '/admin/todos',
|
|
141
|
+
surface: 'admin',
|
|
142
|
+
pathParams: [],
|
|
143
|
+
requiresAuthentication: true,
|
|
144
|
+
},
|
|
145
|
+
mobile: {
|
|
146
|
+
routeCode: 'application.todo-center.mobile',
|
|
147
|
+
path: '/m/todos',
|
|
148
|
+
surface: 'user',
|
|
149
|
+
pathParams: [],
|
|
150
|
+
requiresAuthentication: true,
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
code: 'workflow:work-center',
|
|
155
|
+
kind: 'workflow-work-center',
|
|
156
|
+
desktop: {
|
|
157
|
+
routeCode: 'workflow.work.center.desktop',
|
|
158
|
+
path: '/admin/work-center',
|
|
159
|
+
surface: 'admin',
|
|
160
|
+
pathParams: [],
|
|
161
|
+
requiresAuthentication: true,
|
|
162
|
+
},
|
|
163
|
+
mobile: {
|
|
164
|
+
routeCode: 'workflow.work.center.mobile',
|
|
165
|
+
path: '/m/work-center',
|
|
166
|
+
surface: 'user',
|
|
167
|
+
pathParams: [],
|
|
168
|
+
requiresAuthentication: true,
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
code: 'workflow:task',
|
|
173
|
+
kind: 'workflow-task',
|
|
174
|
+
desktop: {
|
|
175
|
+
routeCode: 'workflow.task.desktop',
|
|
176
|
+
path: '/admin/tasks/:taskId',
|
|
177
|
+
surface: 'admin',
|
|
178
|
+
pathParams: ['taskId'],
|
|
179
|
+
requiresAuthentication: true,
|
|
180
|
+
},
|
|
181
|
+
mobile: {
|
|
182
|
+
routeCode: 'workflow.task.mobile',
|
|
183
|
+
path: '/m/tasks/:taskId',
|
|
184
|
+
surface: 'user',
|
|
185
|
+
pathParams: ['taskId'],
|
|
186
|
+
requiresAuthentication: true,
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
code: 'workflow:instance',
|
|
191
|
+
kind: 'workflow-instance',
|
|
192
|
+
desktop: {
|
|
193
|
+
routeCode: 'workflow.instance.desktop',
|
|
194
|
+
path: '/admin/workflows/:instanceId',
|
|
195
|
+
surface: 'admin',
|
|
196
|
+
pathParams: ['instanceId'],
|
|
197
|
+
requiresAuthentication: true,
|
|
198
|
+
},
|
|
199
|
+
mobile: {
|
|
200
|
+
routeCode: 'workflow.instance.mobile',
|
|
201
|
+
path: '/m/workflows/:instanceId',
|
|
202
|
+
surface: 'user',
|
|
203
|
+
pathParams: ['instanceId'],
|
|
204
|
+
requiresAuthentication: true,
|
|
205
|
+
},
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
code: 'workflow:purchase-approval:launch',
|
|
209
|
+
kind: 'workflow-launch',
|
|
210
|
+
workflowCode: 'purchase-approval',
|
|
211
|
+
desktop: {
|
|
212
|
+
routeCode: 'workflow.purchase-approval.launch.desktop',
|
|
213
|
+
path: '/admin/workflows/purchase-approval/new',
|
|
214
|
+
surface: 'admin',
|
|
215
|
+
pathParams: [],
|
|
216
|
+
requiresAuthentication: true,
|
|
217
|
+
},
|
|
218
|
+
mobile: {
|
|
219
|
+
routeCode: 'workflow.purchase-approval.launch.mobile',
|
|
220
|
+
path: '/m/workflows/:workflowCode/start',
|
|
221
|
+
surface: 'user',
|
|
222
|
+
pathParams: ['workflowCode'],
|
|
223
|
+
requiresAuthentication: true,
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
digest: '34cc08a02cd187a07d9e2d2f99c1080b5b86f3a4512f9e0f43ff4cb05b7195fa',
|
|
228
|
+
} as const;
|
|
229
|
+
|
|
131
230
|
const adminNavigation = [
|
|
132
231
|
{
|
|
133
232
|
code: 'workflow-center',
|
|
@@ -146,11 +245,32 @@ const adminNavigation = [
|
|
|
146
245
|
},
|
|
147
246
|
] as const satisfies AdminNavigationInput;
|
|
148
247
|
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
248
|
+
const fixtureParams = new URLSearchParams(window.location.search);
|
|
249
|
+
const initialPath = fixtureParams.get('initial') || '/admin/work-center';
|
|
250
|
+
const runtimeBase = fixtureParams.get('base')?.trim();
|
|
251
|
+
if (runtimeBase) {
|
|
252
|
+
for (const [name, content] of [
|
|
253
|
+
['openxiangda-runtime-base', runtimeBase],
|
|
254
|
+
['openxiangda-app-code', appCode],
|
|
255
|
+
['openxiangda-environment', 'preproduction'],
|
|
256
|
+
] as const) {
|
|
257
|
+
const meta =
|
|
258
|
+
document.querySelector<HTMLMetaElement>(`meta[name="${name}"]`) ||
|
|
259
|
+
document.createElement('meta');
|
|
260
|
+
meta.name = name;
|
|
261
|
+
meta.content = content;
|
|
262
|
+
if (!meta.parentElement) document.head.appendChild(meta);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
152
265
|
if (location.pathname.endsWith('/workflow-experience.e2e.html')) {
|
|
153
|
-
|
|
266
|
+
const stateToken = fixtureParams.get('state');
|
|
267
|
+
history.replaceState(
|
|
268
|
+
stateToken
|
|
269
|
+
? { usr: { routeNegotiationState: stateToken }, key: 'fixture-state' }
|
|
270
|
+
: {},
|
|
271
|
+
'',
|
|
272
|
+
initialPath,
|
|
273
|
+
);
|
|
154
274
|
}
|
|
155
275
|
|
|
156
276
|
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
@@ -160,6 +280,7 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
160
280
|
appName="流程体验验收"
|
|
161
281
|
adminNavigation={adminNavigation}
|
|
162
282
|
adminPages={adminPages}
|
|
283
|
+
routeManifest={routeManifest}
|
|
163
284
|
contributions={applicationContributions}
|
|
164
285
|
resourceDefinitions={resourceDefinitions}
|
|
165
286
|
workflows={workflowDefinitions}
|
|
@@ -22,6 +22,16 @@ function detailNavigation(custom = false) {
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function workflowFixtureUrl(
|
|
26
|
+
initialPath: string,
|
|
27
|
+
options: { base?: string; state?: string } = {},
|
|
28
|
+
) {
|
|
29
|
+
const params = new URLSearchParams({ initial: initialPath });
|
|
30
|
+
if (options.base) params.set('base', options.base);
|
|
31
|
+
if (options.state) params.set('state', options.state);
|
|
32
|
+
return `/workflow-experience.e2e.html?${params.toString()}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
function task(completed = false, customDetail = false) {
|
|
26
36
|
return {
|
|
27
37
|
schemaVersion: 'openxiangda.workflow-task/v2',
|
|
@@ -673,3 +683,108 @@ test('shows an explicit authorization error instead of an empty work center', as
|
|
|
673
683
|
});
|
|
674
684
|
await expect(page.getByRole('link', { name: '采购申请审批' })).toHaveCount(0);
|
|
675
685
|
});
|
|
686
|
+
|
|
687
|
+
test('negotiates direct standard routes after BrowserRouter listener setup', async ({
|
|
688
|
+
page,
|
|
689
|
+
}) => {
|
|
690
|
+
await mockWorkflow(page);
|
|
691
|
+
await page.setViewportSize({ width: 360, height: 844 });
|
|
692
|
+
await page.goto(
|
|
693
|
+
workflowFixtureUrl('/admin/todos?view=pending#unread', {
|
|
694
|
+
state: 'deep-link',
|
|
695
|
+
}),
|
|
696
|
+
);
|
|
697
|
+
|
|
698
|
+
// The initial desktop URL is replaced by the mobile pair and the rendered
|
|
699
|
+
// surface follows the Router update. The fixture is StrictMode-mounted.
|
|
700
|
+
await expect(page.locator('.oxa-todo-center-mobile')).toBeVisible();
|
|
701
|
+
await expect(page.locator('.oxa-todo-center-desktop')).toHaveCount(0);
|
|
702
|
+
await expect(page).toHaveURL(/\/m\/todos\?view=pending#unread$/);
|
|
703
|
+
const historyLength = await page.evaluate(() => window.history.length);
|
|
704
|
+
const negotiatedUrl = page.url();
|
|
705
|
+
await expect
|
|
706
|
+
.poll(() => page.url(), { timeout: 1_000 })
|
|
707
|
+
.toBe(negotiatedUrl);
|
|
708
|
+
expect(await page.evaluate(() => window.history.state?.usr)).toEqual({
|
|
709
|
+
routeNegotiationState: 'deep-link',
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
// 768px remains mobile; crossing to 769px switches the same manifest pair
|
|
713
|
+
// back to desktop without adding a browser-history entry.
|
|
714
|
+
await page.setViewportSize({ width: 768, height: 844 });
|
|
715
|
+
await expect(page.locator('.oxa-todo-center-mobile')).toBeVisible();
|
|
716
|
+
await page.setViewportSize({ width: 769, height: 844 });
|
|
717
|
+
await expect(page.locator('.oxa-todo-center-desktop')).toBeVisible();
|
|
718
|
+
await expect(page).toHaveURL(/\/admin\/todos\?view=pending#unread$/);
|
|
719
|
+
expect(await page.evaluate(() => window.history.length)).toBe(historyLength);
|
|
720
|
+
expect(await page.evaluate(() => window.history.state?.usr)).toEqual({
|
|
721
|
+
routeNegotiationState: 'deep-link',
|
|
722
|
+
});
|
|
723
|
+
await page.goBack();
|
|
724
|
+
await expect(page).not.toHaveURL(/\/admin\/todos\?view=pending#unread$/);
|
|
725
|
+
|
|
726
|
+
// Direct task and instance URLs carry their dynamic parameter and deep-link
|
|
727
|
+
// context to the independent mobile renderer at the narrow width.
|
|
728
|
+
await page.setViewportSize({ width: 360, height: 844 });
|
|
729
|
+
await page.goto(
|
|
730
|
+
workflowFixtureUrl(`/admin/tasks/${taskId}?from=todo#approval`),
|
|
731
|
+
);
|
|
732
|
+
await expect(page.locator('.oxa-workflow-detail-mobile')).toBeVisible();
|
|
733
|
+
await expect(page).toHaveURL(
|
|
734
|
+
new RegExp(`/m/tasks/${taskId}\\?from=todo#approval$`),
|
|
735
|
+
);
|
|
736
|
+
|
|
737
|
+
await page.goto(
|
|
738
|
+
workflowFixtureUrl(`/admin/workflows/${instanceId}?from=todo#timeline`),
|
|
739
|
+
);
|
|
740
|
+
await expect(page.locator('.oxa-workflow-detail-mobile')).toBeVisible();
|
|
741
|
+
await expect(page).toHaveURL(
|
|
742
|
+
new RegExp(`/m/workflows/${instanceId}\\?from=todo#timeline$`),
|
|
743
|
+
);
|
|
744
|
+
});
|
|
745
|
+
|
|
746
|
+
test('negotiates launch pairs in both directions and preserves the mount basename', async ({
|
|
747
|
+
page,
|
|
748
|
+
}) => {
|
|
749
|
+
await mockWorkflow(page);
|
|
750
|
+
const base = '/runtime/route-negotiation';
|
|
751
|
+
await page.setViewportSize({ width: 360, height: 844 });
|
|
752
|
+
await page.goto(
|
|
753
|
+
workflowFixtureUrl(
|
|
754
|
+
`${base}/admin/workflows/purchase-approval/new?source=todo#launch`,
|
|
755
|
+
{ base },
|
|
756
|
+
),
|
|
757
|
+
);
|
|
758
|
+
await expect(page.locator('.oxa-workflow-submission-mobile')).toBeVisible();
|
|
759
|
+
await expect(page).toHaveURL(
|
|
760
|
+
new RegExp(
|
|
761
|
+
`${base}/m/workflows/purchase-approval/start\\?source=todo#launch$`,
|
|
762
|
+
),
|
|
763
|
+
);
|
|
764
|
+
|
|
765
|
+
await page.setViewportSize({ width: 1_440, height: 900 });
|
|
766
|
+
await expect(page.locator('.oxa-workflow-submission-desktop')).toBeVisible();
|
|
767
|
+
await expect(page).toHaveURL(
|
|
768
|
+
new RegExp(
|
|
769
|
+
`${base}/admin/workflows/purchase-approval/new\\?source=todo#launch$`,
|
|
770
|
+
),
|
|
771
|
+
);
|
|
772
|
+
});
|
|
773
|
+
|
|
774
|
+
test('does not negotiate non-standard application contribution routes', async ({
|
|
775
|
+
page,
|
|
776
|
+
}) => {
|
|
777
|
+
await mockWorkflow(page);
|
|
778
|
+
const base = '/runtime/route-negotiation';
|
|
779
|
+
await page.setViewportSize({ width: 360, height: 844 });
|
|
780
|
+
const customPath = `${base}/admin/operations/purchases/${instanceId}?taskId=${taskId}`;
|
|
781
|
+
await page.goto(workflowFixtureUrl(customPath, { base }));
|
|
782
|
+
await expect(page.getByTestId('custom-workflow-detail')).toContainText(
|
|
783
|
+
`${instanceId} / ${taskId}`,
|
|
784
|
+
);
|
|
785
|
+
const customUrl = page.url();
|
|
786
|
+
await expect(page).toHaveURL(new RegExp(`${base}/admin/operations/`));
|
|
787
|
+
await expect
|
|
788
|
+
.poll(() => page.url(), { timeout: 1_000 })
|
|
789
|
+
.toBe(customUrl);
|
|
790
|
+
});
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
appName,
|
|
13
13
|
appPerspectives,
|
|
14
14
|
appRoutes,
|
|
15
|
+
routeManifest,
|
|
15
16
|
authenticationSurfaces,
|
|
17
|
+
anonymousPublicAccess,
|
|
16
18
|
adminNavigation,
|
|
17
19
|
adminPages,
|
|
18
20
|
resourceDefinitions,
|
|
@@ -49,7 +51,9 @@ ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
|
49
51
|
appName={appName}
|
|
50
52
|
adminNavigation={adminNavigation}
|
|
51
53
|
adminPages={adminPages}
|
|
54
|
+
routeManifest={routeManifest}
|
|
52
55
|
contributions={applicationContributions}
|
|
56
|
+
publicAccess={anonymousPublicAccess}
|
|
53
57
|
perspectives={appPerspectives}
|
|
54
58
|
resourceDefinitions={resourceDefinitions}
|
|
55
59
|
workflows={workflowDefinitions}
|
|
@@ -35,6 +35,7 @@ test('clean template contains only application declarations and one React entry'
|
|
|
35
35
|
assert.match(source, /DefaultDesktopApplicationLoginSurface/);
|
|
36
36
|
assert.match(source, /DefaultMobileApplicationLoginSurface/);
|
|
37
37
|
assert.match(source, /contributions=\{applicationContributions\}/);
|
|
38
|
+
assert.match(source, /publicAccess=\{anonymousPublicAccess\}/);
|
|
38
39
|
assert.match(source, /from 'openxiangda\/react'/);
|
|
39
40
|
assert.match(source, /openxiangda\/react\/styles\.css/);
|
|
40
41
|
const legacyMarkers = [
|
package/template/package.json
CHANGED
|
@@ -84,6 +84,7 @@ export const applicationAuthentication = {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
} as const;
|
|
87
|
+
export const anonymousPublicAccess = undefined;
|
|
87
88
|
export const platformAuthManifest = {
|
|
88
89
|
"schemaVersion": "openxiangda.platform-auth-manifest/v2",
|
|
89
90
|
"appCode": "openxiangda-application",
|
|
@@ -112,6 +113,12 @@ export const platformAuthManifest = {
|
|
|
112
113
|
}
|
|
113
114
|
]
|
|
114
115
|
} as const;
|
|
116
|
+
export const routeManifest = {
|
|
117
|
+
"schemaVersion": "openxiangda.application-route-manifest/v2",
|
|
118
|
+
"appCode": "openxiangda-application",
|
|
119
|
+
"routes": [],
|
|
120
|
+
"digest": "88831760f6e672a77babbf039b35a6febca7852092f1579c2721c99596a265c4"
|
|
121
|
+
} as const;
|
|
115
122
|
export const adminPages = [] as const;
|
|
116
123
|
export const adminNavigation = [] as const;
|
|
117
124
|
export const eventTypes = [] as const;
|
|
@@ -137,6 +144,8 @@ export type AppRouteCode = AppRoute["code"];
|
|
|
137
144
|
export type ApplicationAuthenticationMethod = (typeof authenticationMethods)[number];
|
|
138
145
|
export type ApplicationAuthenticationSurface = (typeof authenticationSurfaces)[keyof typeof authenticationSurfaces];
|
|
139
146
|
export type ApplicationAuthenticationSurfaceCode = ApplicationAuthenticationSurface["routeCode"];
|
|
147
|
+
export type AnonymousPublicAccess = typeof anonymousPublicAccess;
|
|
148
|
+
export type RouteManifest = typeof routeManifest;
|
|
140
149
|
export type AdminPage = (typeof adminPages)[number];
|
|
141
150
|
export type AdminNavigationGroup = (typeof adminNavigation)[number];
|
|
142
151
|
export type AppPerspective = (typeof appPerspectives)[number];
|