@anydocs/core 1.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/dist/config/index.d.ts +2 -0
  2. package/dist/config/index.d.ts.map +1 -0
  3. package/dist/config/index.js +1 -0
  4. package/dist/config/project-config.d.ts +10 -0
  5. package/dist/config/project-config.d.ts.map +1 -0
  6. package/dist/config/project-config.js +52 -0
  7. package/dist/errors/domain-error.d.ts +12 -0
  8. package/dist/errors/domain-error.d.ts.map +1 -0
  9. package/dist/errors/domain-error.js +8 -0
  10. package/dist/errors/index.d.ts +3 -0
  11. package/dist/errors/index.d.ts.map +1 -0
  12. package/dist/errors/index.js +2 -0
  13. package/dist/errors/validation-error.d.ts +5 -0
  14. package/dist/errors/validation-error.d.ts.map +1 -0
  15. package/dist/errors/validation-error.js +7 -0
  16. package/dist/fs/api-source-repository.d.ts +16 -0
  17. package/dist/fs/api-source-repository.d.ts.map +1 -0
  18. package/dist/fs/api-source-repository.js +89 -0
  19. package/dist/fs/content-repository.d.ts +13 -0
  20. package/dist/fs/content-repository.d.ts.map +1 -0
  21. package/dist/fs/content-repository.js +171 -0
  22. package/dist/fs/docs-repository.d.ts +26 -0
  23. package/dist/fs/docs-repository.d.ts.map +1 -0
  24. package/dist/fs/docs-repository.js +270 -0
  25. package/dist/fs/index.d.ts +5 -0
  26. package/dist/fs/index.d.ts.map +1 -0
  27. package/dist/fs/index.js +4 -0
  28. package/dist/fs/project-paths.d.ts +4 -0
  29. package/dist/fs/project-paths.d.ts.map +1 -0
  30. package/dist/fs/project-paths.js +55 -0
  31. package/dist/index.d.ts +9 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +8 -0
  34. package/dist/publishing/build-artifacts.d.ts +4 -0
  35. package/dist/publishing/build-artifacts.d.ts.map +1 -0
  36. package/dist/publishing/build-artifacts.js +453 -0
  37. package/dist/publishing/build-openapi-artifacts.d.ts +3 -0
  38. package/dist/publishing/build-openapi-artifacts.d.ts.map +1 -0
  39. package/dist/publishing/build-openapi-artifacts.js +253 -0
  40. package/dist/publishing/index.d.ts +4 -0
  41. package/dist/publishing/index.d.ts.map +1 -0
  42. package/dist/publishing/index.js +3 -0
  43. package/dist/publishing/publication-filter.d.ts +22 -0
  44. package/dist/publishing/publication-filter.d.ts.map +1 -0
  45. package/dist/publishing/publication-filter.js +98 -0
  46. package/dist/schemas/api-source-schema.d.ts +3 -0
  47. package/dist/schemas/api-source-schema.d.ts.map +1 -0
  48. package/dist/schemas/api-source-schema.js +110 -0
  49. package/dist/schemas/docs-schema.d.ts +7 -0
  50. package/dist/schemas/docs-schema.d.ts.map +1 -0
  51. package/dist/schemas/docs-schema.js +212 -0
  52. package/dist/schemas/index.d.ts +4 -0
  53. package/dist/schemas/index.d.ts.map +1 -0
  54. package/dist/schemas/index.js +3 -0
  55. package/dist/schemas/project-schema.d.ts +3 -0
  56. package/dist/schemas/project-schema.d.ts.map +1 -0
  57. package/dist/schemas/project-schema.js +268 -0
  58. package/dist/services/authoring-service.d.ts +137 -0
  59. package/dist/services/authoring-service.d.ts.map +1 -0
  60. package/dist/services/authoring-service.js +583 -0
  61. package/dist/services/build-service.d.ts +35 -0
  62. package/dist/services/build-service.d.ts.map +1 -0
  63. package/dist/services/build-service.js +84 -0
  64. package/dist/services/index.d.ts +11 -0
  65. package/dist/services/index.d.ts.map +1 -0
  66. package/dist/services/index.js +10 -0
  67. package/dist/services/init-service.d.ts +15 -0
  68. package/dist/services/init-service.d.ts.map +1 -0
  69. package/dist/services/init-service.js +127 -0
  70. package/dist/services/legacy-conversion-service.d.ts +8 -0
  71. package/dist/services/legacy-conversion-service.d.ts.map +1 -0
  72. package/dist/services/legacy-conversion-service.js +601 -0
  73. package/dist/services/legacy-import-service.d.ts +10 -0
  74. package/dist/services/legacy-import-service.d.ts.map +1 -0
  75. package/dist/services/legacy-import-service.js +239 -0
  76. package/dist/services/page-template-service.d.ts +81 -0
  77. package/dist/services/page-template-service.d.ts.map +1 -0
  78. package/dist/services/page-template-service.js +342 -0
  79. package/dist/services/preview-service.d.ts +29 -0
  80. package/dist/services/preview-service.d.ts.map +1 -0
  81. package/dist/services/preview-service.js +45 -0
  82. package/dist/services/watch-service.d.ts +24 -0
  83. package/dist/services/watch-service.d.ts.map +1 -0
  84. package/dist/services/watch-service.js +216 -0
  85. package/dist/services/web-runtime-bridge.d.ts +33 -0
  86. package/dist/services/web-runtime-bridge.d.ts.map +1 -0
  87. package/dist/services/web-runtime-bridge.js +330 -0
  88. package/dist/services/workflow-compatibility-service.d.ts +3 -0
  89. package/dist/services/workflow-compatibility-service.d.ts.map +1 -0
  90. package/dist/services/workflow-compatibility-service.js +53 -0
  91. package/dist/services/workflow-standard-service.d.ts +9 -0
  92. package/dist/services/workflow-standard-service.d.ts.map +1 -0
  93. package/dist/services/workflow-standard-service.js +372 -0
  94. package/dist/types/api-source.d.ts +34 -0
  95. package/dist/types/api-source.d.ts.map +1 -0
  96. package/dist/types/api-source.js +8 -0
  97. package/dist/types/docs.d.ts +65 -0
  98. package/dist/types/docs.d.ts.map +1 -0
  99. package/dist/types/docs.js +8 -0
  100. package/dist/types/index.d.ts +6 -0
  101. package/dist/types/index.d.ts.map +1 -0
  102. package/dist/types/index.js +5 -0
  103. package/dist/types/legacy-import.d.ts +72 -0
  104. package/dist/types/legacy-import.d.ts.map +1 -0
  105. package/dist/types/legacy-import.js +1 -0
  106. package/dist/types/project.d.ts +85 -0
  107. package/dist/types/project.d.ts.map +1 -0
  108. package/dist/types/project.js +5 -0
  109. package/dist/types/workflow-standard.d.ts +51 -0
  110. package/dist/types/workflow-standard.d.ts.map +1 -0
  111. package/dist/types/workflow-standard.js +1 -0
  112. package/dist/utils/index.d.ts +4 -0
  113. package/dist/utils/index.d.ts.map +1 -0
  114. package/dist/utils/index.js +3 -0
  115. package/dist/utils/slug.d.ts +3 -0
  116. package/dist/utils/slug.d.ts.map +1 -0
  117. package/dist/utils/slug.js +21 -0
  118. package/dist/utils/yoopta-content.d.ts +13 -0
  119. package/dist/utils/yoopta-content.d.ts.map +1 -0
  120. package/dist/utils/yoopta-content.js +73 -0
  121. package/dist/utils/yoopta-render.d.ts +7 -0
  122. package/dist/utils/yoopta-render.d.ts.map +1 -0
  123. package/dist/utils/yoopta-render.js +155 -0
  124. package/package.json +30 -0
