@docsxai/engine 0.2.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 (129) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +130 -0
  3. package/dist/auth/api-login.d.ts +69 -0
  4. package/dist/auth/api-login.js +95 -0
  5. package/dist/auth/browser-session.d.ts +28 -0
  6. package/dist/auth/browser-session.js +43 -0
  7. package/dist/auth/cookie-jar.d.ts +58 -0
  8. package/dist/auth/cookie-jar.js +212 -0
  9. package/dist/auth/email-otp.d.ts +210 -0
  10. package/dist/auth/email-otp.js +166 -0
  11. package/dist/auth/http-basic.d.ts +5 -0
  12. package/dist/auth/http-basic.js +17 -0
  13. package/dist/auth/index.d.ts +47 -0
  14. package/dist/auth/index.js +137 -0
  15. package/dist/auth/jwt-injection.d.ts +153 -0
  16. package/dist/auth/jwt-injection.js +136 -0
  17. package/dist/auth/manual-capture.d.ts +35 -0
  18. package/dist/auth/manual-capture.js +30 -0
  19. package/dist/auth/mtls.d.ts +15 -0
  20. package/dist/auth/mtls.js +53 -0
  21. package/dist/auth/pat-header.d.ts +19 -0
  22. package/dist/auth/pat-header.js +34 -0
  23. package/dist/auth/storage-state-cache.d.ts +38 -0
  24. package/dist/auth/storage-state-cache.js +143 -0
  25. package/dist/auth/test-backdoor.d.ts +25 -0
  26. package/dist/auth/test-backdoor.js +51 -0
  27. package/dist/auth/totp.d.ts +39 -0
  28. package/dist/auth/totp.js +108 -0
  29. package/dist/auth/types.d.ts +86 -0
  30. package/dist/auth/types.js +57 -0
  31. package/dist/auth/ui-form.d.ts +204 -0
  32. package/dist/auth/ui-form.js +153 -0
  33. package/dist/auth/webauthn.d.ts +88 -0
  34. package/dist/auth/webauthn.js +67 -0
  35. package/dist/auth.d.ts +1 -0
  36. package/dist/auth.js +3 -0
  37. package/dist/backend-client-contracts.d.ts +88 -0
  38. package/dist/backend-client-contracts.js +19 -0
  39. package/dist/backend-client-oauth-login.d.ts +7 -0
  40. package/dist/backend-client-oauth-login.js +90 -0
  41. package/dist/backend-client-state-cache.d.ts +73 -0
  42. package/dist/backend-client-state-cache.js +185 -0
  43. package/dist/backend-client-token.d.ts +18 -0
  44. package/dist/backend-client-token.js +94 -0
  45. package/dist/backend-client-transport.d.ts +66 -0
  46. package/dist/backend-client-transport.js +181 -0
  47. package/dist/backend-client.d.ts +5 -0
  48. package/dist/backend-client.js +18 -0
  49. package/dist/calibrate.d.ts +31 -0
  50. package/dist/calibrate.js +68 -0
  51. package/dist/cli-commands-authoring.d.ts +5 -0
  52. package/dist/cli-commands-authoring.js +403 -0
  53. package/dist/cli-commands-backend.d.ts +5 -0
  54. package/dist/cli-commands-backend.js +211 -0
  55. package/dist/cli-commands-docpack.d.ts +5 -0
  56. package/dist/cli-commands-docpack.js +280 -0
  57. package/dist/cli-commands-session.d.ts +4 -0
  58. package/dist/cli-commands-session.js +398 -0
  59. package/dist/cli-shared.d.ts +5 -0
  60. package/dist/cli-shared.js +45 -0
  61. package/dist/cli-usage.d.ts +1 -0
  62. package/dist/cli-usage.js +137 -0
  63. package/dist/cli.d.ts +2 -0
  64. package/dist/cli.js +77 -0
  65. package/dist/diagnose.d.ts +50 -0
  66. package/dist/diagnose.js +168 -0
  67. package/dist/diff-compute.d.ts +13 -0
  68. package/dist/diff-compute.js +378 -0
  69. package/dist/diff-report.d.ts +7 -0
  70. package/dist/diff-report.js +125 -0
  71. package/dist/diff-types.d.ts +125 -0
  72. package/dist/diff-types.js +15 -0
  73. package/dist/diff.d.ts +3 -0
  74. package/dist/diff.js +16 -0
  75. package/dist/doc-pack-io.d.ts +30 -0
  76. package/dist/doc-pack-io.js +182 -0
  77. package/dist/doc-pack.d.ts +1814 -0
  78. package/dist/doc-pack.js +328 -0
  79. package/dist/doctor-checks-plugins.d.ts +2 -0
  80. package/dist/doctor-checks-plugins.js +136 -0
  81. package/dist/doctor-checks.d.ts +56 -0
  82. package/dist/doctor-checks.js +367 -0
  83. package/dist/doctor.d.ts +7 -0
  84. package/dist/doctor.js +62 -0
  85. package/dist/export/adf.d.ts +57 -0
  86. package/dist/export/adf.js +323 -0
  87. package/dist/export/playwright-test.d.ts +26 -0
  88. package/dist/export/playwright-test.js +221 -0
  89. package/dist/flow-file.d.ts +21 -0
  90. package/dist/flow-file.js +180 -0
  91. package/dist/flow-lint.d.ts +24 -0
  92. package/dist/flow-lint.js +203 -0
  93. package/dist/flow-runtime.d.ts +113 -0
  94. package/dist/flow-runtime.js +273 -0
  95. package/dist/flow-tree.d.ts +19 -0
  96. package/dist/flow-tree.js +104 -0
  97. package/dist/index.d.ts +27 -0
  98. package/dist/index.js +31 -0
  99. package/dist/playwright-driver.d.ts +105 -0
  100. package/dist/playwright-driver.js +363 -0
  101. package/dist/playwright-instrumented-browser.d.ts +51 -0
  102. package/dist/playwright-instrumented-browser.js +189 -0
  103. package/dist/plugins/load.d.ts +22 -0
  104. package/dist/plugins/load.js +99 -0
  105. package/dist/plugins/lock.d.ts +40 -0
  106. package/dist/plugins/lock.js +122 -0
  107. package/dist/plugins/manifest.d.ts +70 -0
  108. package/dist/plugins/manifest.js +115 -0
  109. package/dist/plugins/plan.d.ts +51 -0
  110. package/dist/plugins/plan.js +279 -0
  111. package/dist/plugins/registry.d.ts +59 -0
  112. package/dist/plugins/registry.js +71 -0
  113. package/dist/plugins/runtime.d.ts +7 -0
  114. package/dist/plugins/runtime.js +27 -0
  115. package/dist/plugins/types.d.ts +58 -0
  116. package/dist/plugins/types.js +4 -0
  117. package/dist/plugins-cli.d.ts +1 -0
  118. package/dist/plugins-cli.js +191 -0
  119. package/dist/redact.d.ts +16 -0
  120. package/dist/redact.js +72 -0
  121. package/dist/style.d.ts +46 -0
  122. package/dist/style.js +151 -0
  123. package/dist/viewer-bin.d.ts +20 -0
  124. package/dist/viewer-bin.js +97 -0
  125. package/dist/workspace.d.ts +60 -0
  126. package/dist/workspace.js +172 -0
  127. package/dist/zip.d.ts +17 -0
  128. package/dist/zip.js +113 -0
  129. package/package.json +64 -0
