@voobase/cli 0.1.1-nonprod.2039 → 0.1.1-nonprod.2050

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 (109) hide show
  1. package/dist-bundle/index.mjs +69 -61
  2. package/package.json +9 -6
  3. package/runtime-sdk/dist/auth/client.d.ts +14 -0
  4. package/runtime-sdk/dist/auth/client.js +28 -0
  5. package/runtime-sdk/dist/blob/client.d.ts +39 -0
  6. package/runtime-sdk/dist/blob/client.js +148 -0
  7. package/runtime-sdk/dist/blob/client.test.d.ts +1 -0
  8. package/runtime-sdk/dist/blob/client.test.js +494 -0
  9. package/runtime-sdk/dist/browser/app.d.ts +142 -0
  10. package/runtime-sdk/dist/browser/app.js +256 -0
  11. package/runtime-sdk/dist/browser/app.test.d.ts +1 -0
  12. package/runtime-sdk/dist/browser/app.test.js +81 -0
  13. package/runtime-sdk/dist/browser/errors.d.ts +39 -0
  14. package/runtime-sdk/dist/browser/errors.js +265 -0
  15. package/runtime-sdk/dist/browser/errors.test.d.ts +1 -0
  16. package/runtime-sdk/dist/browser/errors.test.js +41 -0
  17. package/runtime-sdk/dist/browser.d.ts +5 -0
  18. package/runtime-sdk/dist/browser.js +5 -0
  19. package/runtime-sdk/dist/client.d.ts +16 -0
  20. package/runtime-sdk/dist/client.js +22 -0
  21. package/runtime-sdk/dist/cms/client.d.ts +39 -0
  22. package/runtime-sdk/dist/cms/client.js +56 -0
  23. package/runtime-sdk/dist/cms/client.test.d.ts +1 -0
  24. package/runtime-sdk/dist/cms/client.test.js +56 -0
  25. package/runtime-sdk/dist/cms/media.d.ts +10 -0
  26. package/runtime-sdk/dist/cms/media.js +113 -0
  27. package/runtime-sdk/dist/cms/media.test.d.ts +1 -0
  28. package/runtime-sdk/dist/cms/media.test.js +76 -0
  29. package/runtime-sdk/dist/cms/taxonomy.d.ts +8 -0
  30. package/runtime-sdk/dist/cms/taxonomy.js +77 -0
  31. package/runtime-sdk/dist/cms/taxonomy.test.d.ts +1 -0
  32. package/runtime-sdk/dist/cms/taxonomy.test.js +65 -0
  33. package/runtime-sdk/dist/data-form/client.d.ts +19 -0
  34. package/runtime-sdk/dist/data-form/client.js +118 -0
  35. package/runtime-sdk/dist/data-form/client.test.d.ts +1 -0
  36. package/runtime-sdk/dist/data-form/client.test.js +210 -0
  37. package/runtime-sdk/dist/data-form/contracts.d.ts +10 -0
  38. package/runtime-sdk/dist/data-form/contracts.js +33 -0
  39. package/runtime-sdk/dist/data-form/index.d.ts +3 -0
  40. package/runtime-sdk/dist/data-form/index.js +2 -0
  41. package/runtime-sdk/dist/data-form/types.d.ts +110 -0
  42. package/runtime-sdk/dist/data-form/types.js +1 -0
  43. package/runtime-sdk/dist/http.d.ts +27 -0
  44. package/runtime-sdk/dist/http.js +126 -0
  45. package/runtime-sdk/dist/index.d.ts +19 -0
  46. package/runtime-sdk/dist/index.js +14 -0
  47. package/runtime-sdk/dist/notification/client.d.ts +16 -0
  48. package/runtime-sdk/dist/notification/client.js +39 -0
  49. package/runtime-sdk/dist/notification/index.d.ts +1 -0
  50. package/runtime-sdk/dist/notification/index.js +1 -0
  51. package/runtime-sdk/dist/react/context.d.ts +18 -0
  52. package/runtime-sdk/dist/react/context.js +28 -0
  53. package/runtime-sdk/dist/react/hooks.d.ts +90 -0
  54. package/runtime-sdk/dist/react/hooks.js +172 -0
  55. package/runtime-sdk/dist/react.d.ts +2 -0
  56. package/runtime-sdk/dist/react.js +2 -0
  57. package/runtime-sdk/dist/session/browser.d.ts +25 -0
  58. package/runtime-sdk/dist/session/browser.js +60 -0
  59. package/runtime-sdk/dist/types/auth.d.ts +38 -0
  60. package/runtime-sdk/dist/types/auth.js +1 -0
  61. package/runtime-sdk/dist/types/cms.d.ts +93 -0
  62. package/runtime-sdk/dist/types/cms.js +1 -0
  63. package/runtime-sdk/dist/types/notification.d.ts +37 -0
  64. package/runtime-sdk/dist/types/notification.js +1 -0
  65. package/runtime-sdk/dist/types/object-storage.d.ts +58 -0
  66. package/runtime-sdk/dist/types/object-storage.js +1 -0
  67. package/runtime-sdk/dist/types/workflow.d.ts +52 -0
  68. package/runtime-sdk/dist/types/workflow.js +1 -0
  69. package/runtime-sdk/dist/workflow/client.d.ts +30 -0
  70. package/runtime-sdk/dist/workflow/client.js +45 -0
  71. package/scaffold-assets-manifest.json +429 -0
  72. package/template-blocks/assets.ts +95 -0
  73. package/template-blocks/contract/capabilities.ts +33 -0
  74. package/template-blocks/contract/facade-contract.ts +59 -0
  75. package/template-blocks/contract/index.ts +4 -0
  76. package/template-blocks/contract/path-builders.ts +76 -0
  77. package/template-blocks/contract/route-path-patterns-source.ts +222 -0
  78. package/template-blocks/contract/route-path-patterns.ts +210 -0
  79. package/template-blocks/contract/runtime-config.ts +256 -0
  80. package/template-blocks/dev-support/index.ts +2 -0
  81. package/template-blocks/dev-support/node/auth-shell.ts +31 -0
  82. package/template-blocks/dev-support/node/index.ts +3 -0
  83. package/template-blocks/dev-support/node/proxy.ts +133 -0
  84. package/template-blocks/dev-support/node/runtime-config.ts +163 -0
  85. package/template-blocks/dev-support/vite/auth-shell.ts +23 -0
  86. package/template-blocks/dev-support/vite/index.ts +3 -0
  87. package/template-blocks/dev-support/vite/proxy.ts +451 -0
  88. package/template-blocks/dev-support/vite/runtime-config.ts +107 -0
  89. package/template-blocks/legacy/app-core.ts +153 -0
  90. package/template-blocks/legacy/index.ts +10 -0
  91. package/template-blocks/legacy/lifecycle.ts +38 -0
  92. package/template-blocks/legacy/metadata.ts +59 -0
  93. package/template-blocks/legacy/pages.ts +156 -0
  94. package/template-blocks/legacy/react-lock.ts +1599 -0
  95. package/template-blocks/legacy/react.ts +823 -0
  96. package/template-blocks/legacy/tailwind.ts +1138 -0
  97. package/template-blocks/legacy/wrappers/auth.ts +105 -0
  98. package/template-blocks/legacy/wrappers/proxy.ts +250 -0
  99. package/template-blocks/legacy/wrappers/runtime.ts +535 -0
  100. package/template-blocks/protocol/auth-routes.ts +82 -0
  101. package/template-blocks/protocol/cms-routes.ts +81 -0
  102. package/template-blocks/protocol/index.ts +4 -0
  103. package/template-blocks/protocol/public-app-routes.ts +48 -0
  104. package/template-blocks/protocol/route-map.ts +75 -0
  105. package/template-blocks/routing.ts +62 -0
  106. package/template-blocks/server/html-injection.ts +45 -0
  107. package/template-blocks/server/proxy-routing.ts +65 -0
  108. package/template-blocks/server/request-context.ts +103 -0
  109. package/template-blocks/server/route-strip.ts +47 -0