@@ -0,0 +1,330 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import { createServer } from 'node:net';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { ValidationError } from "../errors/validation-error.js";
8
+ const CORE_PACKAGE_ROOT = path.dirname(fileURLToPath(new URL('../index.ts', import.meta.url)));
9
+ let webRuntimeQueue = Promise.resolve();
10
+ const WEB_RUNTIME_LOCK_DIR = '.anydocs-web-runtime.lock';
11
+ const WEB_RUNTIME_LOCK_TIMEOUT_MS = 5 * 60000;
12
+ const WEB_RUNTIME_LOCK_POLL_MS = 250;
13
+ function resolveWebPackageRoot() {
14
+ const cwd = process.cwd();
15
+ const candidates = [
16
+ cwd,
17
+ path.join(cwd, 'packages', 'web'),
18
+ path.join(path.resolve(CORE_PACKAGE_ROOT, '../../..'), 'packages', 'web'),
19
+ ];
20
+ for (const candidate of candidates) {
21
+ if (existsSync(path.join(candidate, 'scripts', 'gen-public-assets.mjs'))) {
22
+ return candidate;
23
+ }
24
+ }
25
+ return path.join(path.resolve(CORE_PACKAGE_ROOT, '../../..'), 'packages', 'web');
26
+ }
27
+ const BRIDGE_ENV_ALLOWLIST = new Set([
28
+ 'CI',
29
+ 'COLORTERM',
30
+ 'FORCE_COLOR',
31
+ 'HOME',
32
+ 'LANG',
33
+ 'LC_ALL',
34
+ 'LC_CTYPE',
35
+ 'LOGNAME',
36
+ 'PATH',
37
+ 'PNPM_HOME',
38
+ 'SHELL',
39
+ 'TERM',
40
+ 'TMPDIR',
41
+ 'USER',
42
+ 'XDG_CACHE_HOME',
43
+ 'XDG_CONFIG_HOME',
44
+ ]);
45
+ function createRuntimeEnv(mode, options) {
46
+ const baseEnv = Object.fromEntries(Object.entries(process.env).filter(([key]) => BRIDGE_ENV_ALLOWLIST.has(key)));
47
+ return {
48
+ ...baseEnv,
49
+ NODE_ENV: mode === 'export' ? 'production' : 'development',
50
+ ANYDOCS_DOCS_RUNTIME: mode,
51
+ ANYDOCS_DOCS_PROJECT_ROOT: options.projectRoot,
52
+ ...(options.outputRoot ? { ANYDOCS_DOCS_OUTPUT_ROOT: options.outputRoot } : {}),
53
+ ANYDOCS_DISABLE_STUDIO: '1',
54
+ };
55
+ }
56
+ function formatBridgeFailure(command, exitCode, signal, stderr) {
57
+ const details = stderr.trim();
58
+ const suffix = details ? `\n${details}` : '';
59
+ return new Error(`${command} failed (exit=${exitCode ?? 'null'}, signal=${signal ?? 'null'}).${suffix}`);
60
+ }
61
+ function delay(ms) {
62
+ return new Promise((resolve) => setTimeout(resolve, ms));
63
+ }
64
+ function isNodeError(error) {
65
+ return typeof error === 'object' && error !== null && ('code' in error || 'message' in error);
66
+ }
67
+ function isPidAlive(pid) {
68
+ try {
69
+ process.kill(pid, 0);
70
+ return true;
71
+ }
72
+ catch (error) {
73
+ return isNodeError(error) && error.code === 'EPERM';
74
+ }
75
+ }
76
+ async function cleanupStaleFilesystemLock(lockDir) {
77
+ try {
78
+ const owner = JSON.parse(await readFile(path.join(lockDir, 'owner.json'), 'utf8'));
79
+ if (typeof owner.pid === 'number' && !isPidAlive(owner.pid)) {
80
+ await rm(lockDir, { recursive: true, force: true });
81
+ }
82
+ }
83
+ catch (error) {
84
+ if (isNodeError(error) && error.code === 'ENOENT') {
85
+ return;
86
+ }
87
+ throw error;
88
+ }
89
+ }
90
+ async function resolveNodeExecutable() {
91
+ const override = process.env.ANYDOCS_NODE_BINARY?.trim();
92
+ if (override) {
93
+ if (!path.isAbsolute(override)) {
94
+ return override;
95
+ }
96
+ await access(override);
97
+ return override;
98
+ }
99
+ return 'node';
100
+ }
101
+ function appendOutputTail(current, chunk, maxChars) {
102
+ const next = current + chunk;
103
+ return next.length > maxChars ? next.slice(-maxChars) : next;
104
+ }
105
+ function collectChildOutput(child, maxChars = 32000) {
106
+ let stdout = '';
107
+ let stderr = '';
108
+ child.stdout?.on('data', (chunk) => {
109
+ stdout = appendOutputTail(stdout, chunk.toString(), maxChars);
110
+ });
111
+ child.stderr?.on('data', (chunk) => {
112
+ stderr = appendOutputTail(stderr, chunk.toString(), maxChars);
113
+ });
114
+ return {
115
+ stdout: () => stdout,
116
+ stderr: () => stderr,
117
+ };
118
+ }
119
+ function shellEscapeArg(value) {
120
+ return `'${value.replace(/'/g, `'\\''`)}'`;
121
+ }
122
+ async function createBridgeChild(mode, args, options) {
123
+ const nodeExecutable = await resolveNodeExecutable();
124
+ const shell = process.env.SHELL || '/bin/zsh';
125
+ const webPackageRoot = resolveWebPackageRoot();
126
+ const webBridgeScript = path.join(webPackageRoot, 'scripts', 'gen-public-assets.mjs');
127
+ const command = ['exec', nodeExecutable, webBridgeScript, mode, ...args].map(shellEscapeArg).join(' ');
128
+ return spawn(shell, ['-lc', command], {
129
+ cwd: webPackageRoot,
130
+ env: createRuntimeEnv(mode, options),
131
+ stdio: options.stdio === 'inherit' ? 'inherit' : 'pipe',
132
+ });
133
+ }
134
+ function waitForChildExit(child) {
135
+ return new Promise((resolve) => {
136
+ child.once('exit', (exitCode, signal) => {
137
+ resolve({ exitCode, signal });
138
+ });
139
+ });
140
+ }
141
+ async function acquireFilesystemWebRuntimeLock() {
142
+ const lockDir = path.join(resolveWebPackageRoot(), WEB_RUNTIME_LOCK_DIR);
143
+ const ownerPath = path.join(lockDir, 'owner.json');
144
+ const deadline = Date.now() + WEB_RUNTIME_LOCK_TIMEOUT_MS;
145
+ while (true) {
146
+ try {
147
+ await mkdir(lockDir);
148
+ await writeFile(ownerPath, JSON.stringify({
149
+ pid: process.pid,
150
+ acquiredAt: new Date().toISOString(),
151
+ }), 'utf8');
152
+ let released = false;
153
+ return async () => {
154
+ if (released) {
155
+ return;
156
+ }
157
+ released = true;
158
+ await rm(lockDir, { recursive: true, force: true });
159
+ };
160
+ }
161
+ catch (error) {
162
+ if (!isNodeError(error) || error.code !== 'EEXIST') {
163
+ throw error;
164
+ }
165
+ await cleanupStaleFilesystemLock(lockDir);
166
+ if (Date.now() >= deadline) {
167
+ throw new Error(`Timed out waiting for the shared web runtime lock at "${lockDir}".`);
168
+ }
169
+ await delay(WEB_RUNTIME_LOCK_POLL_MS);
170
+ }
171
+ }
172
+ }
173
+ async function acquireWebRuntimeLock() {
174
+ const previous = webRuntimeQueue;
175
+ let releaseProcessQueue;
176
+ webRuntimeQueue = new Promise((resolve) => {
177
+ releaseProcessQueue = resolve;
178
+ });
179
+ await previous;
180
+ const releaseFilesystemLock = await acquireFilesystemWebRuntimeLock();
181
+ let released = false;
182
+ return async () => {
183
+ if (released) {
184
+ return;
185
+ }
186
+ released = true;
187
+ try {
188
+ await releaseFilesystemLock();
189
+ }
190
+ finally {
191
+ releaseProcessQueue();
192
+ }
193
+ };
194
+ }
195
+ export async function exportDocsSite(options) {
196
+ const releaseLock = await acquireWebRuntimeLock();
197
+ try {
198
+ const child = await createBridgeChild('export', [], options);
199
+ const output = collectChildOutput(child);
200
+ if (!child.stdout || !child.stderr) {
201
+ const result = await waitForChildExit(child);
202
+ if (result.exitCode !== 0) {
203
+ throw formatBridgeFailure('Docs site export', result.exitCode, result.signal, '');
204
+ }
205
+ return;
206
+ }
207
+ const result = await waitForChildExit(child);
208
+ if (result.exitCode !== 0) {
209
+ const stderr = [output.stderr().trim(), output.stdout().trim()].filter(Boolean).join('\n');
210
+ throw formatBridgeFailure('Docs site export', result.exitCode, result.signal, stderr);
211
+ }
212
+ }
213
+ finally {
214
+ await releaseLock();
215
+ }
216
+ }
217
+ async function pickAvailablePort(host) {
218
+ return new Promise((resolve, reject) => {
219
+ const server = createServer();
220
+ server.once('error', reject);
221
+ server.listen(0, host, () => {
222
+ const address = server.address();
223
+ if (!address || typeof address === 'string') {
224
+ server.close(() => reject(new Error('Failed to resolve an available preview port.')));
225
+ return;
226
+ }
227
+ const { port } = address;
228
+ server.close((closeError) => {
229
+ if (closeError) {
230
+ reject(closeError);
231
+ return;
232
+ }
233
+ resolve(port);
234
+ });
235
+ });
236
+ });
237
+ }
238
+ async function waitForPreviewServerReady(child, url, timeoutMs) {
239
+ const startedAt = Date.now();
240
+ const output = collectChildOutput(child);
241
+ while (Date.now() - startedAt < timeoutMs) {
242
+ if (child.exitCode !== null) {
243
+ const stderr = [output.stderr().trim(), output.stdout().trim()].filter(Boolean).join('\n');
244
+ throw formatBridgeFailure('Docs preview server', child.exitCode, null, stderr);
245
+ }
246
+ try {
247
+ const response = await fetch(url, { redirect: 'manual' });
248
+ if (response.status >= 200 && response.status < 400) {
249
+ return;
250
+ }
251
+ }
252
+ catch {
253
+ // Keep polling until timeout or process exit.
254
+ }
255
+ await new Promise((resolve) => setTimeout(resolve, 150));
256
+ }
257
+ child.kill('SIGTERM');
258
+ await waitForChildExit(child);
259
+ throw new Error(`Timed out waiting for docs preview server to become ready at ${url}.`);
260
+ }
261
+ export async function startDocsPreviewServer(options) {
262
+ const releaseLock = await acquireWebRuntimeLock();
263
+ try {
264
+ const host = options.host ?? '127.0.0.1';
265
+ const port = options.port ?? (await pickAvailablePort(host));
266
+ const readyPath = options.readyPath ?? '/';
267
+ const startTimeoutMs = options.startTimeoutMs ?? 30000;
268
+ const child = await createBridgeChild('preview', ['--hostname', host, '--port', String(port)], options);
269
+ const url = `http://${host}:${port}`;
270
+ const readyUrl = new URL(readyPath, `${url}/`).toString();
271
+ const exitPromise = waitForChildExit(child).finally(() => releaseLock());
272
+ await waitForPreviewServerReady(child, readyUrl, startTimeoutMs);
273
+ return {
274
+ child,
275
+ host,
276
+ port,
277
+ url,
278
+ stop: async () => {
279
+ if (child.exitCode !== null) {
280
+ await exitPromise;
281
+ return;
282
+ }
283
+ child.kill('SIGTERM');
284
+ await exitPromise;
285
+ },
286
+ waitUntilExit: () => exitPromise,
287
+ };
288
+ }
289
+ catch (error) {
290
+ await releaseLock();
291
+ throw error;
292
+ }
293
+ }
294
+ function isSameOrDescendantPath(candidatePath, parentPath) {
295
+ const relativePath = path.relative(parentPath, candidatePath);
296
+ return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));
297
+ }
298
+ export function assertSafeArtifactRoot(paths) {
299
+ const normalizedArtifactRoot = path.resolve(paths.artifactRoot);
300
+ const normalizedRepoRoot = path.resolve(paths.repoRoot);
301
+ const normalizedProjectRoot = path.resolve(paths.projectRoot);
302
+ if (normalizedArtifactRoot === normalizedRepoRoot || normalizedArtifactRoot === normalizedProjectRoot) {
303
+ throw new ValidationError(`Refusing to export the docs site into "${normalizedArtifactRoot}" because that would overwrite the project workspace.`, {
304
+ entity: 'artifact-root',
305
+ rule: 'artifact-root-must-not-overwrite-project-workspace',
306
+ remediation: 'Use the default dist directory or pass --output to a dedicated build output directory.',
307
+ metadata: { artifactRoot: normalizedArtifactRoot, repoRoot: normalizedRepoRoot, projectRoot: normalizedProjectRoot },
308
+ });
309
+ }
310
+ const protectedRoots = [
311
+ path.resolve(paths.pagesRoot),
312
+ path.resolve(paths.navigationRoot),
313
+ path.resolve(paths.importsRoot),
314
+ ];
315
+ const conflictingRoot = protectedRoots.find((protectedRoot) => isSameOrDescendantPath(normalizedArtifactRoot, protectedRoot));
316
+ if (!conflictingRoot) {
317
+ return;
318
+ }
319
+ throw new ValidationError(`Refusing to export the docs site into "${normalizedArtifactRoot}" because it overlaps source content at "${conflictingRoot}".`, {
320
+ entity: 'artifact-root',
321
+ rule: 'artifact-root-must-not-overlap-source-content',
322
+ remediation: 'Write build output to a dedicated directory such as dist/ or another folder outside pages/, navigation/, and imports/.',
323
+ metadata: {
324
+ artifactRoot: normalizedArtifactRoot,
325
+ conflictingRoot,
326
+ repoRoot: normalizedRepoRoot,
327
+ projectRoot: normalizedProjectRoot,
328
+ },
329
+ });
330
+ }
@@ -0,0 +1,3 @@
1
+ import type { WorkflowCompatibilityAssessment } from '../types/workflow-standard.ts';
2
+ export declare function assessWorkflowForwardCompatibility(repoRoot: string, projectId?: string): Promise<WorkflowCompatibilityAssessment>;
3
+ //# sourceMappingURL=workflow-compatibility-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-compatibility-service.d.ts","sourceRoot":"","sources":["../../src/services/workflow-compatibility-service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAC;AAoBrF,wBAAsB,kCAAkC,CACtD,QAAQ,EAAE,MAAM,EAChB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,+BAA+B,CAAC,CAiE1C"}
@@ -0,0 +1,53 @@
1
+ import { loadProjectContract } from "../fs/content-repository.js";
2
+ import { createWorkflowStandardDefinition, readWorkflowStandardDefinition, } from "./workflow-standard-service.js";
3
+ import { ValidationError } from "../errors/validation-error.js";
4
+ function createWorkflowCompatibilityError(rule, remediation, metadata) {
5
+ return new ValidationError(`Workflow compatibility validation failed for rule "${rule}".`, {
6
+ entity: 'workflow-compatibility',
7
+ rule,
8
+ remediation,
9
+ metadata,
10
+ });
11
+ }
12
+ export async function assessWorkflowForwardCompatibility(repoRoot, projectId) {
13
+ const contractResult = await loadProjectContract(repoRoot, projectId);
14
+ if (!contractResult.ok) {
15
+ throw contractResult.error;
16
+ }
17
+ const contract = contractResult.value;
18
+ const persisted = await readWorkflowStandardDefinition(contract.paths.workflowFile);
19
+ const expected = createWorkflowStandardDefinition(contract);
20
+ if (persisted.standardId !== expected.standardId) {
21
+ throw createWorkflowCompatibilityError('workflow-standard-compatible-standard-id', 'Regenerate the workflow standard so it matches the canonical phase 1 standard id.', { expected: expected.standardId, received: persisted.standardId });
22
+ }
23
+ if (persisted.projectContractVersion !== expected.projectContractVersion) {
24
+ throw createWorkflowCompatibilityError('workflow-standard-compatible-project-contract-version', 'Regenerate the workflow standard so it matches the current project contract version.', { expected: expected.projectContractVersion, received: persisted.projectContractVersion });
25
+ }
26
+ const persistedRequiredFields = [
27
+ ...persisted.contentModel.projectConfigFields,
28
+ ...persisted.contentModel.pageRequiredFields,
29
+ ...persisted.contentModel.navigationRequiredFields,
30
+ ];
31
+ const expectedRequiredFields = [
32
+ ...expected.contentModel.projectConfigFields,
33
+ ...expected.contentModel.pageRequiredFields,
34
+ ...expected.contentModel.navigationRequiredFields,
35
+ ];
36
+ const missingRequiredField = expectedRequiredFields.find((field) => !persistedRequiredFields.includes(field));
37
+ if (missingRequiredField) {
38
+ throw createWorkflowCompatibilityError('workflow-standard-compatible-required-fields', 'Regenerate the workflow standard so it includes the canonical required content-model fields.', { missingRequiredField });
39
+ }
40
+ const missingStep = expected.orchestration.workflowSteps.find((step) => !persisted.orchestration.workflowSteps.includes(step));
41
+ if (missingStep) {
42
+ throw createWorkflowCompatibilityError('workflow-standard-compatible-workflow-steps', 'Regenerate the workflow standard so it preserves the canonical orchestration steps.', { missingStep });
43
+ }
44
+ return {
45
+ compatible: true,
46
+ standardId: persisted.standardId,
47
+ projectContractVersion: persisted.projectContractVersion,
48
+ reusableAcrossProjects: true,
49
+ futureCompatibleWithoutReinitialization: true,
50
+ externalAutomationReady: true,
51
+ validatedAt: new Date().toISOString(),
52
+ };
53
+ }
@@ -0,0 +1,9 @@
1
+ import type { WorkflowStandardDefinition, WorkflowStandardExport } from '../types/workflow-standard.ts';
2
+ import type { ProjectContract } from '../types/project.ts';
3
+ export declare function validateWorkflowStandardDefinition(input: unknown): WorkflowStandardDefinition;
4
+ export declare function readWorkflowStandardDefinition(workflowFile: string): Promise<WorkflowStandardDefinition>;
5
+ export declare function assertWorkflowStandardMatchesContract(definition: WorkflowStandardDefinition, contract: ProjectContract): void;
6
+ export declare function createWorkflowStandardDefinition(contract: ProjectContract): WorkflowStandardDefinition;
7
+ export declare function renderWorkflowStandardGuide(definition: WorkflowStandardDefinition): string;
8
+ export declare function exportWorkflowStandard(contract: ProjectContract): WorkflowStandardExport;
9
+ //# sourceMappingURL=workflow-standard-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workflow-standard-service.d.ts","sourceRoot":"","sources":["../../src/services/workflow-standard-service.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,0BAA0B,EAC1B,sBAAsB,EAEvB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AA6K3D,wBAAgB,kCAAkC,CAAC,KAAK,EAAE,OAAO,GAAG,0BAA0B,CAgJ7F;AA8DD,wBAAsB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,0BAA0B,CAAC,CAyB9G;AAED,wBAAgB,qCAAqC,CACnD,UAAU,EAAE,0BAA0B,EACtC,QAAQ,EAAE,eAAe,GACxB,IAAI,CA0BN;AAED,wBAAgB,gCAAgC,CAC9C,QAAQ,EAAE,eAAe,GACxB,0BAA0B,CAkC5B;AAED,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,0BAA0B,GAAG,MAAM,CAwC1F;AAED,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,eAAe,GAAG,sBAAsB,CAOxF"}