@@ -0,0 +1,30 @@
1
+ import type { AnnotationsPayload, BlobRef, FlowsPayload, LocatorsPayload, ScreenshotsPayload, StylePayload } from "./backend-client.js";
2
+ export interface DocPackPayloads {
3
+ flows: FlowsPayload | null;
4
+ annotations: AnnotationsPayload | null;
5
+ screenshots: ScreenshotsPayload | null;
6
+ style: StylePayload | null;
7
+ locators: LocatorsPayload | null;
8
+ }
9
+ /** Read the workspace's doc pack from disk into the per-artifact payload shape the backend accepts. */
10
+ export declare function readDocPack(workspace: string): Promise<DocPackPayloads>;
11
+ export interface BlobUploader {
12
+ hasBlob(sha256: string): Promise<boolean>;
13
+ putBlob(data: Uint8Array): Promise<BlobRef>;
14
+ }
15
+ export interface BlobFetcher {
16
+ getBlob(sha256: string): Promise<Uint8Array>;
17
+ }
18
+ /** Upload the bytes behind a screenshots manifest, HEAD-probing first so shared blobs are skipped. */
19
+ export declare function uploadScreenshotBlobs(workspace: string, manifest: ScreenshotsPayload, blobs: BlobUploader): Promise<{
20
+ uploaded: number;
21
+ skipped: number;
22
+ }>;
23
+ /** Fetch the bytes behind a screenshots manifest, verifying each blob against its sha256. */
24
+ export declare function fetchScreenshotBlobs(manifest: ScreenshotsPayload, blobs: BlobFetcher): Promise<Record<string, Uint8Array>>;
25
+ export declare function writeDocPack(workspace: string, payloads: Partial<DocPackPayloads>, extras?: {
26
+ /** Screenshot bytes keyed by manifest path (from {@link fetchScreenshotBlobs}). */
27
+ screenshotBytes?: Record<string, Uint8Array>;
28
+ }): Promise<{
29
+ filesWritten: number;
30
+ }>;
@@ -0,0 +1,182 @@
1
+ // Serialise a workspace's on-disk doc pack into the backend's per-artifact payload shapes,
2
+ // and (for `pull`) deserialise the payloads back into workspace files.
3
+ //
4
+ // The backend treats payloads as opaque; the schemas here are the engine's own contract.
5
+ // Screenshot bytes travel as content-addressed blobs — the screenshots artifact carries only a
6
+ // sha256 manifest; `uploadScreenshotBlobs` / `fetchScreenshotBlobs` move the bytes.
7
+ import { createHash } from "node:crypto";
8
+ import { promises as fs } from "node:fs";
9
+ import * as path from "node:path";
10
+ import { resolveWorkspacePath, resolveWorkspacePathReal } from "./workspace.js";
11
+ /** Read the workspace's doc pack from disk into the per-artifact payload shape the backend accepts. */
12
+ export async function readDocPack(workspace) {
13
+ return {
14
+ flows: await readFlows(workspace),
15
+ annotations: await readAnnotations(workspace),
16
+ screenshots: await readScreenshots(workspace),
17
+ style: await readStyle(workspace),
18
+ locators: await readLocators(workspace),
19
+ };
20
+ }
21
+ async function readFlows(workspace) {
22
+ const dir = resolveWorkspacePath(workspace, "flows");
23
+ const entries = await fs.readdir(dir).catch(() => null);
24
+ if (!entries)
25
+ return null;
26
+ const yamls = entries.filter((e) => e.endsWith(".flow.yaml"));
27
+ if (yamls.length === 0)
28
+ return null;
29
+ const files = {};
30
+ for (const f of yamls) {
31
+ files[f] = await fs.readFile(resolveWorkspacePath(workspace, "flows", f), "utf8");
32
+ }
33
+ return { schema: "docsxai/flows@1", files };
34
+ }
35
+ async function readAnnotations(workspace) {
36
+ const docsDir = resolveWorkspacePath(workspace, "docs");
37
+ const flows = await fs.readdir(docsDir, { withFileTypes: true }).catch(() => []);
38
+ const files = {};
39
+ for (const ent of flows) {
40
+ if (!ent.isDirectory())
41
+ continue;
42
+ const annPath = resolveWorkspacePath(workspace, "docs", ent.name, "annotations.json");
43
+ const text = await fs.readFile(annPath, "utf8").catch(() => null);
44
+ if (text === null)
45
+ continue;
46
+ try {
47
+ files[`${ent.name}/annotations.json`] = JSON.parse(text);
48
+ }
49
+ catch {
50
+ // skip unparseable files (push surfaces them in lint output, not here)
51
+ }
52
+ }
53
+ if (Object.keys(files).length === 0)
54
+ return null;
55
+ return { schema: "docsxai/annotations-bundle@1", files };
56
+ }
57
+ async function readScreenshots(workspace) {
58
+ const docsDir = resolveWorkspacePath(workspace, "docs");
59
+ const flows = await fs.readdir(docsDir, { withFileTypes: true }).catch(() => []);
60
+ const files = {};
61
+ for (const ent of flows) {
62
+ if (!ent.isDirectory())
63
+ continue;
64
+ const screenDir = resolveWorkspacePath(workspace, "docs", ent.name, "screenshots");
65
+ const shots = await fs.readdir(screenDir).catch(() => null);
66
+ if (!shots)
67
+ continue;
68
+ for (const f of shots) {
69
+ if (!/\.(png|jpg|jpeg|webp)$/i.test(f))
70
+ continue;
71
+ const buf = await fs.readFile(resolveWorkspacePath(workspace, "docs", ent.name, "screenshots", f));
72
+ files[`${ent.name}/screenshots/${f}`] = {
73
+ sha256: createHash("sha256").update(buf).digest("hex"),
74
+ bytes: buf.byteLength,
75
+ };
76
+ }
77
+ }
78
+ if (Object.keys(files).length === 0)
79
+ return null;
80
+ return { schema: "docsxai/screenshots@2", files };
81
+ }
82
+ /** Upload the bytes behind a screenshots manifest, HEAD-probing first so shared blobs are skipped. */
83
+ export async function uploadScreenshotBlobs(workspace, manifest, blobs) {
84
+ let uploaded = 0;
85
+ let skipped = 0;
86
+ for (const [rel, ref] of Object.entries(manifest.files)) {
87
+ if (await blobs.hasBlob(ref.sha256)) {
88
+ skipped++;
89
+ continue;
90
+ }
91
+ const data = await fs.readFile(resolveWorkspacePath(workspace, "docs", rel));
92
+ const stored = await blobs.putBlob(data);
93
+ if (stored.sha256 !== ref.sha256) {
94
+ throw new Error(`screenshot ${rel} changed on disk between manifest and upload (sha256 ${ref.sha256} → ${stored.sha256})`);
95
+ }
96
+ uploaded++;
97
+ }
98
+ return { uploaded, skipped };
99
+ }
100
+ /** Fetch the bytes behind a screenshots manifest, verifying each blob against its sha256. */
101
+ export async function fetchScreenshotBlobs(manifest, blobs) {
102
+ const out = {};
103
+ for (const [rel, ref] of Object.entries(manifest.files)) {
104
+ const data = await blobs.getBlob(ref.sha256);
105
+ const sha256 = createHash("sha256").update(data).digest("hex");
106
+ if (sha256 !== ref.sha256) {
107
+ throw new Error(`blob for ${rel} failed integrity check (expected ${ref.sha256}, got ${sha256})`);
108
+ }
109
+ out[rel] = data;
110
+ }
111
+ return out;
112
+ }
113
+ async function readStyle(workspace) {
114
+ const yamlPath = resolveWorkspacePath(workspace, "docs", "style.yaml");
115
+ const jsonPath = resolveWorkspacePath(workspace, "docs", "style.json");
116
+ const yaml = await fs.readFile(yamlPath, "utf8").catch(() => null);
117
+ const jsonText = await fs.readFile(jsonPath, "utf8").catch(() => null);
118
+ if (yaml === null && jsonText === null)
119
+ return null;
120
+ const json = jsonText ? JSON.parse(jsonText) : null;
121
+ return { schema: "docsxai/style-bundle@1", yaml, json };
122
+ }
123
+ async function readLocators(workspace) {
124
+ const yamlPath = resolveWorkspacePath(workspace, "docs", "locators.yaml");
125
+ const yaml = await fs.readFile(yamlPath, "utf8").catch(() => null);
126
+ if (yaml === null)
127
+ return null;
128
+ return { schema: "docsxai/locators@1", yaml };
129
+ }
130
+ // --- write back (pull) ------------------------------------------------------
131
+ export async function writeDocPack(workspace, payloads, extras = {}) {
132
+ let n = 0;
133
+ // Pulled payload file names come from the backend — treat as untrusted and resolve with the
134
+ // symlink-aware variant before writing.
135
+ if (payloads.flows) {
136
+ await fs.mkdir(resolveWorkspacePath(workspace, "flows"), { recursive: true });
137
+ for (const [f, text] of Object.entries(payloads.flows.files)) {
138
+ await fs.writeFile(await resolveWorkspacePathReal(workspace, "flows", f), text, "utf8");
139
+ n++;
140
+ }
141
+ }
142
+ if (payloads.annotations) {
143
+ for (const [rel, json] of Object.entries(payloads.annotations.files)) {
144
+ const abs = await resolveWorkspacePathReal(workspace, "docs", rel);
145
+ await fs.mkdir(path.dirname(abs), { recursive: true });
146
+ await fs.writeFile(abs, JSON.stringify(json, null, 2) + "\n", "utf8");
147
+ n++;
148
+ }
149
+ }
150
+ if (payloads.screenshots && extras.screenshotBytes) {
151
+ for (const rel of Object.keys(payloads.screenshots.files)) {
152
+ const data = extras.screenshotBytes[rel];
153
+ if (!data)
154
+ continue;
155
+ const abs = await resolveWorkspacePathReal(workspace, "docs", rel);
156
+ await fs.mkdir(path.dirname(abs), { recursive: true });
157
+ await fs.writeFile(abs, data);
158
+ n++;
159
+ }
160
+ }
161
+ if (payloads.style) {
162
+ if (payloads.style.yaml !== null) {
163
+ const p = resolveWorkspacePath(workspace, "docs", "style.yaml");
164
+ await fs.mkdir(path.dirname(p), { recursive: true });
165
+ await fs.writeFile(p, payloads.style.yaml, "utf8");
166
+ n++;
167
+ }
168
+ if (payloads.style.json !== null) {
169
+ const p = resolveWorkspacePath(workspace, "docs", "style.json");
170
+ await fs.mkdir(path.dirname(p), { recursive: true });
171
+ await fs.writeFile(p, JSON.stringify(payloads.style.json, null, 2) + "\n", "utf8");
172
+ n++;
173
+ }
174
+ }
175
+ if (payloads.locators?.yaml) {
176
+ const p = resolveWorkspacePath(workspace, "docs", "locators.yaml");
177
+ await fs.mkdir(path.dirname(p), { recursive: true });
178
+ await fs.writeFile(p, payloads.locators.yaml, "utf8");
179
+ n++;
180
+ }
181
+ return { filesWritten: n };
182
+ }