@@ -0,0 +1,256 @@
1
+ import { createBrowserRuntimeSdk, createBrowserSessionStore } from "../session/browser.js";
2
+ import { classifyBrowserRuntimeError, classifyBrowserWorkflowError, getBrowserRuntimeErrorMessage, getBrowserWorkflowErrorMessage, resolveEndUserAccess } from "./errors.js";
3
+ import { resolveCmsCoverImageSet as resolveRuntimeCmsCoverImageSet, resolveCmsCoverImageUrl as resolveRuntimeCmsCoverImageUrl, resolveCmsImageSet as resolveRuntimeCmsImageSet, resolveCmsImageUrl as resolveRuntimeCmsImageUrl } from "../cms/media.js";
4
+ import { buildCmsCategoryNameMap as buildRuntimeCmsCategoryNameMap, resolveCmsCategoryName as resolveRuntimeCmsCategoryName, resolveCmsItemCategoryName as resolveRuntimeCmsItemCategoryName, resolveCmsItemTagLabels as resolveRuntimeCmsItemTagLabels, resolveCmsTagLabels as resolveRuntimeCmsTagLabels } from "../cms/taxonomy.js";
5
+ export function createBrowserRuntimeApp(options) {
6
+ const session = options.session ?? createBrowserSessionStore(options.sessionOptions);
7
+ const sdk = createBrowserRuntimeSdk({
8
+ baseUrl: options.baseUrl,
9
+ appId: options.appId,
10
+ env: options.env,
11
+ fetchImpl: options.fetchImpl,
12
+ session,
13
+ });
14
+ const authPath = options.authPath ?? "/auth";
15
+ return {
16
+ sdk,
17
+ session,
18
+ buildSignInUrl(returnTo = getCurrentLocationPath(authPath)) {
19
+ const url = new URL(authPath, window.location.origin);
20
+ url.searchParams.set("return_to", normalizeReturnToTarget(returnTo, authPath));
21
+ return url.toString();
22
+ },
23
+ resolveAccess(me) {
24
+ return resolveEndUserAccess(me);
25
+ },
26
+ classifyError(error) {
27
+ return classifyBrowserRuntimeError(error);
28
+ },
29
+ classifyWorkflowError(error, params = {}) {
30
+ return classifyBrowserWorkflowError(error, {
31
+ appId: options.appId,
32
+ operationLabel: params.operationLabel
33
+ });
34
+ },
35
+ getErrorMessage(error, fallback = "运行时请求失败。") {
36
+ return getBrowserRuntimeErrorMessage(error, fallback);
37
+ },
38
+ getWorkflowErrorMessage(error, fallback = "Workflow 请求失败。", params = {}) {
39
+ return getBrowserWorkflowErrorMessage(error, fallback, {
40
+ appId: options.appId,
41
+ operationLabel: params.operationLabel
42
+ });
43
+ },
44
+ async getCurrentEndUser() {
45
+ return sdk.auth.getCurrentEndUser();
46
+ },
47
+ async getCurrentEndUserRoles() {
48
+ return sdk.auth.getCurrentEndUserRoles();
49
+ },
50
+ async isSignedIn() {
51
+ return sdk.auth.isSignedIn();
52
+ },
53
+ async getMe() {
54
+ return sdk.auth.getCurrentEndUser();
55
+ },
56
+ async listMyRoles() {
57
+ return sdk.auth.getCurrentEndUserRoles();
58
+ },
59
+ async listMyTasks(args) {
60
+ return sdk.workflow.listMyTasks(args);
61
+ },
62
+ async listMyNotifications(args) {
63
+ return sdk.notification.listMyInbox(args);
64
+ },
65
+ async getMyNotificationUnreadCount() {
66
+ return sdk.notification.getMyUnreadCount();
67
+ },
68
+ async listMyAnnouncements(args) {
69
+ return sdk.notification.listMyAnnouncements(args);
70
+ },
71
+ async markNotificationRead(itemId) {
72
+ return sdk.notification.markRead(itemId);
73
+ },
74
+ async dismissNotification(itemId) {
75
+ return sdk.notification.dismiss(itemId);
76
+ },
77
+ async getWorkflowObjectState(args) {
78
+ return sdk.workflow.getObjectState(args);
79
+ },
80
+ async startWorkflow(args) {
81
+ return sdk.workflow.startObjectWorkflow(args);
82
+ },
83
+ async performWorkflowAction(args) {
84
+ return sdk.workflow.performAction(args);
85
+ },
86
+ async listWorkflowTimeline(args) {
87
+ return sdk.workflow.listTimeline(args);
88
+ },
89
+ async listCmsItems(args) {
90
+ return sdk.cms.listItems(args);
91
+ },
92
+ async listCmsCollections(args) {
93
+ return sdk.cms.listCollections(args);
94
+ },
95
+ async uploadBlob(args) {
96
+ return sdk.blob.upload(args);
97
+ },
98
+ async uploadBlobFile(file, args) {
99
+ return sdk.blob.uploadFile(file, args);
100
+ },
101
+ async uploadBlobFiles(files, args) {
102
+ return sdk.blob.uploadFiles(files, args);
103
+ },
104
+ async hydrateBlobRefs(args) {
105
+ return sdk.blob.hydrateBlobRefs(args);
106
+ },
107
+ async hydrateRecordBlobs(args) {
108
+ return sdk.blob.hydrateRecordBlobs(args);
109
+ },
110
+ async getCmsCollectionMeta(args) {
111
+ return sdk.cms.getCollectionMeta(args);
112
+ },
113
+ async listCmsCategories(args) {
114
+ return sdk.cms.listCategories(args);
115
+ },
116
+ async listCmsCategoryNodes(args) {
117
+ const result = await sdk.cms.listCategories(args);
118
+ return Array.isArray(result?.nodes) ? result.nodes : [];
119
+ },
120
+ async getCmsItemBySlug(args) {
121
+ return sdk.cms.getItemBySlug(args);
122
+ },
123
+ async getCmsItemById(args) {
124
+ return sdk.cms.getItemById(args);
125
+ },
126
+ resolveCmsImageSet(value, options = {}) {
127
+ return resolveRuntimeCmsImageSet(value, withBrowserProtocol(options));
128
+ },
129
+ resolveCmsImageUrl(value, options = {}) {
130
+ return resolveRuntimeCmsImageUrl(value, withBrowserProtocol(options));
131
+ },
132
+ resolveCmsCoverImageSet(item, options = {}) {
133
+ return resolveRuntimeCmsCoverImageSet(item, withBrowserProtocol(options));
134
+ },
135
+ resolveCmsCoverImageUrl(item, options = {}) {
136
+ return resolveRuntimeCmsCoverImageUrl(item, withBrowserProtocol(options));
137
+ },
138
+ buildCmsCategoryNameMap(source) {
139
+ return buildRuntimeCmsCategoryNameMap(source);
140
+ },
141
+ resolveCmsCategoryName(categoryId, source, fallback = "未分类") {
142
+ return resolveRuntimeCmsCategoryName(categoryId, source, fallback);
143
+ },
144
+ resolveCmsItemCategoryName(item, source, fallback = "未分类") {
145
+ return resolveRuntimeCmsItemCategoryName(item, source, fallback);
146
+ },
147
+ resolveCmsTagLabels(value) {
148
+ return resolveRuntimeCmsTagLabels(value);
149
+ },
150
+ resolveCmsItemTagLabels(item) {
151
+ return resolveRuntimeCmsItemTagLabels(item);
152
+ },
153
+ async signOut() {
154
+ try {
155
+ await sdk.auth.signOut();
156
+ }
157
+ finally {
158
+ session.clearToken();
159
+ }
160
+ },
161
+ async ensureAuthenticated(args = {}) {
162
+ const shouldRedirect = args.redirectToSignIn ?? true;
163
+ if (!session.readToken()) {
164
+ if (shouldRedirect) {
165
+ window.location.assign(this.buildSignInUrl(args.returnTo));
166
+ }
167
+ return null;
168
+ }
169
+ try {
170
+ const me = await sdk.auth.getCurrentEndUser();
171
+ const access = resolveEndUserAccess(me);
172
+ if (access.kind === "ready") {
173
+ return me;
174
+ }
175
+ if (shouldRedirect && access.shouldRedirectToSignIn) {
176
+ window.location.assign(this.buildSignInUrl(args.returnTo));
177
+ return null;
178
+ }
179
+ return me;
180
+ }
181
+ catch (error) {
182
+ const resolved = classifyBrowserRuntimeError(error);
183
+ if (resolved.shouldClearSession) {
184
+ session.clearToken();
185
+ }
186
+ if (shouldRedirect && resolved.shouldRedirectToSignIn) {
187
+ window.location.assign(this.buildSignInUrl(args.returnTo));
188
+ return null;
189
+ }
190
+ throw error;
191
+ }
192
+ },
193
+ };
194
+ }
195
+ function getCurrentLocationPath(authPath) {
196
+ if (typeof window === "undefined") {
197
+ return "/";
198
+ }
199
+ return normalizeReturnToTarget(`${window.location.pathname}${window.location.search}${window.location.hash}`, authPath);
200
+ }
201
+ function normalizeReturnToTarget(returnTo, authPath) {
202
+ const fallback = "/app";
203
+ if (typeof returnTo !== "string" || !returnTo.trim()) {
204
+ return fallback;
205
+ }
206
+ const candidate = returnTo.trim();
207
+ if (typeof window === "undefined") {
208
+ return candidate.startsWith("/") ? candidate : fallback;
209
+ }
210
+ let normalized = candidate;
211
+ if (/^https?:\/\//u.test(candidate)) {
212
+ const url = new URL(candidate, window.location.origin);
213
+ normalized = `${url.pathname}${url.search}${url.hash}`;
214
+ }
215
+ else if (!candidate.startsWith("/")) {
216
+ const url = new URL(candidate, window.location.origin);
217
+ normalized = `${url.pathname}${url.search}${url.hash}`;
218
+ }
219
+ const basePath = deriveBasePathFromAuthPath(authPath);
220
+ if (basePath !== "/" && (normalized === basePath || normalized.startsWith(`${basePath}/`))) {
221
+ const suffix = normalized.slice(basePath.length) || "/";
222
+ return suffix.startsWith("/") ? suffix : `/${suffix}`;
223
+ }
224
+ return normalized.startsWith("/") ? normalized : fallback;
225
+ }
226
+ function deriveBasePathFromAuthPath(authPath) {
227
+ const url = new URL(authPath, "http://platform.invalid");
228
+ const pathname = url.pathname.trim() || "/";
229
+ if (pathname === "/" || pathname === "/auth") {
230
+ return "/";
231
+ }
232
+ const withoutTrailingSlash = pathname.length > 1 ? pathname.replace(/\/+$/u, "") : pathname;
233
+ const authSuffix = "/auth";
234
+ if (withoutTrailingSlash === authSuffix) {
235
+ return "/";
236
+ }
237
+ if (withoutTrailingSlash.endsWith(authSuffix)) {
238
+ return withoutTrailingSlash.slice(0, -authSuffix.length) || "/";
239
+ }
240
+ return "/";
241
+ }
242
+ function withBrowserProtocol(options) {
243
+ if (options.currentProtocol) {
244
+ return options;
245
+ }
246
+ return {
247
+ ...options,
248
+ currentProtocol: getBrowserLocationProtocol()
249
+ };
250
+ }
251
+ function getBrowserLocationProtocol() {
252
+ if (typeof window === "undefined") {
253
+ return null;
254
+ }
255
+ return typeof window.location?.protocol === "string" ? window.location.protocol : null;
256
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,81 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { createBrowserRuntimeApp } from "./app.js";
4
+ test("buildSignInUrl normalizes preview return target to app-internal path", () => {
5
+ const originalWindow = globalThis.window;
6
+ const location = {
7
+ origin: "http://127.0.0.1.nip.io",
8
+ pathname: "/previews/app-demo/rel-123/submit",
9
+ search: "?draft=1",
10
+ hash: "#section",
11
+ assign() { },
12
+ };
13
+ globalThis.window = {
14
+ location,
15
+ };
16
+ try {
17
+ const app = createBrowserRuntimeApp({
18
+ baseUrl: "http://127.0.0.1.nip.io/previews/app-demo/rel-123/",
19
+ appId: "app-demo",
20
+ authPath: "/previews/app-demo/rel-123/auth",
21
+ fetchImpl: async () => new Response(),
22
+ });
23
+ const signInUrl = new URL(app.buildSignInUrl());
24
+ assert.equal(signInUrl.pathname, "/previews/app-demo/rel-123/auth");
25
+ assert.equal(signInUrl.searchParams.get("return_to"), "/submit?draft=1#section");
26
+ }
27
+ finally {
28
+ globalThis.window = originalWindow;
29
+ }
30
+ });
31
+ test("buildSignInUrl accepts full platform path and stores app-internal return target", () => {
32
+ const originalWindow = globalThis.window;
33
+ globalThis.window = {
34
+ location: {
35
+ origin: "http://127.0.0.1.nip.io",
36
+ pathname: "/previews/app-demo/rel-123/",
37
+ search: "",
38
+ hash: "",
39
+ assign() { },
40
+ },
41
+ };
42
+ try {
43
+ const app = createBrowserRuntimeApp({
44
+ baseUrl: "http://127.0.0.1.nip.io/previews/app-demo/rel-123/",
45
+ appId: "app-demo",
46
+ authPath: "/previews/app-demo/rel-123/auth",
47
+ fetchImpl: async () => new Response(),
48
+ });
49
+ const signInUrl = new URL(app.buildSignInUrl("/previews/app-demo/rel-123/my-submissions/rec-1?tab=edit"));
50
+ assert.equal(signInUrl.searchParams.get("return_to"), "/my-submissions/rec-1?tab=edit");
51
+ }
52
+ finally {
53
+ globalThis.window = originalWindow;
54
+ }
55
+ });
56
+ test("buildSignInUrl keeps host-mode return target as regular path", () => {
57
+ const originalWindow = globalThis.window;
58
+ globalThis.window = {
59
+ location: {
60
+ origin: "https://app-demo.example.com",
61
+ pathname: "/my-submissions",
62
+ search: "",
63
+ hash: "",
64
+ assign() { },
65
+ },
66
+ };
67
+ try {
68
+ const app = createBrowserRuntimeApp({
69
+ baseUrl: "https://app-demo.example.com/",
70
+ appId: "app-demo",
71
+ authPath: "/auth",
72
+ fetchImpl: async () => new Response(),
73
+ });
74
+ const signInUrl = new URL(app.buildSignInUrl());
75
+ assert.equal(signInUrl.pathname, "/auth");
76
+ assert.equal(signInUrl.searchParams.get("return_to"), "/my-submissions");
77
+ }
78
+ finally {
79
+ globalThis.window = originalWindow;
80
+ }
81
+ });
@@ -0,0 +1,39 @@
1
+ import type { RuntimeEndUserAccessState, RuntimeEndUserAuthMe } from "../types/auth.js";
2
+ export type BrowserRuntimeAccessKind = "ready" | "sign_in_required" | "blocked" | "not_provisioned" | "binding_unavailable" | "auth_disabled";
3
+ export type BrowserRuntimeAccessResolution = {
4
+ kind: BrowserRuntimeAccessKind;
5
+ accessState: RuntimeEndUserAccessState;
6
+ message: string;
7
+ shouldRedirectToSignIn: boolean;
8
+ };
9
+ export type BrowserRuntimeErrorKind = "auth" | "business" | "network" | "server" | "unknown";
10
+ export type BrowserRuntimeErrorResolution = {
11
+ kind: BrowserRuntimeErrorKind;
12
+ message: string;
13
+ status?: number;
14
+ code?: string;
15
+ requestId?: string;
16
+ shouldClearSession: boolean;
17
+ shouldRedirectToSignIn: boolean;
18
+ isRetryable: boolean;
19
+ };
20
+ export type BrowserWorkflowErrorKind = "configuration" | "permission" | "state" | "auth" | "network" | "server" | "unknown";
21
+ export type BrowserWorkflowErrorResolution = BrowserRuntimeErrorResolution & {
22
+ workflowKind: BrowserWorkflowErrorKind;
23
+ recommendation?: string;
24
+ suggestedCommand?: string;
25
+ isConfigurationGap: boolean;
26
+ isPermissionGap: boolean;
27
+ isStateGap: boolean;
28
+ };
29
+ export declare function resolveEndUserAccess(me: RuntimeEndUserAuthMe | null | undefined): BrowserRuntimeAccessResolution;
30
+ export declare function classifyBrowserRuntimeError(error: unknown): BrowserRuntimeErrorResolution;
31
+ export declare function getBrowserRuntimeErrorMessage(error: unknown, fallback?: string): string;
32
+ export declare function classifyBrowserWorkflowError(error: unknown, options?: {
33
+ appId?: string;
34
+ operationLabel?: string;
35
+ }): BrowserWorkflowErrorResolution;
36
+ export declare function getBrowserWorkflowErrorMessage(error: unknown, fallback?: string, options?: {
37
+ appId?: string;
38
+ operationLabel?: string;
39
+ }): string;
@@ -0,0 +1,265 @@
1
+ import { RuntimeApiError } from "../http.js";
2
+ export function resolveEndUserAccess(me) {
3
+ const accessState = me?.access_state ?? "not_authenticated";
4
+ switch (accessState) {
5
+ case "authenticated_and_ready":
6
+ return {
7
+ kind: "ready",
8
+ accessState,
9
+ message: "当前终端用户已就绪。",
10
+ shouldRedirectToSignIn: false,
11
+ };
12
+ case "authenticated_but_blocked":
13
+ return {
14
+ kind: "blocked",
15
+ accessState,
16
+ message: "当前终端用户已被封禁,无法继续访问当前应用。",
17
+ shouldRedirectToSignIn: false,
18
+ };
19
+ case "authenticated_but_not_provisioned":
20
+ return {
21
+ kind: "not_provisioned",
22
+ accessState,
23
+ message: "当前终端用户已登录,但尚未在当前应用中开通访问。",
24
+ shouldRedirectToSignIn: false,
25
+ };
26
+ case "binding_unavailable":
27
+ return {
28
+ kind: "binding_unavailable",
29
+ accessState,
30
+ message: "当前应用的终端用户认证绑定不可用,请联系管理员检查配置。",
31
+ shouldRedirectToSignIn: false,
32
+ };
33
+ case "auth_not_enabled":
34
+ return {
35
+ kind: "auth_disabled",
36
+ accessState,
37
+ message: "当前应用尚未启用终端用户认证。",
38
+ shouldRedirectToSignIn: false,
39
+ };
40
+ case "not_authenticated":
41
+ default:
42
+ return {
43
+ kind: "sign_in_required",
44
+ accessState: "not_authenticated",
45
+ message: "当前终端用户尚未登录。",
46
+ shouldRedirectToSignIn: true,
47
+ };
48
+ }
49
+ }
50
+ export function classifyBrowserRuntimeError(error) {
51
+ if (error instanceof RuntimeApiError) {
52
+ if (error.status === 401 || error.status === 403) {
53
+ return {
54
+ kind: "auth",
55
+ message: error.message || "当前登录态已失效,请重新登录。",
56
+ status: error.status,
57
+ code: error.code,
58
+ requestId: error.requestId,
59
+ shouldClearSession: true,
60
+ shouldRedirectToSignIn: true,
61
+ isRetryable: false,
62
+ };
63
+ }
64
+ if (error.status >= 500) {
65
+ return {
66
+ kind: "server",
67
+ message: error.message || "平台运行时服务暂时不可用,请稍后重试。",
68
+ status: error.status,
69
+ code: error.code,
70
+ requestId: error.requestId,
71
+ shouldClearSession: false,
72
+ shouldRedirectToSignIn: false,
73
+ isRetryable: true,
74
+ };
75
+ }
76
+ return {
77
+ kind: "business",
78
+ message: error.message || "当前请求未通过校验。",
79
+ status: error.status,
80
+ code: error.code,
81
+ requestId: error.requestId,
82
+ shouldClearSession: false,
83
+ shouldRedirectToSignIn: false,
84
+ isRetryable: false,
85
+ };
86
+ }
87
+ if (error instanceof TypeError) {
88
+ return {
89
+ kind: "network",
90
+ message: error.message || "网络请求失败,请检查当前网络或代理配置。",
91
+ shouldClearSession: false,
92
+ shouldRedirectToSignIn: false,
93
+ isRetryable: true,
94
+ };
95
+ }
96
+ if (error instanceof Error) {
97
+ return {
98
+ kind: "unknown",
99
+ message: error.message || "运行时请求失败。",
100
+ shouldClearSession: false,
101
+ shouldRedirectToSignIn: false,
102
+ isRetryable: false,
103
+ };
104
+ }
105
+ return {
106
+ kind: "unknown",
107
+ message: "运行时请求失败。",
108
+ shouldClearSession: false,
109
+ shouldRedirectToSignIn: false,
110
+ isRetryable: false,
111
+ };
112
+ }
113
+ export function getBrowserRuntimeErrorMessage(error, fallback = "运行时请求失败。") {
114
+ const resolved = classifyBrowserRuntimeError(error);
115
+ return resolved.message || fallback;
116
+ }
117
+ export function classifyBrowserWorkflowError(error, options = {}) {
118
+ const resolved = classifyBrowserRuntimeError(error);
119
+ const operationLabel = options.operationLabel?.trim() || "Workflow 请求";
120
+ const suggestedDiagnoseCommand = options.appId
121
+ ? `platform workflow diagnose --app ${options.appId}`
122
+ : "platform workflow diagnose";
123
+ const fallback = {
124
+ ...resolved,
125
+ workflowKind: resolved.kind === "auth"
126
+ ? "auth"
127
+ : resolved.kind === "network"
128
+ ? "network"
129
+ : resolved.kind === "server"
130
+ ? "server"
131
+ : "unknown",
132
+ recommendation: resolved.kind === "auth"
133
+ ? "请重新登录后重试。"
134
+ : resolved.kind === "network" || resolved.kind === "server"
135
+ ? "稍后重试;如果持续失败,请检查平台运行时与控制面服务状态。"
136
+ : "先刷新状态;若仍失败,再检查 workflow 定义、绑定与角色绑定。",
137
+ suggestedCommand: resolved.kind === "auth" || resolved.kind === "network" || resolved.kind === "server"
138
+ ? undefined
139
+ : suggestedDiagnoseCommand,
140
+ isConfigurationGap: false,
141
+ isPermissionGap: false,
142
+ isStateGap: false
143
+ };
144
+ switch (resolved.code) {
145
+ case "workflow_definition_not_found":
146
+ return {
147
+ ...resolved,
148
+ workflowKind: "configuration",
149
+ message: "当前应用尚未找到对应的 Workflow 定义或绑定。",
150
+ recommendation: `先检查 definition 与 app binding;可执行 \`${suggestedDiagnoseCommand}\`。`,
151
+ suggestedCommand: suggestedDiagnoseCommand,
152
+ isConfigurationGap: true,
153
+ isPermissionGap: false,
154
+ isStateGap: false
155
+ };
156
+ case "workflow_definition_not_active":
157
+ return {
158
+ ...resolved,
159
+ workflowKind: "configuration",
160
+ message: "当前 Workflow 定义存在,但还不是 active 状态。",
161
+ recommendation: "请先激活定义,再继续启动或执行动作。",
162
+ suggestedCommand: suggestedDiagnoseCommand,
163
+ isConfigurationGap: true,
164
+ isPermissionGap: false,
165
+ isStateGap: false
166
+ };
167
+ case "workflow_runtime_principal_invalid":
168
+ case "workflow_runtime_session_invalid":
169
+ return {
170
+ ...resolved,
171
+ workflowKind: "auth",
172
+ message: "当前 Workflow 运行时需要有效的终端用户会话,请重新登录后重试。",
173
+ recommendation: "重新登录当前轻应用,再继续访问 workflow 页面。",
174
+ suggestedCommand: undefined,
175
+ isConfigurationGap: false,
176
+ isPermissionGap: false,
177
+ isStateGap: false
178
+ };
179
+ case "workflow_instance_already_active":
180
+ return {
181
+ ...resolved,
182
+ workflowKind: "state",
183
+ message: "该对象已经有进行中的流程实例,不需要重复启动。",
184
+ recommendation: "直接刷新当前对象状态,或继续执行后续动作。",
185
+ suggestedCommand: undefined,
186
+ isConfigurationGap: false,
187
+ isPermissionGap: false,
188
+ isStateGap: true
189
+ };
190
+ case "workflow_instance_not_found":
191
+ return {
192
+ ...resolved,
193
+ workflowKind: "state",
194
+ message: "当前对象还没有对应的流程实例。",
195
+ recommendation: "请先启动流程,再执行动作或查看时间线。",
196
+ suggestedCommand: undefined,
197
+ isConfigurationGap: false,
198
+ isPermissionGap: false,
199
+ isStateGap: true
200
+ };
201
+ case "workflow_instance_not_active":
202
+ return {
203
+ ...resolved,
204
+ workflowKind: "state",
205
+ message: "当前流程实例已结束,不能继续执行动作。",
206
+ recommendation: "刷新状态后查看当前对象是否需要重新打开或重新启动流程。",
207
+ suggestedCommand: undefined,
208
+ isConfigurationGap: false,
209
+ isPermissionGap: false,
210
+ isStateGap: true
211
+ };
212
+ case "workflow_action_not_found":
213
+ return {
214
+ ...resolved,
215
+ workflowKind: "configuration",
216
+ message: "当前动作不存在,可能是流程定义或页面状态已经过期。",
217
+ recommendation: "先刷新状态;如果仍然缺失,请检查 binding override 或最近的 definition 变更。",
218
+ suggestedCommand: suggestedDiagnoseCommand,
219
+ isConfigurationGap: true,
220
+ isPermissionGap: false,
221
+ isStateGap: false
222
+ };
223
+ case "workflow_transition_not_allowed":
224
+ return {
225
+ ...resolved,
226
+ workflowKind: "state",
227
+ message: "当前状态不允许执行这个动作。",
228
+ recommendation: "先刷新 workflow 状态,确认当前对象仍处于可执行该动作的状态。",
229
+ suggestedCommand: undefined,
230
+ isConfigurationGap: false,
231
+ isPermissionGap: false,
232
+ isStateGap: true
233
+ };
234
+ case "workflow_action_forbidden":
235
+ return {
236
+ ...resolved,
237
+ workflowKind: "permission",
238
+ message: "当前终端用户没有执行这个动作的权限。",
239
+ recommendation: `检查 workflow role binding 是否把当前用户角色映射到该动作;可执行 \`${suggestedDiagnoseCommand}\`。`,
240
+ suggestedCommand: suggestedDiagnoseCommand,
241
+ isConfigurationGap: false,
242
+ isPermissionGap: true,
243
+ isStateGap: false
244
+ };
245
+ case "workflow_schema_invalid":
246
+ case "workflow_state_not_found":
247
+ case "workflow_instance_update_failed":
248
+ return {
249
+ ...resolved,
250
+ workflowKind: "server",
251
+ message: `${operationLabel}失败,Workflow 定义或实例数据存在异常。`,
252
+ recommendation: "检查 workflow schema、binding override 与控制面日志。",
253
+ suggestedCommand: suggestedDiagnoseCommand,
254
+ isConfigurationGap: false,
255
+ isPermissionGap: false,
256
+ isStateGap: false
257
+ };
258
+ default:
259
+ return fallback;
260
+ }
261
+ }
262
+ export function getBrowserWorkflowErrorMessage(error, fallback = "Workflow 请求失败。", options = {}) {
263
+ const resolved = classifyBrowserWorkflowError(error, options);
264
+ return resolved.message || fallback;
265
+ }
@@ -0,0 +1 @@
1
+ export {};