@micacms/runtime 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 (110) hide show
  1. package/README.md +16 -0
  2. package/dist/app.d.ts +62 -0
  3. package/dist/app.d.ts.map +1 -0
  4. package/dist/app.js +107 -0
  5. package/dist/app.js.map +1 -0
  6. package/dist/config.d.ts +187 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +154 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/context.d.ts +121 -0
  11. package/dist/context.d.ts.map +1 -0
  12. package/dist/context.js +117 -0
  13. package/dist/context.js.map +1 -0
  14. package/dist/db/driver.d.ts +35 -0
  15. package/dist/db/driver.d.ts.map +1 -0
  16. package/dist/db/driver.js +95 -0
  17. package/dist/db/driver.js.map +1 -0
  18. package/dist/http.d.ts +40 -0
  19. package/dist/http.d.ts.map +1 -0
  20. package/dist/http.js +38 -0
  21. package/dist/http.js.map +1 -0
  22. package/dist/index.d.ts +31 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +31 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/lib/errors.d.ts +39 -0
  27. package/dist/lib/errors.d.ts.map +1 -0
  28. package/dist/lib/errors.js +52 -0
  29. package/dist/lib/errors.js.map +1 -0
  30. package/dist/lib/file-type.d.ts +26 -0
  31. package/dist/lib/file-type.d.ts.map +1 -0
  32. package/dist/lib/file-type.js +89 -0
  33. package/dist/lib/file-type.js.map +1 -0
  34. package/dist/lib/git.d.ts +29 -0
  35. package/dist/lib/git.d.ts.map +1 -0
  36. package/dist/lib/git.js +62 -0
  37. package/dist/lib/git.js.map +1 -0
  38. package/dist/lib/id.d.ts +13 -0
  39. package/dist/lib/id.d.ts.map +1 -0
  40. package/dist/lib/id.js +56 -0
  41. package/dist/lib/id.js.map +1 -0
  42. package/dist/lib/logger.d.ts +20 -0
  43. package/dist/lib/logger.d.ts.map +1 -0
  44. package/dist/lib/logger.js +65 -0
  45. package/dist/lib/logger.js.map +1 -0
  46. package/dist/lib/ports.d.ts +17 -0
  47. package/dist/lib/ports.d.ts.map +1 -0
  48. package/dist/lib/ports.js +17 -0
  49. package/dist/lib/ports.js.map +1 -0
  50. package/dist/lib/rate-limit.d.ts +29 -0
  51. package/dist/lib/rate-limit.d.ts.map +1 -0
  52. package/dist/lib/rate-limit.js +47 -0
  53. package/dist/lib/rate-limit.js.map +1 -0
  54. package/dist/lib/schema-stats.d.ts +64 -0
  55. package/dist/lib/schema-stats.d.ts.map +1 -0
  56. package/dist/lib/schema-stats.js +103 -0
  57. package/dist/lib/schema-stats.js.map +1 -0
  58. package/dist/lib/version.d.ts +14 -0
  59. package/dist/lib/version.d.ts.map +1 -0
  60. package/dist/lib/version.js +25 -0
  61. package/dist/lib/version.js.map +1 -0
  62. package/dist/middleware/index.d.ts +41 -0
  63. package/dist/middleware/index.d.ts.map +1 -0
  64. package/dist/middleware/index.js +142 -0
  65. package/dist/middleware/index.js.map +1 -0
  66. package/dist/routes/admin-content.d.ts +22 -0
  67. package/dist/routes/admin-content.d.ts.map +1 -0
  68. package/dist/routes/admin-content.js +194 -0
  69. package/dist/routes/admin-content.js.map +1 -0
  70. package/dist/routes/admin-media.d.ts +19 -0
  71. package/dist/routes/admin-media.d.ts.map +1 -0
  72. package/dist/routes/admin-media.js +81 -0
  73. package/dist/routes/admin-media.js.map +1 -0
  74. package/dist/routes/admin-spa.d.ts +13 -0
  75. package/dist/routes/admin-spa.d.ts.map +1 -0
  76. package/dist/routes/admin-spa.js +72 -0
  77. package/dist/routes/admin-spa.js.map +1 -0
  78. package/dist/routes/admin-staging.d.ts +15 -0
  79. package/dist/routes/admin-staging.d.ts.map +1 -0
  80. package/dist/routes/admin-staging.js +90 -0
  81. package/dist/routes/admin-staging.js.map +1 -0
  82. package/dist/routes/admin-system.d.ts +14 -0
  83. package/dist/routes/admin-system.d.ts.map +1 -0
  84. package/dist/routes/admin-system.js +153 -0
  85. package/dist/routes/admin-system.js.map +1 -0
  86. package/dist/routes/health.d.ts +12 -0
  87. package/dist/routes/health.d.ts.map +1 -0
  88. package/dist/routes/health.js +44 -0
  89. package/dist/routes/health.js.map +1 -0
  90. package/dist/schema.d.ts +56 -0
  91. package/dist/schema.d.ts.map +1 -0
  92. package/dist/schema.js +173 -0
  93. package/dist/schema.js.map +1 -0
  94. package/dist/server.d.ts +28 -0
  95. package/dist/server.d.ts.map +1 -0
  96. package/dist/server.js +47 -0
  97. package/dist/server.js.map +1 -0
  98. package/dist/services/media.d.ts +65 -0
  99. package/dist/services/media.d.ts.map +1 -0
  100. package/dist/services/media.js +180 -0
  101. package/dist/services/media.js.map +1 -0
  102. package/dist/services/staging-local.d.ts +58 -0
  103. package/dist/services/staging-local.d.ts.map +1 -0
  104. package/dist/services/staging-local.js +391 -0
  105. package/dist/services/staging-local.js.map +1 -0
  106. package/dist/services/staging.d.ts +167 -0
  107. package/dist/services/staging.d.ts.map +1 -0
  108. package/dist/services/staging.js +333 -0
  109. package/dist/services/staging.js.map +1 -0
  110. package/package.json +49 -0
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Working-tree staging: local mode's half of the staging service.
3
+ *
4
+ * The checked-out working tree *is* the draft workspace. Autosave has already
5
+ * written the files — that is what lets the Astro dev server hot-reload them,
6
+ * which is the whole value of local mode — so this service's job is reading
7
+ * what Git thinks of the tree and, on Publish, turning exactly the reviewed
8
+ * paths into one commit and one push.
9
+ *
10
+ * Three rules keep it safe in a repository that belongs to a developer:
11
+ *
12
+ * - Only Mica-managed paths. Every Git operation is limited to an explicit
13
+ * path set derived from the change list — never `git add -A` over the
14
+ * repository, so unrelated work in the same checkout is never swept in.
15
+ * - HEAD is verified against the base the editor reviewed. A repository
16
+ * that moved refuses, like a provider branch that moved.
17
+ * - A commit and a push are two operations. When the push fails the commit
18
+ * is retained and reported as `committed-pending-push`; a retry pushes
19
+ * again and never creates a second commit.
20
+ */
21
+ import { realpath, rm } from "node:fs/promises";
22
+ import { join, relative, sep } from "node:path";
23
+ import { MANIFEST_PATH, memorySource, } from "@micacms/core";
24
+ import { within } from "@micacms/core/node";
25
+ import { ApiError, badRequest } from "../lib/errors.js";
26
+ import { firstLine, gitRunner, GitError } from "../lib/git.js";
27
+ import { analyseChanges, compareSources, describeProblems, flattenProblems, } from "./staging.js";
28
+ export function createWorkingTreeStagingService(deps) {
29
+ const { model, connector, contentRoot, logger } = deps;
30
+ // One Git mutation at a time. Editing is untouched — autosave writes files,
31
+ // not Git — this only refuses to interleave two commits or pushes.
32
+ let running = false;
33
+ /**
34
+ * Finds the repository the content root sits in, freshly each time: a
35
+ * `git init` after startup should start working, not require a restart.
36
+ */
37
+ const locate = async () => {
38
+ const probe = gitRunner(contentRoot);
39
+ try {
40
+ const repoRoot = await probe.run(["rev-parse", "--show-toplevel"]);
41
+ // Git reports the toplevel with symlinks resolved (`/private/var` where
42
+ // the caller said `/var`, on macOS). Resolve our side the same way, or
43
+ // the relative prefix walks out of the repository.
44
+ const resolved = await realpath(contentRoot);
45
+ return { git: gitRunner(repoRoot), prefix: toPosix(relative(repoRoot, resolved)) };
46
+ }
47
+ catch (error) {
48
+ return {
49
+ reason: error instanceof GitError && error.exitCode === null
50
+ ? error.message
51
+ : "The content directory is not inside a Git repository.",
52
+ };
53
+ }
54
+ };
55
+ const listChanges = async (workspace) => {
56
+ // `-uall` because Git collapses a fully-untracked directory to one line,
57
+ // and a brand-new entry is exactly that. The change list must name files.
58
+ const raw = await workspace.git.run([
59
+ "status",
60
+ "--porcelain=v1",
61
+ "-z",
62
+ "-uall",
63
+ "--",
64
+ workspace.prefix === "" ? "." : workspace.prefix,
65
+ ]);
66
+ return parseStatus(raw, workspace.prefix);
67
+ };
68
+ const analyse = async (treeChanges) => {
69
+ const { changes, validation } = await analyseChanges(model, connector, treeChanges);
70
+ // A merge conflict is a validity problem the field validator cannot see:
71
+ // the file on disk is Git's conflict format, not content.
72
+ for (const change of treeChanges) {
73
+ if (!change.conflicted)
74
+ continue;
75
+ validation.problems.push({
76
+ path: change.path,
77
+ label: change.path,
78
+ issues: [
79
+ { path: "", message: "This file has a Git merge conflict. Resolve it with your Git tools." },
80
+ ],
81
+ });
82
+ }
83
+ validation.ok = validation.problems.length === 0;
84
+ return { changes, validation };
85
+ };
86
+ const guardPublishable = async () => {
87
+ if (!deps.publishEnabled) {
88
+ throw badRequest("Publishing from local mode is disabled (MICA_LOCAL_PUBLISH=false).");
89
+ }
90
+ const located = await locate();
91
+ if ("reason" in located)
92
+ throw badRequest(located.reason);
93
+ return located;
94
+ };
95
+ /** Runs `fn` holding the one-mutation-at-a-time flag. */
96
+ const exclusive = async (fn) => {
97
+ if (running) {
98
+ throw new ApiError("conflict", "A publication is already running. Wait for it to finish.");
99
+ }
100
+ running = true;
101
+ try {
102
+ return await fn();
103
+ }
104
+ finally {
105
+ running = false;
106
+ }
107
+ };
108
+ const pushOutcome = async (git, revision) => {
109
+ try {
110
+ await git.run(["push"]);
111
+ return { state: "published", revision };
112
+ }
113
+ catch (error) {
114
+ // The commit is real and retained; only the second half failed. This is
115
+ // a state, not an exception — the editor shows it and offers a retry.
116
+ const pushError = error instanceof GitError ? error.message : String(error);
117
+ logger.warn("Publish committed but the push failed", { revision, pushError });
118
+ return { state: "committed-pending-push", revision, pushError };
119
+ }
120
+ };
121
+ return {
122
+ async status() {
123
+ const located = await locate();
124
+ if ("reason" in located) {
125
+ return {
126
+ workspace: "working-tree",
127
+ publish: { enabled: false, reason: located.reason },
128
+ baseRevision: null,
129
+ branch: null,
130
+ ahead: null,
131
+ changes: [],
132
+ validation: emptyValidation(),
133
+ updatedAt: null,
134
+ };
135
+ }
136
+ const treeChanges = await listChanges(located);
137
+ const { changes, validation } = await analyse(treeChanges);
138
+ return {
139
+ workspace: "working-tree",
140
+ publish: deps.publishEnabled
141
+ ? { enabled: true }
142
+ : { enabled: false, reason: "Disabled with MICA_LOCAL_PUBLISH=false." },
143
+ baseRevision: await located.git.tryRun(["rev-parse", "HEAD"]),
144
+ branch: await located.git.tryRun(["rev-parse", "--abbrev-ref", "HEAD"]),
145
+ ahead: await aheadOfUpstream(located.git),
146
+ changes,
147
+ validation,
148
+ updatedAt: null,
149
+ };
150
+ },
151
+ async publish(input) {
152
+ const message = input.message.trim();
153
+ if (!message)
154
+ throw badRequest("A publication needs a commit message.");
155
+ const workspace = await guardPublishable();
156
+ return exclusive(async () => {
157
+ const treeChanges = await listChanges(workspace);
158
+ if (treeChanges.length === 0)
159
+ throw badRequest("There is nothing to publish.");
160
+ /**
161
+ * The reviewed base. The working tree has no per-path gate the way a
162
+ * provider commit does — the tree is already the truth — so the gate
163
+ * is HEAD: if the repository moved since the editor reviewed the
164
+ * change list, what a commit would be based on is not what they saw.
165
+ */
166
+ const head = await workspace.git.tryRun(["rev-parse", "HEAD"]);
167
+ if (input.expectedBase !== head) {
168
+ throw new ApiError("conflict", "The repository moved while these changes were being reviewed. Refresh the " +
169
+ "change list and publish again.");
170
+ }
171
+ // The model drift gate — same rule as the draft store: the staged set
172
+ // was validated against the model this process started with.
173
+ if ((await connector.revision(MANIFEST_PATH)) !== deps.schemaRevision) {
174
+ throw new ApiError("conflict", "The content model changed after this server started. Restart Mica to load " +
175
+ "the new model, then review the pending changes and publish again.");
176
+ }
177
+ const { validation } = await analyse(treeChanges);
178
+ if (!validation.ok) {
179
+ throw new ApiError("validation_failed", describeProblems(validation.problems), {
180
+ issues: flattenProblems(validation.problems),
181
+ });
182
+ }
183
+ const paths = treeChanges.map((change) => inRepo(workspace.prefix, change.path));
184
+ try {
185
+ // Stage and commit exactly the reviewed set. The pathspec limits
186
+ // both operations, so anything else in the developer's index or
187
+ // tree — staged or not — stays theirs.
188
+ for (const batch of chunked(paths, 500)) {
189
+ await workspace.git.run(["add", "-A", "--", ...batch]);
190
+ }
191
+ await workspace.git.run(["commit", "-m", message, "--", ...paths]);
192
+ }
193
+ catch (error) {
194
+ if (error instanceof GitError) {
195
+ // Git's own verdict is the actionable part: no identity
196
+ // configured, a hook that refused, an unborn branch mid-rebase.
197
+ throw new ApiError("conflict", `Git refused the commit: ${error.message}`);
198
+ }
199
+ throw error;
200
+ }
201
+ const revision = await workspace.git.run(["rev-parse", "HEAD"]);
202
+ logger.info("Published from the working tree", { revision, files: paths.length });
203
+ return pushOutcome(workspace.git, revision);
204
+ });
205
+ },
206
+ async push() {
207
+ const workspace = await guardPublishable();
208
+ return exclusive(async () => {
209
+ const revision = await workspace.git.tryRun(["rev-parse", "HEAD"]);
210
+ if (revision === null)
211
+ throw badRequest("There is no commit to push yet.");
212
+ return pushOutcome(workspace.git, revision);
213
+ });
214
+ },
215
+ async discard(requested) {
216
+ const located = await locate();
217
+ if ("reason" in located)
218
+ throw badRequest(located.reason);
219
+ return exclusive(async () => {
220
+ // Only paths the change list actually names. Discard is the one
221
+ // destructive operation here, and it must not be able to reach
222
+ // anything the editor was not shown.
223
+ const current = new Map((await listChanges(located)).map((change) => [change.path, change]));
224
+ const discarded = [];
225
+ for (const path of requested) {
226
+ const change = current.get(path);
227
+ if (!change)
228
+ continue;
229
+ if (change.kind === "create") {
230
+ // Nothing to restore: before this change there was no file. A
231
+ // creation the developer had already staged is unstaged first,
232
+ // so the index does not keep pointing at a file that is gone.
233
+ if (!change.untracked) {
234
+ await located.git.tryRun([
235
+ "rm",
236
+ "--cached",
237
+ "--force",
238
+ "--",
239
+ inRepo(located.prefix, path),
240
+ ]);
241
+ }
242
+ await rm(within(contentRoot, path), { force: true });
243
+ }
244
+ else {
245
+ await located.git.run([
246
+ "restore",
247
+ "--source=HEAD",
248
+ "--staged",
249
+ "--worktree",
250
+ "--",
251
+ inRepo(located.prefix, path),
252
+ ]);
253
+ }
254
+ discarded.push(path);
255
+ }
256
+ return { discarded };
257
+ });
258
+ },
259
+ async compare(target) {
260
+ const located = await locate();
261
+ // Without a repository (or before the first commit) nothing has ever
262
+ // been published, so the honest "before" is a source with no files.
263
+ const published = "reason" in located ? memorySource({}, "unpublished") : headSource(located);
264
+ return compareSources(model, published, connector, target);
265
+ },
266
+ };
267
+ }
268
+ /**
269
+ * The content root as HEAD has it — the published side of a comparison.
270
+ *
271
+ * Reading `HEAD:` rather than the tree is the point: the working tree *is*
272
+ * the draft workspace here, so the repository's own version of a document
273
+ * only exists in Git's object store.
274
+ */
275
+ function headSource(workspace) {
276
+ const at = (path) => `HEAD:${path === "" ? workspace.prefix : inRepo(workspace.prefix, path)}`;
277
+ return {
278
+ origin: "HEAD",
279
+ async read(path) {
280
+ // tryRun, because "not in HEAD" and "no commits yet" both simply mean
281
+ // there is no published version. Stdout arrives trimmed, which the
282
+ // entry parsers already tolerate.
283
+ return workspace.git.tryRun(["show", at(path)]);
284
+ },
285
+ async list(path) {
286
+ const raw = await workspace.git.tryRun(["ls-tree", "-z", at(path)]);
287
+ if (raw === null)
288
+ return [];
289
+ const entries = [];
290
+ for (const field of raw.split("\0")) {
291
+ const tab = field.indexOf("\t");
292
+ if (tab === -1)
293
+ continue;
294
+ const type = field.slice(0, tab).split(" ")[1];
295
+ entries.push({ name: field.slice(tab + 1), type: type === "tree" ? "directory" : "file" });
296
+ }
297
+ return entries;
298
+ },
299
+ };
300
+ }
301
+ /* ------------------------------------------------------------------ */
302
+ function emptyValidation() {
303
+ return { ok: true, problems: [] };
304
+ }
305
+ function toPosix(path) {
306
+ return sep === "/" ? path : path.split(sep).join("/");
307
+ }
308
+ /** A content-root-relative path as Git sees it, from the repository root. */
309
+ function inRepo(prefix, path) {
310
+ return prefix === "" ? path : join(prefix, path).split(sep).join("/");
311
+ }
312
+ function chunked(items, size) {
313
+ const batches = [];
314
+ for (let at = 0; at < items.length; at += size)
315
+ batches.push(items.slice(at, at + size));
316
+ return batches;
317
+ }
318
+ /** Commits waiting to be pushed, or null when there is no upstream to say. */
319
+ async function aheadOfUpstream(git) {
320
+ const counted = await git.tryRun(["rev-list", "--count", "@{upstream}..HEAD"]);
321
+ if (counted === null)
322
+ return null;
323
+ const ahead = Number(counted);
324
+ return Number.isFinite(ahead) ? ahead : null;
325
+ }
326
+ /**
327
+ * Parses `git status --porcelain=v1 -z` into content-root-relative changes.
328
+ *
329
+ * The `-z` format is the one that never munges a path: entries are
330
+ * NUL-terminated, and a rename is two fields — the new path, then the one it
331
+ * came from. A rename becomes a create and a delete, which is how the rest of
332
+ * Mica already thinks about moves.
333
+ *
334
+ * `.mica/` is excluded. The manifest there is build output a developer
335
+ * commits with their own tools; the editor neither shows nor publishes it,
336
+ * and model changes are guarded separately, by the drift check.
337
+ */
338
+ export function parseStatus(raw, prefix) {
339
+ const fields = raw.split("\0").filter((field) => field !== "");
340
+ const changes = [];
341
+ const push = (repoPath, kind, flags = {}) => {
342
+ const path = relativeToContent(repoPath, prefix);
343
+ if (path === null || path === ".mica" || path.startsWith(".mica/"))
344
+ return;
345
+ changes.push({
346
+ path,
347
+ kind,
348
+ untracked: flags.untracked ?? false,
349
+ conflicted: flags.conflicted ?? false,
350
+ });
351
+ };
352
+ for (let at = 0; at < fields.length; at += 1) {
353
+ const field = fields[at];
354
+ const x = field[0] ?? " ";
355
+ const y = field[1] ?? " ";
356
+ const repoPath = field.slice(3);
357
+ if (x === "?" && y === "?") {
358
+ push(repoPath, "create", { untracked: true });
359
+ continue;
360
+ }
361
+ // Both sides touched it in a merge, or one side deleted while the other
362
+ // edited: the file is in Git's conflict state, whatever the tree holds.
363
+ if (x === "U" || y === "U" || (x === "A" && y === "A") || (x === "D" && y === "D")) {
364
+ push(repoPath, "update", { conflicted: true });
365
+ continue;
366
+ }
367
+ if (x === "R" || x === "C") {
368
+ // The next field is the source path. A copy keeps its source; a rename
369
+ // loses it, which the status letters already said (C keeps both files).
370
+ const from = fields[++at];
371
+ push(repoPath, "create");
372
+ if (x === "R")
373
+ push(from, "delete");
374
+ continue;
375
+ }
376
+ if (x === "D" || y === "D") {
377
+ push(repoPath, "delete");
378
+ continue;
379
+ }
380
+ push(repoPath, x === "A" ? "create" : "update");
381
+ }
382
+ return changes;
383
+ }
384
+ function relativeToContent(repoPath, prefix) {
385
+ if (prefix === "")
386
+ return repoPath;
387
+ if (repoPath === prefix)
388
+ return null;
389
+ return repoPath.startsWith(`${prefix}/`) ? repoPath.slice(prefix.length + 1) : null;
390
+ }
391
+ //# sourceMappingURL=staging-local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staging-local.js","sourceRoot":"","sources":["../../src/services/staging-local.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAGhD,OAAO,EACL,aAAa,EACb,YAAY,GAMb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAkB,MAAM,eAAe,CAAC;AAE/E,OAAO,EACL,cAAc,EACd,cAAc,EACd,gBAAgB,EAChB,eAAe,GAOhB,MAAM,cAAc,CAAC;AA6BtB,MAAM,UAAU,+BAA+B,CAC7C,IAA4B;IAE5B,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAEvD,4EAA4E;IAC5E,mEAAmE;IACnE,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB;;;OAGG;IACH,MAAM,MAAM,GAAG,KAAK,IAA6C,EAAE;QACjE,MAAM,KAAK,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC;QACrC,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC,CAAC;YACnE,wEAAwE;YACxE,uEAAuE;YACvE,mDAAmD;YACnD,MAAM,QAAQ,GAAG,MAAM,QAAQ,CAAC,WAAW,CAAC,CAAC;YAC7C,OAAO,EAAE,GAAG,EAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC;QACrF,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,MAAM,EACJ,KAAK,YAAY,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI;oBAClD,CAAC,CAAC,KAAK,CAAC,OAAO;oBACf,CAAC,CAAC,uDAAuD;aAC9D,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,EAAE,SAAoB,EAAyB,EAAE;QACxE,yEAAyE;QACzE,0EAA0E;QAC1E,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;YAClC,QAAQ;YACR,gBAAgB;YAChB,IAAI;YACJ,OAAO;YACP,IAAI;YACJ,SAAS,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM;SACjD,CAAC,CAAC;QACH,OAAO,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC,CAAC;IAEF,MAAM,OAAO,GAAG,KAAK,EAAE,WAAyB,EAAE,EAAE;QAClD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;QAEpF,yEAAyE;QACzE,0DAA0D;QAC1D,KAAK,MAAM,MAAM,IAAI,WAAW,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,CAAC,UAAU;gBAAE,SAAS;YACjC,UAAU,CAAC,QAAQ,CAAC,IAAI,CAAC;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,KAAK,EAAE,MAAM,CAAC,IAAI;gBAClB,MAAM,EAAE;oBACN,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,qEAAqE,EAAE;iBAC7F;aACF,CAAC,CAAC;QACL,CAAC;QACD,UAAU,CAAC,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;QAEjD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,CAAC;IACjC,CAAC,CAAC;IAEF,MAAM,gBAAgB,GAAG,KAAK,IAAwB,EAAE;QACtD,IAAI,CAAC,IAAI,CAAC,cAAc,EAAE,CAAC;YACzB,MAAM,UAAU,CAAC,oEAAoE,CAAC,CAAC;QACzF,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;QAC/B,IAAI,QAAQ,IAAI,OAAO;YAAE,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;QAC1D,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;IAEF,yDAAyD;IACzD,MAAM,SAAS,GAAG,KAAK,EAAK,EAAoB,EAAc,EAAE;QAC9D,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,0DAA0D,CAAC,CAAC;QAC7F,CAAC;QACD,OAAO,GAAG,IAAI,CAAC;QACf,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,OAAO,GAAG,KAAK,CAAC;QAClB,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,WAAW,GAAG,KAAK,EAAE,GAAc,EAAE,QAAgB,EAA0B,EAAE;QACrF,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;YACxB,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC;QAC1C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,wEAAwE;YACxE,sEAAsE;YACtE,MAAM,SAAS,GAAG,KAAK,YAAY,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5E,MAAM,CAAC,IAAI,CAAC,uCAAuC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;YAC9E,OAAO,EAAE,KAAK,EAAE,wBAAwB,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QAClE,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,MAAM;YACV,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;YAE/B,IAAI,QAAQ,IAAI,OAAO,EAAE,CAAC;gBACxB,OAAO;oBACL,SAAS,EAAE,cAAc;oBACzB,OAAO,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;oBACnD,YAAY,EAAE,IAAI;oBAClB,MAAM,EAAE,IAAI;oBACZ,KAAK,EAAE,IAAI;oBACX,OAAO,EAAE,EAAE;oBACX,UAAU,EAAE,eAAe,EAAE;oBAC7B,SAAS,EAAE,IAAI;iBAChB,CAAC;YACJ,CAAC;YAED,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;YAC/C,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;YAE3D,OAAO;gBACL,SAAS,EAAE,cAAc;gBACzB,OAAO,EAAE,IAAI,CAAC,cAAc;oBAC1B,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE;oBACnB,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,yCAAyC,EAAE;gBACzE,YAAY,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;gBAC7D,MAAM,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;gBACvE,KAAK,EAAE,MAAM,eAAe,CAAC,OAAO,CAAC,GAAG,CAAC;gBACzC,OAAO;gBACP,UAAU;gBACV,SAAS,EAAE,IAAI;aAChB,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,KAAmB;YAC/B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YACrC,IAAI,CAAC,OAAO;gBAAE,MAAM,UAAU,CAAC,uCAAuC,CAAC,CAAC;YAExE,MAAM,SAAS,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAE3C,OAAO,SAAS,CAAC,KAAK,IAAI,EAAE;gBAC1B,MAAM,WAAW,GAAG,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;gBACjD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;oBAAE,MAAM,UAAU,CAAC,8BAA8B,CAAC,CAAC;gBAE/E;;;;;mBAKG;gBACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;gBAC/D,IAAI,KAAK,CAAC,YAAY,KAAK,IAAI,EAAE,CAAC;oBAChC,MAAM,IAAI,QAAQ,CAChB,UAAU,EACV,4EAA4E;wBAC1E,gCAAgC,CACnC,CAAC;gBACJ,CAAC;gBAED,sEAAsE;gBACtE,6DAA6D;gBAC7D,IAAI,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,KAAK,IAAI,CAAC,cAAc,EAAE,CAAC;oBACtE,MAAM,IAAI,QAAQ,CAChB,UAAU,EACV,4EAA4E;wBAC1E,mEAAmE,CACtE,CAAC;gBACJ,CAAC;gBAED,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;gBAClD,IAAI,CAAC,UAAU,CAAC,EAAE,EAAE,CAAC;oBACnB,MAAM,IAAI,QAAQ,CAAC,mBAAmB,EAAE,gBAAgB,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE;wBAC7E,MAAM,EAAE,eAAe,CAAC,UAAU,CAAC,QAAQ,CAAC;qBAC7C,CAAC,CAAC;gBACL,CAAC;gBAED,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;gBAEjF,IAAI,CAAC;oBACH,iEAAiE;oBACjE,gEAAgE;oBAChE,uCAAuC;oBACvC,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,CAAC;wBACxC,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;oBACzD,CAAC;oBACD,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;gBACrE,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;wBAC9B,wDAAwD;wBACxD,gEAAgE;wBAChE,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,2BAA2B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;oBAC7E,CAAC;oBACD,MAAM,KAAK,CAAC;gBACd,CAAC;gBAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;gBAChE,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;gBAElF,OAAO,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC9C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,IAAI;YACR,MAAM,SAAS,GAAG,MAAM,gBAAgB,EAAE,CAAC;YAE3C,OAAO,SAAS,CAAC,KAAK,IAAI,EAAE;gBAC1B,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC,CAAC;gBACnE,IAAI,QAAQ,KAAK,IAAI;oBAAE,MAAM,UAAU,CAAC,iCAAiC,CAAC,CAAC;gBAC3E,OAAO,WAAW,CAAC,SAAS,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;YAC9C,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,SAAmB;YAC/B,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;YAC/B,IAAI,QAAQ,IAAI,OAAO;gBAAE,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAE1D,OAAO,SAAS,CAAC,KAAK,IAAI,EAAE;gBAC1B,gEAAgE;gBAChE,+DAA+D;gBAC/D,qCAAqC;gBACrC,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,CAAC,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CACpE,CAAC;gBAEF,MAAM,SAAS,GAAa,EAAE,CAAC;gBAC/B,KAAK,MAAM,IAAI,IAAI,SAAS,EAAE,CAAC;oBAC7B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;oBACjC,IAAI,CAAC,MAAM;wBAAE,SAAS;oBAEtB,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;wBAC7B,8DAA8D;wBAC9D,+DAA+D;wBAC/D,8DAA8D;wBAC9D,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;4BACtB,MAAM,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;gCACvB,IAAI;gCACJ,UAAU;gCACV,SAAS;gCACT,IAAI;gCACJ,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;6BAC7B,CAAC,CAAC;wBACL,CAAC;wBACD,MAAM,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;oBACvD,CAAC;yBAAM,CAAC;wBACN,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;4BACpB,SAAS;4BACT,eAAe;4BACf,UAAU;4BACV,YAAY;4BACZ,IAAI;4BACJ,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC;yBAC7B,CAAC,CAAC;oBACL,CAAC;oBACD,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACvB,CAAC;gBAED,OAAO,EAAE,SAAS,EAAE,CAAC;YACvB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,KAAK,CAAC,OAAO,CAAC,MAAqB;YACjC,MAAM,OAAO,GAAG,MAAM,MAAM,EAAE,CAAC;YAC/B,qEAAqE;YACrE,oEAAoE;YACpE,MAAM,SAAS,GAAG,QAAQ,IAAI,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;YAC9F,OAAO,cAAc,CAAC,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,CAAC,CAAC;QAC7D,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,UAAU,CAAC,SAAoB;IACtC,MAAM,EAAE,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,QAAQ,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,CAAC,EAAE,CAAC;IAEvG,OAAO;QACL,MAAM,EAAE,MAAM;QAEd,KAAK,CAAC,IAAI,CAAC,IAAI;YACb,sEAAsE;YACtE,mEAAmE;YACnE,kCAAkC;YAClC,OAAO,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClD,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,IAAI;YACb,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpE,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,EAAE,CAAC;YAE5B,MAAM,OAAO,GAAqB,EAAE,CAAC;YACrC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpC,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAChC,IAAI,GAAG,KAAK,CAAC,CAAC;oBAAE,SAAS;gBACzB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBAC/C,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;YAC7F,CAAC;YACD,OAAO,OAAO,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,wEAAwE;AAExE,SAAS,eAAe;IACtB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AACpC,CAAC;AAED,SAAS,OAAO,CAAC,IAAY;IAC3B,OAAO,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxD,CAAC;AAED,6EAA6E;AAC7E,SAAS,MAAM,CAAC,MAAc,EAAE,IAAY;IAC1C,OAAO,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACxE,CAAC;AAED,SAAS,OAAO,CAAI,KAAU,EAAE,IAAY;IAC1C,MAAM,OAAO,GAAU,EAAE,CAAC;IAC1B,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,EAAE,IAAI,IAAI;QAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;IACzF,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,eAAe,CAAC,GAAc;IAC3C,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,MAAM,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,mBAAmB,CAAC,CAAC,CAAC;IAC/E,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAClC,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AAC/C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,MAAc;IACrD,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAiB,EAAE,CAAC;IAEjC,MAAM,IAAI,GAAG,CAAC,QAAgB,EAAE,IAAwB,EAAE,QAAuD,EAAE,EAAE,EAAE;QACrH,MAAM,IAAI,GAAG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACjD,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,OAAO,IAAI,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,OAAO;QAC3E,OAAO,CAAC,IAAI,CAAC;YACX,IAAI;YACJ,IAAI;YACJ,SAAS,EAAE,KAAK,CAAC,SAAS,IAAI,KAAK;YACnC,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,KAAK;SACtC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;QAC7C,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;QAC1B,MAAM,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC;QAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAEhC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,SAAS;QACX,CAAC;QAED,wEAAwE;QACxE,wEAAwE;QACxE,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,CAAC,EAAE,CAAC;YACnF,IAAI,CAAC,QAAQ,EAAE,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,SAAS;QACX,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAC3B,uEAAuE;YACvE,wEAAwE;YACxE,MAAM,IAAI,GAAG,MAAM,CAAC,EAAE,EAAE,CAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACzB,IAAI,CAAC,KAAK,GAAG;gBAAE,IAAI,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;YACpC,SAAS;QACX,CAAC;QAED,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QAED,IAAI,CAAC,QAAQ,EAAE,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,iBAAiB,CAAC,QAAgB,EAAE,MAAc;IACzD,IAAI,MAAM,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IACnC,IAAI,QAAQ,KAAK,MAAM;QAAE,OAAO,IAAI,CAAC;IACrC,OAAO,QAAQ,CAAC,UAAU,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACtF,CAAC"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Content staging: the orchestration between "saved" and "published".
3
+ *
4
+ * Two implementations of one service, because the two deployment shapes have
5
+ * genuinely different draft workspaces:
6
+ *
7
+ * - working tree (`staging-local.ts`): the checkout is the draft. Autosave
8
+ * writes files the Astro dev server can hot-reload, which is the whole
9
+ * value of local mode; Recent changes is `git status`, and Publish is a
10
+ * real commit and push through the developer's own Git.
11
+ * - draft store (this file): the repository is remote and writing through
12
+ * its API would already be a commit, so saves accumulate in SQLite and
13
+ * Publish turns the whole set into one provider-side commit.
14
+ *
15
+ * The editor sees one API either way. What differs is only what Saved means —
16
+ * and the two must stay visibly different words in the UI, because in neither
17
+ * mode does Saved imply that a change is in Git.
18
+ */
19
+ import type { Author, RepositoryConnector } from "@micacms/connectors";
20
+ import { type ContentChange, type ContentSource, type DraftStore, type FieldIssue, type PublishResult, type Site } from "@micacms/core";
21
+ /** Where the change happened, in words an editor recognises. */
22
+ export type ChangeOwner = {
23
+ kind: "entry";
24
+ collection: string;
25
+ slug: string;
26
+ label: string;
27
+ } | {
28
+ kind: "singleton";
29
+ name: string;
30
+ label: string;
31
+ } | {
32
+ kind: "order";
33
+ collection: string;
34
+ label: string;
35
+ } | {
36
+ kind: "media";
37
+ label: string;
38
+ } | {
39
+ kind: "other";
40
+ label: string;
41
+ };
42
+ export interface AnnotatedChange extends ContentChange {
43
+ owner: ChangeOwner;
44
+ }
45
+ /** One thing that would make the staged result unpublishable. */
46
+ export interface StagingProblem {
47
+ /** The file the problem is about, relative to the content root. */
48
+ path: string;
49
+ label: string;
50
+ issues: FieldIssue[];
51
+ }
52
+ export interface StagingValidation {
53
+ ok: boolean;
54
+ problems: StagingProblem[];
55
+ }
56
+ export interface StagingStatus {
57
+ /** How this deployment stages. The UI words differ with it. */
58
+ workspace: "working-tree" | "draft-store";
59
+ publish: {
60
+ enabled: boolean;
61
+ reason?: string;
62
+ };
63
+ /**
64
+ * What the pending changes are based on: HEAD for a working tree, the
65
+ * branch head for a draft store. Sent back with Publish as `expectedBase`.
66
+ */
67
+ baseRevision: string | null;
68
+ /** The branch a publication lands on, where the workspace knows it. */
69
+ branch: string | null;
70
+ /** Commits created and not yet pushed. Working tree only. */
71
+ ahead: number | null;
72
+ changes: AnnotatedChange[];
73
+ validation: StagingValidation;
74
+ /** When the pending set last moved. Null when nothing is pending. */
75
+ updatedAt: string | null;
76
+ }
77
+ export interface PublishInput {
78
+ /** Subject line of the commit. Written by the editor, for `git log`. */
79
+ message: string;
80
+ /** The base the editor reviewed. A repository that moved past it refuses. */
81
+ expectedBase: string | null;
82
+ author?: Author;
83
+ }
84
+ export interface ContentStagingService {
85
+ status(): Promise<StagingStatus>;
86
+ publish(input: PublishInput): Promise<PublishResult>;
87
+ discard(paths: string[]): Promise<{
88
+ discarded: string[];
89
+ }>;
90
+ /** Retries the push after `committed-pending-push`. Working tree only. */
91
+ push(): Promise<PublishResult>;
92
+ /** The document a pending change touches, before and after that change. */
93
+ compare(target: CompareTarget): Promise<Comparison>;
94
+ }
95
+ /** One thing an editor recognises on the Publish page, named for comparison. */
96
+ export type CompareTarget = {
97
+ kind: "entry";
98
+ collection: string;
99
+ slug: string;
100
+ } | {
101
+ kind: "singleton";
102
+ name: string;
103
+ } | {
104
+ kind: "order";
105
+ collection: string;
106
+ };
107
+ /**
108
+ * A document on both sides of the pending change set.
109
+ *
110
+ * Raw field data, deliberately: the editor holds the model and can name,
111
+ * order and render every field, so the friendly comparison is its job. What
112
+ * only the server can do is read the same document from two places.
113
+ */
114
+ export interface Comparison {
115
+ /** As the repository has it — null when the change creates the document. */
116
+ before: Record<string, unknown> | null;
117
+ /** As staged for publication — null when the change deletes it. */
118
+ after: Record<string, unknown> | null;
119
+ }
120
+ /**
121
+ * Reads one document from the repository (`published`) and from the pending
122
+ * workspace (`staged`) — the whole of a before/after comparison, shared by
123
+ * both staging implementations since a `ContentSource` is all it needs.
124
+ *
125
+ * An order target compares the collection's ordering rather than a document:
126
+ * each side becomes `{ order: [{ slug, title }] }`, in position order.
127
+ */
128
+ export declare function compareSources(model: Site, published: ContentSource, staged: ContentSource, target: CompareTarget): Promise<Comparison>;
129
+ /**
130
+ * Annotates a change set with owners and validates the entries it touches.
131
+ *
132
+ * One pass on purpose: naming a change and validating it both need the same
133
+ * read of the same entries, and content trees are small enough to read the
134
+ * affected collections whole.
135
+ *
136
+ * Validation is scoped to *changed* documents. Content that was already in
137
+ * the repository is not this publication's problem — refusing
138
+ * to publish a fixed typo because somebody once hand-committed a broken entry
139
+ * elsewhere would make the editor hostage to history it cannot touch.
140
+ */
141
+ export declare function analyseChanges(model: Site, source: ContentSource, changes: ContentChange[]): Promise<{
142
+ changes: AnnotatedChange[];
143
+ validation: StagingValidation;
144
+ }>;
145
+ /**
146
+ * Which piece of content a file belongs to.
147
+ *
148
+ * The path layout is the model's own (`layout.ts`), so this is a reading of
149
+ * it, not a second convention: `collection/slug/…` or `collection/slug.json`,
150
+ * `singleton.json` or `singleton/…`, and the shared `media/` directory.
151
+ */
152
+ export declare function classifyPath(model: Site, path: string): ChangeOwner;
153
+ export interface DraftStagingDeps {
154
+ model: Site;
155
+ drafts: DraftStore;
156
+ /** The real repository. The one thing here that writes to it. */
157
+ repository: RepositoryConnector;
158
+ /** The staged overlay the rest of the application reads through. */
159
+ overlay: RepositoryConnector;
160
+ /** Revision of `.mica/schema.json` when the model was loaded. */
161
+ schemaRevision: string | null;
162
+ }
163
+ export declare function createDraftStagingService(deps: DraftStagingDeps): ContentStagingService;
164
+ export declare function describeProblems(problems: StagingProblem[]): string;
165
+ /** Field issues with the file path folded in, for the flat API envelope. */
166
+ export declare function flattenProblems(problems: StagingProblem[]): FieldIssue[];
167
+ //# sourceMappingURL=staging.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staging.d.ts","sourceRoot":"","sources":["../../src/services/staging.ts"],"names":[],"mappings":"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"}