e10-ebuilder-prototype 0.5.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 (54) hide show
  1. package/README.md +113 -0
  2. package/dist/api.d.ts +12 -0
  3. package/dist/api.js +125 -0
  4. package/dist/application.d.ts +7 -0
  5. package/dist/application.js +16 -0
  6. package/dist/archive.d.ts +130 -0
  7. package/dist/archive.js +151 -0
  8. package/dist/capture.d.ts +15 -0
  9. package/dist/capture.js +440 -0
  10. package/dist/common.d.ts +20 -0
  11. package/dist/common.js +87 -0
  12. package/dist/dom.d.mts +1 -0
  13. package/dist/dom.mjs +58 -0
  14. package/dist/form-context.d.ts +3 -0
  15. package/dist/form-context.js +58 -0
  16. package/dist/form-runtime.d.mts +2 -0
  17. package/dist/form-runtime.mjs +149 -0
  18. package/dist/forms.d.ts +51 -0
  19. package/dist/forms.js +603 -0
  20. package/dist/html.d.ts +22 -0
  21. package/dist/html.js +427 -0
  22. package/dist/index.d.ts +2 -0
  23. package/dist/index.js +370 -0
  24. package/dist/menus.d.ts +32 -0
  25. package/dist/menus.js +330 -0
  26. package/dist/model.d.ts +164 -0
  27. package/dist/model.js +8 -0
  28. package/dist/offline-store.d.mts +5 -0
  29. package/dist/offline-store.mjs +80 -0
  30. package/dist/platform.d.ts +10 -0
  31. package/dist/platform.js +123 -0
  32. package/dist/readiness.d.ts +124 -0
  33. package/dist/readiness.js +529 -0
  34. package/dist/runtime-support.d.mts +52 -0
  35. package/dist/runtime-support.mjs +279 -0
  36. package/dist/site.d.ts +34 -0
  37. package/dist/site.js +195 -0
  38. package/dist/store.d.ts +90 -0
  39. package/dist/store.js +296 -0
  40. package/dist/templates/form-guide.md +539 -0
  41. package/dist/templates/index.html +803 -0
  42. package/dist/templates/placeholder.html +143 -0
  43. package/dist/templates/workflow-guide.md +95 -0
  44. package/dist/templates/workflow-presets.json +89 -0
  45. package/dist/temporary-records.d.ts +15 -0
  46. package/dist/temporary-records.js +286 -0
  47. package/dist/vendor/environment-auth.d.ts +61 -0
  48. package/dist/vendor/environment-auth.js +455 -0
  49. package/dist/workflow-runtime.d.mts +2 -0
  50. package/dist/workflow-runtime.mjs +298 -0
  51. package/dist/workflows.d.ts +28 -0
  52. package/dist/workflows.js +90 -0
  53. package/docs/PROTOCOL.md +299 -0
  54. package/package.json +45 -0
@@ -0,0 +1,123 @@
1
+ import { CaptureError, id } from './common.js';
2
+ export function parsePages(payload, appId, origin) {
3
+ const p = payload;
4
+ if (!p ||
5
+ typeof p !== 'object' ||
6
+ ![0, 200, '0', '200'].includes(p.code) ||
7
+ p.status === false ||
8
+ p.fail === true ||
9
+ !Array.isArray(p.data))
10
+ throw new CaptureError('PAGE_LIST_INVALID', '页面列表返回结构或业务状态异常');
11
+ const seen = new Set();
12
+ return p.data.map((raw) => {
13
+ if (!raw || typeof raw !== 'object')
14
+ throw new CaptureError('PAGE_ITEM_INVALID', '页面项必须是对象');
15
+ const item = raw;
16
+ const viewId = id(item.id);
17
+ if (seen.has(viewId))
18
+ throw new CaptureError('PAGE_ID_DUPLICATE', `重复页面 ID: ${viewId}`);
19
+ seen.add(viewId);
20
+ if (item.appid !== appId ||
21
+ !['PAGE', 'ECODE_HTML', 'ECODE_REACT'].includes(String(item.type)) ||
22
+ typeof item.name !== 'string' ||
23
+ !item.name.trim())
24
+ throw new CaptureError('PAGE_ITEM_INVALID', `页面 ${viewId} 的 appid/type/name 无效`);
25
+ if (!Array.isArray(item.terminalScope) ||
26
+ !item.terminalScope.length ||
27
+ item.terminalScope.some((v) => !['PC', 'MOBILE', 'ALL'].includes(v)))
28
+ throw new CaptureError('TERMINAL_UNKNOWN', `页面 ${viewId} 的终端类型未知`);
29
+ return {
30
+ id: viewId,
31
+ name: item.name,
32
+ appId,
33
+ type: item.type,
34
+ terminal: item.terminalScope.every((v) => v === 'MOBILE') ? 'MOBILE' : 'PC',
35
+ url: new URL(`/sp/ebdpage/view/${viewId}`, origin).href,
36
+ };
37
+ });
38
+ }
39
+ function envelope(payload) {
40
+ const p = payload;
41
+ if (!p ||
42
+ ![0, 200, '0', '200'].includes(p.code) ||
43
+ p.status === false ||
44
+ p.fail === true)
45
+ throw new CaptureError('CATALOG_INVALID', '应用/表单列表返回业务状态异常');
46
+ return p.data;
47
+ }
48
+ export function parseApp(payload, appId) {
49
+ const d = envelope(payload);
50
+ if (!d || d.id !== appId || typeof d.name !== 'string' || !d.name.trim())
51
+ throw new CaptureError('APP_INFO_INVALID', '应用信息的 id/name 无效');
52
+ return d.name;
53
+ }
54
+ export function parseForms(payload, appId, origin) {
55
+ const data = envelope(payload);
56
+ if (!Array.isArray(data))
57
+ throw new CaptureError('FORM_LIST_INVALID', '表单列表必须是数组');
58
+ const seen = new Set();
59
+ return data.map((raw) => {
60
+ if (!raw || typeof raw !== 'object')
61
+ throw new CaptureError('FORM_ITEM_INVALID', '表单项无效');
62
+ const formId = id(raw.id), name = raw.showName || raw.name || raw.objName;
63
+ if (raw.appId !== appId || typeof name !== 'string' || !name.trim())
64
+ throw new CaptureError('FORM_ITEM_INVALID', `表单 ${formId} 的 appId/name 无效`);
65
+ if (seen.has(formId))
66
+ throw new CaptureError('FORM_ID_DUPLICATE', `重复表单 ID: ${formId}`);
67
+ seen.add(formId);
68
+ return {
69
+ id: formId,
70
+ name,
71
+ appId,
72
+ url: new URL(`/sp/ebdapp/detail/${appId}/form/view/${formId}`, origin).href,
73
+ };
74
+ });
75
+ }
76
+ export async function fetchCatalog(auth, appId) {
77
+ id(appId, 'appId');
78
+ const get = async (pathname) => {
79
+ const response = await fetch(new URL(pathname, auth.baseUrl), {
80
+ headers: { Cookie: `ETEAMSID=${auth.eteamsId}`, accept: 'application/json' },
81
+ redirect: 'manual',
82
+ signal: AbortSignal.timeout(30000),
83
+ });
84
+ if ([301, 302, 303, 307, 308, 401, 403].includes(response.status))
85
+ throw new CaptureError('E10_LOGIN_REQUIRED', '登录已失效,请重新执行 auth set');
86
+ if (!response.ok)
87
+ throw new CaptureError('CATALOG_HTTP', `应用目录 HTTP ${response.status}`);
88
+ const data = await response.json().catch(() => {
89
+ throw new CaptureError('CATALOG_INVALID', '应用目录不是 JSON');
90
+ });
91
+ if ([401, 403, '401', '403'].includes(data?.code))
92
+ throw new CaptureError('E10_LOGIN_REQUIRED', '登录已失效,请重新执行 auth set');
93
+ return data;
94
+ };
95
+ const responses = await Promise.allSettled([
96
+ get(`/api/bs/ebuilder/app/info?id=${appId}`),
97
+ get(`/api/bs/ebuilder/form/obj/getList/${appId}?apid=${appId}`),
98
+ ]);
99
+ for (const r of responses)
100
+ if (r.status === 'rejected')
101
+ throw r.reason;
102
+ const [app, forms] = responses.map((r) => r.value);
103
+ return { appName: parseApp(app, appId), forms: parseForms(forms, appId, auth.baseUrl) };
104
+ }
105
+ export async function fetchPages(auth, appId) {
106
+ const url = new URL('/api/bs/ebuilder/page/list', auth.baseUrl);
107
+ url.searchParams.set('appid', id(appId, 'appId'));
108
+ const response = await fetch(url, {
109
+ headers: { Cookie: `ETEAMSID=${auth.eteamsId}`, accept: 'application/json' },
110
+ redirect: 'manual',
111
+ signal: AbortSignal.timeout(30000),
112
+ });
113
+ if ([301, 302, 303, 307, 308, 401, 403].includes(response.status))
114
+ throw new CaptureError('E10_LOGIN_REQUIRED', '登录已失效,请重新执行 auth set');
115
+ if (!response.ok)
116
+ throw new CaptureError('PAGE_LIST_HTTP', `页面列表 HTTP ${response.status}`);
117
+ const payload = await response.json().catch(() => {
118
+ throw new CaptureError('PAGE_LIST_INVALID', '页面列表不是 JSON');
119
+ });
120
+ if ([401, 403, '401', '403'].includes(payload?.code))
121
+ throw new CaptureError('E10_LOGIN_REQUIRED', '登录已失效,请重新执行 auth set');
122
+ return parsePages(payload, appId, auth.baseUrl);
123
+ }
@@ -0,0 +1,124 @@
1
+ import type { Page, Frame, Request } from 'playwright-core';
2
+ export declare class Monitor {
3
+ readonly page: Page;
4
+ readonly origin: string;
5
+ readonly expectedPage?: {
6
+ id: string;
7
+ layoutType?: string;
8
+ } | undefined;
9
+ generation: number;
10
+ lastSample: unknown;
11
+ requestStarted: Map<Request, number>;
12
+ entranceAt: number;
13
+ pending: Set<Request>;
14
+ processing: Set<Promise<void>>;
15
+ processingRequests: Map<Request, Promise<void>>;
16
+ lastActivity: number;
17
+ epoch: number;
18
+ issues: {
19
+ path: string;
20
+ kind: string;
21
+ critical: boolean;
22
+ }[];
23
+ pageConfig?: {
24
+ id?: string;
25
+ componentCount?: number;
26
+ terminalMessage?: string;
27
+ layoutType?: string;
28
+ };
29
+ entrance: boolean;
30
+ constructor(page: Page, origin: string, expectedPage?: {
31
+ id: string;
32
+ layoutType?: string;
33
+ } | undefined);
34
+ touch(): void;
35
+ relevant(r: Request): boolean;
36
+ blocking(r: Request): boolean;
37
+ issue(r: Request, kind: string): void;
38
+ evidence(): {
39
+ lastSample: unknown;
40
+ pending: string[];
41
+ processing: number;
42
+ issues: {
43
+ path: string;
44
+ kind: string;
45
+ critical: boolean;
46
+ }[];
47
+ };
48
+ check(): void;
49
+ }
50
+ export declare function sample(page: Page, viewId: string, requireEntrance: boolean, monitor: Monitor): Promise<{
51
+ evidence: {
52
+ warnings: {
53
+ code: string;
54
+ message: string;
55
+ }[];
56
+ timeOrigin: number;
57
+ origin: string;
58
+ pathname: string;
59
+ root: boolean;
60
+ boundContent: boolean;
61
+ pageState: string;
62
+ rootSize: {
63
+ width: number;
64
+ height: number;
65
+ } | null;
66
+ readyState: DocumentReadyState;
67
+ loading: number;
68
+ error: number;
69
+ components: {
70
+ id: string;
71
+ type: string;
72
+ }[];
73
+ canvases: string[];
74
+ broken: number;
75
+ pendingImages: number;
76
+ fonts: FontFaceSetLoadStatus;
77
+ finiteAnimations: number;
78
+ virtual: number;
79
+ width: number;
80
+ height: number;
81
+ frames: number;
82
+ };
83
+ contentSignature: string;
84
+ signature: string;
85
+ ready: boolean;
86
+ }>;
87
+ export declare function ready(page: Page, viewId: string, monitor: Monitor, deadline: number, stableMs: number, requireEntrance?: boolean): Promise<{
88
+ evidence: {
89
+ warnings: {
90
+ code: string;
91
+ message: string;
92
+ }[];
93
+ timeOrigin: number;
94
+ origin: string;
95
+ pathname: string;
96
+ root: boolean;
97
+ boundContent: boolean;
98
+ pageState: string;
99
+ rootSize: {
100
+ width: number;
101
+ height: number;
102
+ } | null;
103
+ readyState: DocumentReadyState;
104
+ loading: number;
105
+ error: number;
106
+ components: {
107
+ id: string;
108
+ type: string;
109
+ }[];
110
+ canvases: string[];
111
+ broken: number;
112
+ pendingImages: number;
113
+ fonts: FontFaceSetLoadStatus;
114
+ finiteAnimations: number;
115
+ virtual: number;
116
+ width: number;
117
+ height: number;
118
+ frames: number;
119
+ };
120
+ contentSignature: string;
121
+ signature: string;
122
+ ready: boolean;
123
+ }>;
124
+ export declare function lazyScroll(page: Page | Frame, waitReady: () => Promise<unknown>): Promise<number>;