emdash 0.40.0 → 0.40.1

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 (200) hide show
  1. package/dist/api/route-utils.mjs +6 -6
  2. package/dist/api/schemas/index.d.mts +1 -1
  3. package/dist/{api-cFFZpyS0.mjs → api-CuyNEHZG.mjs} +3 -3
  4. package/dist/{api-cFFZpyS0.mjs.map → api-CuyNEHZG.mjs.map} +1 -1
  5. package/dist/{apply-CoT603H3.mjs → apply-npY1TAhG.mjs} +237 -34
  6. package/dist/apply-npY1TAhG.mjs.map +1 -0
  7. package/dist/astro/index.d.mts +3 -3
  8. package/dist/astro/index.mjs +9 -9
  9. package/dist/astro/index.mjs.map +1 -1
  10. package/dist/astro/middleware/auth.d.mts +3 -3
  11. package/dist/astro/middleware/redirect.mjs +1 -1
  12. package/dist/astro/middleware.d.mts +3 -3
  13. package/dist/astro/middleware.d.mts.map +1 -1
  14. package/dist/astro/middleware.mjs +19 -18
  15. package/dist/astro/middleware.mjs.map +1 -1
  16. package/dist/astro/routes/api/admin/media-usage/progress.mjs +2 -2
  17. package/dist/astro/routes/api/admin/media-usage/repair.mjs +2 -2
  18. package/dist/astro/routes/api/admin/plugins/_id_/index.mjs +8 -8
  19. package/dist/astro/routes/api/admin/plugins/_id_/settings.mjs +8 -8
  20. package/dist/astro/routes/api/admin/plugins/_id_/uninstall.mjs +8 -8
  21. package/dist/astro/routes/api/admin/plugins/_id_/update.mjs +11 -11
  22. package/dist/astro/routes/api/admin/plugins/index.mjs +8 -8
  23. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/index.mjs +8 -8
  24. package/dist/astro/routes/api/admin/plugins/marketplace/_id_/install.mjs +11 -11
  25. package/dist/astro/routes/api/admin/plugins/marketplace/index.mjs +8 -8
  26. package/dist/astro/routes/api/admin/plugins/registry/_id_/uninstall.mjs +8 -8
  27. package/dist/astro/routes/api/admin/plugins/registry/_id_/update.mjs +12 -12
  28. package/dist/astro/routes/api/admin/plugins/registry/install.mjs +9 -9
  29. package/dist/astro/routes/api/admin/plugins/registry/verify.mjs +9 -9
  30. package/dist/astro/routes/api/admin/plugins/updates.mjs +8 -8
  31. package/dist/astro/routes/api/admin/themes/marketplace/_id_/index.mjs +8 -8
  32. package/dist/astro/routes/api/admin/themes/marketplace/index.mjs +8 -8
  33. package/dist/astro/routes/api/admin/transfer/approvals/_id_/approve.mjs +3 -3
  34. package/dist/astro/routes/api/admin/transfer/approvals/_id_/deny.mjs +3 -3
  35. package/dist/astro/routes/api/admin/transfer/approvals/index.mjs +3 -3
  36. package/dist/astro/routes/api/admin/transfer/capabilities.mjs +3 -3
  37. package/dist/astro/routes/api/admin/transfer/exports/_id_/advance.mjs +3 -3
  38. package/dist/astro/routes/api/admin/transfer/exports/_id_/archive.mjs +3 -3
  39. package/dist/astro/routes/api/admin/transfer/exports/_id_/files/_...path_.mjs +3 -3
  40. package/dist/astro/routes/api/admin/transfer/exports/_id_/index.mjs +3 -3
  41. package/dist/astro/routes/api/admin/transfer/exports/_id_/manifest.mjs +3 -3
  42. package/dist/astro/routes/api/admin/transfer/exports/index.mjs +3 -3
  43. package/dist/astro/routes/api/admin/transfer/imports/_id_/abandon.mjs +3 -3
  44. package/dist/astro/routes/api/admin/transfer/imports/_id_/advance.mjs +3 -3
  45. package/dist/astro/routes/api/admin/transfer/imports/_id_/analyze.mjs +3 -3
  46. package/dist/astro/routes/api/admin/transfer/imports/_id_/cancel.mjs +3 -3
  47. package/dist/astro/routes/api/admin/transfer/imports/_id_/execute.mjs +3 -3
  48. package/dist/astro/routes/api/admin/transfer/imports/_id_/files/_...path_.mjs +3 -3
  49. package/dist/astro/routes/api/admin/transfer/imports/_id_/index.mjs +3 -3
  50. package/dist/astro/routes/api/admin/transfer/imports/_id_/missing.mjs +3 -3
  51. package/dist/astro/routes/api/admin/transfer/imports/_id_/plan.mjs +3 -3
  52. package/dist/astro/routes/api/admin/transfer/imports/_id_/receipt.mjs +3 -3
  53. package/dist/astro/routes/api/admin/transfer/imports/index.mjs +3 -3
  54. package/dist/astro/routes/api/dashboard.mjs +2 -2
  55. package/dist/astro/routes/api/health.mjs +1 -1
  56. package/dist/astro/routes/api/import/probe.mjs +3 -3
  57. package/dist/astro/routes/api/import/wordpress/execute.d.mts +3 -3
  58. package/dist/astro/routes/api/import/wordpress/media.d.mts +3 -3
  59. package/dist/astro/routes/api/import/wordpress/rewrite-urls.d.mts +3 -3
  60. package/dist/astro/routes/api/import/wordpress-plugin/analyze.mjs +3 -3
  61. package/dist/astro/routes/api/import/wordpress-plugin/execute.d.mts +3 -3
  62. package/dist/astro/routes/api/import/wordpress-plugin/execute.mjs +3 -3
  63. package/dist/astro/routes/api/manifest.mjs +1 -1
  64. package/dist/astro/routes/api/mcp.mjs +13 -33
  65. package/dist/astro/routes/api/mcp.mjs.map +1 -1
  66. package/dist/astro/routes/api/media/_id_/confirm.mjs +1 -1
  67. package/dist/astro/routes/api/media/_id_/upload.mjs +1 -1
  68. package/dist/astro/routes/api/media/_id_/usage.mjs +2 -2
  69. package/dist/astro/routes/api/media/_id_.mjs +2 -2
  70. package/dist/astro/routes/api/media/asset/_id_/_filename_.mjs +1 -1
  71. package/dist/astro/routes/api/media/upload-url.mjs +1 -1
  72. package/dist/astro/routes/api/media.mjs +2 -2
  73. package/dist/astro/routes/api/redirects/404s/index.mjs +2 -2
  74. package/dist/astro/routes/api/redirects/404s/summary.mjs +2 -2
  75. package/dist/astro/routes/api/redirects/_id_.mjs +2 -2
  76. package/dist/astro/routes/api/redirects/index.mjs +2 -2
  77. package/dist/astro/routes/api/schema/block-types/_slug_/index.mjs +8 -8
  78. package/dist/astro/routes/api/schema/block-types/_slug_/versions/_version_/activate.mjs +8 -8
  79. package/dist/astro/routes/api/schema/block-types/index.mjs +8 -8
  80. package/dist/astro/routes/api/schema/collections/_slug_/fields/_fieldSlug_.mjs +8 -8
  81. package/dist/astro/routes/api/schema/collections/_slug_/fields/index.mjs +8 -8
  82. package/dist/astro/routes/api/schema/collections/_slug_/fields/reorder.mjs +8 -8
  83. package/dist/astro/routes/api/schema/collections/_slug_/index.mjs +8 -8
  84. package/dist/astro/routes/api/schema/collections/index.mjs +8 -8
  85. package/dist/astro/routes/api/schema/collections/reorder.mjs +8 -8
  86. package/dist/astro/routes/api/schema/orphans/_slug_.mjs +8 -8
  87. package/dist/astro/routes/api/schema/orphans/index.mjs +8 -8
  88. package/dist/astro/routes/api/settings/backups/archives/_name_.mjs +2 -2
  89. package/dist/astro/routes/api/settings/backups/archives/index.mjs +2 -2
  90. package/dist/astro/routes/api/settings/backups/export.mjs +2 -2
  91. package/dist/astro/routes/api/settings/backups/index.mjs +2 -2
  92. package/dist/astro/routes/api/settings.mjs +3 -3
  93. package/dist/astro/routes/api/setup/dev-bypass.mjs +4 -4
  94. package/dist/astro/routes/api/setup/index.d.mts.map +1 -1
  95. package/dist/astro/routes/api/setup/index.mjs +35 -10
  96. package/dist/astro/routes/api/setup/index.mjs.map +1 -1
  97. package/dist/astro/routes/api/snapshot.mjs +2 -2
  98. package/dist/astro/routes/api/snapshot.mjs.map +1 -1
  99. package/dist/astro/routes/robots.txt.mjs +2 -2
  100. package/dist/astro/routes/sitemap-_collection_.xml.mjs +2 -2
  101. package/dist/astro/routes/sitemap.xml.mjs +2 -2
  102. package/dist/astro/types.d.mts +7 -3
  103. package/dist/astro/types.d.mts.map +1 -1
  104. package/dist/{backup-CBu0LrXf.mjs → backup-BQRj3afm.mjs} +3 -3
  105. package/dist/{backup-CBu0LrXf.mjs.map → backup-BQRj3afm.mjs.map} +1 -1
  106. package/dist/cli/index.mjs +6 -6
  107. package/dist/client/index.d.mts +14 -14
  108. package/dist/{config-5ii2haYu.d.mts → config-BjEm_3xL.d.mts} +25 -16
  109. package/dist/config-BjEm_3xL.d.mts.map +1 -0
  110. package/dist/{context-BeGccdUX.mjs → context-BV_7t-Ua.mjs} +6 -6
  111. package/dist/{context-BeGccdUX.mjs.map → context-BV_7t-Ua.mjs.map} +1 -1
  112. package/dist/{dashboard-DjrB-xxZ.mjs → dashboard-BP-iJqpd.mjs} +2 -2
  113. package/dist/{dashboard-DjrB-xxZ.mjs.map → dashboard-BP-iJqpd.mjs.map} +1 -1
  114. package/dist/db/libsql-migrations.mjs +2 -2
  115. package/dist/db/postgres-migrations.mjs +2 -2
  116. package/dist/db/sqlite-migrations.mjs +2 -2
  117. package/dist/{direct-executor-BmuFJJZV.mjs → direct-executor-D2lNadwo.mjs} +2 -2
  118. package/dist/{direct-executor-BmuFJJZV.mjs.map → direct-executor-D2lNadwo.mjs.map} +1 -1
  119. package/dist/{emdash-runtime-DAjghyEG.mjs → emdash-runtime-CtfnZmPi.mjs} +56 -56
  120. package/dist/emdash-runtime-CtfnZmPi.mjs.map +1 -0
  121. package/dist/{entry-lock-DVhCt49A.d.mts → entry-lock-Cf5OoIgN.d.mts} +18 -18
  122. package/dist/{entry-lock-DVhCt49A.d.mts.map → entry-lock-Cf5OoIgN.d.mts.map} +1 -1
  123. package/dist/{hreflang-DMFBL2eb.mjs → hreflang-CbVI4paR.mjs} +2 -2
  124. package/dist/{hreflang-DMFBL2eb.mjs.map → hreflang-CbVI4paR.mjs.map} +1 -1
  125. package/dist/{identity-IyNWwXr6.mjs → identity-Be5kzutJ.mjs} +2 -2
  126. package/dist/{identity-IyNWwXr6.mjs.map → identity-Be5kzutJ.mjs.map} +1 -1
  127. package/dist/{import-C3JZplWq.mjs → import-YzfKCaco.mjs} +2 -2
  128. package/dist/{import-C3JZplWq.mjs.map → import-YzfKCaco.mjs.map} +1 -1
  129. package/dist/index.d.mts +4 -4
  130. package/dist/index.mjs +16 -16
  131. package/dist/{manifest-builder-B8zR-73J.mjs → manifest-builder-BmSAOOEF.mjs} +2 -2
  132. package/dist/{manifest-builder-B8zR-73J.mjs.map → manifest-builder-BmSAOOEF.mjs.map} +1 -1
  133. package/dist/media/local-runtime.d.mts +3 -3
  134. package/dist/media/local-runtime.mjs +3 -3
  135. package/dist/{media-Qp5S3eH3.mjs → media-CPXTbb1R.mjs} +20 -2
  136. package/dist/media-CPXTbb1R.mjs.map +1 -0
  137. package/dist/{media-h7tOiDLj.mjs → media-JXRWDhw3.mjs} +77 -4
  138. package/dist/media-JXRWDhw3.mjs.map +1 -0
  139. package/dist/{media-usage-My-Vi-ex.mjs → media-usage-De-zeR9E.mjs} +2 -2
  140. package/dist/{media-usage-My-Vi-ex.mjs.map → media-usage-De-zeR9E.mjs.map} +1 -1
  141. package/dist/{menus-TsSGmSR4.mjs → menus-Cm68rsAq.mjs} +4 -4
  142. package/dist/{menus-TsSGmSR4.mjs.map → menus-Cm68rsAq.mjs.map} +1 -1
  143. package/dist/migrations/index.mjs +2 -2
  144. package/dist/page/index.mjs +2 -2
  145. package/dist/plugin-test-runtime.d.mts +3 -3
  146. package/dist/plugin-test-runtime.mjs +18 -18
  147. package/dist/plugin-utils.d.mts +3 -3
  148. package/dist/plugins/adapt-sandbox-entry.d.mts +3 -3
  149. package/dist/plugins/host.d.mts +1 -1
  150. package/dist/plugins/host.mjs +6 -6
  151. package/dist/{redirect-iJf5fltD.mjs → redirect-B29UjdUn.mjs} +10 -14
  152. package/dist/redirect-B29UjdUn.mjs.map +1 -0
  153. package/dist/{redirects-CYu1u1aK.mjs → redirects-Ca2MPfEG.mjs} +2 -2
  154. package/dist/{redirects-CYu1u1aK.mjs.map → redirects-Ca2MPfEG.mjs.map} +1 -1
  155. package/dist/{routes-CUsM40Cc.mjs → routes-vrR95WR6.mjs} +2 -2
  156. package/dist/{routes-CUsM40Cc.mjs.map → routes-vrR95WR6.mjs.map} +1 -1
  157. package/dist/runtime.d.mts +3 -3
  158. package/dist/seed/index.mjs +4 -4
  159. package/dist/seo/index.mjs +3 -3
  160. package/dist/{settings-CgjRWGW9.mjs → settings-B4vDl1fK.mjs} +2 -2
  161. package/dist/{settings-CgjRWGW9.mjs.map → settings-B4vDl1fK.mjs.map} +1 -1
  162. package/dist/{settings-2xNYr90o.mjs → settings-Dyj6v8C4.mjs} +2 -2
  163. package/dist/{settings-2xNYr90o.mjs.map → settings-Dyj6v8C4.mjs.map} +1 -1
  164. package/dist/{snapshot-CugwUqKQ.mjs → snapshot-PawoX-WG.mjs} +180 -3
  165. package/dist/snapshot-PawoX-WG.mjs.map +1 -0
  166. package/dist/{storage-query-Bdv7A62k.d.mts → storage-query-FXJH5pI8.d.mts} +6 -1
  167. package/dist/storage-query-FXJH5pI8.d.mts.map +1 -0
  168. package/dist/{transfer-BhUCrgDc.mjs → transfer-DgeCvHnj.mjs} +4 -4
  169. package/dist/{transfer-BhUCrgDc.mjs.map → transfer-DgeCvHnj.mjs.map} +1 -1
  170. package/dist/validate-CM79QXYE.d.mts.map +1 -1
  171. package/dist/version-DXsxRrob.mjs +7 -0
  172. package/dist/{version-DUQDHgrf.mjs.map → version-DXsxRrob.mjs.map} +1 -1
  173. package/package.json +5 -5
  174. package/src/api/handlers/index.ts +1 -0
  175. package/src/api/handlers/media-upload.ts +17 -71
  176. package/src/api/handlers/media.ts +97 -3
  177. package/src/api/handlers/snapshot.ts +257 -3
  178. package/src/astro/integration/vite-config.ts +10 -4
  179. package/src/astro/middleware.ts +1 -0
  180. package/src/astro/routes/api/setup/index.ts +66 -23
  181. package/src/astro/routes/api/snapshot.ts +2 -1
  182. package/src/astro/types.ts +5 -0
  183. package/src/cleanup.ts +10 -0
  184. package/src/components/Columns.astro +3 -1
  185. package/src/components/Cover.astro +3 -1
  186. package/src/database/repositories/media.ts +40 -1
  187. package/src/database/repositories/redirect.ts +17 -34
  188. package/src/emdash-runtime.ts +28 -0
  189. package/src/index.ts +1 -0
  190. package/src/mcp/server.ts +13 -48
  191. package/src/seed/apply.ts +322 -41
  192. package/dist/apply-CoT603H3.mjs.map +0 -1
  193. package/dist/config-5ii2haYu.d.mts.map +0 -1
  194. package/dist/emdash-runtime-DAjghyEG.mjs.map +0 -1
  195. package/dist/media-Qp5S3eH3.mjs.map +0 -1
  196. package/dist/media-h7tOiDLj.mjs.map +0 -1
  197. package/dist/redirect-iJf5fltD.mjs.map +0 -1
  198. package/dist/snapshot-CugwUqKQ.mjs.map +0 -1
  199. package/dist/storage-query-Bdv7A62k.d.mts.map +0 -1
  200. package/dist/version-DUQDHgrf.mjs +0 -7
@@ -1 +1 @@
1
- {"version":3,"file":"transfer-BhUCrgDc.mjs","names":["encoder","decodeRecordLine","encoder","#manifest","decodeRecordLine","encoder","isPlainObject","parseEmbeddedJson","count","runUnit","stageFor","#queryCeiling","#byteLimit","#metrics","#unitCeiling","#units","#bytesUsed","count","contentTable","#db","#config","#options","#columns","#covered","#slugs","#collections","#fields","#input","#db","#operations","#stagedFiles","#blobs","#budget","#stage","#writer","#options","#leaseToken","#mediaExported","#operation","#comments","#readers","#keys","#scannable","#packageReader","#storage","#operationId","#chunks","#fields","#rewrittenKinds","#input","#db","#identity","#reader","#readers","#cursor","#packageBlobs","#rewrites","#keys","#context","#mediaChunk"],"sources":["../src/transfer/ops/collation.ts","../src/transfer/ops/staged-files.ts","../src/transfer/site-id.ts","../src/transfer/format/records.ts","../src/transfer/staging/package.ts","../src/transfer/domain.ts","../src/transfer/analyze/read.ts","../src/transfer/analyze/write-rules.ts","../src/transfer/analyze/target.ts","../src/transfer/analyze/plan.ts","../src/transfer/ops/package-index.ts","../src/transfer/analyze/issues.ts","../src/transfer/analyze/unique-keys.ts","../src/transfer/format/media-refs.ts","../src/transfer/analyze/values.ts","../src/transfer/analyze/validate.ts","../src/transfer/analyze/step.ts","../src/transfer/audit.ts","../src/transfer/ops/budget.ts","../src/transfer/ops/media-blobs.ts","../src/transfer/export/fence.ts","../src/transfer/export/media.ts","../src/transfer/export/readers.ts","../src/transfer/export/exporter.ts","../src/transfer/ops/identity-map.ts","../src/transfer/import/context.ts","../src/transfer/import/ids.ts","../src/transfer/import/writers.ts","../src/transfer/import/entries.ts","../src/transfer/import/media.ts","../src/transfer/import/stages.ts","../src/transfer/export/verify.ts","../src/transfer/import/rebuild.ts","../src/transfer/import/scaffold.ts","../src/transfer/import/advance.ts","../src/api/handlers/transfer.ts"],"sourcesContent":["import { sql, type Kysely, type RawBuilder } from \"kysely\";\n\nimport { isPostgres } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\n\n/**\n * A text column compared bytewise. Package ordering is by UTF-16 code unit\n * and portable ids and paths are ASCII, so bytewise order is package order.\n * SQLite compares TEXT with BINARY by default; Postgres needs `COLLATE \"C\"`\n * because database collations are usually linguistic.\n */\nexport function bytewise(db: Kysely<Database>, column: string): RawBuilder<string> {\n\treturn isPostgres(db)\n\t\t? sql<string>`${sql.ref(column)} COLLATE \"C\"`\n\t\t: sql<string>`${sql.ref(column)}`;\n}\n\n/** `LIKE` pattern matching values that start with `prefix` (use with `ESCAPE '\\'`). */\nexport function likePrefix(prefix: string): string {\n\treturn `${prefix.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\")}%`;\n}\n","/**\n * Files belonging to an operation's staged package.\n *\n * For an import, every file the manifest's index declares is `declared` with\n * its expected size and digest, then becomes `verified` once `putVerified`\n * stored exactly those bytes. For an export, each file the exporter writes is\n * recorded `verified` as it is written; finalization streams them in path\n * order into the index chunks. Verification stores each record chunk's\n * logical hash in `logical_sha256`.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport type { ExpectedFile } from \"../staging/stage.js\";\nimport { bytewise, likePrefix } from \"./collation.js\";\nimport { timestampNow } from \"./time.js\";\n\nexport type StagedFileState = \"declared\" | \"verified\";\n\nexport interface StagedFile {\n\tpath: string;\n\tbytes: number;\n\tsha256: string;\n\tstate: StagedFileState;\n\tverifiedAt: string | null;\n\tlogicalSha256: string | null;\n}\n\nexport interface DeclaredFile {\n\tpath: string;\n\tbytes: number;\n\tsha256: string;\n}\n\nfunction toStagedFile(row: {\n\tpath: string;\n\tbytes: number | string;\n\tsha256: string;\n\tstate: string;\n\tverified_at: string | null;\n\tlogical_sha256: string | null;\n}): StagedFile {\n\treturn {\n\t\tpath: row.path,\n\t\tbytes: Number(row.bytes),\n\t\tsha256: row.sha256,\n\t\tstate: row.state === \"verified\" ? \"verified\" : \"declared\",\n\t\tverifiedAt: row.verified_at,\n\t\tlogicalSha256: row.logical_sha256,\n\t};\n}\n\n/** Bound values per inserted row: six columns plus the timestamp offset in `verified_at`. */\nconst STAGED_FILE_BINDS = 7;\n\nexport class TransferStagedFileRepository {\n\tconstructor(private readonly db: Kysely<Database>) {}\n\n\t/**\n\t * Declare expected files. Re-declaring an identical file is a no-op; a\n\t * different size or digest for an existing path throws\n\t * `TRANSFER_FILE_DIGEST_MISMATCH`.\n\t */\n\tasync declareMany(\n\t\toperationId: string,\n\t\tfiles: readonly DeclaredFile[],\n\t\tstate: StagedFileState = \"declared\",\n\t): Promise<void> {\n\t\tfor (const batch of chunks([...files], rowsPerInsert(STAGED_FILE_BINDS))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_staged_files\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((file) => ({\n\t\t\t\t\t\toperation_id: operationId,\n\t\t\t\t\t\tpath: file.path,\n\t\t\t\t\t\tbytes: file.bytes,\n\t\t\t\t\t\tsha256: file.sha256,\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\tverified_at: state === \"verified\" ? timestampNow(this.db) : null,\n\t\t\t\t\t\tlogical_sha256: null,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) => conflict.columns([\"operation_id\", \"path\"]).doNothing())\n\t\t\t\t.execute();\n\t\t}\n\t\tfor (const batch of chunks([...files], SQL_BATCH_SIZE)) {\n\t\t\tconst stored = await this.getMany(\n\t\t\t\toperationId,\n\t\t\t\tbatch.map((file) => file.path),\n\t\t\t);\n\t\t\tfor (const file of batch) {\n\t\t\t\tconst existing = stored.get(file.path);\n\t\t\t\tif (!existing || existing.bytes !== file.bytes || existing.sha256 !== file.sha256) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_FILE_DIGEST_MISMATCH\",\n\t\t\t\t\t\t\"File was already declared with a different size or digest\",\n\t\t\t\t\t\t{ detail: { path: file.path } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Record that the declared bytes were stored and verified. Returns false if the declaration differs. */\n\tasync markVerified(operationId: string, file: DeclaredFile): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"_emdash_transfer_staged_files\")\n\t\t\t.set({ state: \"verified\", verified_at: timestampNow(this.db) })\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"path\", \"=\", file.path)\n\t\t\t.where(\"bytes\", \"=\", file.bytes)\n\t\t\t.where(\"sha256\", \"=\", file.sha256)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numUpdatedRows ?? 0n) > 0;\n\t}\n\n\t/**\n\t * The size and digest each staged file of an operation was verified with,\n\t * or null for a file that is not verified. Readers check what they read\n\t * against these, since a later upload can replace a verified object.\n\t */\n\tverifiedDigests(operationId: string): (path: string) => Promise<ExpectedFile | null> {\n\t\treturn async (path) => {\n\t\t\tconst file = await this.get(operationId, path);\n\t\t\treturn file?.state === \"verified\" ? { bytes: file.bytes, sha256: file.sha256 } : null;\n\t\t};\n\t}\n\n\tasync isVerified(operationId: string, path: string): Promise<boolean> {\n\t\treturn (await this.get(operationId, path))?.state === \"verified\";\n\t}\n\n\tasync setLogicalSha256(operationId: string, path: string, logicalSha256: string): Promise<void> {\n\t\tawait this.db\n\t\t\t.updateTable(\"_emdash_transfer_staged_files\")\n\t\t\t.set({ logical_sha256: logicalSha256 })\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"path\", \"=\", path)\n\t\t\t.execute();\n\t}\n\n\tasync get(operationId: string, path: string): Promise<StagedFile | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select([\"path\", \"bytes\", \"sha256\", \"state\", \"verified_at\", \"logical_sha256\"])\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"path\", \"=\", path)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? toStagedFile(row) : null;\n\t}\n\n\tasync getMany(operationId: string, paths: readonly string[]): Promise<Map<string, StagedFile>> {\n\t\tconst result = new Map<string, StagedFile>();\n\t\tfor (const batch of chunks([...new Set(paths)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t\t.select([\"path\", \"bytes\", \"sha256\", \"state\", \"verified_at\", \"logical_sha256\"])\n\t\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t\t.where(\"path\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.path, toStagedFile(row));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Files in path order, optionally filtered by state or path prefix. */\n\tasync list(\n\t\toperationId: string,\n\t\toptions: { state?: StagedFileState; prefix?: string; after?: string; limit?: number } = {},\n\t): Promise<StagedFile[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select([\"path\", \"bytes\", \"sha256\", \"state\", \"verified_at\", \"logical_sha256\"])\n\t\t\t.where(\"operation_id\", \"=\", operationId);\n\t\tif (options.state) query = query.where(\"state\", \"=\", options.state);\n\t\tif (options.prefix !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`path LIKE ${likePrefix(options.prefix)} ESCAPE '\\\\'`);\n\t\t}\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"path\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"path\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map(toStagedFile);\n\t}\n\n\tasync countByState(operationId: string): Promise<Record<StagedFileState, number>> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select((eb) => [\"state\", eb.fn.countAll<number | string>().as(\"count\")])\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.groupBy(\"state\")\n\t\t\t.execute();\n\t\tconst counts: Record<StagedFileState, number> = { declared: 0, verified: 0 };\n\t\tfor (const row of rows) {\n\t\t\tif (row.state === \"declared\" || row.state === \"verified\")\n\t\t\t\tcounts[row.state] = Number(row.count);\n\t\t}\n\t\treturn counts;\n\t}\n\n\t/** Delete up to `limit` rows for an operation; returns how many were deleted. */\n\tasync deleteForOperation(operationId: string, limit = 500): Promise<number> {\n\t\tconst paths = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select(\"path\")\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.limit(limit)\n\t\t\t.execute();\n\t\tlet deleted = 0;\n\t\tfor (const batch of chunks(\n\t\t\tpaths.map((row) => row.path),\n\t\t\tSQL_BATCH_SIZE,\n\t\t)) {\n\t\t\tconst result = await this.db\n\t\t\t\t.deleteFrom(\"_emdash_transfer_staged_files\")\n\t\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t\t.where(\"path\", \"in\", batch)\n\t\t\t\t.executeTakeFirst();\n\t\t\tdeleted += Number(result.numDeletedRows ?? 0n);\n\t\t}\n\t\treturn deleted;\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { OptionsRepository } from \"../database/repositories/options.js\";\nimport type { Database } from \"../database/types.js\";\n\n/**\n * Option holding this installation's site id. Target-local: never exported\n * and never overwritten by an import.\n */\nexport const SITE_ID_OPTION = \"emdash:site_id\";\n\n/**\n * This installation's site id, created on first use. Concurrent first callers\n * converge on one value: creation is an insert-if-absent, and a caller that\n * loses the race reads the winner's value.\n */\nexport async function getOrCreateSiteId(db: Kysely<Database>): Promise<string> {\n\tconst options = new OptionsRepository(db);\n\tconst existing = await options.get(SITE_ID_OPTION);\n\tif (typeof existing === \"string\" && existing.length > 0) return existing;\n\n\tconst candidate = ulid();\n\tconst result = await options.compareAndSet(SITE_ID_OPTION, null, candidate);\n\tif (result.applied) return candidate;\n\n\tconst winner = await options.get(SITE_ID_OPTION);\n\tif (typeof winner === \"string\" && winner.length > 0) return winner;\n\tthrow new Error(\"Site id option exists but is not a non-empty string\");\n}\n","/**\n * NDJSON encoding of record and index chunks.\n *\n * A chunk is a sequence of lines, each the canonical JSON of one record (or\n * index entry) followed by `\\n`, with no blank lines. A chunk holds at most\n * {@link TRANSFER_LIMITS.chunkRecords} lines and\n * {@link TRANSFER_LIMITS.chunkBytes} bytes; a record line is at most\n * {@link TRANSFER_LIMITS.recordLineBytes} bytes.\n */\n\nimport { TransferError } from \"../errors.js\";\nimport { canonicalJson, CanonicalJsonError, parseCanonicalJson } from \"./canonical.js\";\nimport { type RecordKind, type RecordOfKind, validateRecord } from \"./kinds.js\";\nimport { TRANSFER_LIMITS } from \"./limits.js\";\nimport { decodeUtf8 } from \"./manifest.js\";\n\nconst encoder = new TextEncoder();\n\n/** Canonical line (without newline) for a record; enforces the line limit. */\nexport function encodeRecordLine(record: { kind: RecordKind; id: string }): string {\n\tconst line = canonicalJson(record);\n\tconst bytes = encoder.encode(line).byteLength;\n\tif (bytes > TRANSFER_LIMITS.recordLineBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Record exceeds the line size limit\", {\n\t\t\tdetail: { kind: record.kind, id: record.id, bytes, limit: TRANSFER_LIMITS.recordLineBytes },\n\t\t});\n\t}\n\treturn line;\n}\n\nexport interface DecodedRecord<K extends RecordKind> {\n\trecord: RecordOfKind<K>;\n\t/** The canonical line without its newline; its SHA-256 is the record hash. */\n\tline: string;\n}\n\n/**\n * Validate one line as a record of `kind`. Throws `TRANSFER_RECORD_INVALID`\n * (with a location but never record content) or `TRANSFER_LIMIT_EXCEEDED`.\n */\nexport function decodeRecordLine<K extends RecordKind>(\n\tkind: K,\n\tline: string,\n\tlocation: { path: string; line: number },\n): DecodedRecord<K> {\n\tif (encoder.encode(line).byteLength > TRANSFER_LIMITS.recordLineBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Record exceeds the line size limit\", {\n\t\t\tdetail: { path: location.path, line: location.line },\n\t\t});\n\t}\n\tlet raw: unknown;\n\ttry {\n\t\traw = parseCanonicalJson(line);\n\t} catch (error) {\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Record is not canonical JSON\", {\n\t\t\tdetail: {\n\t\t\t\tpath: location.path,\n\t\t\t\tline: location.line,\n\t\t\t\treason: error instanceof CanonicalJsonError ? error.message : \"invalid\",\n\t\t\t},\n\t\t});\n\t}\n\tconst result = validateRecord(kind, raw);\n\tif (!result.success) {\n\t\tconst first = result.issues[0];\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Record failed validation\", {\n\t\t\tdetail: {\n\t\t\t\tpath: location.path,\n\t\t\t\tline: location.line,\n\t\t\t\tfield: first?.path ?? \"\",\n\t\t\t\treason: first?.message ?? \"invalid\",\n\t\t\t},\n\t\t});\n\t}\n\treturn { record: result.record, line };\n}\n\n/**\n * Split chunk text into lines, enforcing chunk limits and the trailing\n * newline. Returns the lines without their newlines.\n */\nexport function splitChunkLines(bytes: Uint8Array, path: string): string[] {\n\tif (bytes.byteLength > TRANSFER_LIMITS.chunkBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk exceeds the size limit\", {\n\t\t\tdetail: { path, limit: TRANSFER_LIMITS.chunkBytes },\n\t\t});\n\t}\n\tconst text = decodeUtf8(bytes, \"TRANSFER_RECORD_INVALID\");\n\tif (text.length === 0) {\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Chunk is empty\", { detail: { path } });\n\t}\n\tif (!text.endsWith(\"\\n\")) {\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Chunk must end with a newline\", {\n\t\t\tdetail: { path },\n\t\t});\n\t}\n\tconst lines = text.slice(0, -1).split(\"\\n\");\n\tif (lines.length > TRANSFER_LIMITS.chunkRecords) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk has too many lines\", {\n\t\t\tdetail: { path, limit: TRANSFER_LIMITS.chunkRecords },\n\t\t});\n\t}\n\tlines.forEach((line, index) => {\n\t\tif (line.length === 0) {\n\t\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Chunk contains a blank line\", {\n\t\t\t\tdetail: { path, line: index + 1 },\n\t\t\t});\n\t\t}\n\t});\n\treturn lines;\n}\n\n/** Join canonical lines into chunk bytes, enforcing chunk limits. */\nexport function encodeChunk(lines: readonly string[], path: string): Uint8Array {\n\tif (lines.length === 0 || lines.length > TRANSFER_LIMITS.chunkRecords) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk line count out of range\", {\n\t\t\tdetail: { path, lines: lines.length },\n\t\t});\n\t}\n\tconst bytes = encoder.encode(`${lines.join(\"\\n\")}\\n`);\n\tif (bytes.byteLength > TRANSFER_LIMITS.chunkBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk exceeds the size limit\", {\n\t\t\tdetail: { path, bytes: bytes.byteLength },\n\t\t});\n\t}\n\treturn bytes;\n}\n","/**\n * Staged package reader and writer.\n *\n * The writer stores package files under a {@link TransferStage}, returning\n * the index entry (size and digest) for each. The reader parses and validates\n * what is staged: the manifest, index chunks (checked against the digests the\n * manifest pins), record chunks (every line strictly validated), and blobs.\n */\n\nimport { TransferError } from \"../errors.js\";\nimport { canonicalJson } from \"../format/canonical.js\";\nimport { packageDigest, sha256Hex, type Sha256Digest } from \"../format/digest.js\";\nimport type { RecordKind, RecordOfKind } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tparseIndexLine,\n\tparseManifest,\n\tserializeManifest,\n\ttype IndexChunkRef,\n\ttype PackageFileEntry,\n\ttype SitePackageManifest,\n} from \"../format/manifest.js\";\nimport { indexChunkPath, MANIFEST_PATH, mediaBlobPath, recordChunkPath } from \"../format/paths.js\";\nimport {\n\tdecodeRecordLine,\n\tencodeChunk,\n\tencodeRecordLine,\n\tsplitChunkLines,\n} from \"../format/records.js\";\nimport { readStreamBytes, TransferStage, type ExpectedFile } from \"./stage.js\";\n\nconst encoder = new TextEncoder();\n\nexport class StagedPackageWriter {\n\tconstructor(readonly stage: TransferStage) {}\n\n\t/** Store bytes at a package path; returns its index entry (without `records`). */\n\tasync writeFile(path: string, bytes: Uint8Array): Promise<PackageFileEntry> {\n\t\tconst sha256 = await sha256Hex(bytes);\n\t\tawait this.stage.putVerified(path, bytes, bytes.byteLength, sha256);\n\t\treturn { path, bytes: bytes.byteLength, sha256 };\n\t}\n\n\t/** Encode and store one record chunk. Records must already be in stream order. */\n\tasync writeRecordChunk<K extends RecordKind>(\n\t\tkind: K,\n\t\tseq: number,\n\t\trecords: readonly RecordOfKind<K>[],\n\t): Promise<PackageFileEntry> {\n\t\tconst path = recordChunkPath(kind, seq);\n\t\tfor (const record of records) {\n\t\t\tif (record.kind !== kind) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Record kind does not match its chunk\", {\n\t\t\t\t\tdetail: { path, id: record.id },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tconst lines = records.map((record) => encodeRecordLine(record));\n\t\tconst entry = await this.writeFile(path, encodeChunk(lines, path));\n\t\treturn { ...entry, records: records.length };\n\t}\n\n\t/** Encode and store one index chunk. */\n\tasync writeIndexChunk(seq: number, entries: readonly PackageFileEntry[]): Promise<IndexChunkRef> {\n\t\tconst path = indexChunkPath(seq);\n\t\tconst lines = entries.map((entry) => canonicalJson(entry));\n\t\tconst file = await this.writeFile(path, encodeChunk(lines, path));\n\t\treturn { path, bytes: file.bytes, sha256: file.sha256, entries: entries.length };\n\t}\n\n\t/** Store a media blob, verifying the declared size and digest as it streams. */\n\tasync writeBlob(\n\t\tsha256: string,\n\t\tbody: ReadableStream<Uint8Array> | Uint8Array,\n\t\tbytes: number,\n\t): Promise<PackageFileEntry> {\n\t\tconst path = mediaBlobPath(sha256);\n\t\tawait this.stage.putVerified(path, body, bytes, sha256);\n\t\treturn { path, bytes, sha256 };\n\t}\n\n\t/** Store the manifest; returns its package digest. */\n\tasync writeManifest(manifest: SitePackageManifest): Promise<Sha256Digest> {\n\t\tconst text = serializeManifest(parseManifest(serializeManifest(manifest)));\n\t\tconst bytes = encoder.encode(text);\n\t\tawait this.stage.putVerified(MANIFEST_PATH, bytes, bytes.byteLength, await sha256Hex(bytes));\n\t\treturn packageDigest(manifest);\n\t}\n}\n\nexport interface StagedRecord<K extends RecordKind> {\n\trecord: RecordOfKind<K>;\n\t/** Canonical line without newline; its SHA-256 is the record hash. */\n\tline: string;\n\tseq: number;\n\t/** Zero-based line number within the chunk. */\n\tindex: number;\n}\n\n/** Size and digest a staged file must have when read, or null when it is not verified. */\nexport type StagedFileDigests = (path: string) => Promise<ExpectedFile | null>;\n\nexport class StagedPackageReader {\n\t#manifest: SitePackageManifest | undefined;\n\n\t/**\n\t * With `digests`, every record chunk read is checked against the size and\n\t * digest it was verified with, and a chunk that is not verified is missing.\n\t */\n\tconstructor(\n\t\treadonly stage: TransferStage,\n\t\tprivate readonly digests?: StagedFileDigests,\n\t) {}\n\n\t/** The parsed, validated manifest (read once). */\n\tasync manifest(): Promise<SitePackageManifest> {\n\t\tif (!this.#manifest) {\n\t\t\tconst bytes = await this.stage.readBytes(MANIFEST_PATH, TRANSFER_LIMITS.manifestBytes);\n\t\t\tthis.#manifest = parseManifest(bytes);\n\t\t}\n\t\treturn this.#manifest;\n\t}\n\n\tasync digest(): Promise<Sha256Digest> {\n\t\treturn packageDigest(await this.manifest());\n\t}\n\n\t/** Entries of one index chunk, verified against the digest the manifest pins. */\n\tasync indexChunk(seq: number): Promise<PackageFileEntry[]> {\n\t\tconst manifest = await this.manifest();\n\t\tconst ref = manifest.index[seq];\n\t\tif (!ref) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Index chunk is not declared\", {\n\t\t\t\tdetail: { seq },\n\t\t\t});\n\t\t}\n\t\tconst bytes = await this.readVerified(ref.path, ref);\n\t\tconst entries = splitChunkLines(bytes, ref.path).map((line) => parseIndexLine(line));\n\t\tif (entries.length !== ref.entries) {\n\t\t\tthrow new TransferError(\"TRANSFER_MANIFEST_INVALID\", \"Index chunk entry count mismatch\", {\n\t\t\t\tdetail: { path: ref.path },\n\t\t\t});\n\t\t}\n\t\treturn entries;\n\t}\n\n\t/** Every index entry in path order, starting at index chunk `fromSeq`. */\n\tasync *index(fromSeq = 0): AsyncGenerator<{ seq: number; entry: PackageFileEntry }> {\n\t\tconst manifest = await this.manifest();\n\t\tfor (let seq = fromSeq; seq < manifest.index.length; seq++) {\n\t\t\tfor (const entry of await this.indexChunk(seq)) yield { seq, entry };\n\t\t}\n\t}\n\n\t/**\n\t * Records of one chunk, each strictly validated. Pass `expected` (from the\n\t * index) to also verify the chunk's size and digest; otherwise the reader's\n\t * `digests`, when it has them, supply it.\n\t */\n\tasync readChunk<K extends RecordKind>(\n\t\tkind: K,\n\t\tseq: number,\n\t\texpected?: ExpectedFile,\n\t): Promise<Array<StagedRecord<K>>> {\n\t\tconst path = recordChunkPath(kind, seq);\n\t\tconst file = expected ?? (await this.expectedFile(path));\n\t\tconst bytes = file\n\t\t\t? await this.readVerified(path, file)\n\t\t\t: await this.stage.readBytes(path, TRANSFER_LIMITS.chunkBytes);\n\t\treturn splitChunkLines(bytes, path).map((line, index) => {\n\t\t\tconst decoded = decodeRecordLine(kind, line, { path, line: index + 1 });\n\t\t\treturn { record: decoded.record, line: decoded.line, seq, index };\n\t\t});\n\t}\n\n\t/** Records of `kind` in stream order, starting at chunk `fromSeq`. */\n\tasync *records<K extends RecordKind>(kind: K, fromSeq = 0): AsyncGenerator<StagedRecord<K>> {\n\t\tconst manifest = await this.manifest();\n\t\tconst chunks = manifest.records[kind]?.chunks ?? 0;\n\t\tfor (let seq = fromSeq; seq < chunks; seq++) {\n\t\t\tyield* await this.readChunk(kind, seq);\n\t\t}\n\t}\n\n\tasync blob(sha256: string): Promise<ReadableStream<Uint8Array>> {\n\t\treturn (await this.stage.open(mediaBlobPath(sha256))).body;\n\t}\n\n\tprivate async expectedFile(path: string): Promise<ExpectedFile | undefined> {\n\t\tif (!this.digests) return undefined;\n\t\tconst expected = await this.digests(path);\n\t\tif (!expected) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Staged file is not verified\", {\n\t\t\t\tdetail: { path },\n\t\t\t});\n\t\t}\n\t\treturn expected;\n\t}\n\n\tprivate async readVerified(path: string, expected: ExpectedFile): Promise<Uint8Array> {\n\t\tconst file = await this.stage.open(path);\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = await readStreamBytes(file.body, Math.max(expected.bytes, 0));\n\t\t} catch (error) {\n\t\t\tif (error instanceof TransferError && error.code === \"TRANSFER_LIMIT_EXCEEDED\") {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\", {\n\t\t\t\t\tdetail: { path },\n\t\t\t\t});\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tif (bytes.byteLength !== expected.bytes) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\", {\n\t\t\t\tdetail: { path },\n\t\t\t});\n\t\t}\n\t\tif ((await sha256Hex(bytes)) !== expected.sha256) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_FILE_DIGEST_MISMATCH\",\n\t\t\t\t\"Staged file digest does not match\",\n\t\t\t\t{\n\t\t\t\t\tdetail: { path },\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn bytes;\n\t}\n}\n","/**\n * Is the target's portable domain empty enough to import into?\n *\n * Setup always applies a seed (the project's seed file or the built-in\n * default), so a brand-new site is never row-empty. The domain counts as\n * empty when it holds no content and no user-made schema: no term\n * assignments, relations, content references, bylines or byline fields,\n * media or media folders, revisions, SEO rows, comments or reactions,\n * redirects, or user sections, and only seeded collections and block types,\n * no collection with a row in its content table (trash included). Everything\n * else a seed leaves is scaffold:\n * - the seeded collections;\n * - the seeded block types (`source = 'seed'`) and their versions;\n * - taxonomy definitions attached only to those collections or to\n * collections that do not exist, and their unassigned terms;\n * - menus and their items, widget areas and their widgets;\n * - sections with `source = 'theme'` (seeded theme sections).\n *\n * The importer's `clear_scaffold` stage deletes exactly the reported\n * `seededScaffold` items, in order: terms before their definitions, menu\n * items before menus, widgets before widget areas, and block types after the\n * collections whose fields name them.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../database/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\n\nexport type ScaffoldItem =\n\t| { type: \"collection\"; id: string; slug: string }\n\t| { type: \"term\"; id: string; name: string; slug: string; locale: string }\n\t| { type: \"taxonomy_def\"; id: string; name: string; locale: string }\n\t| { type: \"menu_item\"; id: string; menuId: string; label: string }\n\t| { type: \"menu\"; id: string; name: string; locale: string }\n\t| { type: \"widget\"; id: string; areaId: string; widgetType: string }\n\t| { type: \"widget_area\"; id: string; name: string }\n\t| { type: \"section\"; id: string; slug: string }\n\t| { type: \"block_type\"; id: string; slug: string };\n\nexport type DomainBlocker =\n\t| { code: \"table_not_empty\"; table: string }\n\t| { code: \"collection_not_seeded\"; id: string; slug: string }\n\t| { code: \"block_type_not_seeded\"; id: string; slug: string }\n\t| { code: \"collection_has_entries\"; id: string; slug: string }\n\t| { code: \"taxonomy_def_not_scaffold\"; id: string; name: string };\n\nexport interface PortableDomainInspection {\n\tempty: boolean;\n\tseededScaffold: ScaffoldItem[];\n\tblockers: DomainBlocker[];\n}\n\n/** Tables that must hold no rows at all (sections are checked separately). */\nconst MUST_BE_EMPTY = [\n\t\"content_taxonomies\",\n\t\"_emdash_relations\",\n\t\"_emdash_content_references\",\n\t\"_emdash_bylines\",\n\t\"_emdash_byline_fields\",\n\t\"_emdash_byline_field_values\",\n\t\"_emdash_byline_field_group_values\",\n\t\"_emdash_content_bylines\",\n\t\"media\",\n\t\"media_folders\",\n\t\"revisions\",\n\t\"_emdash_seo\",\n\t\"_emdash_comments\",\n\t\"_emdash_comment_reactions\",\n\t\"_emdash_redirects\",\n] as const;\n\nfunction isSeededSource(source: string | null): boolean {\n\treturn source === \"seed\" || (source?.startsWith(\"template:\") ?? false);\n}\n\nfunction parseCollections(value: string | null): string[] | null {\n\tif (value === null) return [];\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(value);\n\t\tif (!Array.isArray(parsed)) return null;\n\t\treturn parsed.every((item): item is string => typeof item === \"string\") ? parsed : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function inspectPortableDomain(\n\tdb: Kysely<Database>,\n): Promise<PortableDomainInspection> {\n\tconst blockers: DomainBlocker[] = [];\n\tconst seededScaffold: ScaffoldItem[] = [];\n\n\tconst probes = MUST_BE_EMPTY.map(\n\t\t(table, index) => sql`(SELECT 1 FROM ${sql.ref(table)} LIMIT 1) AS ${sql.ref(`t${index}`)}`,\n\t);\n\tprobes.push(\n\t\tsql`(SELECT 1 FROM _emdash_sections WHERE source <> 'theme' LIMIT 1) AS ${sql.ref(\"user_sections\")}`,\n\t);\n\tconst occupied = await sql<Record<string, unknown>>`SELECT ${sql.join(probes)}`.execute(db);\n\tconst flags = occupied.rows[0] ?? {};\n\tMUST_BE_EMPTY.forEach((table, index) => {\n\t\tif (flags[`t${index}`] != null) blockers.push({ code: \"table_not_empty\", table });\n\t});\n\tif (flags.user_sections != null)\n\t\tblockers.push({ code: \"table_not_empty\", table: \"_emdash_sections\" });\n\n\tconst collections = await db\n\t\t.selectFrom(\"_emdash_collections\")\n\t\t.select([\"id\", \"slug\", \"source\"])\n\t\t.orderBy(\"slug\")\n\t\t.execute();\n\tconst seeded = collections.filter((collection) => isSeededSource(collection.source));\n\tfor (const collection of collections) {\n\t\tif (!isSeededSource(collection.source)) {\n\t\t\tblockers.push({ code: \"collection_not_seeded\", id: collection.id, slug: collection.slug });\n\t\t}\n\t}\n\n\tif (seeded.length > 0) {\n\t\tconst contentProbes = seeded.map((collection, index) => {\n\t\t\tvalidateIdentifier(collection.slug, \"collection slug\");\n\t\t\treturn sql`(SELECT 1 FROM ${sql.ref(`ec_${collection.slug}`)} LIMIT 1) AS ${sql.ref(`c${index}`)}`;\n\t\t});\n\t\tconst content = await sql<Record<string, unknown>>`SELECT ${sql.join(contentProbes)}`.execute(\n\t\t\tdb,\n\t\t);\n\t\tconst contentFlags = content.rows[0] ?? {};\n\t\tseeded.forEach((collection, index) => {\n\t\t\tif (contentFlags[`c${index}`] != null) {\n\t\t\t\tblockers.push({ code: \"collection_has_entries\", id: collection.id, slug: collection.slug });\n\t\t\t} else {\n\t\t\t\tseededScaffold.push({ type: \"collection\", id: collection.id, slug: collection.slug });\n\t\t\t}\n\t\t});\n\t}\n\n\tconst scaffoldSlugs = new Set(\n\t\tseededScaffold.flatMap((item) => (item.type === \"collection\" ? [item.slug] : [])),\n\t);\n\tconst existingSlugs = new Set(collections.map((collection) => collection.slug));\n\tconst taxonomyDefs = await db\n\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t.select([\"id\", \"name\", \"locale\", \"collections\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tconst scaffoldDefs: ScaffoldItem[] = [];\n\tfor (const def of taxonomyDefs) {\n\t\tconst attached = parseCollections(def.collections);\n\t\tif (attached?.every((slug) => scaffoldSlugs.has(slug) || !existingSlugs.has(slug))) {\n\t\t\tscaffoldDefs.push({ type: \"taxonomy_def\", id: def.id, name: def.name, locale: def.locale });\n\t\t} else {\n\t\t\tblockers.push({ code: \"taxonomy_def_not_scaffold\", id: def.id, name: def.name });\n\t\t}\n\t}\n\n\tconst blockTypes = await db\n\t\t.selectFrom(\"_emdash_block_types\")\n\t\t.select([\"id\", \"slug\", \"source\"])\n\t\t.orderBy(\"slug\")\n\t\t.execute();\n\tfor (const blockType of blockTypes) {\n\t\tif (blockType.source !== \"seed\") {\n\t\t\tblockers.push({ code: \"block_type_not_seeded\", id: blockType.id, slug: blockType.slug });\n\t\t}\n\t}\n\n\t// Terms, menu items, and widgets are only scaffold on a site without content;\n\t// on any other site the blockers already say it is not empty.\n\tif (blockers.length > 0) return { empty: false, seededScaffold, blockers };\n\n\tconst terms = await db\n\t\t.selectFrom(\"taxonomies\")\n\t\t.select([\"id\", \"name\", \"slug\", \"locale\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const term of terms) {\n\t\tseededScaffold.push({\n\t\t\ttype: \"term\",\n\t\t\tid: term.id,\n\t\t\tname: term.name,\n\t\t\tslug: term.slug,\n\t\t\tlocale: term.locale,\n\t\t});\n\t}\n\tseededScaffold.push(...scaffoldDefs);\n\n\tconst menuItems = await db\n\t\t.selectFrom(\"_emdash_menu_items\")\n\t\t.select([\"id\", \"menu_id\", \"label\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const item of menuItems) {\n\t\tseededScaffold.push({\n\t\t\ttype: \"menu_item\",\n\t\t\tid: item.id,\n\t\t\tmenuId: item.menu_id,\n\t\t\tlabel: item.label,\n\t\t});\n\t}\n\n\tconst menus = await db\n\t\t.selectFrom(\"_emdash_menus\")\n\t\t.select([\"id\", \"name\", \"locale\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const menu of menus) {\n\t\tseededScaffold.push({ type: \"menu\", id: menu.id, name: menu.name, locale: menu.locale });\n\t}\n\n\tconst widgets = await db\n\t\t.selectFrom(\"_emdash_widgets\")\n\t\t.select([\"id\", \"area_id\", \"type\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const widget of widgets) {\n\t\tseededScaffold.push({\n\t\t\ttype: \"widget\",\n\t\t\tid: widget.id,\n\t\t\tareaId: widget.area_id,\n\t\t\twidgetType: widget.type,\n\t\t});\n\t}\n\n\tconst areas = await db\n\t\t.selectFrom(\"_emdash_widget_areas\")\n\t\t.select([\"id\", \"name\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const area of areas)\n\t\tseededScaffold.push({ type: \"widget_area\", id: area.id, name: area.name });\n\n\tconst sections = await db\n\t\t.selectFrom(\"_emdash_sections\")\n\t\t.select([\"id\", \"slug\"])\n\t\t.where(\"source\", \"=\", \"theme\")\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const section of sections) {\n\t\tseededScaffold.push({ type: \"section\", id: section.id, slug: section.slug });\n\t}\n\n\tfor (const blockType of blockTypes) {\n\t\tseededScaffold.push({ type: \"block_type\", id: blockType.id, slug: blockType.slug });\n\t}\n\n\treturn { empty: true, seededScaffold, blockers };\n}\n","/**\n * Reading staged record chunks for analysis, turning every failure into a\n * blocker whose message and detail never include package content: only the\n * error code of a read failure is used, with a fixed message.\n */\n\nimport { TransferError, type TransferErrorCode } from \"../errors.js\";\nimport { parseCanonicalJson } from \"../format/canonical.js\";\nimport { sha256Hex } from \"../format/digest.js\";\nimport { validateRecord, type RecordKind, type RecordOfKind } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { PlanBlocker, PlanBlockerCode } from \"../format/plan.js\";\nimport { splitChunkLines } from \"../format/records.js\";\nimport { readStreamBytes, type ExpectedFile, type TransferStage } from \"../staging/stage.js\";\n\nconst encoder = new TextEncoder();\n\nconst ERROR_BLOCKERS: Partial<\n\tRecord<TransferErrorCode, { code: PlanBlockerCode; message: string }>\n> = {\n\tTRANSFER_LIMIT_EXCEEDED: { code: \"limit_exceeded\", message: \"Package file exceeds a limit\" },\n\tTRANSFER_FILE_MISSING: { code: \"file_missing\", message: \"Package file is missing\" },\n\tTRANSFER_FILE_SIZE_MISMATCH: {\n\t\tcode: \"file_mismatch\",\n\t\tmessage: \"Package file size does not match its declaration\",\n\t},\n\tTRANSFER_FILE_DIGEST_MISMATCH: {\n\t\tcode: \"file_mismatch\",\n\t\tmessage: \"Package file digest does not match its declaration\",\n\t},\n\tTRANSFER_UNSUPPORTED_FORMAT: {\n\t\tcode: \"unsupported_format\",\n\t\tmessage: \"Unsupported package format or version\",\n\t},\n\tTRANSFER_UNSUPPORTED_FEATURE: {\n\t\tcode: \"unsupported_feature\",\n\t\tmessage: \"Package requires features this site does not support\",\n\t},\n\tTRANSFER_RECORD_INVALID: { code: \"record_invalid\", message: \"Package file is malformed\" },\n\tTRANSFER_PATH_INVALID: { code: \"package_invalid\", message: \"Package path is invalid\" },\n};\n\n/**\n * A blocker for a {@link TransferError} raised while reading package files.\n * Only the error code is used; the location comes from the caller.\n */\nexport function blockerForError(\n\terror: TransferError,\n\tlocation: { path?: string; line?: number } = {},\n): PlanBlocker {\n\tconst mapped = ERROR_BLOCKERS[error.code] ?? {\n\t\tcode: \"package_invalid\",\n\t\tmessage: \"Package file failed validation\",\n\t};\n\tconst detail: Record<string, string | number> = {};\n\tif (location.path !== undefined) detail.path = location.path;\n\tif (location.line !== undefined) detail.line = location.line;\n\treturn { code: mapped.code, message: mapped.message, detail };\n}\n\n/** Read one staged chunk, verifying size and digest, and split it into lines. */\nexport async function readVerifiedChunk(\n\tstage: TransferStage,\n\tpath: string,\n\texpected: ExpectedFile,\n): Promise<string[]> {\n\tconst file = await stage.open(path);\n\tlet bytes: Uint8Array;\n\ttry {\n\t\tbytes = await readStreamBytes(file.body, expected.bytes);\n\t} catch (error) {\n\t\tif (error instanceof TransferError && error.code === \"TRANSFER_LIMIT_EXCEEDED\") {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\");\n\t\t}\n\t\tthrow error;\n\t}\n\tif (bytes.byteLength !== expected.bytes) {\n\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\");\n\t}\n\tif ((await sha256Hex(bytes)) !== expected.sha256) {\n\t\tthrow new TransferError(\"TRANSFER_FILE_DIGEST_MISMATCH\", \"Staged file digest does not match\");\n\t}\n\treturn splitChunkLines(bytes, path);\n}\n\nexport type DecodedLine<K extends RecordKind> =\n\t| { ok: true; record: RecordOfKind<K> }\n\t| { ok: false; blocker: PlanBlocker };\n\n/**\n * Decode and strictly validate one record line. A failure names the chunk,\n * the one-based line, and at most a known top-level property of the kind.\n */\nexport function decodeRecordLine<K extends RecordKind>(\n\tkind: K,\n\tline: string,\n\tlocation: { path: string; line: number },\n): DecodedLine<K> {\n\tconst detail = { path: location.path, line: location.line };\n\tif (encoder.encode(line).byteLength > TRANSFER_LIMITS.recordLineBytes) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tblocker: {\n\t\t\t\tcode: \"limit_exceeded\",\n\t\t\t\tmessage: \"Record exceeds the line size limit\",\n\t\t\t\tkind,\n\t\t\t\tdetail,\n\t\t\t},\n\t\t};\n\t}\n\tlet raw: unknown;\n\ttry {\n\t\traw = parseCanonicalJson(line);\n\t} catch {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tblocker: { code: \"record_invalid\", message: \"Record is not canonical JSON\", kind, detail },\n\t\t};\n\t}\n\tconst result = validateRecord(kind, raw);\n\tif (!result.success) {\n\t\tconst field = result.issues[0]?.path || undefined;\n\t\treturn {\n\t\t\tok: false,\n\t\t\tblocker: {\n\t\t\t\tcode: \"record_invalid\",\n\t\t\t\tmessage: \"Record failed schema validation\",\n\t\t\t\tkind,\n\t\t\t\tdetail: field === undefined ? detail : { ...detail, field },\n\t\t\t},\n\t\t};\n\t}\n\treturn { ok: true, record: result.record };\n}\n","/**\n * Values the site's own write paths refuse. The importer writes rows\n * directly, so analysis applies the same validators the admin API does and\n * blocks a package holding a value that API would reject.\n */\n\nimport { httpUrl } from \"../../api/schemas/common.js\";\nimport { safeHref } from \"../../api/schemas/menus.js\";\nimport { createRedirectBody } from \"../../api/schemas/redirects.js\";\nimport { coerceFieldValue } from \"../../database/repositories/byline.js\";\nimport { EmDashValidationError } from \"../../database/repositories/types.js\";\nimport { isPattern, validateDestinationParams, validatePattern } from \"../../redirects/patterns.js\";\nimport { isTerminalStatus } from \"../../redirects/status.js\";\nimport { validateBlockFields } from \"../../schema/block-type-contract.js\";\nimport type { BlockFieldDefinition } from \"../../schema/block-types.js\";\nimport { SchemaError } from \"../../schema/registry.js\";\nimport { RESERVED_FIELD_SLUGS, type BylineFieldType } from \"../../schema/types.js\";\nimport { compileUrlPattern } from \"../../schema/url-pattern.js\";\nimport type {\n\tBlockTypeRecord,\n\tBlockTypeVersionRecord,\n\tRedirectRecord,\n\tSitePackageRecord,\n} from \"../format/kinds.js\";\nimport type { ValueIssue } from \"./values.js\";\n\n/** What the byline field write path checks a value against. */\nexport interface BylineFieldFacts {\n\ttype: BylineFieldType;\n\t/** Choices of a `select` field. */\n\toptions?: string[];\n}\n\n/** Facts from earlier records that some rules need. */\nexport interface WriteRuleFacts {\n\t/** Byline fields by id. */\n\tbylineFields: ReadonlyMap<string, BylineFieldFacts>;\n}\n\nfunction rejected(property: string, message: string): ValueIssue {\n\treturn { code: \"value_constraint_violation\", message, property };\n}\n\nconst REDIRECT_BODY_MESSAGES: Record<string, string> = {\n\tsource: \"Redirect source is not a path on this site\",\n\tdestination: \"Redirect destination is not a path on this site\",\n\ttype: \"Redirect type is not supported\",\n};\n\nfunction redirectIssues(record: RedirectRecord): ValueIssue[] {\n\tconst issues: ValueIssue[] = [];\n\tconst body = createRedirectBody.safeParse({\n\t\tsource: record.source,\n\t\tdestination: record.destination,\n\t\ttype: record.type,\n\t});\n\tif (!body.success) {\n\t\tconst properties = new Set(body.error.issues.map((issue) => String(issue.path[0])));\n\t\tfor (const [property, message] of Object.entries(REDIRECT_BODY_MESSAGES)) {\n\t\t\tif (properties.has(property)) issues.push(rejected(property, message));\n\t\t}\n\t}\n\tconst pattern = isPattern(record.source);\n\tif (record.isPattern !== pattern) {\n\t\tissues.push(rejected(\"isPattern\", \"Redirect pattern flag does not match its source\"));\n\t}\n\tif (pattern) {\n\t\tif (validatePattern(record.source) !== null) {\n\t\t\tissues.push(rejected(\"source\", \"Redirect source is not a valid pattern\"));\n\t\t} else if (\n\t\t\t!isTerminalStatus(record.type) &&\n\t\t\tvalidateDestinationParams(record.source, record.destination) !== null\n\t\t) {\n\t\t\tissues.push(\n\t\t\t\trejected(\n\t\t\t\t\t\"destination\",\n\t\t\t\t\t\"Redirect destination uses a parameter its source does not capture\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\treturn issues;\n}\n\n/** Whether the redirect API would accept this redirect; only these may be compiled. */\nexport function isImportableRedirect(record: RedirectRecord): boolean {\n\treturn redirectIssues(record).length === 0;\n}\n\nconst BYLINE_FIELD_VALUE_MESSAGES: Record<BylineFieldType, string> = {\n\tstring: \"Byline field value is not a string\",\n\ttext: \"Byline field value is not a string\",\n\turl: \"Byline field value is not an http or https URL\",\n\tboolean: \"Byline field value is not a boolean\",\n\tselect: \"Byline field value is not one of the field's choices\",\n};\n\nfunction bylineFieldValueIssues(field: BylineFieldFacts | undefined, value: unknown): ValueIssue[] {\n\tif (!field) return [];\n\ttry {\n\t\tcoerceFieldValue(\n\t\t\t{ slug: \"\", type: field.type, validation: { options: field.options } },\n\t\t\tvalue ?? null,\n\t\t);\n\t\treturn [];\n\t} catch (error) {\n\t\tif (error instanceof EmDashValidationError) {\n\t\t\treturn [rejected(\"value\", BYLINE_FIELD_VALUE_MESSAGES[field.type])];\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction acceptsUrlPattern(pattern: string): boolean {\n\ttry {\n\t\tcompileUrlPattern(pattern);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nconst URL_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*:/;\n\n/**\n * The SEO API takes only http(s) canonical URLs, but stored canonicals may\n * also be site paths, which the renderer resolves against the site URL.\n */\nfunction acceptsCanonical(canonical: string): boolean {\n\tif (URL_SCHEME.test(canonical) || canonical.startsWith(\"//\")) {\n\t\treturn httpUrl.safeParse(canonical).success;\n\t}\n\treturn true;\n}\n\nconst RESERVED_BLOCK_TYPE_SLUGS: ReadonlySet<string> = new Set(RESERVED_FIELD_SLUGS);\nconst MAX_BLOCK_TYPE_LABEL = 200;\n\nfunction blockTypeIssues(record: BlockTypeRecord): ValueIssue[] {\n\tconst issues: ValueIssue[] = [];\n\tif (RESERVED_BLOCK_TYPE_SLUGS.has(record.slug)) {\n\t\tissues.push(rejected(\"slug\", \"Block type slug is reserved\"));\n\t}\n\tif (record.label.trim().length === 0 || record.label.length > MAX_BLOCK_TYPE_LABEL) {\n\t\tissues.push(rejected(\"label\", \"Block type label is empty or too long\"));\n\t}\n\tif (record.source !== \"user\" && record.source !== \"seed\") {\n\t\tissues.push(rejected(\"source\", \"Block type source is not supported\"));\n\t}\n\treturn issues;\n}\n\nfunction blockTypeVersionIssues(record: BlockTypeVersionRecord): ValueIssue[] {\n\tconst issues: ValueIssue[] = [];\n\tif (record.version < 1) issues.push(rejected(\"version\", \"Block type version is not positive\"));\n\ttry {\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- validateBlockFields checks every entry's shape\n\t\tvalidateBlockFields(record.fields as unknown as BlockFieldDefinition[]);\n\t} catch (error) {\n\t\tif (!(error instanceof SchemaError)) throw error;\n\t\tissues.push(rejected(\"fields\", \"Block type fields are not valid on this site\"));\n\t}\n\treturn issues;\n}\n\nexport function writeRuleIssues(record: SitePackageRecord, facts: WriteRuleFacts): ValueIssue[] {\n\tswitch (record.kind) {\n\t\tcase \"block_type\":\n\t\t\treturn blockTypeIssues(record);\n\t\tcase \"block_type_version\":\n\t\t\treturn blockTypeVersionIssues(record);\n\t\tcase \"redirect\":\n\t\t\treturn redirectIssues(record);\n\t\tcase \"collection\":\n\t\t\treturn record.urlPattern !== undefined && !acceptsUrlPattern(record.urlPattern)\n\t\t\t\t? [rejected(\"urlPattern\", \"Collection URL pattern is invalid\")]\n\t\t\t\t: [];\n\t\tcase \"byline\":\n\t\t\treturn record.websiteUrl !== undefined && !httpUrl.safeParse(record.websiteUrl).success\n\t\t\t\t? [rejected(\"websiteUrl\", \"Byline website is not an http or https URL\")]\n\t\t\t\t: [];\n\t\tcase \"byline_field_value\":\n\t\tcase \"byline_field_group_value\":\n\t\t\treturn bylineFieldValueIssues(facts.bylineFields.get(record.fieldId), record.value);\n\t\tcase \"seo\":\n\t\t\treturn record.seoCanonical !== undefined && !acceptsCanonical(record.seoCanonical)\n\t\t\t\t? [rejected(\"seoCanonical\", \"Canonical URL is not an http or https URL or a site path\")]\n\t\t\t\t: [];\n\t\tcase \"menu_item\":\n\t\t\treturn record.customUrl !== undefined && !safeHref.safeParse(record.customUrl).success\n\t\t\t\t? [rejected(\"customUrl\", \"Menu item URL uses a scheme menus do not allow\")]\n\t\t\t\t: [];\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n","/**\n * Inspection of the import target: whether its portable domain is empty,\n * whether it is configured for the package's locales, which redirects would\n * loop, and which target users match package principals.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { isValidLocaleCode, type I18nConfig } from \"../../i18n/config.js\";\nimport { detectLoops, type RedirectEdge } from \"../../redirects/loops.js\";\nimport { SchemaRegistry } from \"../../schema/registry.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { VERSION } from \"../../version.js\";\nimport { inspectPortableDomain, type DomainBlocker, type ScaffoldItem } from \"../domain.js\";\nimport { isTransferError } from \"../errors.js\";\nimport { compareIds } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport { recordChunkPath } from \"../format/paths.js\";\nimport type { PlanBlocker } from \"../format/plan.js\";\nimport type { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport type { TransferStage } from \"../staging/stage.js\";\nimport { decodeRecordLine, readVerifiedChunk } from \"./read.js\";\nimport { isImportableRedirect } from \"./write-rules.js\";\n\n/** What analysis needs to know about the target site besides its database. */\nexport interface AnalysisTargetContext {\n\t/** Locales the site is configured for (Astro `i18n.locales`). */\n\tlocales: readonly string[];\n\t/** Largest media upload the site accepts, in bytes (`maxUploadSize`). */\n\tmaxUploadSize: number;\n\t/** EmDash version of the target, recorded in the plan. */\n\temdashVersion: string;\n}\n\n/**\n * Target context from the site's configuration. A site without i18n config\n * serves only the default locale `en`.\n */\nexport function analysisTargetContext(config: {\n\ti18n: I18nConfig | null;\n\tmaxUploadSize?: number;\n\temdashVersion?: string;\n}): AnalysisTargetContext {\n\treturn {\n\t\tlocales: config.i18n ? [...config.i18n.locales] : [\"en\"],\n\t\tmaxUploadSize: config.maxUploadSize ?? TRANSFER_LIMITS.defaultMaxBlobBytes,\n\t\temdashVersion: config.emdashVersion ?? VERSION,\n\t};\n}\n\nconst DOMAIN_BLOCKER_MESSAGES: Record<DomainBlocker[\"code\"], string> = {\n\ttable_not_empty: \"The site already has content of this kind\",\n\tcollection_not_seeded: \"The site has a collection that was not created by setup\",\n\tcollection_has_entries: \"A collection on the site already has entries\",\n\ttaxonomy_def_not_scaffold: \"The site has a taxonomy that was not created by setup\",\n\tblock_type_not_seeded: \"The site has a block type that was not created by setup\",\n};\n\nfunction domainBlocker(blocker: DomainBlocker): PlanBlocker {\n\tconst detail: Record<string, string> = { reason: blocker.code };\n\tif (blocker.code === \"table_not_empty\") detail.table = blocker.table;\n\telse if (blocker.code === \"taxonomy_def_not_scaffold\") detail.taxonomy = blocker.name;\n\telse if (blocker.code === \"block_type_not_seeded\") detail.blockType = blocker.slug;\n\telse detail.collection = blocker.slug;\n\treturn {\n\t\tcode: \"target_not_empty\",\n\t\tmessage: DOMAIN_BLOCKER_MESSAGES[blocker.code],\n\t\tdetail,\n\t};\n}\n\nexport interface DomainFindings {\n\tblockers: PlanBlocker[];\n\tscaffold: ScaffoldItem[];\n}\n\n/**\n * Domain blockers and scaffold, plus a blocker for each `ec_*` table named\n * for a package collection that has no collection row: the importer would\n * reuse it as the collection's table.\n */\nexport async function inspectTargetDomain(\n\tdb: Kysely<Database>,\n\tcollectionSlugs: readonly string[],\n): Promise<DomainFindings> {\n\tconst inspection = await inspectPortableDomain(db);\n\tconst blockers = inspection.blockers.map(domainBlocker);\n\tconst packaged = new Set(collectionSlugs);\n\tif (packaged.size > 0) {\n\t\tfor (const orphan of await new SchemaRegistry(db).discoverOrphanedTables()) {\n\t\t\tif (!packaged.has(orphan.slug)) continue;\n\t\t\tblockers.push({\n\t\t\t\tcode: \"target_not_empty\",\n\t\t\t\tmessage: \"The site has a leftover content table for a collection in the package\",\n\t\t\t\tdetail: { reason: \"orphaned_table\", table: orphan.tableName },\n\t\t\t});\n\t\t}\n\t}\n\treturn { blockers, scaffold: inspection.seededScaffold };\n}\n\n/** The target's spelling of `locale`: an exact match, else a case-insensitive one. */\nfunction configuredLocale(locale: string, target: AnalysisTargetContext): string | undefined {\n\tif (target.locales.includes(locale)) return locale;\n\tconst folded = locale.toLowerCase();\n\treturn target.locales.find((candidate) => candidate.toLowerCase() === folded);\n}\n\n/**\n * A blocker for each package locale the target is not configured for\n * (case-insensitive), and for each that shares the target's spelling with\n * another package locale, since their rows would collide once recased.\n */\nexport function checkLocales(\n\tmanifest: SitePackageManifest,\n\ttarget: AnalysisTargetContext,\n): PlanBlocker[] {\n\tconst blockers: PlanBlocker[] = [];\n\tconst claimed = new Set(\n\t\tmanifest.locales.used.filter((locale) => target.locales.includes(locale)),\n\t);\n\tfor (const locale of manifest.locales.used) {\n\t\tif (target.locales.includes(locale)) continue;\n\t\tconst configured = configuredLocale(locale, target);\n\t\tif (configured !== undefined && !claimed.has(configured)) {\n\t\t\tclaimed.add(configured);\n\t\t\tcontinue;\n\t\t}\n\t\tblockers.push({\n\t\t\tcode: \"locale_not_configured\",\n\t\t\tmessage:\n\t\t\t\tconfigured === undefined\n\t\t\t\t\t? \"The package uses a locale this site is not configured for\"\n\t\t\t\t\t: \"The package uses locales that differ only in case\",\n\t\t\t...(isValidLocaleCode(locale) ? { detail: { locale } } : {}),\n\t\t});\n\t}\n\treturn blockers;\n}\n\n/** Package locales the target configures with different casing, and the target's spelling. */\nexport function localeRecasing(\n\tmanifest: SitePackageManifest,\n\ttarget: AnalysisTargetContext,\n): Array<{ from: string; to: string }> {\n\treturn manifest.locales.used.flatMap((locale) => {\n\t\tconst configured = configuredLocale(locale, target);\n\t\treturn configured === undefined || configured === locale\n\t\t\t? []\n\t\t\t: [{ from: locale, to: configured }];\n\t});\n}\n\n/** Redirect packages above this size are not checked for loops. */\nexport const MAX_LOOP_CHECKED_REDIRECTS = 10_000;\n\n/**\n * Ids of package redirects that take part in a loop, using the same detection\n * the redirect admin uses. Reads every redirect chunk; unreadable chunks and\n * redirects the redirect API would refuse were already reported by\n * validation and are skipped, so no unvalidated pattern is compiled.\n */\nexport async function findRedirectLoops(\n\tmanifest: SitePackageManifest,\n\tstage: TransferStage,\n\tstagedFiles: TransferStagedFileRepository,\n\toperationId: string,\n): Promise<string[]> {\n\tconst summary = manifest.records.redirect;\n\tif (!summary || summary.count > MAX_LOOP_CHECKED_REDIRECTS) return [];\n\tconst edges: RedirectEdge[] = [];\n\tfor (let seq = 0; seq < summary.chunks; seq++) {\n\t\tconst path = recordChunkPath(\"redirect\", seq);\n\t\tconst file = await stagedFiles.get(operationId, path);\n\t\tif (!file || file.state !== \"verified\") continue;\n\t\tlet lines: string[];\n\t\ttry {\n\t\t\tlines = await readVerifiedChunk(stage, path, file);\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error)) continue;\n\t\t\tthrow error;\n\t\t}\n\t\tlines.forEach((line, index) => {\n\t\t\tconst decoded = decodeRecordLine(\"redirect\", line, { path, line: index + 1 });\n\t\t\tif (!decoded.ok || !isImportableRedirect(decoded.record)) return;\n\t\t\tconst { record } = decoded;\n\t\t\tedges.push({\n\t\t\t\tid: record.id,\n\t\t\t\tsource: record.source,\n\t\t\t\tdestination: record.destination,\n\t\t\t\tenabled: record.enabled,\n\t\t\t\tisPattern: record.isPattern,\n\t\t\t});\n\t\t});\n\t}\n\treturn detectLoops(edges).toSorted(compareIds);\n}\n\n/** Target users read per query while matching principal emails. */\nconst USER_PAGE_SIZE = 500;\n\n/**\n * Email case folding for principal matching. SQL `lower()` folds only ASCII\n * on SQLite, so folding happens here, identically on every dialect.\n */\nexport function foldEmail(email: string): string {\n\treturn email.normalize(\"NFC\").toLowerCase();\n}\n\n/**\n * Target users whose email matches a principal's, case-insensitively. A\n * principal gets a suggestion only when exactly one user matches. Reads the\n * users table in id-ordered pages of {@link USER_PAGE_SIZE}.\n */\nexport async function suggestPrincipalUsers(\n\tdb: Kysely<Database>,\n\tprincipals: ReadonlyArray<{ id: string; email?: string }>,\n): Promise<Map<string, string>> {\n\tconst wanted = new Set(\n\t\tprincipals.flatMap((principal) => (principal.email ? [foldEmail(principal.email)] : [])),\n\t);\n\tconst usersByEmail = new Map<string, string[]>();\n\tif (wanted.size > 0) {\n\t\tlet after: string | null = null;\n\t\tfor (;;) {\n\t\t\tlet query = db\n\t\t\t\t.selectFrom(\"users\")\n\t\t\t\t.select([\"id\", \"email\"])\n\t\t\t\t.orderBy(\"id\")\n\t\t\t\t.limit(USER_PAGE_SIZE);\n\t\t\tif (after !== null) query = query.where(\"id\", \">\", after);\n\t\t\tconst rows = await query.execute();\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst folded = foldEmail(row.email);\n\t\t\t\tif (!wanted.has(folded)) continue;\n\t\t\t\tconst list = usersByEmail.get(folded) ?? [];\n\t\t\t\tlist.push(row.id);\n\t\t\t\tusersByEmail.set(folded, list);\n\t\t\t}\n\t\t\tconst last = rows.at(-1);\n\t\t\tif (rows.length < USER_PAGE_SIZE || !last) break;\n\t\t\tafter = last.id;\n\t\t}\n\t}\n\tconst suggestions = new Map<string, string>();\n\tfor (const principal of principals) {\n\t\tif (!principal.email) continue;\n\t\tconst matches = usersByEmail.get(foldEmail(principal.email)) ?? [];\n\t\tconst [only] = matches;\n\t\tif (matches.length === 1 && only !== undefined) suggestions.set(principal.id, only);\n\t}\n\treturn suggestions;\n}\n\n/** Ids among `userIds` that are not target users. */\nexport async function findMissingUsers(\n\tdb: Kysely<Database>,\n\tuserIds: readonly string[],\n): Promise<string[]> {\n\tconst unique = [...new Set(userIds)];\n\tconst found = new Set<string>();\n\tfor (const batch of chunks(unique, SQL_BATCH_SIZE)) {\n\t\tconst rows = await db.selectFrom(\"users\").select(\"id\").where(\"id\", \"in\", batch).execute();\n\t\tfor (const row of rows) found.add(row.id);\n\t}\n\treturn unique.filter((id) => !found.has(id)).toSorted(compareIds);\n}\n","/**\n * Import plan assembly and decisions.\n *\n * A plan has decision-independent parts (counts, validation and target\n * findings, the package's export transformations, transformations the\n * target forces) and parts that follow from the decisions (principal mapping\n * transformations, principal conflict blockers). {@link applyDecisions} recomputes\n * only the latter, so resubmitting decisions never needs the package again.\n */\n\nimport type { ScaffoldItem } from \"../domain.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport {\n\tsiteImportPlanSchema,\n\ttype PlanBlocker,\n\ttype PlanPrincipal,\n\ttype PlanWarning,\n\ttype SiteImportDecisions,\n\ttype SiteImportPlan,\n} from \"../format/plan.js\";\nimport {\n\tEXPORT_TRANSFORMATION_CODES,\n\tIMPORT_TRANSFORMATION_CODES,\n\ttype ImportTransformationCode,\n\ttype PlanTransformation,\n} from \"../format/transformations.js\";\nimport { SITE_PACKAGE_FORMAT_VERSION } from \"../format/version.js\";\nimport { MAX_LOOP_CHECKED_REDIRECTS } from \"./target.js\";\nimport type { ValidationSummary } from \"./validate.js\";\nimport type { TargetDialect } from \"./values.js\";\n\nconst MAX_LISTED_IDS = 10_000;\nconst MAX_PROVIDER_WARNINGS = 100;\n\n/** Stages an import always runs besides its record chunks and media steps. */\nconst FIXED_IMPORT_STEPS = 10;\n\nconst DECISION_BLOCKER_CODES: ReadonlySet<string> = new Set([\"principal_conflict\"]);\nconst DECISION_TRANSFORMATION_CODES: ReadonlySet<string> = new Set<ImportTransformationCode>([\n\t\"principal_mapped\",\n\t\"principal_unmapped\",\n]);\n\nexport interface PlanOrigin {\n\tsiteId: string;\n\tpackageId: string;\n\tcreatedAt: string;\n\tcreatedByEmDashVersion: string;\n}\n\nexport interface PlanTarget {\n\tsiteId: string;\n\tdialect: TargetDialect;\n\temdashVersion: string;\n}\n\n/** Byline facts the principal-conflict check needs, by principal id. */\nexport interface PrincipalBylines {\n\t/** Locales in which each principal has a byline. */\n\tlocales: ReadonlyMap<string, ReadonlySet<string>>;\n\t/** Principals with more than one byline in some locale. */\n\tsharedLocale: ReadonlySet<string>;\n}\n\nexport interface PlanInputs {\n\tpackageDigest: `sha256:${string}`;\n\tmanifest: SitePackageManifest;\n\ttarget: PlanTarget;\n\tsummary: ValidationSummary;\n\tvalidationBlockers: readonly PlanBlocker[];\n\tvalidationWarnings: readonly PlanWarning[];\n\ttargetBlockers: readonly PlanBlocker[];\n\tscaffold: readonly ScaffoldItem[];\n\tredirectLoops: readonly string[];\n\tlocaleRecasing: ReadonlyArray<{ from: string; to: string }>;\n\tsuggestions: ReadonlyMap<string, string>;\n\ttargetSettings: { title?: string; tagline?: string };\n}\n\nconst TRANSFORMATION_ORDER: readonly string[] = [\n\t...EXPORT_TRANSFORMATION_CODES,\n\t...IMPORT_TRANSFORMATION_CODES,\n];\n\n/** Export transformations first, then import transformations; each in vocabulary order. */\nfunction sortTransformations(transformations: PlanTransformation[]): PlanTransformation[] {\n\treturn transformations.toSorted(\n\t\t(a, b) => TRANSFORMATION_ORDER.indexOf(a.code) - TRANSFORMATION_ORDER.indexOf(b.code),\n\t);\n}\n\nfunction externalProviderWarnings(summary: ValidationSummary): PlanWarning[] {\n\treturn [...summary.externalProviders].slice(0, MAX_PROVIDER_WARNINGS).map(([provider, uses]) => ({\n\t\tcode: \"media_provider_external\",\n\t\tmessage: \"Content uses media from an external provider, which is not copied\",\n\t\tcount: uses,\n\t\tdetail: { provider },\n\t}));\n}\n\nfunction uncheckedRedirectWarnings(manifest: SitePackageManifest): PlanWarning[] {\n\tconst count = manifest.records.redirect?.count ?? 0;\n\tif (count <= MAX_LOOP_CHECKED_REDIRECTS) return [];\n\treturn [\n\t\t{\n\t\t\tcode: \"redirect_loops_unchecked\",\n\t\t\tmessage:\n\t\t\t\t\"The package has too many redirects to check for loops before importing; a redirect that would close a loop is imported disabled\",\n\t\t\tkind: \"redirect\",\n\t\t\tcount,\n\t\t},\n\t];\n}\n\nfunction estimateSteps(manifest: SitePackageManifest): number {\n\tlet chunks = 0;\n\tfor (const summary of Object.values(manifest.records)) chunks += summary?.chunks ?? 0;\n\treturn (\n\t\tFIXED_IMPORT_STEPS + chunks + Math.ceil(manifest.media.totalBytes / TRANSFER_LIMITS.stepBytes)\n\t);\n}\n\nexport function defaultDecisions(\n\tprincipals: readonly Pick<PlanPrincipal, \"id\" | \"suggestedUserId\">[],\n): SiteImportDecisions {\n\treturn {\n\t\tprincipalMappings: Object.fromEntries(\n\t\t\tprincipals.map((principal) => [principal.id, principal.suggestedUserId ?? null]),\n\t\t),\n\t\tsiteTitle: \"package\",\n\t\tsiteTagline: \"package\",\n\t};\n}\n\nfunction settingSummary(packageValue?: string, targetValue?: string) {\n\treturn {\n\t\t...(packageValue === undefined ? {} : { package: packageValue }),\n\t\t...(targetValue === undefined ? {} : { target: targetValue.slice(0, 4096) }),\n\t};\n}\n\n/** Build the plan with default decisions applied. */\nexport function buildPlan(inputs: PlanInputs, bylines: PrincipalBylines): SiteImportPlan {\n\tconst { manifest, summary } = inputs;\n\n\tconst principals: PlanPrincipal[] = summary.principals.map((principal) => {\n\t\tconst suggestedUserId = inputs.suggestions.get(principal.id);\n\t\treturn {\n\t\t\tid: principal.id,\n\t\t\tdisplayName: principal.displayName,\n\t\t\t...(principal.email === undefined ? {} : { email: principal.email }),\n\t\t\treferences: summary.principalReferences.get(principal.id) ?? 0,\n\t\t\t...(suggestedUserId === undefined ? {} : { suggestedUserId }),\n\t\t};\n\t});\n\n\tconst transformations: PlanTransformation[] = [...manifest.transformations];\n\tif (inputs.scaffold.length > 0) {\n\t\ttransformations.push({\n\t\t\tcode: \"seeded_scaffold_removed\",\n\t\t\tcount: inputs.scaffold.length,\n\t\t\titems: inputs.scaffold\n\t\t\t\t.slice(0, MAX_LISTED_IDS)\n\t\t\t\t.map((item) => ({ type: item.type, id: item.id })),\n\t\t});\n\t}\n\tif (inputs.redirectLoops.length > 0) {\n\t\ttransformations.push({\n\t\t\tcode: \"redirect_loop_disabled\",\n\t\t\tkind: \"redirect\",\n\t\t\tids: inputs.redirectLoops.slice(0, MAX_LISTED_IDS),\n\t\t});\n\t}\n\tif (inputs.localeRecasing.length > 0) {\n\t\ttransformations.push({ code: \"locale_recased\", locales: [...inputs.localeRecasing] });\n\t}\n\tif (inputs.target.dialect === \"postgres\") {\n\t\tif (summary.searchEnabledCollections.length > 0) {\n\t\t\ttransformations.push({\n\t\t\t\tcode: \"search_unsupported\",\n\t\t\t\tkind: \"collection\",\n\t\t\t\tids: summary.searchEnabledCollections.slice(0, MAX_LISTED_IDS),\n\t\t\t});\n\t\t}\n\t\tif (summary.float4Rounded > 0) {\n\t\t\ttransformations.push({ code: \"float4_rounded\", count: summary.float4Rounded });\n\t\t}\n\t}\n\n\tconst plan: SiteImportPlan = {\n\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\tpackageDigest: inputs.packageDigest,\n\t\torigin: {\n\t\t\tsiteId: manifest.originSiteId,\n\t\t\tpackageId: manifest.packageId,\n\t\t\tcreatedAt: manifest.createdAt,\n\t\t\tcreatedByEmDashVersion: manifest.createdByEmDashVersion,\n\t\t},\n\t\ttarget: inputs.target,\n\t\tcounts: Object.fromEntries(\n\t\t\tObject.entries(manifest.records).map(([kind, record]) => [kind, record.count]),\n\t\t),\n\t\tbytes: { records: summary.recordBytes, media: manifest.media.totalBytes },\n\t\tprincipals,\n\t\tsettings: {\n\t\t\ttitle: settingSummary(summary.settings.title, inputs.targetSettings.title),\n\t\t\ttagline: settingSummary(summary.settings.tagline, inputs.targetSettings.tagline),\n\t\t},\n\t\tdecisions: defaultDecisions(principals),\n\t\ttransformations,\n\t\twarnings: [\n\t\t\t...inputs.validationWarnings,\n\t\t\t...externalProviderWarnings(summary),\n\t\t\t...uncheckedRedirectWarnings(manifest),\n\t\t],\n\t\tblockers: [...inputs.validationBlockers, ...inputs.targetBlockers],\n\t\testimatedSteps: estimateSteps(manifest),\n\t};\n\treturn applyDecisions(plan, plan.decisions, bylines);\n}\n\n/**\n * A plan for a package whose manifest could not be read: identity and\n * blockers only.\n */\nexport function buildBlockedPlan(input: {\n\tpackageDigest: `sha256:${string}`;\n\torigin: PlanOrigin;\n\ttarget: PlanTarget;\n\tblockers: readonly PlanBlocker[];\n\twarnings: readonly PlanWarning[];\n}): SiteImportPlan {\n\treturn siteImportPlanSchema.parse({\n\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\tpackageDigest: input.packageDigest,\n\t\torigin: input.origin,\n\t\ttarget: input.target,\n\t\tcounts: {},\n\t\tbytes: { records: 0, media: 0 },\n\t\tprincipals: [],\n\t\tsettings: { title: {}, tagline: {} },\n\t\tdecisions: defaultDecisions([]),\n\t\ttransformations: [],\n\t\twarnings: [...input.warnings],\n\t\tblockers: [...input.blockers],\n\t\testimatedSteps: 0,\n\t});\n}\n\n/**\n * The plan with `decisions` in place and every decision-dependent\n * transformation and blocker recomputed.\n */\nexport function applyDecisions(\n\tplan: SiteImportPlan,\n\tdecisions: SiteImportDecisions,\n\tbylines: PrincipalBylines,\n): SiteImportPlan {\n\tlet mappedReferences = 0;\n\tlet unmappedReferences = 0;\n\tconst principalsByUser = new Map<string, string[]>();\n\tconst conflicts: PlanBlocker[] = [];\n\tfor (const principal of plan.principals) {\n\t\tconst userId = Object.hasOwn(decisions.principalMappings, principal.id)\n\t\t\t? decisions.principalMappings[principal.id]\n\t\t\t: null;\n\t\tif (userId === null || userId === undefined) {\n\t\t\tunmappedReferences += principal.references;\n\t\t\tcontinue;\n\t\t}\n\t\tmappedReferences += principal.references;\n\t\tif (bylines.sharedLocale.has(principal.id)) {\n\t\t\tconflicts.push({\n\t\t\t\tcode: \"principal_conflict\",\n\t\t\t\tmessage: \"A principal with several bylines in one locale is mapped to a user\",\n\t\t\t\tkind: \"principal\",\n\t\t\t\tid: principal.id,\n\t\t\t\tdetail: { user: userId },\n\t\t\t});\n\t\t}\n\t\tconst list = principalsByUser.get(userId) ?? [];\n\t\tlist.push(principal.id);\n\t\tprincipalsByUser.set(userId, list);\n\t}\n\n\tfor (const [userId, principalIds] of principalsByUser) {\n\t\tfor (let i = 0; i < principalIds.length; i++) {\n\t\t\tfor (let j = i + 1; j < principalIds.length; j++) {\n\t\t\t\tconst first = principalIds[i];\n\t\t\t\tconst second = principalIds[j];\n\t\t\t\tif (first === undefined || second === undefined) continue;\n\t\t\t\tconst firstLocales = bylines.locales.get(first);\n\t\t\t\tconst secondLocales = bylines.locales.get(second);\n\t\t\t\tif (!firstLocales || !secondLocales) continue;\n\t\t\t\tif (![...firstLocales].some((locale) => secondLocales.has(locale))) continue;\n\t\t\t\tconflicts.push({\n\t\t\t\t\tcode: \"principal_conflict\",\n\t\t\t\t\tmessage: \"Two principals with bylines in the same locale are mapped to one user\",\n\t\t\t\t\tkind: \"principal\",\n\t\t\t\t\tid: second,\n\t\t\t\t\tdetail: { principal: first, user: userId },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tconst transformations = plan.transformations.filter(\n\t\t(transformation) => !DECISION_TRANSFORMATION_CODES.has(transformation.code),\n\t);\n\tif (mappedReferences > 0) {\n\t\ttransformations.push({ code: \"principal_mapped\", count: mappedReferences });\n\t}\n\tif (unmappedReferences > 0) {\n\t\ttransformations.push({ code: \"principal_unmapped\", count: unmappedReferences });\n\t}\n\n\treturn siteImportPlanSchema.parse({\n\t\t...plan,\n\t\tdecisions,\n\t\ttransformations: sortTransformations(transformations),\n\t\tblockers: [\n\t\t\t...plan.blockers.filter((blocker) => !DECISION_BLOCKER_CODES.has(blocker.code)),\n\t\t\t...conflicts,\n\t\t],\n\t});\n}\n","/**\n * Per-operation index of package records, filled while analysis parses the\n * record streams, so cross-reference checks run as bounded SQL lookups\n * instead of holding the package in memory.\n *\n * Conventions for what analysis stores:\n * - `group_id`: the record's `translationGroup`, or its `id` when it has none\n * (what `by: \"group\"` references resolve against);\n * - `name_key`: the collection or block type `slug`, the menu `name`, or the\n * block type version's `blockTypeVersionKey` (what `by: \"slug\"` and\n * `by: \"name\"` references resolve against);\n * - `parent_id` and `depth` for topological kinds.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { compareIds, isRecordKind, type RecordKind, type ReferenceKey } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\n\nexport interface PackageIndexEntry {\n\tkind: RecordKind;\n\tid: string;\n\tgroupId?: string | null;\n\tparentId?: string | null;\n\tnameKey?: string | null;\n\tdepth?: number;\n}\n\nconst KEY_COLUMN = {\n\tid: \"id\",\n\tgroup: \"group_id\",\n\tslug: \"name_key\",\n\tname: \"name_key\",\n} as const satisfies Record<ReferenceKey, string>;\n\nexport class TransferPackageIndexRepository {\n\tconstructor(\n\t\tprivate readonly db: Kysely<Database>,\n\t\tprivate readonly operationId: string,\n\t) {}\n\n\t/** Insert entries; an entry already present (a retried batch) is left as is. */\n\tasync insertMany(entries: readonly PackageIndexEntry[]): Promise<void> {\n\t\tfor (const batch of chunks([...entries], rowsPerInsert(7))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_package_index\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((entry) => ({\n\t\t\t\t\t\toperation_id: this.operationId,\n\t\t\t\t\t\tkind: entry.kind,\n\t\t\t\t\t\tid: entry.id,\n\t\t\t\t\t\tgroup_id: entry.groupId ?? null,\n\t\t\t\t\t\tparent_id: entry.parentId ?? null,\n\t\t\t\t\t\tname_key: entry.nameKey ?? null,\n\t\t\t\t\t\tdepth: entry.depth ?? 0,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) => conflict.columns([\"operation_id\", \"kind\", \"id\"]).doNothing())\n\t\t\t\t.execute();\n\t\t}\n\t}\n\n\tasync get(kind: RecordKind, id: string): Promise<PackageIndexEntry | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.selectAll()\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.where(\"kind\", \"=\", kind)\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\tif (!row || !isRecordKind(row.kind)) return null;\n\t\treturn {\n\t\t\tkind: row.kind,\n\t\t\tid: row.id,\n\t\t\tgroupId: row.group_id,\n\t\t\tparentId: row.parent_id,\n\t\t\tnameKey: row.name_key,\n\t\t\tdepth: Number(row.depth),\n\t\t};\n\t}\n\n\t/**\n\t * Values from `values` that no indexed record of any of `kinds` matches on\n\t * `key` (sorted, unique).\n\t */\n\tasync findMissing(\n\t\tkinds: readonly RecordKind[],\n\t\tkey: ReferenceKey,\n\t\tvalues: readonly string[],\n\t): Promise<string[]> {\n\t\tconst column = KEY_COLUMN[key];\n\t\tconst unique = [...new Set(values)];\n\t\tconst found = new Set<string>();\n\t\tfor (const batch of chunks(unique, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t\t.select(sql<string>`${sql.ref(column)}`.as(\"value\"))\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"kind\", \"in\", [...kinds])\n\t\t\t\t.where(sql.ref(column), \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) found.add(row.value);\n\t\t}\n\t\treturn unique.filter((value) => !found.has(value)).toSorted(compareIds);\n\t}\n\n\t/** Depth of each indexed record of `kind` among `ids`. */\n\tasync depths(kind: RecordKind, ids: readonly string[]): Promise<Map<string, number>> {\n\t\tconst result = new Map<string, number>();\n\t\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t\t.select([\"id\", \"depth\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"kind\", \"=\", kind)\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.id, Number(row.depth));\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync count(kind?: RecordKind): Promise<number> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.select((eb) => eb.fn.countAll<number | string>().as(\"count\"))\n\t\t\t.where(\"operation_id\", \"=\", this.operationId);\n\t\tif (kind) query = query.where(\"kind\", \"=\", kind);\n\t\tconst row = await query.executeTakeFirstOrThrow();\n\t\treturn Number(row.count);\n\t}\n\n\t/** Delete up to `limit` entries; returns how many were deleted. */\n\tasync deleteSome(limit = 500): Promise<number> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.select([\"kind\", \"id\"])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.limit(limit)\n\t\t\t.execute();\n\t\tlet deleted = 0;\n\t\tconst byKind = new Map<string, string[]>();\n\t\tfor (const row of rows) byKind.set(row.kind, [...(byKind.get(row.kind) ?? []), row.id]);\n\t\tfor (const [kind, ids] of byKind) {\n\t\t\tfor (const batch of chunks(ids, SQL_BATCH_SIZE)) {\n\t\t\t\tconst result = await this.db\n\t\t\t\t\t.deleteFrom(\"_emdash_transfer_package_index\")\n\t\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t\t.where(\"kind\", \"=\", kind)\n\t\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t\t.executeTakeFirst();\n\t\t\t\tdeleted += Number(result.numDeletedRows ?? 0n);\n\t\t\t}\n\t\t}\n\t\treturn deleted;\n\t}\n}\n","/**\n * Bounded blocker and warning lists for analysis.\n *\n * Issue messages are fixed strings and details carry only locations (package\n * paths, line numbers, property names, record kinds and ids) — never record\n * values. Package content is untrusted and plans, errors, and logs are shown\n * to people who did not necessarily write the package.\n */\n\nimport { z } from \"zod\";\n\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tplanBlockerSchema,\n\tplanWarningSchema,\n\ttype PlanBlocker,\n\ttype PlanWarning,\n} from \"../format/plan.js\";\n\nexport const issueStateSchema = z.strictObject({\n\tblockers: z.array(planBlockerSchema),\n\twarnings: z.array(planWarningSchema),\n\tdroppedBlockers: z.number().int().nonnegative(),\n\tdroppedWarnings: z.number().int().nonnegative(),\n});\n\nexport type IssueState = z.infer<typeof issueStateSchema>;\n\nexport function emptyIssues(): IssueState {\n\treturn { blockers: [], warnings: [], droppedBlockers: 0, droppedWarnings: 0 };\n}\n\nexport function addBlocker(issues: IssueState, blocker: PlanBlocker): void {\n\tif (issues.blockers.length < TRANSFER_LIMITS.planIssues) issues.blockers.push(blocker);\n\telse issues.droppedBlockers++;\n}\n\nexport function addWarning(issues: IssueState, warning: PlanWarning): void {\n\tif (issues.warnings.length < TRANSFER_LIMITS.planIssues) issues.warnings.push(warning);\n\telse issues.droppedWarnings++;\n}\n\n/** The warnings plus an `issues_truncated` warning when either list overflowed. */\nexport function finalWarnings(issues: IssueState): PlanWarning[] {\n\tif (issues.droppedBlockers === 0 && issues.droppedWarnings === 0) return [...issues.warnings];\n\treturn [\n\t\t...issues.warnings,\n\t\t{\n\t\t\tcode: \"issues_truncated\",\n\t\t\tmessage: \"More issues were found than the plan lists\",\n\t\t\tcount: issues.droppedBlockers + issues.droppedWarnings,\n\t\t\tdetail: { blockers: issues.droppedBlockers, warnings: issues.droppedWarnings },\n\t\t},\n\t];\n}\n","/**\n * Package-internal violations of the target's unique constraints.\n *\n * Each record contributes a key per unique constraint it would occupy on the\n * target. Keys are stored as extra rows of the package index under the kind\n * `unique:<constraint>`, with the key's digest as `id` and the owning record\n * id as `group_id`. Inserting is insert-if-absent, so the first owner of a\n * key wins; any other record whose key row names a different owner collides\n * with it. Retrying a chunk re-inserts the same rows and finds the same\n * owners, so the check is idempotent and needs no memory between chunks.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { canonicalJson } from \"../format/canonical.js\";\nimport { sha256Hex } from \"../format/digest.js\";\nimport type { SitePackageRecord } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\n\nexport const UNIQUE_CONSTRAINTS = [\n\t\"block_type_slug\",\n\t\"block_type_version\",\n\t\"entry_slug_locale\",\n\t\"entry_active_group_locale\",\n\t\"term_name_slug_locale\",\n\t\"term_group_locale\",\n\t\"taxonomy_def_name_locale\",\n\t\"byline_slug_locale\",\n\t\"byline_group_locale\",\n\t\"byline_principal_locale\",\n\t\"byline_field_slug\",\n\t\"menu_name_locale\",\n\t\"relation_name_locale\",\n\t\"relation_group_locale\",\n\t\"widget_area_name\",\n\t\"section_slug\",\n\t\"content_reference_groups\",\n\t\"content_byline_entry_byline\",\n\t\"media_folder_name_key\",\n] as const;\n\nexport type UniqueConstraint = (typeof UNIQUE_CONSTRAINTS)[number];\n\n/** Key-row kind prefix; never a record kind, so record lookups ignore these rows. */\nconst KEY_KIND_PREFIX = \"unique:\";\n\nexport interface UniqueKey {\n\tconstraint: UniqueConstraint;\n\tparts: readonly string[];\n}\n\nfunction key(constraint: UniqueConstraint, ...parts: string[]): UniqueKey {\n\treturn { constraint, parts };\n}\n\n/**\n * Postgres `lower()` folds the way JavaScript does for the locales EmDash\n * accepts; SQLite's ASCII-only `lower()` agrees on ASCII locale codes.\n */\nfunction lowerLocale(locale: string): string {\n\treturn locale.toLowerCase();\n}\n\n/** Keys a record occupies in the target's unique constraints. */\nexport function uniqueKeysOf(record: SitePackageRecord): UniqueKey[] {\n\tswitch (record.kind) {\n\t\tcase \"block_type\":\n\t\t\treturn [key(\"block_type_slug\", record.slug)];\n\t\tcase \"block_type_version\":\n\t\t\treturn [key(\"block_type_version\", record.blockTypeId, String(record.version))];\n\t\tcase \"entry\": {\n\t\t\tconst keys: UniqueKey[] = [];\n\t\t\tif (record.slug !== undefined) {\n\t\t\t\tkeys.push(key(\"entry_slug_locale\", record.collection, record.slug, record.locale));\n\t\t\t}\n\t\t\tif (record.deletedAt === undefined && record.translationGroup !== undefined) {\n\t\t\t\tkeys.push(\n\t\t\t\t\tkey(\n\t\t\t\t\t\t\"entry_active_group_locale\",\n\t\t\t\t\t\trecord.collection,\n\t\t\t\t\t\trecord.translationGroup,\n\t\t\t\t\t\tlowerLocale(record.locale),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn keys;\n\t\t}\n\t\tcase \"term\": {\n\t\t\tconst keys = [key(\"term_name_slug_locale\", record.name, record.slug, record.locale)];\n\t\t\tif (record.translationGroup !== undefined) {\n\t\t\t\tkeys.push(key(\"term_group_locale\", record.translationGroup, record.locale));\n\t\t\t}\n\t\t\treturn keys;\n\t\t}\n\t\tcase \"taxonomy_def\":\n\t\t\treturn [key(\"taxonomy_def_name_locale\", record.name, record.locale)];\n\t\tcase \"byline\": {\n\t\t\tconst keys = [key(\"byline_slug_locale\", record.slug, record.locale)];\n\t\t\tif (record.translationGroup !== undefined) {\n\t\t\t\tkeys.push(key(\"byline_group_locale\", record.translationGroup, record.locale));\n\t\t\t}\n\t\t\tif (record.userPrincipal !== undefined) {\n\t\t\t\tkeys.push(key(\"byline_principal_locale\", record.userPrincipal, record.locale));\n\t\t\t}\n\t\t\treturn keys;\n\t\t}\n\t\tcase \"byline_field\":\n\t\t\treturn [key(\"byline_field_slug\", record.slug)];\n\t\tcase \"menu\":\n\t\t\treturn [key(\"menu_name_locale\", record.name, record.locale)];\n\t\tcase \"relation\":\n\t\t\treturn [\n\t\t\t\tkey(\"relation_name_locale\", record.name, record.locale),\n\t\t\t\tkey(\"relation_group_locale\", record.translationGroup, record.locale),\n\t\t\t];\n\t\tcase \"widget_area\":\n\t\t\treturn [key(\"widget_area_name\", record.name)];\n\t\tcase \"section\":\n\t\t\treturn [key(\"section_slug\", record.slug)];\n\t\tcase \"content_reference\":\n\t\t\treturn [\n\t\t\t\tkey(\n\t\t\t\t\t\"content_reference_groups\",\n\t\t\t\t\trecord.relationGroup,\n\t\t\t\t\trecord.parentGroup,\n\t\t\t\t\trecord.childGroup,\n\t\t\t\t),\n\t\t\t];\n\t\tcase \"content_byline\":\n\t\t\treturn [\n\t\t\t\tkey(\"content_byline_entry_byline\", record.collection, record.entryId, record.bylineGroup),\n\t\t\t];\n\t\tcase \"media_folder\":\n\t\t\treturn [key(\"media_folder_name_key\", record.nameKey)];\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n\nexport interface KeyedRecord<T> {\n\townerId: string;\n\tkeys: readonly UniqueKey[];\n\titem: T;\n}\n\nexport interface UniqueCollision<T> {\n\tconstraint: UniqueConstraint;\n\titem: T;\n\t/** Id of the record that holds the key first. */\n\tholderId: string;\n}\n\n/** Most key rows one records chunk can write (1000 records × at most 3 keys). */\nexport const MAX_KEYS_PER_CHUNK = 3000;\n\n/** Upper bound on the queries {@link findUniqueCollisions} runs for one chunk. */\nexport const UNIQUE_CHECK_QUERIES =\n\tMath.ceil(MAX_KEYS_PER_CHUNK / rowsPerInsert(4)) + Math.ceil(MAX_KEYS_PER_CHUNK / SQL_BATCH_SIZE);\n\n/**\n * Record the keys of `records` and return every record whose key is already\n * held by a different record of the package (earlier chunks included).\n */\nexport async function findUniqueCollisions<T>(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\trecords: readonly KeyedRecord<T>[],\n): Promise<UniqueCollision<T>[]> {\n\tconst rows: Array<{\n\t\tkind: string;\n\t\tid: string;\n\t\townerId: string;\n\t\titem: T;\n\t\tconstraint: UniqueConstraint;\n\t}> = [];\n\tfor (const record of records) {\n\t\tfor (const unique of record.keys) {\n\t\t\trows.push({\n\t\t\t\tkind: `${KEY_KIND_PREFIX}${unique.constraint}`,\n\t\t\t\tid: await sha256Hex(canonicalJson(unique.parts)),\n\t\t\t\townerId: record.ownerId,\n\t\t\t\titem: record.item,\n\t\t\t\tconstraint: unique.constraint,\n\t\t\t});\n\t\t}\n\t}\n\tif (rows.length === 0) return [];\n\n\tfor (const batch of chunks(rows, rowsPerInsert(4))) {\n\t\tawait db\n\t\t\t.insertInto(\"_emdash_transfer_package_index\")\n\t\t\t.values(\n\t\t\t\tbatch.map((row) => ({\n\t\t\t\t\toperation_id: operationId,\n\t\t\t\t\tkind: row.kind,\n\t\t\t\t\tid: row.id,\n\t\t\t\t\tgroup_id: row.ownerId,\n\t\t\t\t})),\n\t\t\t)\n\t\t\t.onConflict((conflict) => conflict.columns([\"operation_id\", \"kind\", \"id\"]).doNothing())\n\t\t\t.execute();\n\t}\n\n\tconst holders = new Map<string, string>();\n\tfor (const batch of chunks([...new Set(rows.map((row) => row.id))], SQL_BATCH_SIZE)) {\n\t\tconst stored = await db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.select([\"kind\", \"id\", \"group_id\"])\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"kind\", \"like\", `${KEY_KIND_PREFIX}%`)\n\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of stored) {\n\t\t\tif (row.group_id !== null) holders.set(`${row.kind}\\u0000${row.id}`, row.group_id);\n\t\t}\n\t}\n\n\tconst collisions: UniqueCollision<T>[] = [];\n\tfor (const row of rows) {\n\t\tconst holderId = holders.get(`${row.kind}\\u0000${row.id}`);\n\t\tif (holderId !== undefined && holderId !== row.ownerId) {\n\t\t\tcollisions.push({ constraint: row.constraint, item: row.item, holderId });\n\t\t}\n\t}\n\treturn collisions;\n}\n","/**\n * Storage-key references inside records.\n *\n * Origin storage keys are deployment state and never appear in a package.\n * The exporter replaces every reference to a local media object's storage key\n * with the placeholder `emdash-media:<mediaId>`; the importer replaces each\n * placeholder with the key it stored that media row's bytes under on the\n * target; verification turns target keys back into placeholders.\n *\n * The walker is schema-agnostic. It visits every string of a record except\n * the record's identity properties ({@link identityProperties}), including\n * strings that hold JSON (image and file field values) which it parses,\n * rewrites, and re-serializes with `JSON.stringify` only when something\n * changed. It recognizes:\n *\n * - `/_emdash/api/media/file/<key>` anywhere in a string, relative or behind\n * any origin; only the key segment is replaced, unless the caller asks to\n * relativize, in which case an absolute URL's scheme and host are dropped\n * too so the importer resolves it against the target;\n * - `meta.storageKey` of a media value object;\n * - a local media value whose `id` is a storage key (a value stored without\n * `meta.storageKey`);\n * - a bare storage key as the whole value of `seo.seoImage` or of a top-level\n * entry field.\n *\n * Text that already reads `emdash-media:` in an origin string is escaped as\n * `emdash-media::` on export and unescaped on import, so every unescaped\n * `emdash-media:` in a package is a placeholder and literal text round-trips\n * exactly. Import and escaping work on each record string as text; a string\n * holding JSON is re-serialized only when a storage key inside it was\n * rewritten.\n *\n * A key that equals some media row's id is treated as that id (ids are\n * portable) and left alone. When several media rows share a key, the smallest\n * id wins. Keys that are not in the origin `media` table are left untouched\n * and reported as `unknown_storage_key` warnings.\n */\n\nimport { measureJsonDepth } from \"./canonical.js\";\nimport { compareIds, identityProperties, type RecordKind } from \"./kinds.js\";\nimport { TRANSFER_LIMITS } from \"./limits.js\";\n\nexport const MEDIA_PLACEHOLDER_PREFIX = \"emdash-media:\";\nexport const MEDIA_FILE_PATH = \"/_emdash/api/media/file/\";\n\nconst PLACEHOLDER_ID_PATTERN = /^[0-9A-Za-z_-]{1,128}$/;\nconst PLACEHOLDER_ESCAPE = `${MEDIA_PLACEHOLDER_PREFIX}:`;\nconst PERCENT_RUN = /(?:%[0-9A-Fa-f]{2})+/g;\nconst PERCENT_ESCAPE = /%[0-9A-F]{2}/g;\nconst HARD_SEGMENT_END = /[?#\"'<>`\\r\\n\\t]/g;\nconst SOFT_SEGMENT_END = /[\\s)\\]]/g;\nconst STORAGE_KEY_CHARS = /^[A-Za-z0-9._-]+$/;\nconst KEY_TOKEN_PATTERN = /[A-Za-z0-9._-]+/g;\nconst MAX_ISSUES_PER_RECORD = 20;\n/** Characters before a media file path searched for the URL's scheme and host. */\nconst ORIGIN_WINDOW = 2048;\n\nfunction isDigit(code: number): boolean {\n\treturn code >= 48 && code <= 57;\n}\n\nfunction isLetter(code: number): boolean {\n\tconst lower = code | 0x20;\n\treturn lower >= 97 && lower <= 122;\n}\n\n/** `[A-Za-z0-9.-]` */\nfunction isHostChar(code: number): boolean {\n\treturn isLetter(code) || isDigit(code) || code === 46 || code === 45;\n}\n\n/** `[A-Za-z0-9+.-]` */\nfunction isSchemeChar(code: number): boolean {\n\treturn isHostChar(code) || code === 43;\n}\n\n/** `[0-9A-Za-z_-]` */\nfunction isPlaceholderIdChar(code: number): boolean {\n\treturn isLetter(code) || isDigit(code) || code === 95 || code === 45;\n}\n\n/**\n * One `emdash-media:` in a package string: group 1 is set for an escape\n * (`emdash-media::`, standing for the text `emdash-media:`), group 2 holds\n * the media id of a placeholder, and neither is set for a malformed one.\n */\nexport const PLACEHOLDER_TOKEN = /emdash-media:(?:(:)|([0-9A-Za-z_-]{1,128}))?/g;\n\n/** Escape every `emdash-media:` already in `value` (see {@link PLACEHOLDER_TOKEN}). */\nexport function escapePlaceholderText(value: string): string {\n\treturn value.includes(MEDIA_PLACEHOLDER_PREFIX)\n\t\t? value.replaceAll(MEDIA_PLACEHOLDER_PREFIX, PLACEHOLDER_ESCAPE)\n\t\t: value;\n}\n\nexport function canUsePlaceholder(mediaId: string): boolean {\n\treturn PLACEHOLDER_ID_PATTERN.test(mediaId);\n}\n\nexport function mediaPlaceholder(mediaId: string): string {\n\tif (!canUsePlaceholder(mediaId)) {\n\t\tthrow new TypeError(\"Media id cannot be used in a media placeholder\");\n\t}\n\treturn `${MEDIA_PLACEHOLDER_PREFIX}${mediaId}`;\n}\n\n/** The media id when `value` is exactly one placeholder, else null. */\nexport function parseMediaPlaceholder(value: string): string | null {\n\tif (!value.startsWith(MEDIA_PLACEHOLDER_PREFIX)) return null;\n\tconst id = value.slice(MEDIA_PLACEHOLDER_PREFIX.length);\n\treturn PLACEHOLDER_ID_PATTERN.test(id) ? id : null;\n}\n\nexport interface MediaKeyIndex {\n\t/** Storage key → media id (smallest id when keys are shared). */\n\treadonly keyToMediaId: ReadonlyMap<string, string>;\n\t/** Every media id; a key equal to one of these is treated as an id. */\n\treadonly mediaIds: ReadonlySet<string>;\n}\n\nexport function buildMediaKeyIndex(\n\trows: Iterable<{ id: string; storageKey: string }>,\n): MediaKeyIndex {\n\tconst keyToMediaId = new Map<string, string>();\n\tconst mediaIds = new Set<string>();\n\tfor (const row of rows) {\n\t\tmediaIds.add(row.id);\n\t\tconst existing = keyToMediaId.get(row.storageKey);\n\t\tif (existing === undefined || compareIds(row.id, existing) < 0) {\n\t\t\tkeyToMediaId.set(row.storageKey, row.id);\n\t\t}\n\t}\n\treturn { keyToMediaId, mediaIds };\n}\n\nexport type MediaRefIssueCode =\n\t/** A storage-key reference whose key is not in the origin media table. */\n\t| \"unknown_storage_key\"\n\t/** An import placeholder names a media id with no target key. */\n\t| \"unresolved_placeholder\"\n\t/** A referenced media id cannot be written as a placeholder. */\n\t| \"media_id_not_placeholderable\";\n\nexport interface MediaRefIssue {\n\tcode: MediaRefIssueCode;\n\t/** Path inside the record, e.g. `fields.content[2].asset.url`. */\n\tpath: string;\n\t/** The unknown key (export/verify) or the media id (import). */\n\tvalue: string;\n}\n\nexport type MediaRefMode = \"export\" | \"import\" | \"verify\";\n\n/**\n * - `export`: `keys` indexes the origin media table. With `relativize`, an\n * absolute URL to the media file route whose key is known loses its scheme\n * and host (declared as `media_url_relativized`).\n * - `verify`: `keys` indexes the target media table with ids mapped back to\n * portable media ids, so the result compares equal to the package record.\n * `relativize` predicts the exporter's relativization.\n * - `import`: `mediaIdToKey` maps portable media ids to target storage keys.\n */\nexport type RewriteMediaRefsOptions =\n\t| { mode: \"export\" | \"verify\"; keys: MediaKeyIndex; relativize?: boolean }\n\t| { mode: \"import\"; mediaIdToKey: ReadonlyMap<string, string> };\n\nexport interface RewriteMediaRefsResult<T> {\n\tvalue: T;\n\tchanged: boolean;\n\t/** Media ids referenced through storage keys or placeholders (sorted, unique). */\n\tmediaIds: string[];\n\t/** Non-fatal issues (at most 20 per record). */\n\twarnings: MediaRefIssue[];\n\t/** Fatal issues: the record must not be exported, imported, or verified as is. */\n\terrors: MediaRefIssue[];\n\t/** Absolute media file URLs made relative (with `relativize`). */\n\trelativized: number;\n}\n\ninterface WalkContext {\n\toptions: RewriteMediaRefsOptions;\n\tkind: RecordKind;\n\tmediaIds: Set<string>;\n\twarnings: MediaRefIssue[];\n\terrors: MediaRefIssue[];\n\trelativized: number;\n\t/** Storage keys replaced with placeholders so far. */\n\tplaceholders: number;\n}\n\n/**\n * Rewrite the storage-key references in one record. Returns the input object\n * itself when nothing changed; never mutates it.\n */\nexport function rewriteMediaRefs<T extends { kind: RecordKind }>(\n\trecord: T,\n\toptions: RewriteMediaRefsOptions,\n): RewriteMediaRefsResult<T> {\n\tconst context: WalkContext = {\n\t\toptions,\n\t\tkind: record.kind,\n\t\tmediaIds: new Set(),\n\t\twarnings: [],\n\t\terrors: [],\n\t\trelativized: 0,\n\t\tplaceholders: 0,\n\t};\n\tconst skip = identityProperties(record.kind);\n\tconst changes: Record<string, unknown> = {};\n\tlet changed = false;\n\tfor (const [property, value] of Object.entries(record)) {\n\t\tif (skip.has(property)) continue;\n\t\tconst next = walk(value, context, property, [property]);\n\t\tif (next !== value) {\n\t\t\tchanges[property] = next;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\treturn {\n\t\tvalue: changed ? { ...record, ...changes } : record,\n\t\tchanged,\n\t\tmediaIds: [...context.mediaIds].toSorted(compareIds),\n\t\twarnings: context.warnings,\n\t\terrors: context.errors,\n\t\trelativized: context.relativized,\n\t};\n}\n\nfunction report(list: MediaRefIssue[], issue: MediaRefIssue): void {\n\tif (list.length < MAX_ISSUES_PER_RECORD) list.push(issue);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isBareKeyPosition(kind: RecordKind, segments: readonly string[]): boolean {\n\tif (kind === \"seo\") return segments.length === 1 && segments[0] === \"seoImage\";\n\tif (kind === \"entry\") return segments.length === 2 && segments[0] === \"fields\";\n\treturn false;\n}\n\nfunction walk(value: unknown, context: WalkContext, path: string, segments: string[]): unknown {\n\tif (typeof value === \"string\") return rewriteString(value, context, path, segments);\n\tif (Array.isArray(value)) {\n\t\tlet changed = false;\n\t\tconst next = value.map((item, index) => {\n\t\t\tconst rewritten = walk(item, context, `${path}[${index}]`, [...segments, String(index)]);\n\t\t\tif (rewritten !== item) changed = true;\n\t\t\treturn rewritten;\n\t\t});\n\t\treturn changed ? next : value;\n\t}\n\tif (isPlainObject(value)) return rewriteObject(value, context, path, segments);\n\treturn value;\n}\n\nfunction rewriteObject(\n\tvalue: Record<string, unknown>,\n\tcontext: WalkContext,\n\tpath: string,\n\tsegments: string[],\n): Record<string, unknown> {\n\tlet changed = false;\n\tconst next: Record<string, unknown> = {};\n\tfor (const [key, child] of Object.entries(value)) {\n\t\tconst rewritten = walk(child, context, `${path}.${key}`, [...segments, key]);\n\t\tif (rewritten !== child) changed = true;\n\t\tnext[key] = rewritten;\n\t}\n\n\tif (context.options.mode !== \"import\") {\n\t\tconst { keys } = context.options;\n\t\tconst provider = value.provider;\n\t\tconst isLocal = provider === undefined || provider === null || provider === \"local\";\n\n\t\tconst meta = value.meta;\n\t\tif (isLocal && isPlainObject(meta) && typeof meta.storageKey === \"string\") {\n\t\t\tconst storageKey = meta.storageKey;\n\t\t\tconst placeholder = placeholderForKey(storageKey, keys, context, `${path}.meta.storageKey`);\n\t\t\tif (placeholder !== null) {\n\t\t\t\tconst nextMeta = isPlainObject(next.meta) ? next.meta : meta;\n\t\t\t\tnext.meta = { ...nextMeta, storageKey: placeholder };\n\t\t\t\tchanged = true;\n\t\t\t} else if (!keys.mediaIds.has(storageKey)) {\n\t\t\t\treport(context.warnings, {\n\t\t\t\t\tcode: \"unknown_storage_key\",\n\t\t\t\t\tpath: `${path}.meta.storageKey`,\n\t\t\t\t\tvalue: storageKey,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst id = value.id;\n\t\tif (isLocal && typeof id === \"string\" && !keys.mediaIds.has(id)) {\n\t\t\tconst placeholder = placeholderForKey(id, keys, context, `${path}.id`);\n\t\t\tif (placeholder !== null) {\n\t\t\t\tnext.id = placeholder;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn changed ? next : value;\n}\n\n/** Placeholder for a known storage key, or null when `key` is not a known key. */\nfunction placeholderForKey(\n\tkey: string,\n\tkeys: MediaKeyIndex,\n\tcontext: WalkContext,\n\tpath: string,\n): string | null {\n\tif (keys.mediaIds.has(key)) return null;\n\tconst mediaId = keys.keyToMediaId.get(key);\n\tif (mediaId === undefined) return null;\n\tif (!canUsePlaceholder(mediaId)) {\n\t\treport(context.errors, { code: \"media_id_not_placeholderable\", path, value: mediaId });\n\t\treturn null;\n\t}\n\tcontext.mediaIds.add(mediaId);\n\tcontext.placeholders++;\n\treturn `${MEDIA_PLACEHOLDER_PREFIX}${mediaId}`;\n}\n\nfunction rewriteString(\n\tvalue: string,\n\tcontext: WalkContext,\n\tpath: string,\n\tsegments: string[],\n): string {\n\tif (context.options.mode === \"import\") {\n\t\treturn resolvePlaceholders(value, context.options.mediaIdToKey, context, path);\n\t}\n\tconst { keys } = context.options;\n\n\tif (isBareKeyPosition(context.kind, segments)) {\n\t\tconst placeholder = placeholderForKey(value, keys, context, path);\n\t\tif (placeholder !== null) return placeholder;\n\t}\n\n\tconst trimmed = value.trimStart();\n\tif (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n\t\tconst parsed = parseEmbeddedJson(value);\n\t\tif (parsed !== undefined) {\n\t\t\tconst placeholders = context.placeholders;\n\t\t\tconst rewritten = walk(parsed, context, path, segments);\n\t\t\t// Escaping the text rather than re-serializing keeps the JSON byte for byte.\n\t\t\treturn context.placeholders === placeholders\n\t\t\t\t? escapePlaceholderText(value)\n\t\t\t\t: JSON.stringify(rewritten);\n\t\t}\n\t}\n\n\tconst escaped = escapePlaceholderText(value);\n\tif (!escaped.includes(MEDIA_FILE_PATH)) return escaped;\n\treturn rewriteMediaFileUrls(escaped, keys, context, path, context.options.relativize === true);\n}\n\nfunction decodePercent(segment: string): string | null {\n\tif (!segment.includes(\"%\")) return null;\n\ttry {\n\t\treturn decodeURIComponent(segment);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Index of the first match of the global `pattern` at or after a start, for\n * starts that never decrease: a match found earlier is reused while it is\n * still ahead, so all calls together scan `value` once.\n */\nfunction endFinder(value: string, pattern: RegExp): (start: number) => number {\n\tlet found = -1;\n\treturn (start) => {\n\t\tif (found >= start) return found;\n\t\tpattern.lastIndex = start;\n\t\tconst match = pattern.exec(value);\n\t\tfound = match ? match.index : value.length;\n\t\treturn found;\n\t};\n}\n\n/**\n * Start of the `scheme://host[:port]` or `//host[:port]` that ends at `at`,\n * or -1. Only `value[from, at)` is examined; the scheme is the longest one\n * that fits there.\n */\nfunction originStart(value: string, from: number, at: number): number {\n\tconst floor = Math.max(from, at - ORIGIN_WINDOW);\n\tconst is = (test: (code: number) => boolean, index: number) =>\n\t\tindex >= floor && test(value.charCodeAt(index));\n\tlet end = at;\n\tlet digits = end;\n\twhile (is(isDigit, digits - 1)) digits--;\n\tif (digits < end && value[digits - 1] === \":\" && digits - 1 >= floor) end = digits - 1;\n\tlet host = end;\n\twhile (is(isHostChar, host - 1)) host--;\n\tif (host === end || host - 2 < floor || value[host - 1] !== \"/\" || value[host - 2] !== \"/\") {\n\t\treturn -1;\n\t}\n\tconst slashes = host - 2;\n\tif (slashes - 1 < floor || value[slashes - 1] !== \":\") return slashes;\n\tlet scheme = slashes - 1;\n\twhile (is(isSchemeChar, scheme - 1)) scheme--;\n\tfor (let index = scheme; index < slashes - 1; index++) {\n\t\tif (isLetter(value.charCodeAt(index))) return index;\n\t}\n\treturn slashes;\n}\n\n/**\n * Replace the key segment of every `/_emdash/api/media/file/<key>` in\n * `value`. The segment runs to the first `?#\"'<>`, backtick, or line break.\n * The longest prefix of the segment that is a known storage key, raw or\n * percent-decoded, is replaced; this covers keys with spaces, parentheses,\n * `+`, or non-ASCII characters, percent-encoded URLs, and keys followed by\n * punctuation. A segment whose prefix up to whitespace, `)` or `]` is neither\n * a key nor a media id is reported as `unknown_storage_key`. With\n * `relativize`, a replaced URL also loses the scheme and host before it.\n */\nfunction rewriteMediaFileUrls(\n\tvalue: string,\n\tkeys: MediaKeyIndex,\n\tcontext: WalkContext,\n\tpath: string,\n\trelativize: boolean,\n): string {\n\tconst maxRawLength = maxKeyLength(keys) * MAX_ENCODED_CHARS_PER_CHAR;\n\tconst hardEnd = endFinder(value, HARD_SEGMENT_END);\n\tconst softEnd = endFinder(value, SOFT_SEGMENT_END);\n\tlet output = \"\";\n\tlet cursor = 0;\n\tlet at = value.indexOf(MEDIA_FILE_PATH);\n\twhile (at !== -1) {\n\t\tconst start = at + MEDIA_FILE_PATH.length;\n\t\tconst remainder = value.slice(start, Math.min(hardEnd(start), start + maxRawLength));\n\t\tconst match = longestKeyPrefix(remainder, keys);\n\t\tconst placeholder = match ? placeholderForKey(match.key, keys, context, path) : null;\n\n\t\tif (match && placeholder !== null) {\n\t\t\tconst origin = relativize ? originStart(value, cursor, at) : -1;\n\t\t\tif (origin !== -1) context.relativized++;\n\t\t\toutput += value.slice(cursor, origin === -1 ? at : origin);\n\t\t\toutput += MEDIA_FILE_PATH + placeholder;\n\t\t\tcursor = start + match.length;\n\t\t} else {\n\t\t\toutput += value.slice(cursor, start);\n\t\t\tcursor = start;\n\t\t}\n\t\tif (!match && context.warnings.length < MAX_ISSUES_PER_RECORD) {\n\t\t\tconst end = Math.min(hardEnd(start), softEnd(start), start + MAX_MEDIA_ID_SEGMENT);\n\t\t\tconst segment = value.slice(start, end);\n\t\t\tconst decoded = decodePercent(segment);\n\t\t\tif (\n\t\t\t\tsegment.length > 0 &&\n\t\t\t\t!keys.mediaIds.has(segment) &&\n\t\t\t\t!(decoded !== null && keys.mediaIds.has(decoded))\n\t\t\t) {\n\t\t\t\treport(context.warnings, { code: \"unknown_storage_key\", path, value: segment });\n\t\t\t}\n\t\t}\n\t\tat = value.indexOf(MEDIA_FILE_PATH, Math.max(cursor, start));\n\t}\n\treturn output + value.slice(cursor);\n}\n\nfunction longestKeyPrefix(\n\tremainder: string,\n\tkeys: MediaKeyIndex,\n): { key: string; length: number } | null {\n\tconst lengths = keyLengths(keys);\n\tconst decodedEnds = decodedKeyLengthEnds(remainder, keys);\n\tconst candidates =\n\t\tdecodedEnds.size === 0\n\t\t\t? sortedKeyLengths(keys)\n\t\t\t: [...new Set([...lengths, ...decodedEnds])].toSorted((a, b) => b - a);\n\tfor (const length of candidates) {\n\t\tif (length > remainder.length || length === 0) continue;\n\t\tif (lengths.has(length)) {\n\t\t\tconst prefix = remainder.slice(0, length);\n\t\t\tif (keys.keyToMediaId.has(prefix) && !keys.mediaIds.has(prefix)) {\n\t\t\t\treturn { key: prefix, length };\n\t\t\t}\n\t\t}\n\t\tif (decodedEnds.has(length)) {\n\t\t\tconst decoded = decodePercent(remainder.slice(0, length));\n\t\t\tif (decoded !== null && keys.keyToMediaId.has(decoded) && !keys.mediaIds.has(decoded)) {\n\t\t\t\treturn { key: decoded, length };\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction hexDigit(code: number): number {\n\tif (code >= 48 && code <= 57) return code - 48;\n\tconst lower = code | 0x20;\n\treturn lower >= 97 && lower <= 102 ? lower - 87 : -1;\n}\n\n/**\n * Lengths of the prefixes of `remainder` that contain a percent escape and\n * would percent-decode to a string as long as some key, so only those are\n * decoded. Stops at the first escape that cannot start or continue a UTF-8\n * sequence, since no longer prefix decodes, and past the longest key.\n */\nfunction decodedKeyLengthEnds(remainder: string, keys: MediaKeyIndex): Set<number> {\n\tconst lengths = keyLengths(keys);\n\tconst ends = new Set<number>();\n\tlet index = remainder.indexOf(\"%\");\n\tif (index === -1) return ends;\n\tconst longest = sortedKeyLengths(keys)[0] ?? 0;\n\tlet decoded = index;\n\tlet pending = 0;\n\tlet units = 0;\n\twhile (index < remainder.length && decoded <= longest) {\n\t\tif (remainder[index] === \"%\") {\n\t\t\tconst high = hexDigit(remainder.charCodeAt(index + 1));\n\t\t\tconst low = hexDigit(remainder.charCodeAt(index + 2));\n\t\t\tif (high === -1 || low === -1) break;\n\t\t\tconst byte = high * 16 + low;\n\t\t\tindex += 3;\n\t\t\tif (pending > 0) {\n\t\t\t\tif ((byte & 0xc0) !== 0x80) break;\n\t\t\t\tpending--;\n\t\t\t\tif (pending === 0) decoded += units;\n\t\t\t} else if (byte < 0x80) {\n\t\t\t\tdecoded++;\n\t\t\t} else if ((byte & 0xe0) === 0xc0) {\n\t\t\t\tpending = 1;\n\t\t\t\tunits = 1;\n\t\t\t} else if ((byte & 0xf0) === 0xe0) {\n\t\t\t\tpending = 2;\n\t\t\t\tunits = 1;\n\t\t\t} else if ((byte & 0xf8) === 0xf0) {\n\t\t\t\tpending = 3;\n\t\t\t\tunits = 2;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tif (pending > 0) break;\n\t\t\tdecoded++;\n\t\t\tindex++;\n\t\t}\n\t\tif (pending === 0 && lengths.has(decoded)) ends.add(index);\n\t}\n\treturn ends;\n}\n\n/** A UTF-8 character percent-encodes to at most 12 characters (`%XX` × 4). */\nconst MAX_ENCODED_CHARS_PER_CHAR = 12;\n\n/** Longest media file URL segment that can still spell a media id. */\nconst MAX_MEDIA_ID_SEGMENT = TRANSFER_LIMITS.idLength * MAX_ENCODED_CHARS_PER_CHAR;\n\nconst keyLengthsCache = new WeakMap<MediaKeyIndex, ReadonlySet<number>>();\n\nfunction keyLengths(keys: MediaKeyIndex): ReadonlySet<number> {\n\tlet lengths = keyLengthsCache.get(keys);\n\tif (lengths === undefined) {\n\t\tlengths = new Set(Array.from(keys.keyToMediaId.keys(), (key) => key.length));\n\t\tkeyLengthsCache.set(keys, lengths);\n\t}\n\treturn lengths;\n}\n\nconst sortedKeyLengthsCache = new WeakMap<MediaKeyIndex, readonly number[]>();\n\n/** Distinct key lengths, longest first. */\nfunction sortedKeyLengths(keys: MediaKeyIndex): readonly number[] {\n\tlet sorted = sortedKeyLengthsCache.get(keys);\n\tif (sorted === undefined) {\n\t\tsorted = [...keyLengths(keys)].toSorted((a, b) => b - a);\n\t\tsortedKeyLengthsCache.set(keys, sorted);\n\t}\n\treturn sorted;\n}\n\nfunction maxKeyLength(keys: MediaKeyIndex): number {\n\treturn sortedKeyLengths(keys)[0] ?? 0;\n}\n\nfunction parseEmbeddedJson(value: string): unknown {\n\tif (measureJsonDepth(value, TRANSFER_LIMITS.jsonDepth) > TRANSFER_LIMITS.jsonDepth) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(value);\n\t\treturn typeof parsed === \"object\" && parsed !== null ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nconst PLACEHOLDER_FILE_PATH = `${MEDIA_FILE_PATH}${MEDIA_PLACEHOLDER_PREFIX}`;\n\n/**\n * Drop the scheme and host before every placeholder media file URL. A\n * placeholder names media on the site that holds the package's data, so on\n * import its URL is the target's own relative media file route. Verification\n * applies the same normalization to package records before comparing.\n */\nexport function relativizePlaceholderUrls(value: string): string {\n\tlet output = \"\";\n\tlet cursor = 0;\n\tlet at = value.indexOf(PLACEHOLDER_FILE_PATH);\n\twhile (at !== -1) {\n\t\tconst next = at + PLACEHOLDER_FILE_PATH.length;\n\t\tif (isPlaceholderIdChar(value.charCodeAt(next))) {\n\t\t\tconst origin = originStart(value, cursor, at);\n\t\t\tif (origin !== -1) {\n\t\t\t\toutput += value.slice(cursor, origin);\n\t\t\t\tcursor = at;\n\t\t\t}\n\t\t}\n\t\tat = value.indexOf(PLACEHOLDER_FILE_PATH, next);\n\t}\n\treturn cursor === 0 ? value : output + value.slice(cursor);\n}\n\nfunction resolvePlaceholders(\n\tvalue: string,\n\tmediaIdToKey: ReadonlyMap<string, string>,\n\tcontext: WalkContext,\n\tpath: string,\n): string {\n\tif (!value.includes(MEDIA_PLACEHOLDER_PREFIX)) return value;\n\treturn relativizePlaceholderUrls(value).replace(\n\t\tPLACEHOLDER_TOKEN,\n\t\t(match, escape: string | undefined, mediaId: string | undefined) => {\n\t\t\tif (escape !== undefined) return MEDIA_PLACEHOLDER_PREFIX;\n\t\t\tif (mediaId === undefined) return match;\n\t\t\tconst key = mediaIdToKey.get(mediaId);\n\t\t\tif (key === undefined) {\n\t\t\t\treport(context.errors, { code: \"unresolved_placeholder\", path, value: mediaId });\n\t\t\t\treturn match;\n\t\t\t}\n\t\t\tcontext.mediaIds.add(mediaId);\n\t\t\treturn key;\n\t\t},\n\t);\n}\n\n/**\n * Keys suitable for {@link scanForKeys}: every storage key except those equal\n * to a media id (those are indistinguishable from the portable id).\n */\nexport function scannableKeys(keys: MediaKeyIndex): Set<string> {\n\tconst result = new Set<string>();\n\tfor (const key of keys.keyToMediaId.keys()) {\n\t\tif (!keys.mediaIds.has(key)) result.add(key);\n\t}\n\treturn result;\n}\n\n/**\n * Walker-independent check: every key from `keys` that occurs anywhere in\n * `text` as a substring, raw, percent-encoded (either hex case), or with\n * JSON string escaping (sorted, unique). Exporter self-validation runs it\n * over every record line and fails the export if anything is found.\n */\nexport function scanForKeys(text: string, keys: ReadonlySet<string>): string[] {\n\tif (keys.size === 0 || text.length === 0) return [];\n\tconst found = new Set<string>();\n\tconst lengths = new Set<number>();\n\tconst irregular: string[] = [];\n\tfor (const key of keys) {\n\t\tif (STORAGE_KEY_CHARS.test(key)) lengths.add(key.length);\n\t\telse if (key.length > 0) irregular.push(key);\n\t}\n\tconst sortedLengths = [...lengths].toSorted((a, b) => a - b);\n\tconst texts = text.includes(\"%\") ? [text, decodePercentRuns(text)] : [text];\n\tfor (const candidateText of texts) {\n\t\tfor (const match of candidateText.matchAll(KEY_TOKEN_PATTERN)) {\n\t\t\tconst token = match[0];\n\t\t\tfor (const length of sortedLengths) {\n\t\t\t\tif (length > token.length) break;\n\t\t\t\tfor (let start = 0; start + length <= token.length; start++) {\n\t\t\t\t\tconst candidate = token.slice(start, start + length);\n\t\t\t\t\tif (keys.has(candidate)) found.add(candidate);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const key of irregular) {\n\t\t\tif (keyForms(key).some((form) => candidateText.includes(form))) found.add(key);\n\t\t}\n\t}\n\treturn [...found].toSorted(compareIds);\n}\n\nfunction keyForms(key: string): string[] {\n\tconst encoded = encodeURIComponent(key);\n\treturn [\n\t\t...new Set([\n\t\t\tkey,\n\t\t\tJSON.stringify(key).slice(1, -1),\n\t\t\tencoded,\n\t\t\tencoded.replace(PERCENT_ESCAPE, (escape) => escape.toLowerCase()),\n\t\t\tencodeURI(key),\n\t\t]),\n\t];\n}\n\n/** Decode each run of `%XX` escapes that forms valid UTF-8; leave the rest. */\nfunction decodePercentRuns(text: string): string {\n\treturn text.replace(PERCENT_RUN, (run) => {\n\t\ttry {\n\t\t\treturn decodeURIComponent(run);\n\t\t} catch {\n\t\t\treturn run;\n\t\t}\n\t});\n}\n","/**\n * Per-record value checks: media placeholders and external media providers\n * inside record values, and the constraints a target database puts on stored\n * values (column types, NOT NULL, Postgres int4 / float4).\n */\n\nimport { isTransferError } from \"../errors.js\";\nimport { measureJsonDepth } from \"../format/canonical.js\";\nimport { encodeColumn } from \"../format/column-codec.js\";\nimport { codecForColumnType } from \"../format/columns.js\";\nimport { identityProperties, type EntryRecord, type SitePackageRecord } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport { PLACEHOLDER_TOKEN } from \"../format/media-refs.js\";\nimport type { PlanBlockerCode } from \"../format/plan.js\";\nimport type { FieldColumnType } from \"../format/transformations.js\";\n\nexport type TargetDialect = \"sqlite\" | \"postgres\";\n\nexport interface FieldInfo {\n\tcolumnType: FieldColumnType;\n\trequired: boolean;\n}\n\nconst PROVIDER_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;\n\n/** Reported in place of a provider id that is not a plain identifier. */\nexport const OTHER_PROVIDER = \"other\";\n\nconst INT4_MIN = -2_147_483_648;\nconst INT4_MAX = 2_147_483_647;\n\n/**\n * Top-level record properties stored in JSON (or JSON-shaped) columns. Numbers\n * directly under them are JSON numbers, not integer columns.\n */\nconst JSON_PROPERTIES: ReadonlySet<string> = new Set([\n\t\"adminConfig\",\n\t\"componentProps\",\n\t\"content\",\n\t\"data\",\n\t\"defaultValue\",\n\t\"fields\",\n\t\"keywords\",\n\t\"moderationMetadata\",\n\t\"options\",\n\t\"searchConfig\",\n\t\"validation\",\n\t\"value\",\n]);\n\n/** Top-level properties stored in REAL columns. */\nconst REAL_PROPERTIES: ReadonlySet<string> = new Set([\"focalX\", \"focalY\"]);\n\nexport interface RecordScan {\n\t/** Media ids named by `emdash-media:` placeholders. */\n\tplaceholders: Set<string>;\n\t/** `emdash-media:` occurrences that are neither a placeholder nor an escape. */\n\tmalformed: number;\n\t/** Media values whose provider is not local, by provider id. */\n\tproviders: Map<string, number>;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseEmbeddedJson(value: string): unknown {\n\tconst trimmed = value.trimStart();\n\tif (!trimmed.startsWith(\"{\") && !trimmed.startsWith(\"[\")) return undefined;\n\tif (measureJsonDepth(value) > TRANSFER_LIMITS.jsonDepth) return undefined;\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction scanValue(value: unknown, scan: RecordScan, embedded: boolean): void {\n\tif (typeof value === \"string\") {\n\t\tif (!embedded) {\n\t\t\tfor (const match of value.matchAll(PLACEHOLDER_TOKEN)) {\n\t\t\t\tif (match[2] !== undefined) scan.placeholders.add(match[2]);\n\t\t\t\telse if (match[1] === undefined) scan.malformed++;\n\t\t\t}\n\t\t\tconst parsed = parseEmbeddedJson(value);\n\t\t\tif (parsed !== undefined) scanValue(parsed, scan, true);\n\t\t}\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) scanValue(item, scan, embedded);\n\t\treturn;\n\t}\n\tif (!isPlainObject(value)) return;\n\tconst provider = value.provider;\n\tif (typeof provider === \"string\" && provider !== \"local\" && typeof value.id === \"string\") {\n\t\tconst key = PROVIDER_ID_PATTERN.test(provider) ? provider : OTHER_PROVIDER;\n\t\tscan.providers.set(key, (scan.providers.get(key) ?? 0) + 1);\n\t}\n\tfor (const child of Object.values(value)) scanValue(child, scan, embedded);\n}\n\n/**\n * Placeholders and external media values in every non-identity property of a\n * record. Placeholders are read from each string as text, the way the\n * importer resolves them, never from JSON parsed out of a string.\n */\nexport function scanRecordValues(record: SitePackageRecord): RecordScan {\n\tconst scan: RecordScan = { placeholders: new Set(), malformed: 0, providers: new Map() };\n\tconst skip = identityProperties(record.kind);\n\tfor (const [property, value] of Object.entries(record)) {\n\t\tif (!skip.has(property)) scanValue(value, scan, false);\n\t}\n\treturn scan;\n}\n\nexport interface ValueIssue {\n\tcode: Extract<PlanBlockerCode, \"integer_out_of_range\" | \"value_constraint_violation\">;\n\tmessage: string;\n\tproperty: string;\n\tfield?: string;\n}\n\nexport interface ValueCheckResult {\n\tissues: ValueIssue[];\n\t/** Values a float4 column would store differently. */\n\tfloat4Rounded: number;\n}\n\nfunction isInt4(value: number): boolean {\n\treturn value >= INT4_MIN && value <= INT4_MAX;\n}\n\nfunction roundsInFloat4(value: number): boolean {\n\treturn Math.fround(value) !== value;\n}\n\n/**\n * Top-level integer and real properties of any record against a Postgres\n * target, where `integer` is int4 and `real` is float4.\n */\nexport function checkRecordNumbers(\n\trecord: SitePackageRecord,\n\tdialect: TargetDialect,\n): ValueCheckResult {\n\tconst result: ValueCheckResult = { issues: [], float4Rounded: 0 };\n\tif (dialect !== \"postgres\") return result;\n\tfor (const [property, value] of Object.entries(record)) {\n\t\tif (typeof value !== \"number\" || JSON_PROPERTIES.has(property)) continue;\n\t\tif (REAL_PROPERTIES.has(property)) {\n\t\t\tif (roundsInFloat4(value)) result.float4Rounded++;\n\t\t} else if (!isInt4(value)) {\n\t\t\tresult.issues.push({\n\t\t\t\tcode: \"integer_out_of_range\",\n\t\t\t\tmessage: \"Integer is outside the target database's integer range\",\n\t\t\t\tproperty,\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction mismatch(field: string, message: string): ValueIssue {\n\treturn { code: \"value_constraint_violation\", message, property: \"fields\", field };\n}\n\n/**\n * Entry field values against the target column each field is stored in,\n * through the shared column codec: a value the codec cannot encode for the\n * column is an issue, as is a missing value in a NOT NULL (required) column\n * other than a JSON one (which stores it as JSON `null`) and, on Postgres,\n * an integer outside int4. Boolean fields are INTEGER\n * columns, so their values are 0/1 numbers.\n */\nexport function checkEntryFields(\n\tentry: EntryRecord,\n\tfields: ReadonlyMap<string, FieldInfo>,\n\tdialect: TargetDialect,\n): ValueCheckResult {\n\tconst result: ValueCheckResult = { issues: [], float4Rounded: 0 };\n\tfor (const [slug, value] of Object.entries(entry.fields)) {\n\t\tconst info = fields.get(slug);\n\t\tif (!info) {\n\t\t\tresult.issues.push(mismatch(slug, \"Entry has a value for a field its collection lacks\"));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tencodeColumn(dialect, codecForColumnType(info.columnType), value);\n\t\t} catch (error) {\n\t\t\tif (!isTransferError(error)) throw error;\n\t\t\tresult.issues.push(mismatch(slug, \"Value does not fit the field's column type\"));\n\t\t\tcontinue;\n\t\t}\n\t\tif (dialect !== \"postgres\" || typeof value !== \"number\") continue;\n\t\tif (info.columnType === \"INTEGER\" && !isInt4(value)) {\n\t\t\tresult.issues.push({\n\t\t\t\tcode: \"integer_out_of_range\",\n\t\t\t\tmessage: \"Integer is outside the target database's integer range\",\n\t\t\t\tproperty: \"fields\",\n\t\t\t\tfield: slug,\n\t\t\t});\n\t\t} else if (info.columnType === \"REAL\" && roundsInFloat4(value)) {\n\t\t\tresult.float4Rounded++;\n\t\t}\n\t}\n\tfor (const [slug, info] of fields) {\n\t\tif (info.required && info.columnType !== \"JSON\" && !Object.hasOwn(entry.fields, slug)) {\n\t\t\tresult.issues.push(mismatch(slug, \"Required field has no value\"));\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Kinds whose records carry a `locale`. */\nexport function recordLocale(record: SitePackageRecord): string | undefined {\n\tconst locale: unknown = Reflect.get(record, \"locale\");\n\treturn typeof locale === \"string\" ? locale : undefined;\n}\n\nexport function recordStringProperty(\n\trecord: SitePackageRecord,\n\tproperty: string,\n): string | undefined {\n\tif (!Object.hasOwn(record, property)) return undefined;\n\tconst value: unknown = Reflect.get(record, property);\n\treturn typeof value === \"string\" ? value : undefined;\n}\n","/**\n * Staged package validation in bounded steps.\n *\n * Three passes, each resumable from a JSON-serializable state:\n * - `structure`: the manifest, every index chunk (verified against the digest\n * the manifest pins), path grammar and ordering, per-kind chunk and record\n * totals, and every indexed file staged, verified, and matching its index\n * entry. Staged content files that the index does not list are rejected.\n * - `records`: every record chunk read and verified, every line strictly\n * validated, per-kind counts, stream order (topological kinds: each parent\n * earlier, depth = parent depth + 1), unique ids, and the package index\n * (`_emdash_transfer_package_index`) filled for reference resolution.\n * - `references`: every `KIND_REFERENCES` entry, and the block type\n * references held inside `blocks` fields and block types, resolved against\n * the package index with bounded lookups, media placeholders resolved to `media`\n * records, every media record's blob staged and verified, and — when a\n * target is given — values checked against the target's column\n * constraints.\n *\n * A step processes whole chunks and stops when the budget refuses the next\n * one. Nothing is held in memory between steps: all progress is in the\n * returned state and the package index.\n */\n\nimport type { Kysely } from \"kysely\";\nimport { z } from \"zod\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { MAX_SELECT_OPTIONS } from \"../../schema/byline-registry.js\";\nimport {\n\tBYLINE_FIELD_TYPES,\n\tFIELD_TYPE_TO_COLUMN,\n\tFIELD_TYPES,\n\ttype BylineFieldType,\n} from \"../../schema/types.js\";\nimport { SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { isTransferError, TransferError } from \"../errors.js\";\nimport {\n\tblocksFieldTypeSlugs,\n\tblockTypeVersionKey,\n\tcompareIds,\n\tcompareStreamOrder,\n\tKIND_REFERENCES,\n\tRECORD_KINDS,\n\tstreamOrderOf,\n\tTOPOLOGICAL_PARENT_PROPERTY,\n\ttype RecordKind,\n\ttype ReferenceKey,\n\ttype SitePackageRecord,\n\ttype StreamOrderKey,\n\ttype TopologicalKind,\n} from \"../format/kinds.js\";\nimport { rowsPerInsert, TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { PackageFileEntry, SitePackageManifest } from \"../format/manifest.js\";\nimport { mediaBlobPath, parsePackagePath, recordChunkPath } from \"../format/paths.js\";\nimport type { PlanBlocker, PlanWarning } from \"../format/plan.js\";\nimport { settingMediaIds } from \"../format/settings.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferPackageIndexRepository, type PackageIndexEntry } from \"../ops/package-index.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport type { StagedPackageReader } from \"../staging/package.js\";\nimport {\n\taddBlocker,\n\taddWarning,\n\temptyIssues,\n\tfinalWarnings,\n\tissueStateSchema,\n\ttype IssueState,\n} from \"./issues.js\";\nimport { blockerForError, decodeRecordLine, readVerifiedChunk } from \"./read.js\";\nimport { findUniqueCollisions, UNIQUE_CHECK_QUERIES, uniqueKeysOf } from \"./unique-keys.js\";\nimport {\n\tcheckEntryFields,\n\tcheckRecordNumbers,\n\trecordLocale,\n\trecordStringProperty,\n\tscanRecordValues,\n\tOTHER_PROVIDER,\n\ttype FieldInfo,\n\ttype TargetDialect,\n\ttype ValueIssue,\n} from \"./values.js\";\nimport { writeRuleIssues, type BylineFieldFacts } from \"./write-rules.js\";\n\nconst count = z.number().int().nonnegative();\nconst kindSchema = z.enum(RECORD_KINDS);\nconst kindCounts = z.array(z.tuple([kindSchema, count]));\n\nexport const VALIDATION_PHASES = [\"structure\", \"records\", \"references\", \"done\"] as const;\nexport type ValidationPhase = (typeof VALIDATION_PHASES)[number];\n\n/**\n * Serialized validation progress. Maps are stored as entry lists: keys come\n * from the package and must never become object properties.\n */\nexport const validationStateSchema = z.strictObject({\n\tversion: z.literal(1),\n\tphase: z.enum(VALIDATION_PHASES),\n\tnextIndexSeq: count,\n\tlastIndexPath: z.string().nullable(),\n\tindexedChunks: kindCounts,\n\tindexedRecords: kindCounts,\n\tindexedFiles: count,\n\tindexedBytes: count,\n\tindexedBlobs: count,\n\tindexedBlobBytes: count,\n\trecordBytes: count,\n\tkindIndex: count,\n\tseq: count,\n\tlastKey: z.strictObject({ id: z.string(), depth: count.optional() }).nullable(),\n\tseenRecords: kindCounts,\n\tunreadableKinds: z.array(kindSchema),\n\tcollections: z.array(\n\t\tz.tuple([z.string(), z.strictObject({ id: z.string(), searchEnabled: z.boolean() })]),\n\t),\n\tfields: z.array(\n\t\tz.tuple([\n\t\t\tz.string(),\n\t\t\tz.array(\n\t\t\t\tz.tuple([\n\t\t\t\t\tz.string(),\n\t\t\t\t\tz.strictObject({\n\t\t\t\t\t\tcolumnType: z.enum([\"TEXT\", \"REAL\", \"INTEGER\", \"JSON\"]),\n\t\t\t\t\t\trequired: z.boolean(),\n\t\t\t\t\t}),\n\t\t\t\t]),\n\t\t\t),\n\t\t]),\n\t),\n\tprincipals: z.array(\n\t\tz.strictObject({ id: z.string(), displayName: z.string(), email: z.string().optional() }),\n\t),\n\tprincipalReferences: z.array(z.tuple([z.string(), count])),\n\tprincipalBylineLocales: z.array(z.tuple([z.string(), z.array(z.string())])),\n\tprincipalsWithSharedLocaleBylines: z.array(z.string()),\n\tsettings: z.strictObject({ title: z.string().optional(), tagline: z.string().optional() }),\n\tbylineFields: z.array(\n\t\tz.tuple([\n\t\t\tz.string(),\n\t\t\tz.strictObject({\n\t\t\t\ttype: z.custom<BylineFieldType>(isBylineFieldType),\n\t\t\t\toptions: z.array(z.string()).optional(),\n\t\t\t}),\n\t\t]),\n\t),\n\tfloat4Rounded: count,\n\texternalProviders: z.array(z.tuple([z.string(), count])),\n\tissues: issueStateSchema,\n});\n\nexport type ValidationState = z.infer<typeof validationStateSchema>;\n\nexport interface ValidationTarget {\n\tdialect: TargetDialect;\n\t/** Largest media blob the target accepts, in bytes. */\n\tmaxBlobBytes: number;\n}\n\nexport interface ValidationOptions {\n\t/** Check values and blob sizes against a target site. */\n\ttarget?: ValidationTarget;\n}\n\nexport interface ValidateStagedPackageInput {\n\tdb: Kysely<Database>;\n\treader: StagedPackageReader;\n\t/** Operation whose staged-file rows and package index this validation uses. */\n\toperationId: string;\n\t/** State returned by the previous step, or null to start. */\n\tstate: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport interface ValidationStepResult {\n\tdone: boolean;\n\tstate: ValidationState;\n\t/** Every blocker found so far. */\n\tblockers: PlanBlocker[];\n\t/** Every warning found so far. */\n\twarnings: PlanWarning[];\n}\n\nexport interface PrincipalSummary {\n\tid: string;\n\tdisplayName: string;\n\temail?: string;\n}\n\ninterface WorkingState {\n\tphase: ValidationPhase;\n\tnextIndexSeq: number;\n\tlastIndexPath: string | null;\n\tindexedChunks: Map<RecordKind, number>;\n\tindexedRecords: Map<RecordKind, number>;\n\tindexedFiles: number;\n\tindexedBytes: number;\n\tindexedBlobs: number;\n\tindexedBlobBytes: number;\n\trecordBytes: number;\n\tkindIndex: number;\n\tseq: number;\n\tlastKey: StreamOrderKey | null;\n\tseenRecords: Map<RecordKind, number>;\n\tunreadableKinds: Set<RecordKind>;\n\tcollections: Map<string, { id: string; searchEnabled: boolean }>;\n\tfields: Map<string, Map<string, FieldInfo>>;\n\tprincipals: PrincipalSummary[];\n\tprincipalReferences: Map<string, number>;\n\tprincipalBylineLocales: Map<string, Set<string>>;\n\tprincipalsWithSharedLocaleBylines: Set<string>;\n\tsettings: { title?: string; tagline?: string };\n\tbylineFields: Map<string, BylineFieldFacts>;\n\tfloat4Rounded: number;\n\texternalProviders: Map<string, number>;\n\tissues: IssueState;\n}\n\nexport function initialValidationState(): ValidationState {\n\treturn serialize(initialWorkingState());\n}\n\nfunction initialWorkingState(): WorkingState {\n\treturn {\n\t\tphase: \"structure\",\n\t\tnextIndexSeq: 0,\n\t\tlastIndexPath: null,\n\t\tindexedChunks: new Map(),\n\t\tindexedRecords: new Map(),\n\t\tindexedFiles: 0,\n\t\tindexedBytes: 0,\n\t\tindexedBlobs: 0,\n\t\tindexedBlobBytes: 0,\n\t\trecordBytes: 0,\n\t\tkindIndex: 0,\n\t\tseq: 0,\n\t\tlastKey: null,\n\t\tseenRecords: new Map(),\n\t\tunreadableKinds: new Set(),\n\t\tcollections: new Map(),\n\t\tfields: new Map(),\n\t\tprincipals: [],\n\t\tprincipalReferences: new Map(),\n\t\tprincipalBylineLocales: new Map(),\n\t\tprincipalsWithSharedLocaleBylines: new Set(),\n\t\tsettings: {},\n\t\tbylineFields: new Map(),\n\t\tfloat4Rounded: 0,\n\t\texternalProviders: new Map(),\n\t\tissues: emptyIssues(),\n\t};\n}\n\nfunction sortedEntries<V>(map: ReadonlyMap<string, V>): Array<[string, V]> {\n\treturn [...map.entries()].toSorted(([a], [b]) => compareIds(a, b));\n}\n\nfunction serialize(state: WorkingState): ValidationState {\n\treturn {\n\t\tversion: 1,\n\t\tphase: state.phase,\n\t\tnextIndexSeq: state.nextIndexSeq,\n\t\tlastIndexPath: state.lastIndexPath,\n\t\tindexedChunks: [...state.indexedChunks.entries()],\n\t\tindexedRecords: [...state.indexedRecords.entries()],\n\t\tindexedFiles: state.indexedFiles,\n\t\tindexedBytes: state.indexedBytes,\n\t\tindexedBlobs: state.indexedBlobs,\n\t\tindexedBlobBytes: state.indexedBlobBytes,\n\t\trecordBytes: state.recordBytes,\n\t\tkindIndex: state.kindIndex,\n\t\tseq: state.seq,\n\t\tlastKey: state.lastKey\n\t\t\t? {\n\t\t\t\t\tid: state.lastKey.id,\n\t\t\t\t\t...(state.lastKey.depth === undefined ? {} : { depth: state.lastKey.depth }),\n\t\t\t\t}\n\t\t\t: null,\n\t\tseenRecords: [...state.seenRecords.entries()],\n\t\tunreadableKinds: [...state.unreadableKinds],\n\t\tcollections: sortedEntries(state.collections),\n\t\tfields: sortedEntries(state.fields).map(([slug, fields]) => [slug, sortedEntries(fields)]),\n\t\tprincipals: state.principals,\n\t\tprincipalReferences: sortedEntries(state.principalReferences),\n\t\tprincipalBylineLocales: sortedEntries(state.principalBylineLocales).map(([id, locales]) => [\n\t\t\tid,\n\t\t\t[...locales].toSorted(compareIds),\n\t\t]),\n\t\tprincipalsWithSharedLocaleBylines: [...state.principalsWithSharedLocaleBylines].toSorted(\n\t\t\tcompareIds,\n\t\t),\n\t\tsettings: state.settings,\n\t\tbylineFields: sortedEntries(state.bylineFields),\n\t\tfloat4Rounded: state.float4Rounded,\n\t\texternalProviders: sortedEntries(state.externalProviders),\n\t\tissues: state.issues,\n\t};\n}\n\nfunction deserialize(state: ValidationState): WorkingState {\n\treturn {\n\t\tphase: state.phase,\n\t\tnextIndexSeq: state.nextIndexSeq,\n\t\tlastIndexPath: state.lastIndexPath,\n\t\tindexedChunks: new Map(state.indexedChunks),\n\t\tindexedRecords: new Map(state.indexedRecords),\n\t\tindexedFiles: state.indexedFiles,\n\t\tindexedBytes: state.indexedBytes,\n\t\tindexedBlobs: state.indexedBlobs,\n\t\tindexedBlobBytes: state.indexedBlobBytes,\n\t\trecordBytes: state.recordBytes,\n\t\tkindIndex: state.kindIndex,\n\t\tseq: state.seq,\n\t\tlastKey: state.lastKey,\n\t\tseenRecords: new Map(state.seenRecords),\n\t\tunreadableKinds: new Set(state.unreadableKinds),\n\t\tcollections: new Map(state.collections),\n\t\tfields: new Map(state.fields.map(([slug, fields]) => [slug, new Map(fields)])),\n\t\tprincipals: state.principals,\n\t\tprincipalReferences: new Map(state.principalReferences),\n\t\tprincipalBylineLocales: new Map(\n\t\t\tstate.principalBylineLocales.map(([id, locales]) => [id, new Set(locales)]),\n\t\t),\n\t\tprincipalsWithSharedLocaleBylines: new Set(state.principalsWithSharedLocaleBylines),\n\t\tsettings: state.settings,\n\t\tbylineFields: new Map(state.bylineFields),\n\t\tfloat4Rounded: state.float4Rounded,\n\t\texternalProviders: new Map(state.externalProviders),\n\t\tissues: state.issues,\n\t};\n}\n\nexport function parseValidationState(value: unknown): ValidationState {\n\tconst result = validationStateSchema.safeParse(value);\n\tif (!result.success) {\n\t\tthrow new TransferError(\"TRANSFER_ANALYZE_ERROR\", \"Validation state is invalid\");\n\t}\n\treturn result.data;\n}\n\ninterface Context {\n\tdb: Kysely<Database>;\n\treader: StagedPackageReader;\n\toperationId: string;\n\tmanifest: SitePackageManifest;\n\tstate: WorkingState;\n\tstagedFiles: TransferStagedFileRepository;\n\tindex: TransferPackageIndexRepository;\n\ttarget: ValidationTarget | undefined;\n}\n\n/**\n * Run one bounded validation step. Blockers and warnings in the result are\n * cumulative; `done` is true once every pass has finished. Usable directly as\n * the exporter's self-validation hook.\n */\nexport async function validateStagedPackageStep(\n\tinput: ValidateStagedPackageInput,\n): Promise<ValidationStepResult> {\n\treturn runValidationStep(input, {});\n}\n\n/** Validate a staged package to completion in one call (small packages, tests, tools). */\nexport async function validateStagedPackage(\n\tinput: Omit<ValidateStagedPackageInput, \"state\" | \"budget\"> & {\n\t\tbudget: () => TransferStepBudget;\n\t\toptions?: ValidationOptions;\n\t},\n): Promise<ValidationStepResult> {\n\tlet state: unknown = null;\n\tfor (;;) {\n\t\tconst result = await runValidationStep(\n\t\t\t{ ...input, state, budget: input.budget() },\n\t\t\tinput.options ?? {},\n\t\t);\n\t\tif (result.done) return result;\n\t\tstate = result.state;\n\t}\n}\n\nexport async function runValidationStep(\n\tinput: ValidateStagedPackageInput,\n\toptions: ValidationOptions,\n): Promise<ValidationStepResult> {\n\tconst state = deserialize(\n\t\tinput.state === null || input.state === undefined\n\t\t\t? initialValidationState()\n\t\t\t: parseValidationState(input.state),\n\t);\n\n\tlet manifest: SitePackageManifest | null = null;\n\tif (state.phase !== \"done\") {\n\t\ttry {\n\t\t\tmanifest = await input.reader.manifest();\n\t\t} catch (error) {\n\t\t\tif (!isTransferError(error)) throw error;\n\t\t\taddBlocker(state.issues, blockerForError(error, { path: \"manifest.json\" }));\n\t\t\tstate.phase = \"done\";\n\t\t}\n\t}\n\n\tif (manifest && state.phase !== \"done\") {\n\t\tconst context: Context = {\n\t\t\tdb: input.db,\n\t\t\treader: input.reader,\n\t\t\toperationId: input.operationId,\n\t\t\tmanifest,\n\t\t\tstate,\n\t\t\tstagedFiles: new TransferStagedFileRepository(input.db),\n\t\t\tindex: new TransferPackageIndexRepository(input.db, input.operationId),\n\t\t\ttarget: options.target,\n\t\t};\n\t\twhile (context.state.phase !== \"done\") {\n\t\t\tconst bytes = await nextUnitBytes(context);\n\t\t\tif (!input.budget.canStart({ bytes, queries: unitQueries(context.state.phase) })) break;\n\t\t\tinput.budget.start(bytes);\n\t\t\tawait runUnit(context);\n\t\t}\n\t}\n\n\tconst serialized = serialize(state);\n\treturn {\n\t\tdone: state.phase === \"done\",\n\t\tstate: serialized,\n\t\tblockers: [...state.issues.blockers],\n\t\twarnings: finalWarnings(state.issues),\n\t};\n}\n\n// ── Scheduling ──────────────────────────────────────────────────\n\nfunction kindAt(index: number): RecordKind | undefined {\n\treturn RECORD_KINDS[index];\n}\n\n/** Index of the first kind at or after `from` that the manifest declares, or -1. */\nfunction nextDeclaredKind(manifest: SitePackageManifest, from: number): number {\n\tfor (let index = from; index < RECORD_KINDS.length; index++) {\n\t\tconst kind = kindAt(index);\n\t\tif (kind && manifest.records[kind]) return index;\n\t}\n\treturn -1;\n}\n\n/**\n * Upper bound on the queries one unit runs: a records chunk writes up to 1000\n * index rows and their unique keys; a references chunk looks up each\n * reference property of up to 1000 records.\n */\nfunction unitQueries(phase: ValidationPhase): number {\n\tswitch (phase) {\n\t\tcase \"records\":\n\t\t\treturn (\n\t\t\t\tMath.ceil(TRANSFER_LIMITS.chunkRecords / rowsPerInsert(7)) +\n\t\t\t\t2 * Math.ceil(TRANSFER_LIMITS.chunkRecords / SQL_BATCH_SIZE) +\n\t\t\t\tUNIQUE_CHECK_QUERIES +\n\t\t\t\t2\n\t\t\t);\n\t\tcase \"references\":\n\t\t\treturn 6 * Math.ceil(TRANSFER_LIMITS.chunkRecords / SQL_BATCH_SIZE) + 4;\n\t\tdefault:\n\t\t\treturn 4;\n\t}\n}\n\nasync function nextUnitBytes(context: Context): Promise<number> {\n\tconst { state, manifest } = context;\n\tif (state.phase === \"structure\") {\n\t\treturn manifest.index[state.nextIndexSeq]?.bytes ?? 0;\n\t}\n\tif (state.phase === \"records\" || state.phase === \"references\") {\n\t\tconst kind = kindAt(state.kindIndex);\n\t\tif (!kind) return 0;\n\t\tconst file = await context.stagedFiles.get(\n\t\t\tcontext.operationId,\n\t\t\trecordChunkPath(kind, state.seq),\n\t\t);\n\t\treturn file?.bytes ?? 0;\n\t}\n\treturn 0;\n}\n\nasync function runUnit(context: Context): Promise<void> {\n\tconst { state, manifest } = context;\n\tswitch (state.phase) {\n\t\tcase \"structure\":\n\t\t\tif (state.nextIndexSeq < manifest.index.length) await structureChunk(context);\n\t\t\telse {\n\t\t\t\tawait finishStructure(context);\n\t\t\t\tstartPass(context, \"records\");\n\t\t\t}\n\t\t\treturn;\n\t\tcase \"records\":\n\t\tcase \"references\": {\n\t\t\tconst kind = kindAt(state.kindIndex);\n\t\t\tif (!kind) {\n\t\t\t\tstate.phase = state.phase === \"records\" ? \"references\" : \"done\";\n\t\t\t\tif (state.phase === \"references\") startPass(context, \"references\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (state.phase === \"records\") await recordsChunk(context, kind);\n\t\t\telse await referencesChunk(context, kind);\n\t\t\tadvanceChunk(context, kind);\n\t\t\treturn;\n\t\t}\n\t\tcase \"done\":\n\t\t\treturn;\n\t}\n}\n\nfunction startPass(context: Context, phase: \"records\" | \"references\"): void {\n\tconst { state, manifest } = context;\n\tconst first = nextDeclaredKind(manifest, 0);\n\tstate.phase = first === -1 ? (phase === \"records\" ? \"references\" : \"done\") : phase;\n\tstate.kindIndex = first === -1 ? RECORD_KINDS.length : first;\n\tstate.seq = 0;\n\tstate.lastKey = null;\n\tif (first === -1 && phase === \"records\") startPass(context, \"references\");\n}\n\nfunction advanceChunk(context: Context, kind: RecordKind): void {\n\tconst { state, manifest } = context;\n\tstate.seq++;\n\tif (state.seq < (manifest.records[kind]?.chunks ?? 0)) return;\n\tif (state.phase === \"records\") finishKindRecords(context, kind);\n\tconst next = nextDeclaredKind(manifest, state.kindIndex + 1);\n\tstate.kindIndex = next === -1 ? RECORD_KINDS.length : next;\n\tstate.seq = 0;\n\tstate.lastKey = null;\n\tif (next === -1) {\n\t\tif (state.phase === \"records\") startPass(context, \"references\");\n\t\telse state.phase = \"done\";\n\t}\n}\n\n// ── Structure ───────────────────────────────────────────────────\n\nfunction bumpCount<K>(map: Map<K, number>, key: K, by = 1): void {\n\tmap.set(key, (map.get(key) ?? 0) + by);\n}\n\nasync function structureChunk(context: Context): Promise<void> {\n\tconst { state, manifest } = context;\n\tconst seq = state.nextIndexSeq;\n\tstate.nextIndexSeq++;\n\tconst indexPath = manifest.index[seq]?.path;\n\n\tlet entries: PackageFileEntry[];\n\ttry {\n\t\tentries = await context.reader.indexChunk(seq);\n\t} catch (error) {\n\t\tif (!isTransferError(error)) throw error;\n\t\taddBlocker(state.issues, blockerForError(error, { path: indexPath }));\n\t\treturn;\n\t}\n\n\tfor (const entry of entries) {\n\t\tif (state.lastIndexPath !== null && compareIds(state.lastIndexPath, entry.path) >= 0) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"package_invalid\",\n\t\t\t\tmessage: \"Index entries are not sorted by path or repeat a path\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t}\n\t\tstate.lastIndexPath = entry.path;\n\t\tstate.indexedFiles++;\n\t\tstate.indexedBytes += entry.bytes;\n\n\t\tconst parsed = parsePackagePath(entry.path);\n\t\tif (parsed?.type === \"records\") {\n\t\t\tconst summary = manifest.records[parsed.kind];\n\t\t\tif (!summary || parsed.seq >= summary.chunks) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"package_invalid\",\n\t\t\t\t\tmessage: \"Record chunk is not declared by the manifest\",\n\t\t\t\t\tkind: parsed.kind,\n\t\t\t\t\tdetail: { path: entry.path },\n\t\t\t\t});\n\t\t\t}\n\t\t\tbumpCount(state.indexedChunks, parsed.kind);\n\t\t\tbumpCount(state.indexedRecords, parsed.kind, entry.records ?? 0);\n\t\t\tstate.recordBytes += entry.bytes;\n\t\t} else if (parsed?.type === \"media\") {\n\t\t\tstate.indexedBlobs++;\n\t\t\tstate.indexedBlobBytes += entry.bytes;\n\t\t\tif (context.target && entry.bytes > context.target.maxBlobBytes) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"media_blob_too_large\",\n\t\t\t\t\tmessage: \"Media file is larger than this site accepts\",\n\t\t\t\t\tdetail: { path: entry.path, bytes: entry.bytes, limit: context.target.maxBlobBytes },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tconst staged = await context.stagedFiles.getMany(\n\t\tcontext.operationId,\n\t\tentries.map((entry) => entry.path),\n\t);\n\tfor (const entry of entries) {\n\t\tconst file = staged.get(entry.path);\n\t\tif (!file) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"file_missing\",\n\t\t\t\tmessage: \"Package file has not been staged\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t} else if (file.bytes !== entry.bytes || file.sha256 !== entry.sha256) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"file_mismatch\",\n\t\t\t\tmessage: \"Staged file does not match its index entry\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t} else if (file.state !== \"verified\") {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"file_missing\",\n\t\t\t\tmessage: \"Package file has not been uploaded\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t}\n\t}\n}\n\nasync function countStagedContentFiles(context: Context): Promise<number> {\n\tconst row = await context.db\n\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t.select((eb) => eb.fn.countAll<number | string>().as(\"count\"))\n\t\t.where(\"operation_id\", \"=\", context.operationId)\n\t\t.where((eb) => eb.or([eb(\"path\", \"like\", \"records/%\"), eb(\"path\", \"like\", \"media/%\")]))\n\t\t.executeTakeFirstOrThrow();\n\treturn Number(row.count);\n}\n\nasync function finishStructure(context: Context): Promise<void> {\n\tconst { state, manifest } = context;\n\tfor (const kind of RECORD_KINDS) {\n\t\tconst summary = manifest.records[kind];\n\t\tconst chunks = state.indexedChunks.get(kind) ?? 0;\n\t\tconst records = state.indexedRecords.get(kind) ?? 0;\n\t\tif ((summary?.chunks ?? 0) !== chunks) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"package_invalid\",\n\t\t\t\tmessage: \"Index does not list every record chunk the manifest declares\",\n\t\t\t\tkind,\n\t\t\t\tdetail: { declared: summary?.chunks ?? 0, indexed: chunks },\n\t\t\t});\n\t\t} else if ((summary?.count ?? 0) !== records) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"record_count_mismatch\",\n\t\t\t\tmessage: \"Index record counts do not match the manifest\",\n\t\t\t\tkind,\n\t\t\t\tdetail: { declared: summary?.count ?? 0, indexed: records },\n\t\t\t});\n\t\t}\n\t}\n\tif (\n\t\tstate.indexedBlobs !== manifest.media.count ||\n\t\tstate.indexedBlobBytes !== manifest.media.totalBytes\n\t) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"package_invalid\",\n\t\t\tmessage: \"Indexed media does not match the manifest\",\n\t\t});\n\t}\n\tif (\n\t\tstate.indexedFiles !== manifest.files.count ||\n\t\tstate.indexedBytes !== manifest.files.totalBytes\n\t) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"package_invalid\",\n\t\t\tmessage: \"Indexed files do not match the manifest\",\n\t\t});\n\t}\n\tconst staged = await countStagedContentFiles(context);\n\tif (staged > state.indexedFiles) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"package_invalid\",\n\t\t\tmessage: \"Staged files are not listed in the package index\",\n\t\t\tcount: staged - state.indexedFiles,\n\t\t});\n\t}\n}\n\n// ── Records ─────────────────────────────────────────────────────\n\ninterface ChunkRecord {\n\trecord: SitePackageRecord;\n\tline: number;\n}\n\n/**\n * Decode one record chunk. With `report`, read and decode failures become\n * blockers; the references pass re-reads chunks the records pass already\n * reported and stays quiet.\n */\nasync function loadChunk(\n\tcontext: Context,\n\tkind: RecordKind,\n\treport: boolean,\n): Promise<{ records: ChunkRecord[]; lines: number; path: string } | null> {\n\tconst path = recordChunkPath(kind, context.state.seq);\n\tconst file = await context.stagedFiles.get(context.operationId, path);\n\tif (!file || file.state !== \"verified\") return null;\n\tlet lines: string[];\n\ttry {\n\t\tlines = await readVerifiedChunk(context.reader.stage, path, file);\n\t} catch (error) {\n\t\tif (!isTransferError(error)) throw error;\n\t\tif (report) addBlocker(context.state.issues, blockerForError(error, { path }));\n\t\treturn null;\n\t}\n\tconst records: ChunkRecord[] = [];\n\tlines.forEach((line, index) => {\n\t\tconst decoded = decodeRecordLine(kind, line, { path, line: index + 1 });\n\t\tif (decoded.ok) records.push({ record: decoded.record, line: index + 1 });\n\t\telse if (report) addBlocker(context.state.issues, decoded.blocker);\n\t});\n\treturn { records, lines: lines.length, path };\n}\n\nfunction groupIdOf(record: SitePackageRecord): string {\n\treturn recordStringProperty(record, \"translationGroup\") ?? record.id;\n}\n\nfunction nameKeyOf(record: SitePackageRecord): string | null {\n\tif (record.kind === \"collection\" || record.kind === \"block_type\") return record.slug;\n\tif (record.kind === \"menu\") return record.name;\n\tif (record.kind === \"block_type_version\") {\n\t\treturn blockTypeVersionKey(record.blockTypeId, record.version);\n\t}\n\treturn null;\n}\n\nfunction isTopologicalKind(kind: RecordKind): kind is TopologicalKind {\n\treturn Object.hasOwn(TOPOLOGICAL_PARENT_PROPERTY, kind);\n}\n\nfunction parentOf(kind: RecordKind, record: SitePackageRecord): string | undefined {\n\tif (!isTopologicalKind(kind)) return undefined;\n\treturn recordStringProperty(record, TOPOLOGICAL_PARENT_PROPERTY[kind]);\n}\n\nasync function recordsChunk(context: Context, kind: RecordKind): Promise<void> {\n\tconst { state, manifest } = context;\n\tconst chunk = await loadChunk(context, kind, true);\n\tif (!chunk) {\n\t\tstate.unreadableKinds.add(kind);\n\t\treturn;\n\t}\n\tbumpCount(state.seenRecords, kind, chunk.lines);\n\tconst topological = streamOrderOf(kind) === \"topological\";\n\n\tconst chunkDepths = new Map<string, number>();\n\tlet knownDepths = new Map<string, number>();\n\tif (topological) {\n\t\tconst lookups = new Set<string>();\n\t\tfor (const { record } of chunk.records) {\n\t\t\tlookups.add(record.id);\n\t\t\tconst parent = parentOf(kind, record);\n\t\t\tif (parent !== undefined) lookups.add(parent);\n\t\t}\n\t\tknownDepths = await context.index.depths(kind, [...lookups]);\n\t}\n\n\tconst usedLocales = new Set(manifest.locales.used);\n\tconst entries: PackageIndexEntry[] = [];\n\tfor (const { record, line } of chunk.records) {\n\t\tconst location = { path: chunk.path, line };\n\t\tlet depth: number | undefined;\n\t\tif (topological) {\n\t\t\tdepth = 0;\n\t\t\tconst parent = parentOf(kind, record);\n\t\t\tif (parent === record.id) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"reference_cycle\",\n\t\t\t\t\tmessage: \"Record is its own parent\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t} else if (parent !== undefined) {\n\t\t\t\tconst parentDepth = chunkDepths.get(parent) ?? knownDepths.get(parent);\n\t\t\t\tif (parentDepth === undefined) {\n\t\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\t\tcode: \"record_order_invalid\",\n\t\t\t\t\t\tmessage: \"Parent does not appear before its child\",\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tid: record.id,\n\t\t\t\t\t\tdetail: location,\n\t\t\t\t\t});\n\t\t\t\t} else depth = parentDepth + 1;\n\t\t\t}\n\t\t\tconst stored = knownDepths.get(record.id);\n\t\t\tif (chunkDepths.has(record.id) || (stored !== undefined && stored !== depth)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"duplicate_id\",\n\t\t\t\t\tmessage: \"Record id appears more than once\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t}\n\t\t\tchunkDepths.set(record.id, depth);\n\t\t}\n\n\t\tconst key: StreamOrderKey = depth === undefined ? { id: record.id } : { id: record.id, depth };\n\t\tif (state.lastKey && compareStreamOrder(kind, state.lastKey, key) >= 0) {\n\t\t\tconst duplicate = state.lastKey.id === record.id;\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: duplicate ? \"duplicate_id\" : \"record_order_invalid\",\n\t\t\t\tmessage: duplicate ? \"Record id appears more than once\" : \"Records are out of stream order\",\n\t\t\t\tkind,\n\t\t\t\tid: record.id,\n\t\t\t\tdetail: location,\n\t\t\t});\n\t\t}\n\t\tstate.lastKey = key;\n\n\t\tconst locale = recordLocale(record);\n\t\tif (locale !== undefined && !usedLocales.has(locale)) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"package_invalid\",\n\t\t\t\tmessage: \"Record locale is not listed in the manifest\",\n\t\t\t\tkind,\n\t\t\t\tid: record.id,\n\t\t\t\tdetail: location,\n\t\t\t});\n\t\t}\n\n\t\tcollectRecordFacts(context, record, location);\n\n\t\tconst parent = parentOf(kind, record);\n\t\tentries.push({\n\t\t\tkind,\n\t\t\tid: record.id,\n\t\t\tgroupId: groupIdOf(record),\n\t\t\tnameKey: nameKeyOf(record),\n\t\t\tparentId: parent ?? null,\n\t\t\tdepth: depth ?? 0,\n\t\t});\n\t}\n\tawait context.index.insertMany(entries);\n\tawait checkUniqueKeys(context, kind, chunk.records, chunk.path);\n}\n\nasync function checkUniqueKeys(\n\tcontext: Context,\n\tkind: RecordKind,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst keyed = records.map((item) => ({\n\t\townerId: item.record.id,\n\t\tkeys: uniqueKeysOf(item.record),\n\t\titem,\n\t}));\n\tconst collisions = await findUniqueCollisions(context.db, context.operationId, keyed);\n\tfor (const { constraint, item, holderId } of collisions) {\n\t\tif (constraint === \"byline_principal_locale\") {\n\t\t\tconst principal = recordStringProperty(item.record, \"userPrincipal\");\n\t\t\tif (principal !== undefined) context.state.principalsWithSharedLocaleBylines.add(principal);\n\t\t\tcontinue;\n\t\t}\n\t\taddBlocker(context.state.issues, {\n\t\t\tcode: \"unique_violation\",\n\t\t\tmessage: \"Record would duplicate another record's unique key on the target\",\n\t\t\tkind,\n\t\t\tid: item.record.id,\n\t\t\tdetail: { constraint, conflictsWith: holderId, path, line: item.line },\n\t\t});\n\t}\n}\n\nconst FIELD_TYPE_SET: ReadonlySet<string> = new Set(FIELD_TYPES);\nconst BYLINE_FIELD_TYPE_SET: ReadonlySet<unknown> = new Set(BYLINE_FIELD_TYPES);\n\nfunction isBylineFieldType(type: unknown): type is BylineFieldType {\n\treturn BYLINE_FIELD_TYPE_SET.has(type);\n}\n\n/** The string choices in a select field's `validation.options`, as the write path reads them. */\nfunction selectOptions(validation: unknown): string[] {\n\tif (typeof validation !== \"object\" || validation === null || Array.isArray(validation)) {\n\t\treturn [];\n\t}\n\tconst options: unknown = Reflect.get(validation, \"options\");\n\treturn Array.isArray(options)\n\t\t? options.filter((option): option is string => typeof option === \"string\")\n\t\t: [];\n}\n\nfunction isKnownFieldType(type: string): type is keyof typeof FIELD_TYPE_TO_COLUMN {\n\treturn FIELD_TYPE_SET.has(type);\n}\n\n/**\n * Records whose facts analysis keeps in its state. A package beyond these is\n * rejected rather than letting per-step state grow with the package.\n */\nconst MAX_TRACKED = {\n\tprincipals: 10_000,\n\tcollections: 1_000,\n\tfields: 20_000,\n\tbylineFields: 1_000,\n\tproviders: 100,\n} as const;\n\nfunction countFields(state: WorkingState): number {\n\tlet total = 0;\n\tfor (const fields of state.fields.values()) total += fields.size;\n\treturn total;\n}\n\nfunction reportTrackingLimit(state: WorkingState, kind: RecordKind): void {\n\tconst message = \"Package has more records of this kind than a site supports\";\n\tconst reported = state.issues.blockers.some(\n\t\t(blocker) =>\n\t\t\tblocker.code === \"limit_exceeded\" && blocker.kind === kind && blocker.message === message,\n\t);\n\tif (!reported) addBlocker(state.issues, { code: \"limit_exceeded\", message, kind });\n}\n\nfunction collectRecordFacts(\n\tcontext: Context,\n\trecord: SitePackageRecord,\n\tlocation: { path: string; line: number },\n): void {\n\tconst { state } = context;\n\tswitch (record.kind) {\n\t\tcase \"principal\":\n\t\t\tif (record.id === \"__proto__\") {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"record_invalid\",\n\t\t\t\t\tmessage: \"Principal id is reserved\",\n\t\t\t\t\tkind: \"principal\",\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (state.principals.length >= MAX_TRACKED.principals) {\n\t\t\t\treportTrackingLimit(state, \"principal\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.principals.push({\n\t\t\t\tid: record.id,\n\t\t\t\tdisplayName: record.displayName,\n\t\t\t\t...(record.email === undefined ? {} : { email: record.email }),\n\t\t\t});\n\t\t\treturn;\n\t\tcase \"collection\": {\n\t\t\tconst existing = state.collections.get(record.slug);\n\t\t\tif (existing && existing.id !== record.id) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"duplicate_id\",\n\t\t\t\t\tmessage: \"Collection slug appears more than once\",\n\t\t\t\t\tkind: \"collection\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst config = record.searchConfig;\n\t\t\tconst searchEnabled =\n\t\t\t\ttypeof config === \"object\" &&\n\t\t\t\tconfig !== null &&\n\t\t\t\t!Array.isArray(config) &&\n\t\t\t\tconfig.enabled === true;\n\t\t\tif (state.collections.size >= MAX_TRACKED.collections) {\n\t\t\t\treportTrackingLimit(state, \"collection\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.collections.set(record.slug, { id: record.id, searchEnabled });\n\t\t\treturn;\n\t\t}\n\t\tcase \"field\": {\n\t\t\tif (!isKnownFieldType(record.type)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"field_type_unknown\",\n\t\t\t\t\tmessage: \"Field type is not supported by this site\",\n\t\t\t\t\tkind: \"field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (FIELD_TYPE_TO_COLUMN[record.type] !== record.columnType) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"record_invalid\",\n\t\t\t\t\tmessage: \"Field column type does not match its field type\",\n\t\t\t\t\tkind: \"field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet collectionSlug: string | undefined;\n\t\t\tfor (const [slug, collection] of state.collections) {\n\t\t\t\tif (collection.id === record.collectionId) collectionSlug = slug;\n\t\t\t}\n\t\t\tif (collectionSlug === undefined) return;\n\t\t\tif (countFields(state) >= MAX_TRACKED.fields) {\n\t\t\t\treportTrackingLimit(state, \"field\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst fields = state.fields.get(collectionSlug) ?? new Map<string, FieldInfo>();\n\t\t\tif (fields.has(record.slug)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"duplicate_id\",\n\t\t\t\t\tmessage: \"Field slug appears more than once in its collection\",\n\t\t\t\t\tkind: \"field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfields.set(record.slug, {\n\t\t\t\tcolumnType: record.columnType,\n\t\t\t\trequired: record.required === true,\n\t\t\t});\n\t\t\tstate.fields.set(collectionSlug, fields);\n\t\t\treturn;\n\t\t}\n\t\tcase \"byline_field\": {\n\t\t\tif (!isBylineFieldType(record.type)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"field_type_unknown\",\n\t\t\t\t\tmessage: \"Byline field type is not supported by this site\",\n\t\t\t\t\tkind: \"byline_field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst options = record.type === \"select\" ? selectOptions(record.validation) : undefined;\n\t\t\tif (options !== undefined && options.length > MAX_SELECT_OPTIONS) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"value_constraint_violation\",\n\t\t\t\t\tmessage: \"Byline field has more choices than a site supports\",\n\t\t\t\t\tkind: \"byline_field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: { ...location, property: \"validation\" },\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (state.bylineFields.size >= MAX_TRACKED.bylineFields) {\n\t\t\t\treportTrackingLimit(state, \"byline_field\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.bylineFields.set(record.id, {\n\t\t\t\ttype: record.type,\n\t\t\t\t...(options === undefined ? {} : { options }),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tcase \"setting\":\n\t\t\tif (typeof record.value === \"string\") {\n\t\t\t\tif (\n\t\t\t\t\trecord.id === \"site:title\" ||\n\t\t\t\t\t(record.id === \"emdash:site_title\" && !state.settings.title)\n\t\t\t\t) {\n\t\t\t\t\tstate.settings.title = record.value.slice(0, 4096);\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\trecord.id === \"site:tagline\" ||\n\t\t\t\t\t(record.id === \"emdash:site_tagline\" && !state.settings.tagline)\n\t\t\t\t) {\n\t\t\t\t\tstate.settings.tagline = record.value.slice(0, 4096);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\tdefault:\n\t\t\treturn;\n\t}\n}\n\nfunction finishKindRecords(context: Context, kind: RecordKind): void {\n\tconst { state, manifest } = context;\n\tconst declared = manifest.records[kind]?.count ?? 0;\n\tconst seen = state.seenRecords.get(kind) ?? 0;\n\tif (declared !== seen && !state.unreadableKinds.has(kind)) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"record_count_mismatch\",\n\t\t\tmessage: \"Record count does not match the manifest\",\n\t\t\tkind,\n\t\t\tdetail: { declared, found: seen },\n\t\t});\n\t}\n}\n\n// ── References ──────────────────────────────────────────────────\n\nfunction referenceValues(record: SitePackageRecord, property: string, many: boolean): string[] {\n\tif (!Object.hasOwn(record, property)) return [];\n\tconst raw: unknown = Reflect.get(record, property);\n\tif (many) {\n\t\treturn Array.isArray(raw)\n\t\t\t? raw.filter((value): value is string => typeof value === \"string\")\n\t\t\t: [];\n\t}\n\treturn typeof raw === \"string\" ? [raw] : [];\n}\n\nasync function referencesChunk(context: Context, kind: RecordKind): Promise<void> {\n\tconst { state } = context;\n\tconst chunk = await loadChunk(context, kind, false);\n\tif (!chunk) return;\n\n\tconst principalIds = new Set(state.principals.map((principal) => principal.id));\n\tfor (const reference of KIND_REFERENCES[kind]) {\n\t\tconst owners = new Map<string, ChunkRecord[]>();\n\t\tfor (const item of chunk.records) {\n\t\t\tfor (const value of referenceValues(\n\t\t\t\titem.record,\n\t\t\t\treference.property,\n\t\t\t\treference.many === true,\n\t\t\t)) {\n\t\t\t\tconst list = owners.get(value) ?? [];\n\t\t\t\tlist.push(item);\n\t\t\t\towners.set(value, list);\n\t\t\t\tif (reference.targets.includes(\"principal\") && principalIds.has(value)) {\n\t\t\t\t\tbumpCount(state.principalReferences, value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (owners.size === 0) continue;\n\t\tconst missing = await context.index.findMissing(reference.targets, reference.by, [\n\t\t\t...owners.keys(),\n\t\t]);\n\t\tfor (const value of missing) {\n\t\t\tfor (const item of owners.get(value) ?? []) {\n\t\t\t\tconst detail = { property: reference.property, path: chunk.path, line: item.line };\n\t\t\t\tif (reference.soft) {\n\t\t\t\t\taddWarning(state.issues, {\n\t\t\t\t\t\tcode: \"soft_reference_dangling\",\n\t\t\t\t\t\tmessage: \"Reference does not resolve to a record in the package\",\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tid: item.record.id,\n\t\t\t\t\t\tdetail,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\t\tcode: \"dangling_reference\",\n\t\t\t\t\t\tmessage: \"Reference does not resolve to a record in the package\",\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tid: item.record.id,\n\t\t\t\t\t\tdetail,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tawait checkNestedReferences(context, kind, chunk.records, chunk.path);\n\tawait checkMediaReferences(context, kind, chunk.records, chunk.path);\n\tif (kind === \"media\") await checkMediaBlobs(context, chunk.records, chunk.path);\n\n\tfor (const { record, line } of chunk.records) {\n\t\tif (\n\t\t\trecord.kind === \"byline\" &&\n\t\t\trecord.userPrincipal !== undefined &&\n\t\t\tprincipalIds.has(record.userPrincipal)\n\t\t) {\n\t\t\tconst locales = state.principalBylineLocales.get(record.userPrincipal) ?? new Set<string>();\n\t\t\tlocales.add(record.locale);\n\t\t\tstate.principalBylineLocales.set(record.userPrincipal, locales);\n\t\t}\n\t\tif (context.target) checkTargetValues(context, record, { path: chunk.path, line });\n\t}\n}\n\ninterface NestedReference {\n\tproperty: string;\n\ttargets: readonly RecordKind[];\n\tby: ReferenceKey;\n\tvalues: (record: SitePackageRecord) => string[];\n}\n\n/**\n * References that live inside a property rather than being one: the block\n * types a `blocks` field names in `validation`, and the version a block type\n * names as current.\n */\nconst NESTED_REFERENCES: Partial<Record<RecordKind, NestedReference>> = {\n\tfield: {\n\t\tproperty: \"validation\",\n\t\ttargets: [\"block_type\"],\n\t\tby: \"slug\",\n\t\tvalues: (record) => (record.kind === \"field\" ? blocksFieldTypeSlugs(record) : []),\n\t},\n\tblock_type: {\n\t\tproperty: \"currentVersion\",\n\t\ttargets: [\"block_type_version\"],\n\t\tby: \"name\",\n\t\tvalues: (record) =>\n\t\t\trecord.kind === \"block_type\" ? [blockTypeVersionKey(record.id, record.currentVersion)] : [],\n\t},\n};\n\nasync function checkNestedReferences(\n\tcontext: Context,\n\tkind: RecordKind,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst reference = NESTED_REFERENCES[kind];\n\tif (!reference) return;\n\tconst owners = new Map<string, ChunkRecord[]>();\n\tfor (const item of records) {\n\t\tfor (const value of reference.values(item.record)) {\n\t\t\tconst list = owners.get(value) ?? [];\n\t\t\tlist.push(item);\n\t\t\towners.set(value, list);\n\t\t}\n\t}\n\tif (owners.size === 0) return;\n\tconst missing = await context.index.findMissing(reference.targets, reference.by, [\n\t\t...owners.keys(),\n\t]);\n\tfor (const value of missing) {\n\t\tfor (const item of owners.get(value) ?? []) {\n\t\t\taddBlocker(context.state.issues, {\n\t\t\t\tcode: \"dangling_reference\",\n\t\t\t\tmessage: \"Reference does not resolve to a record in the package\",\n\t\t\t\tkind,\n\t\t\t\tid: item.record.id,\n\t\t\t\tdetail: { property: reference.property, path, line: item.line },\n\t\t\t});\n\t\t}\n\t}\n}\n\nasync function checkMediaReferences(\n\tcontext: Context,\n\tkind: RecordKind,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst { state } = context;\n\tconst placeholderOwners = new Map<string, ChunkRecord[]>();\n\tconst settingOwners = new Map<string, ChunkRecord[]>();\n\tfor (const item of records) {\n\t\tconst scan = scanRecordValues(item.record);\n\t\tif (scan.malformed > 0) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"media_ref_invalid\",\n\t\t\t\tmessage: \"Record holds media placeholder text that is not a placeholder or an escape\",\n\t\t\t\tkind,\n\t\t\t\tid: item.record.id,\n\t\t\t\tdetail: { path, line: item.line },\n\t\t\t});\n\t\t}\n\t\tfor (const mediaId of scan.placeholders) {\n\t\t\tconst list = placeholderOwners.get(mediaId) ?? [];\n\t\t\tlist.push(item);\n\t\t\tplaceholderOwners.set(mediaId, list);\n\t\t}\n\t\tfor (const [provider, uses] of scan.providers) {\n\t\t\tconst key =\n\t\t\t\tstate.externalProviders.has(provider) ||\n\t\t\t\tstate.externalProviders.size < MAX_TRACKED.providers\n\t\t\t\t\t? provider\n\t\t\t\t\t: OTHER_PROVIDER;\n\t\t\tbumpCount(state.externalProviders, key, uses);\n\t\t}\n\t\tif (item.record.kind === \"setting\") {\n\t\t\tfor (const mediaId of settingMediaIds(item.record.id, item.record.value)) {\n\t\t\t\tconst list = settingOwners.get(mediaId) ?? [];\n\t\t\t\tlist.push(item);\n\t\t\t\tsettingOwners.set(mediaId, list);\n\t\t\t}\n\t\t}\n\t}\n\tif (placeholderOwners.size > 0) {\n\t\tconst missing = await context.index.findMissing([\"media\"], \"id\", [...placeholderOwners.keys()]);\n\t\tfor (const mediaId of missing) {\n\t\t\tfor (const item of placeholderOwners.get(mediaId) ?? []) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"media_ref_invalid\",\n\t\t\t\t\tmessage: \"Media placeholder does not name a media record in the package\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: item.record.id,\n\t\t\t\t\tdetail: { path, line: item.line },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\tif (settingOwners.size > 0) {\n\t\tconst missing = await context.index.findMissing([\"media\"], \"id\", [...settingOwners.keys()]);\n\t\tfor (const mediaId of missing) {\n\t\t\tfor (const item of settingOwners.get(mediaId) ?? []) {\n\t\t\t\taddWarning(state.issues, {\n\t\t\t\t\tcode: \"media_row_missing\",\n\t\t\t\t\tmessage: \"Setting refers to media that is not in the package\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: item.record.id,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\nasync function checkMediaBlobs(\n\tcontext: Context,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst blobPaths = new Map<string, ChunkRecord[]>();\n\tfor (const item of records) {\n\t\tif (item.record.kind !== \"media\") continue;\n\t\tconst blobPath = mediaBlobPath(item.record.blob);\n\t\tconst list = blobPaths.get(blobPath) ?? [];\n\t\tlist.push(item);\n\t\tblobPaths.set(blobPath, list);\n\t}\n\tif (blobPaths.size === 0) return;\n\tconst staged = await context.stagedFiles.getMany(context.operationId, [...blobPaths.keys()]);\n\tfor (const [blobPath, items] of blobPaths) {\n\t\tconst file = staged.get(blobPath);\n\t\tif (file && file.state === \"verified\") continue;\n\t\tfor (const item of items) {\n\t\t\taddBlocker(context.state.issues, {\n\t\t\t\tcode: \"media_blob_missing\",\n\t\t\t\tmessage: \"Media record's file is not in the package\",\n\t\t\t\tkind: \"media\",\n\t\t\t\tid: item.record.id,\n\t\t\t\tdetail: { path, line: item.line },\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction reportValueIssues(\n\tcontext: Context,\n\trecord: SitePackageRecord,\n\tissues: readonly ValueIssue[],\n\tlocation: { path: string; line: number },\n): void {\n\tfor (const issue of issues) {\n\t\taddBlocker(context.state.issues, {\n\t\t\tcode: issue.code,\n\t\t\tmessage: issue.message,\n\t\t\tkind: record.kind,\n\t\t\tid: record.id,\n\t\t\tdetail: {\n\t\t\t\t...location,\n\t\t\t\tproperty: issue.property,\n\t\t\t\t...(issue.field === undefined ? {} : { field: issue.field }),\n\t\t\t},\n\t\t});\n\t}\n}\n\nfunction checkTargetValues(\n\tcontext: Context,\n\trecord: SitePackageRecord,\n\tlocation: { path: string; line: number },\n): void {\n\tconst target = context.target;\n\tif (!target) return;\n\tconst numbers = checkRecordNumbers(record, target.dialect);\n\tcontext.state.float4Rounded += numbers.float4Rounded;\n\treportValueIssues(context, record, numbers.issues, location);\n\treportValueIssues(\n\t\tcontext,\n\t\trecord,\n\t\twriteRuleIssues(record, { bylineFields: context.state.bylineFields }),\n\t\tlocation,\n\t);\n\tif (record.kind === \"entry\") {\n\t\tconst fields = context.state.fields.get(record.collection);\n\t\tif (!fields) return;\n\t\tconst values = checkEntryFields(record, fields, target.dialect);\n\t\tcontext.state.float4Rounded += values.float4Rounded;\n\t\treportValueIssues(context, record, values.issues, location);\n\t}\n}\n\n// ── Summary for analysis ────────────────────────────────────────\n\nexport interface ValidationSummary {\n\trecordBytes: number;\n\tprincipals: PrincipalSummary[];\n\tprincipalReferences: ReadonlyMap<string, number>;\n\tprincipalBylineLocales: ReadonlyMap<string, ReadonlySet<string>>;\n\t/** Principals linked to more than one byline in some locale. */\n\tprincipalsWithSharedLocaleBylines: ReadonlySet<string>;\n\tsettings: { title?: string; tagline?: string };\n\t/** Slugs of the package's collections. */\n\tcollectionSlugs: string[];\n\t/** Collections whose search config enables full-text search. */\n\tsearchEnabledCollections: string[];\n\tfloat4Rounded: number;\n\texternalProviders: ReadonlyMap<string, number>;\n}\n\nexport function summarizeValidation(state: ValidationState): ValidationSummary {\n\tconst working = deserialize(state);\n\treturn {\n\t\trecordBytes: working.recordBytes,\n\t\tprincipals: working.principals,\n\t\tprincipalReferences: working.principalReferences,\n\t\tprincipalBylineLocales: working.principalBylineLocales,\n\t\tprincipalsWithSharedLocaleBylines: working.principalsWithSharedLocaleBylines,\n\t\tsettings: working.settings,\n\t\tcollectionSlugs: [...working.collections.keys()].toSorted(compareIds),\n\t\tsearchEnabledCollections: [...working.collections.values()]\n\t\t\t.filter((collection) => collection.searchEnabled)\n\t\t\t.map((collection) => collection.id)\n\t\t\t.toSorted(compareIds),\n\t\tfloat4Rounded: working.float4Rounded,\n\t\texternalProviders: working.externalProviders,\n\t};\n}\n","/**\n * The import analysis operation: validation, target inspection, and the plan,\n * driven in bounded steps under the operation's lease.\n *\n * Progress lives in the operation cursor plus a state file in the\n * operation's staging area keyed by that cursor's digest. A step writes the\n * state for its new cursor before it moves the cursor, so a step that dies\n * midway leaves the previous cursor and its state intact and the next step\n * repeats the work (package index writes are insert-if-absent).\n */\n\nimport type { Kysely } from \"kysely\";\nimport { z } from \"zod\";\n\nimport { detectDialect } from \"../../database/dialect-helpers.js\";\nimport { OptionsRepository } from \"../../database/repositories/options.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { isTransferError, TransferError } from \"../errors.js\";\nimport { canonicalJson, parseCanonicalJson } from \"../format/canonical.js\";\nimport { canonicalDigest, planDigest, sha256Hex, type Sha256Digest } from \"../format/digest.js\";\nimport { compareIds, portableIdSchema, RECORD_KINDS } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport { MANIFEST_PATH, recordChunkPath } from \"../format/paths.js\";\nimport {\n\tmergeDecisions,\n\tsiteImportDecisionsInputSchema,\n\tsiteImportPlanSchema,\n\ttype SiteImportPlan,\n} from \"../format/plan.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferOperationRepository, type TransferOperation } from \"../ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport { analysisCursorSchema, type AnalysisCursor, type TransferProgress } from \"../ops/states.js\";\nimport { getOrCreateSiteId } from \"../site-id.js\";\nimport { stagingPrefix } from \"../staging/keys.js\";\nimport { StagedPackageReader } from \"../staging/package.js\";\nimport { readStreamBytes, TransferStage } from \"../staging/stage.js\";\nimport {\n\tapplyDecisions,\n\tbuildBlockedPlan,\n\tbuildPlan,\n\tdefaultDecisions,\n\ttype PrincipalBylines,\n} from \"./plan.js\";\nimport {\n\tcheckLocales,\n\tlocaleRecasing,\n\tfindMissingUsers,\n\tfindRedirectLoops,\n\tinspectTargetDomain,\n\tsuggestPrincipalUsers,\n\ttype AnalysisTargetContext,\n} from \"./target.js\";\nimport {\n\tinitialValidationState,\n\tparseValidationState,\n\trunValidationStep,\n\tsummarizeValidation,\n\ttype ValidationState,\n\ttype ValidationStepResult,\n} from \"./validate.js\";\n\nconst ANALYSIS_DIRECTORY = \"_analysis/\";\nconst MAX_STATE_BYTES = 64 * 1024 * 1024;\nconst MAX_PLAN_BYTES = 64 * 1024 * 1024;\n\nconst ANALYZABLE_STATES = [\"uploading\", \"analyzing\"] as const;\n\nexport interface AnalyzeImportStepInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/** A lease the caller already holds on the operation; claimed here when omitted. */\n\tleaseToken?: string;\n\tbudget: TransferStepBudget;\n\ttargetContext: AnalysisTargetContext;\n}\n\nexport interface AnalyzeImportStepResult {\n\toperation: TransferOperation;\n\t/** True once the operation is `planned` (or ended); false when more steps are needed. */\n\tdone: boolean;\n\tplan: SiteImportPlan | null;\n\tplanDigest: Sha256Digest | null;\n}\n\nconst analysisContextSchema = z.strictObject({\n\tversion: z.literal(1),\n\tprincipalBylineLocales: z.array(z.tuple([z.string(), z.array(z.string())])),\n\tprincipalsWithSharedLocaleBylines: z.array(z.string()),\n});\n\ntype AnalysisContextFile = z.infer<typeof analysisContextSchema>;\n\nfunction stageFor(storage: Storage, operation: TransferOperation): TransferStage {\n\treturn new TransferStage(storage, stagingPrefix(\"import\", operation.id, operation.stagingSecret));\n}\n\nasync function stateKey(stage: TransferStage, cursor: AnalysisCursor): Promise<string> {\n\treturn `${stage.prefix}${ANALYSIS_DIRECTORY}state-${await sha256Hex(canonicalJson(cursor))}.json`;\n}\n\nfunction contextKey(stage: TransferStage): string {\n\treturn `${stage.prefix}${ANALYSIS_DIRECTORY}context.json`;\n}\n\nasync function readJson(storage: Storage, key: string, maxBytes: number): Promise<unknown> {\n\tif (!(await storage.exists(key))) return null;\n\tconst download = await storage.download(key);\n\treturn JSON.parse(new TextDecoder().decode(await readStreamBytes(download.body, maxBytes)));\n}\n\nasync function writeJson(storage: Storage, key: string, value: unknown): Promise<void> {\n\tawait storage.upload({\n\t\tkey,\n\t\tbody: new TextEncoder().encode(JSON.stringify(value)),\n\t\tcontentType: \"application/json\",\n\t});\n}\n\nfunction cursorFor(state: ValidationState): AnalysisCursor {\n\tconst kind = RECORD_KINDS[state.kindIndex];\n\tswitch (state.phase) {\n\t\tcase \"structure\":\n\t\t\treturn { stage: \"analyze_structure\", nextIndexSeq: state.nextIndexSeq };\n\t\tcase \"records\":\n\t\t\tif (kind) {\n\t\t\t\treturn { stage: \"analyze_records\", position: { kind, seq: state.seq, line: 0 } };\n\t\t\t}\n\t\t\treturn { stage: \"analyze_references\", check: state.kindIndex, after: null };\n\t\tcase \"references\":\n\t\t\treturn {\n\t\t\t\tstage: \"analyze_references\",\n\t\t\t\tcheck: state.kindIndex,\n\t\t\t\tafter: kind && state.seq > 0 ? recordChunkPath(kind, state.seq - 1) : null,\n\t\t\t};\n\t\tcase \"done\":\n\t\t\treturn { stage: \"analyze_target\" };\n\t}\n}\n\nfunction chunksBefore(\n\tmanifest: SitePackageManifest | null,\n\tkindIndex: number,\n\tseq: number,\n): { before: number; total: number } {\n\tlet before = 0;\n\tlet total = 0;\n\tRECORD_KINDS.forEach((kind, index) => {\n\t\tconst chunks = manifest?.records[kind]?.chunks ?? 0;\n\t\ttotal += chunks;\n\t\tif (index < kindIndex) before += chunks;\n\t});\n\treturn { before: before + seq, total };\n}\n\nfunction progressFor(\n\tstate: ValidationState,\n\tmanifest: SitePackageManifest | null,\n): TransferProgress {\n\tconst indexChunks = manifest?.index.length ?? 0;\n\tconst { before, total: recordChunks } = chunksBefore(manifest, state.kindIndex, state.seq);\n\tconst total = indexChunks + 2 * recordChunks + 1;\n\tswitch (state.phase) {\n\t\tcase \"structure\":\n\t\t\treturn { done: Math.min(state.nextIndexSeq, indexChunks), total };\n\t\tcase \"records\":\n\t\t\treturn { done: indexChunks + before, total };\n\t\tcase \"references\":\n\t\t\treturn { done: indexChunks + recordChunks + before, total };\n\t\tcase \"done\":\n\t\t\treturn { done: total - 1, total };\n\t}\n}\n\nasync function loadValidationState(\n\tstage: TransferStage,\n\tcursor: TransferOperation[\"cursor\"],\n): Promise<ValidationState> {\n\tconst analysisCursor = analysisCursorSchema.safeParse(cursor);\n\tif (!analysisCursor.success) return initialValidationState();\n\tconst raw = await readJson(\n\t\tstage.storage,\n\t\tawait stateKey(stage, analysisCursor.data),\n\t\tMAX_STATE_BYTES,\n\t);\n\treturn raw === null ? initialValidationState() : parseValidationState(raw);\n}\n\nasync function readManifestSafely(\n\treader: StagedPackageReader,\n): Promise<SitePackageManifest | null> {\n\ttry {\n\t\treturn await reader.manifest();\n\t} catch (error) {\n\t\tif (isTransferError(error)) return null;\n\t\tthrow error;\n\t}\n}\n\nconst looseIdentitySchema = z.looseObject({\n\tpackageId: portableIdSchema,\n\toriginSiteId: portableIdSchema,\n\tcreatedAt: z.string().min(1).max(64),\n\tcreatedByEmDashVersion: z.string().min(1).max(128),\n});\n\n/**\n * Identity and digest of a manifest that failed full validation, when its\n * identity fields are still well-formed.\n */\nasync function looseManifestIdentity(stage: TransferStage): Promise<{\n\tdigest: Sha256Digest;\n\torigin: z.infer<typeof looseIdentitySchema>;\n} | null> {\n\ttry {\n\t\tconst bytes = await stage.readBytes(MANIFEST_PATH, TRANSFER_LIMITS.manifestBytes);\n\t\tconst raw = parseCanonicalJson(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n\t\tconst identity = looseIdentitySchema.safeParse(raw);\n\t\tif (!identity.success) return null;\n\t\treturn { digest: await canonicalDigest(raw), origin: identity.data };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function readTargetSettings(\n\tdb: Kysely<Database>,\n): Promise<{ title?: string; tagline?: string }> {\n\tconst options = new OptionsRepository(db);\n\tconst title = await options.get(\"site:title\");\n\tconst tagline = await options.get(\"site:tagline\");\n\treturn {\n\t\t...(typeof title === \"string\" ? { title } : {}),\n\t\t...(typeof tagline === \"string\" ? { tagline } : {}),\n\t};\n}\n\nfunction principalBylinesFrom(file: AnalysisContextFile): PrincipalBylines {\n\treturn {\n\t\tlocales: new Map(file.principalBylineLocales.map(([id, locales]) => [id, new Set(locales)])),\n\t\tsharedLocale: new Set(file.principalsWithSharedLocaleBylines),\n\t};\n}\n\nasync function storePlan(\n\tstage: TransferStage,\n\tplan: SiteImportPlan,\n\tcontext: AnalysisContextFile,\n): Promise<Sha256Digest> {\n\tawait writeJson(stage.storage, contextKey(stage), context);\n\tawait stage.putAux(\"plan\", canonicalJson(plan));\n\treturn planDigest(plan);\n}\n\nasync function buildAnalysisPlan(\n\tinput: AnalyzeImportStepInput,\n\tstage: TransferStage,\n\treader: StagedPackageReader,\n\tvalidation: ValidationStepResult,\n): Promise<{ plan: SiteImportPlan; context: AnalysisContextFile } | null> {\n\tconst { db, targetContext } = input;\n\tconst target = {\n\t\tsiteId: await getOrCreateSiteId(db),\n\t\tdialect: detectDialect(db),\n\t\temdashVersion: targetContext.emdashVersion,\n\t};\n\tconst manifest = await readManifestSafely(reader);\n\tif (!manifest) {\n\t\tconst identity = await looseManifestIdentity(stage);\n\t\tif (!identity) return null;\n\t\treturn {\n\t\t\tplan: buildBlockedPlan({\n\t\t\t\tpackageDigest: identity.digest,\n\t\t\t\torigin: {\n\t\t\t\t\tsiteId: identity.origin.originSiteId,\n\t\t\t\t\tpackageId: identity.origin.packageId,\n\t\t\t\t\tcreatedAt: identity.origin.createdAt,\n\t\t\t\t\tcreatedByEmDashVersion: identity.origin.createdByEmDashVersion,\n\t\t\t\t},\n\t\t\t\ttarget,\n\t\t\t\tblockers: validation.blockers,\n\t\t\t\twarnings: validation.warnings,\n\t\t\t}),\n\t\t\tcontext: { version: 1, principalBylineLocales: [], principalsWithSharedLocaleBylines: [] },\n\t\t};\n\t}\n\n\tconst summary = summarizeValidation(validation.state);\n\tconst domain = await inspectTargetDomain(db, summary.collectionSlugs);\n\tconst redirectLoops = await findRedirectLoops(\n\t\tmanifest,\n\t\tstage,\n\t\tnew TransferStagedFileRepository(db),\n\t\tinput.operationId,\n\t);\n\tconst context: AnalysisContextFile = {\n\t\tversion: 1,\n\t\tprincipalBylineLocales: Array.from(\n\t\t\tsummary.principalBylineLocales,\n\t\t\t([id, locales]): [string, string[]] => [id, [...locales].toSorted(compareIds)],\n\t\t).toSorted(([a], [b]) => compareIds(a, b)),\n\t\tprincipalsWithSharedLocaleBylines: [...summary.principalsWithSharedLocaleBylines].toSorted(\n\t\t\tcompareIds,\n\t\t),\n\t};\n\tconst plan = buildPlan(\n\t\t{\n\t\t\tpackageDigest: await reader.digest(),\n\t\t\tmanifest,\n\t\t\ttarget,\n\t\t\tsummary,\n\t\t\tvalidationBlockers: validation.blockers,\n\t\t\tvalidationWarnings: validation.warnings,\n\t\t\ttargetBlockers: [...domain.blockers, ...checkLocales(manifest, targetContext)],\n\t\t\tscaffold: domain.scaffold,\n\t\t\tredirectLoops,\n\t\t\tlocaleRecasing: localeRecasing(manifest, targetContext),\n\t\t\tsuggestions: await suggestPrincipalUsers(db, summary.principals),\n\t\t\ttargetSettings: await readTargetSettings(db),\n\t\t},\n\t\tprincipalBylinesFrom(context),\n\t);\n\treturn { plan, context };\n}\n\nasync function claimForAnalysis(\n\trepo: TransferOperationRepository,\n\tinput: AnalyzeImportStepInput,\n): Promise<{ operation: TransferOperation; leaseToken: string } | { planned: TransferOperation }> {\n\tif (input.leaseToken !== undefined) {\n\t\tconst operation = await repo.require(input.operationId);\n\t\tif (operation.leaseToken !== input.leaseToken) {\n\t\t\tthrow new TransferError(\"TRANSFER_LEASE_LOST\", \"Transfer operation lease was lost\");\n\t\t}\n\t\tif (operation.kind !== \"import\" || !isAnalyzable(operation.state)) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be analyzed in this state\");\n\t\t}\n\t\treturn { operation, leaseToken: input.leaseToken };\n\t}\n\tconst claim = await repo.claim(input.operationId, ANALYZABLE_STATES);\n\tswitch (claim.outcome) {\n\t\tcase \"claimed\":\n\t\t\tif (claim.operation.kind !== \"import\") {\n\t\t\t\tawait repo.release(claim.operation.id, claim.leaseToken);\n\t\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Only imports can be analyzed\");\n\t\t\t}\n\t\t\treturn { operation: claim.operation, leaseToken: claim.leaseToken };\n\t\tcase \"lease_active\":\n\t\t\tthrow new TransferError(\"TRANSFER_LEASE_ACTIVE\", \"Another step is running\");\n\t\tcase \"invalid_state\":\n\t\t\tif (claim.operation.kind === \"import\" && claim.operation.state === \"planned\") {\n\t\t\t\treturn { planned: claim.operation };\n\t\t\t}\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be analyzed in this state\");\n\t}\n}\n\nfunction isAnalyzable(state: string): boolean {\n\treturn (ANALYZABLE_STATES as readonly string[]).includes(state);\n}\n\n/**\n * Run one bounded analysis step. The final step stores the plan (default\n * decisions) in staging as `_plan.json` and moves the operation to\n * `planned`. Calling it on a planned operation returns the stored plan.\n */\nexport async function analyzeImportStep(\n\tinput: AnalyzeImportStepInput,\n): Promise<AnalyzeImportStepResult> {\n\tconst repo = new TransferOperationRepository(input.db);\n\tconst claimed = await claimForAnalysis(repo, input);\n\tif (\"planned\" in claimed) {\n\t\tconst plan = await loadImportPlan(input.storage, claimed.planned);\n\t\treturn {\n\t\t\toperation: claimed.planned,\n\t\t\tdone: true,\n\t\t\tplan,\n\t\t\tplanDigest: plan ? await planDigest(plan) : null,\n\t\t};\n\t}\n\tconst { operation, leaseToken } = claimed;\n\n\ttry {\n\t\tif (operation.cancelRequestedAt !== null) {\n\t\t\treturn {\n\t\t\t\toperation: await repo.finishCancelled(operation.id, leaseToken),\n\t\t\t\tdone: true,\n\t\t\t\tplan: null,\n\t\t\t\tplanDigest: null,\n\t\t\t};\n\t\t}\n\n\t\tconst stage = stageFor(input.storage, operation);\n\t\tconst reader = new StagedPackageReader(stage);\n\t\tconst validationState = await loadValidationState(stage, operation.cursor);\n\t\tconst validation = await runValidationStep(\n\t\t\t{\n\t\t\t\tdb: input.db,\n\t\t\t\treader,\n\t\t\t\toperationId: operation.id,\n\t\t\t\tstate: validationState,\n\t\t\t\tbudget: input.budget,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttarget: {\n\t\t\t\t\tdialect: detectDialect(input.db),\n\t\t\t\t\tmaxBlobBytes: input.targetContext.maxUploadSize,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tconst manifest = await readManifestSafely(reader);\n\t\tconst cursor = cursorFor(validation.state);\n\n\t\tif (!validation.done || !input.budget.canStart()) {\n\t\t\tawait writeJson(input.storage, await stateKey(stage, cursor), validation.state);\n\t\t\tconst updated = await repo.release(operation.id, leaseToken, {\n\t\t\t\tstate: \"analyzing\",\n\t\t\t\tstage: cursor.stage,\n\t\t\t\tcursor,\n\t\t\t\tprogress: progressFor(validation.state, manifest),\n\t\t\t});\n\t\t\treturn { operation: updated, done: false, plan: null, planDigest: null };\n\t\t}\n\t\tinput.budget.start();\n\n\t\tconst built = await buildAnalysisPlan(input, stage, reader, validation);\n\t\tif (!built) {\n\t\t\tconst first = validation.blockers[0];\n\t\t\treturn {\n\t\t\t\toperation: await repo.fail(operation.id, leaseToken, {\n\t\t\t\t\tcode: \"TRANSFER_MANIFEST_INVALID\",\n\t\t\t\t\tdetail: first ? { blocker: first.code } : undefined,\n\t\t\t\t}),\n\t\t\t\tdone: true,\n\t\t\t\tplan: null,\n\t\t\t\tplanDigest: null,\n\t\t\t};\n\t\t}\n\t\tconst digest = await storePlan(stage, built.plan, built.context);\n\t\tconst progress = progressFor(validation.state, manifest);\n\t\tconst updated = await repo.releaseUnlessCancelled(operation.id, leaseToken, \"planned\", {\n\t\t\tstage: null,\n\t\t\tcursor: null,\n\t\t\tplanDigest: digest,\n\t\t\tprogress: { done: progress.total, total: progress.total },\n\t\t});\n\t\tif (updated.state === \"cancelled\") {\n\t\t\treturn { operation: updated, done: true, plan: null, planDigest: null };\n\t\t}\n\t\treturn { operation: updated, done: true, plan: built.plan, planDigest: digest };\n\t} catch (error) {\n\t\tif (!(isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\")) {\n\t\t\tawait repo.release(operation.id, leaseToken).catch(() => undefined);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** The stored plan of an analyzed import, or null when none has been stored. */\nexport async function loadImportPlan(\n\tstorage: Storage,\n\toperation: TransferOperation,\n): Promise<SiteImportPlan | null> {\n\tconst text = await stageFor(storage, operation).readAux(\"plan\", MAX_PLAN_BYTES);\n\tif (text === null) return null;\n\treturn siteImportPlanSchema.parse(JSON.parse(text));\n}\n\nexport interface FinalizePlanInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/** Decisions to apply over the plan's defaults (unvalidated caller input). */\n\tdecisions: unknown;\n}\n\n/**\n * Apply submitted decisions to a planned import: validate them, recompute the\n * decision-dependent blockers, warnings, and transformations, store the plan,\n * and record its digest on the operation. Unknown principal ids and mappings\n * to users that do not exist are rejected with `TRANSFER_DECISIONS_INVALID`.\n * Once execution is requested the plan is frozen: `TRANSFER_INVALID_STATE`.\n */\nexport async function finalizePlan(\n\tinput: FinalizePlanInput,\n): Promise<{ plan: SiteImportPlan; planDigest: Sha256Digest }> {\n\tconst parsed = siteImportDecisionsInputSchema.safeParse(input.decisions);\n\tif (!parsed.success) {\n\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"Decisions are malformed\");\n\t}\n\n\tconst repo = new TransferOperationRepository(input.db);\n\tconst claim = await repo.claim(input.operationId, [\"planned\"]);\n\tif (claim.outcome === \"lease_active\") {\n\t\tthrow new TransferError(\"TRANSFER_LEASE_ACTIVE\", \"Another step is running\");\n\t}\n\tif (claim.outcome === \"invalid_state\" || claim.operation.kind !== \"import\") {\n\t\tif (claim.outcome === \"claimed\") await repo.release(claim.operation.id, claim.leaseToken);\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has not been analyzed\");\n\t}\n\tif (claim.operation.stage === \"reserve\") {\n\t\tawait repo.release(claim.operation.id, claim.leaseToken);\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\"Import execution was requested; its plan can no longer change\",\n\t\t);\n\t}\n\tconst { operation, leaseToken } = claim;\n\n\ttry {\n\t\tconst stage = stageFor(input.storage, operation);\n\t\tconst stored = await loadImportPlan(input.storage, operation);\n\t\tconst contextRaw = await readJson(input.storage, contextKey(stage), MAX_STATE_BYTES);\n\t\tconst context = analysisContextSchema.safeParse(contextRaw);\n\t\tif (!stored || !context.success) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has no stored plan\");\n\t\t}\n\n\t\tconst known = new Set(stored.principals.map((principal) => principal.id));\n\t\tconst submitted = Object.entries(parsed.data.principalMappings ?? {});\n\t\tconst unknown = submitted.filter(([principalId]) => !known.has(principalId));\n\t\tif (unknown.length > 0) {\n\t\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"Decisions name unknown principals\", {\n\t\t\t\tdetail: { principals: unknown.length },\n\t\t\t});\n\t\t}\n\t\tconst missingUsers = await findMissingUsers(\n\t\t\tinput.db,\n\t\t\tsubmitted.flatMap(([, userId]) => (userId === null ? [] : [userId])),\n\t\t);\n\t\tif (missingUsers.length > 0) {\n\t\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"Decisions name unknown users\", {\n\t\t\t\tdetail: { users: missingUsers.length },\n\t\t\t});\n\t\t}\n\n\t\tconst decisions = mergeDecisions(defaultDecisions(stored.principals), parsed.data);\n\t\tconst plan = applyDecisions(stored, decisions, principalBylinesFrom(context.data));\n\t\tconst digest = await storePlan(stage, plan, context.data);\n\t\tawait repo.release(operation.id, leaseToken, { planDigest: digest });\n\t\treturn { plan, planDigest: digest };\n\t} catch (error) {\n\t\tif (!(isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\")) {\n\t\t\tawait repo.release(operation.id, leaseToken).catch(() => undefined);\n\t\t}\n\t\tthrow error;\n\t}\n}\n","/**\n * Audit log entries for transfer actions. Entries carry operation and\n * approval ids, digests, counts, and error codes, never package content.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport {\n\tAuditRepository,\n\ttype AuditAction,\n\ttype AuditStatus,\n} from \"../database/repositories/audit.js\";\nimport type { Database } from \"../database/types.js\";\n\nexport interface TransferAuditEntry {\n\tactorId: string;\n\taction: Extract<AuditAction, `transfer_${string}`>;\n\tresourceType: \"transfer_operation\" | \"transfer_approval\";\n\tresourceId: string;\n\tdetails?: Record<string, string | number | null>;\n\tstatus?: AuditStatus;\n}\n\n/**\n * Write an audit entry for a transfer action that has already taken effect.\n * A failed write is logged, not thrown, so it never reports a completed\n * action as failed.\n */\nexport async function recordTransferAudit(\n\tdb: Kysely<Database>,\n\tentry: TransferAuditEntry,\n): Promise<void> {\n\ttry {\n\t\tawait new AuditRepository(db).log({ status: \"success\", ...entry });\n\t} catch (error) {\n\t\tconsole.error(\"[transfer] Failed to write an audit log entry:\", error);\n\t}\n}\n","/**\n * Work budget for one `advance` step.\n *\n * Queries are counted by the request's `metrics.dbCount` (the Kysely log hook\n * bumps it), so the budget also covers queries the request ran before the\n * step. A unit of work may start only if its estimated query cost still fits\n * under the ceiling with `stepClosingQueries` to spare for the writes that end\n * the step, and only if its bytes fit the step's byte budget. The\n * byte check skips the first unit of a step, so one blob larger than the byte\n * budget gets a step of its own.\n */\n\nimport { getRequestContext } from \"../../request-context.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\n\nexport interface StepBudget {\n\tqueries: number;\n\tbytes: number;\n}\n\nexport interface StepBudgetOptions {\n\t/** Stop starting units once the request has run this many queries. */\n\tqueryCeiling?: number;\n\t/** Media bytes per step. */\n\tbytes?: number;\n\t/** Query counter; defaults to the current request's metrics. */\n\tmetrics?: { dbCount: number };\n}\n\nexport class TransferStepBudget {\n\treadonly #queryCeiling: number;\n\treadonly #byteLimit: number;\n\treadonly #metrics: { dbCount: number } | undefined;\n\t#bytesUsed = 0;\n\t#units = 0;\n\n\tget #unitCeiling(): number {\n\t\treturn this.#queryCeiling - TRANSFER_LIMITS.stepClosingQueries;\n\t}\n\n\tconstructor(options: StepBudgetOptions = {}) {\n\t\tthis.#queryCeiling = options.queryCeiling ?? TRANSFER_LIMITS.stepQueryCeiling;\n\t\tthis.#byteLimit = options.bytes ?? TRANSFER_LIMITS.stepBytes;\n\t\tthis.#metrics = options.metrics ?? getRequestContext()?.metrics;\n\t}\n\n\t/**\n\t * Whether a unit costing `cost` may start. Defaults to the standard unit\n\t * query cost and no bytes. Without request metrics only bytes are limited.\n\t */\n\tcanStart(cost: Partial<StepBudget> = {}): boolean {\n\t\tconst queries = cost.queries ?? TRANSFER_LIMITS.stepQueries;\n\t\tconst bytes = cost.bytes ?? 0;\n\t\tif (this.#metrics && this.#metrics.dbCount + queries > this.#unitCeiling) return false;\n\t\tif (this.#units === 0) return true;\n\t\treturn bytes === 0 || this.#bytesUsed + bytes <= this.#byteLimit;\n\t}\n\n\t/** Record that a unit started, with the bytes it will move. */\n\tstart(bytes = 0): void {\n\t\tthis.#units++;\n\t\tthis.#bytesUsed += bytes;\n\t}\n\n\tget units(): number {\n\t\treturn this.#units;\n\t}\n\n\tget bytesUsed(): number {\n\t\treturn this.#bytesUsed;\n\t}\n\n\t/** Remaining budget, for display and for sizing batch reads. */\n\tremaining(): StepBudget {\n\t\treturn {\n\t\t\tqueries: this.#metrics\n\t\t\t\t? Math.max(0, this.#unitCeiling - this.#metrics.dbCount)\n\t\t\t\t: Number.POSITIVE_INFINITY,\n\t\t\tbytes: Math.max(0, this.#byteLimit - this.#bytesUsed),\n\t\t};\n\t}\n}\n","/**\n * Export-side record of each exported media row's blob digest and size,\n * computed by hashing the origin object during the export's media stage.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { bytewise } from \"./collation.js\";\n\nexport interface MediaBlobEntry {\n\tmediaId: string;\n\tsha256: string;\n\tbytes: number;\n}\n\nexport class TransferMediaBlobRepository {\n\tconstructor(\n\t\tprivate readonly db: Kysely<Database>,\n\t\tprivate readonly operationId: string,\n\t) {}\n\n\t/** Record blobs; re-recording a media id (retried batch) overwrites it with the new hash. */\n\tasync putMany(entries: readonly MediaBlobEntry[]): Promise<void> {\n\t\tfor (const batch of chunks([...entries], rowsPerInsert(4))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_media_blobs\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((entry) => ({\n\t\t\t\t\t\toperation_id: this.operationId,\n\t\t\t\t\t\tmedia_id: entry.mediaId,\n\t\t\t\t\t\tsha256: entry.sha256,\n\t\t\t\t\t\tbytes: entry.bytes,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) =>\n\t\t\t\t\tconflict.columns([\"operation_id\", \"media_id\"]).doUpdateSet({\n\t\t\t\t\t\tsha256: (eb) => eb.ref(\"excluded.sha256\"),\n\t\t\t\t\t\tbytes: (eb) => eb.ref(\"excluded.bytes\"),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t}\n\t}\n\n\tasync getMany(mediaIds: readonly string[]): Promise<Map<string, MediaBlobEntry>> {\n\t\tconst result = new Map<string, MediaBlobEntry>();\n\t\tfor (const batch of chunks([...new Set(mediaIds)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t\t.select([\"media_id\", \"sha256\", \"bytes\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"media_id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) {\n\t\t\t\tresult.set(row.media_id, {\n\t\t\t\t\tmediaId: row.media_id,\n\t\t\t\t\tsha256: row.sha256,\n\t\t\t\t\tbytes: Number(row.bytes),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Blob entries in media-id order. */\n\tasync list(options: { after?: string; limit?: number } = {}): Promise<MediaBlobEntry[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select([\"media_id\", \"sha256\", \"bytes\"])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId);\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"media_id\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"media_id\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map((row) => ({\n\t\t\tmediaId: row.media_id,\n\t\t\tsha256: row.sha256,\n\t\t\tbytes: Number(row.bytes),\n\t\t}));\n\t}\n\n\t/** Distinct blobs (by digest) with their size, in digest order. */\n\tasync listDistinctBlobs(\n\t\toptions: { after?: string; limit?: number } = {},\n\t): Promise<Array<{ sha256: string; bytes: number }>> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select([\"sha256\", (eb) => eb.fn.max(\"bytes\").as(\"bytes\")])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.groupBy(\"sha256\");\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"sha256\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"sha256\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map((row) => ({ sha256: row.sha256, bytes: Number(row.bytes) }));\n\t}\n\n\tasync totals(): Promise<{ mediaRows: number; blobs: number; blobBytes: number }> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select((eb) => [\n\t\t\t\teb.fn.countAll<number | string>().as(\"media_rows\"),\n\t\t\t\teb.fn.count<number | string>(\"sha256\").distinct().as(\"blobs\"),\n\t\t\t])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.executeTakeFirstOrThrow();\n\t\tconst bytes = await this.db\n\t\t\t.selectFrom(\n\t\t\t\tthis.db\n\t\t\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t\t\t.select([\"sha256\", (eb) => eb.fn.max(\"bytes\").as(\"bytes\")])\n\t\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t\t.groupBy(\"sha256\")\n\t\t\t\t\t.as(\"blob\"),\n\t\t\t)\n\t\t\t.select((eb) => eb.fn.sum<number | string | null>(\"blob.bytes\").as(\"total\"))\n\t\t\t.executeTakeFirstOrThrow();\n\t\treturn {\n\t\t\tmediaRows: Number(row.media_rows),\n\t\t\tblobs: Number(row.blobs),\n\t\t\tblobBytes: Number(bytes.total ?? 0),\n\t\t};\n\t}\n}\n","/**\n * Optimistic-read fence for an export: per portable table, the row count,\n * the latest `updated_at` (or `created_at`), and the largest id. A write that\n * changes none of these (an in-place edit of a table without `updated_at`) is\n * caught by the operation's `write_epoch`, which fenced writes bump.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { validateIdentifier } from \"../../database/validate.js\";\nimport { CONTENT_TABLE_PREFIX, PORTABLE_TABLES } from \"../format/columns.js\";\nimport type { ExportFence } from \"../ops/states.js\";\n\ntype Db = Kysely<Database>;\n\ninterface FencedTable {\n\ttable: string;\n\tchanged: string | null;\n\tid: string | null;\n}\n\nasync function fencedTables(db: Db): Promise<FencedTable[]> {\n\tconst tables: FencedTable[] = PORTABLE_TABLES.map((spec) => ({\n\t\ttable: spec.table,\n\t\tchanged: Object.hasOwn(spec.columns, \"updated_at\")\n\t\t\t? \"updated_at\"\n\t\t\t: Object.hasOwn(spec.columns, \"created_at\")\n\t\t\t\t? \"created_at\"\n\t\t\t\t: null,\n\t\tid: Object.hasOwn(spec.columns, \"id\") ? \"id\" : null,\n\t}));\n\ttables.push({ table: \"users\", changed: \"updated_at\", id: \"id\" });\n\tconst collections = await db\n\t\t.selectFrom(\"_emdash_collections\")\n\t\t.select(\"slug\")\n\t\t.orderBy(\"slug\")\n\t\t.execute();\n\tfor (const { slug } of collections) {\n\t\tvalidateIdentifier(slug, \"collection slug\");\n\t\ttables.push({ table: `${CONTENT_TABLE_PREFIX}${slug}`, changed: \"updated_at\", id: \"id\" });\n\t}\n\treturn tables.toSorted((a, b) => (a.table < b.table ? -1 : a.table > b.table ? 1 : 0));\n}\n\nfunction optionalText(value: unknown): string | undefined {\n\tif (typeof value === \"string\") return value;\n\tif (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n\tif (value instanceof Date) return value.toISOString();\n\treturn undefined;\n}\n\nexport async function captureFence(db: Db, writeEpoch: number): Promise<ExportFence> {\n\tconst result: ExportFence = { writeEpoch, tables: [] };\n\tfor (const table of await fencedTables(db)) {\n\t\tconst changed = table.changed ? sql`MAX(${sql.ref(table.changed)})` : sql`NULL`;\n\t\tconst id = table.id ? sql`MAX(${sql.ref(table.id)})` : sql`NULL`;\n\t\tconst row = await sql<{ n: unknown; changed: unknown; id: unknown }>`\n\t\t\tSELECT COUNT(*) AS n, ${changed} AS changed, ${id} AS id FROM ${sql.ref(table.table)}\n\t\t`.execute(db);\n\t\tconst values = row.rows[0];\n\t\tresult.tables.push({\n\t\t\ttable: table.table,\n\t\t\tcount: Number(values?.n ?? 0),\n\t\t\tmaxChanged: optionalText(values?.changed),\n\t\t\tmaxId: optionalText(values?.id),\n\t\t});\n\t}\n\treturn result;\n}\n\nexport function fencesEqual(a: ExportFence, b: ExportFence): boolean {\n\tif (a.writeEpoch !== b.writeEpoch || a.tables.length !== b.tables.length) return false;\n\treturn a.tables.every((table, index) => {\n\t\tconst other = b.tables[index];\n\t\treturn (\n\t\t\tother !== undefined &&\n\t\t\tother.table === table.table &&\n\t\t\tother.count === table.count &&\n\t\t\tother.maxChanged === table.maxChanged &&\n\t\t\tother.maxId === table.maxId\n\t\t);\n\t});\n}\n","/**\n * Media for an export: which rows are exported, their blob digests, and the\n * storage-key index the reference walker needs.\n *\n * A media row is exported when it is `ready`, or when a byline avatar or a\n * section preview references it and its object exists. Its object is hashed\n * once from the origin key; the bytes are never copied into staging.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { createSha256 } from \"../format/digest.js\";\nimport {\n\tbuildMediaKeyIndex,\n\tMEDIA_PLACEHOLDER_PREFIX,\n\ttype MediaKeyIndex,\n} from \"../format/media-refs.js\";\nimport { bytewise } from \"../ops/collation.js\";\n\ntype Db = Kysely<Database>;\n\nconst KEY_INDEX_PAGE = 1000;\n\nexport interface MediaCandidate {\n\tid: string;\n\tstorageKey: string;\n\tstatus: string;\n\tsize: number | null;\n}\n\n/** Media rows eligible for export after `after`, in id order. */\nexport async function listMediaCandidates(\n\tdb: Db,\n\tafter: string | null,\n\tlimit: number,\n): Promise<MediaCandidate[]> {\n\tlet query = db\n\t\t.selectFrom(\"media\")\n\t\t.select([\"id\", \"storage_key\", \"status\", \"size\"])\n\t\t.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"status\", \"=\", \"ready\"),\n\t\t\t\teb(\n\t\t\t\t\t\"id\",\n\t\t\t\t\t\"in\",\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t\t\t\t.select(\"avatar_media_id\")\n\t\t\t\t\t\t.where(\"avatar_media_id\", \"is not\", null)\n\t\t\t\t\t\t.$castTo<string>(),\n\t\t\t\t),\n\t\t\t\teb(\n\t\t\t\t\t\"id\",\n\t\t\t\t\t\"in\",\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_sections\")\n\t\t\t\t\t\t.select(\"preview_media_id\")\n\t\t\t\t\t\t.where(\"preview_media_id\", \"is not\", null)\n\t\t\t\t\t\t.$castTo<string>(),\n\t\t\t\t),\n\t\t\t]),\n\t\t);\n\tif (after !== null) query = query.where(sql<boolean>`${bytewise(db, \"id\")} > ${after}`);\n\tconst rows = await query.orderBy(bytewise(db, \"id\")).limit(limit).execute();\n\treturn rows.map((row) => ({\n\t\tid: row.id,\n\t\tstorageKey: row.storage_key,\n\t\tstatus: row.status,\n\t\tsize: row.size === null ? null : Number(row.size),\n\t}));\n}\n\n/**\n * SHA-256 and size of a stored object, counted from the bytes actually\n * streamed. Returns null when the object does not exist, and `\"too_large\"`\n * (after cancelling the download) as soon as more than `maxBytes` arrive.\n */\nexport async function hashStoredObject(\n\tstorage: Storage,\n\tkey: string,\n\toptions: { maxBytes?: number } = {},\n): Promise<{ sha256: string; bytes: number } | null | \"too_large\"> {\n\tif (!(await storage.exists(key))) return null;\n\tconst download = await storage.download(key);\n\tconst hasher = await createSha256();\n\tconst reader = download.body.getReader();\n\tlet bytes = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbytes += value.byteLength;\n\t\t\tif (options.maxBytes !== undefined && bytes > options.maxBytes) {\n\t\t\t\tawait reader.cancel().catch(() => undefined);\n\t\t\t\treturn \"too_large\";\n\t\t\t}\n\t\t\thasher.update(value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\treturn { sha256: await hasher.digest(), bytes };\n}\n\n/** Every media row's id and storage key, in id order. */\nexport async function loadMediaKeyRows(db: Db): Promise<Array<{ id: string; storageKey: string }>> {\n\tconst rows: Array<{ id: string; storageKey: string }> = [];\n\tlet after: string | null = null;\n\tfor (;;) {\n\t\tlet query = db.selectFrom(\"media\").select([\"id\", \"storage_key\"]);\n\t\tif (after !== null) query = query.where(sql<boolean>`${bytewise(db, \"id\")} > ${after}`);\n\t\tconst page = await query.orderBy(bytewise(db, \"id\")).limit(KEY_INDEX_PAGE).execute();\n\t\tfor (const row of page) rows.push({ id: row.id, storageKey: row.storage_key });\n\t\tconst last = page.at(-1);\n\t\tif (page.length < KEY_INDEX_PAGE || !last) break;\n\t\tafter = last.id;\n\t}\n\treturn rows;\n}\n\n/** Every media row's storage key, for the reference walker and the key scan. */\nexport async function loadMediaKeyIndex(db: Db): Promise<MediaKeyIndex> {\n\treturn buildMediaKeyIndex(await loadMediaKeyRows(db));\n}\n\nconst PLACEHOLDER = new RegExp(`${MEDIA_PLACEHOLDER_PREFIX}([0-9A-Za-z_-]{1,128})`, \"g\");\n\nfunction unlinkValue(\n\tvalue: unknown,\n\tdrop: ReadonlySet<string>,\n\tcounter: { count: number },\n): unknown {\n\tif (typeof value === \"string\") {\n\t\tif (!value.includes(MEDIA_PLACEHOLDER_PREFIX)) return value;\n\t\treturn value.replace(PLACEHOLDER, (match, mediaId: string) => {\n\t\t\tif (!drop.has(mediaId)) return match;\n\t\t\tcounter.count++;\n\t\t\treturn \"\";\n\t\t});\n\t}\n\tif (Array.isArray(value)) return value.map((item) => unlinkValue(item, drop, counter));\n\tif (typeof value === \"object\" && value !== null) {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(value).map(([key, item]) => [key, unlinkValue(item, drop, counter)]),\n\t\t);\n\t}\n\treturn value;\n}\n\n/**\n * Remove placeholders naming media that is not in the package, leaving the\n * rest of each string. Returns the record unchanged when there are none.\n */\nexport function unlinkMediaPlaceholders<T extends { kind: string; id: string }>(\n\trecord: T,\n\tdrop: ReadonlySet<string>,\n): { record: T; count: number } {\n\tif (drop.size === 0) return { record, count: 0 };\n\tconst counter = { count: 0 };\n\tconst next = unlinkValue(record, drop, counter);\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- same record with some placeholder substrings removed\n\treturn counter.count === 0 ? { record, count: 0 } : { record: next as T, count: counter.count };\n}\n","/**\n * Per-kind readers: turn portable rows into strict package records.\n *\n * A reader pages through its kind in package stream order (`id` order, or\n * `(depth, id)` for the tree kinds) and can also fetch rows by id. The\n * exporter uses the paging side against the origin; import verification\n * uses the same readers against the target, so any database works.\n *\n * When paging, rows a package must not contain are left out: rows whose\n * reference (hard or soft) names a row that does not exist, tree rows below\n * such a row, and (for an export) media rows that were not hashed. Optional\n * references to missing rows are removed from the record instead and\n * reported as adjustments. A real database can hold any of these orphans,\n * because not every reference has a foreign key on every dialect and\n * installation. The number of rows a reader leaves out of a kind is\n * `countRows() - exported`. `byIds` never filters.\n */\n\nimport { sql, type Kysely, type RawBuilder } from \"kysely\";\n\nimport { isPostgres, listTableColumns } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { validateIdentifier } from \"../../database/validate.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport { decodeContentRow, decodeRow, selectExportedColumns } from \"../format/column-codec.js\";\nimport {\n\tassertColumnCoverage,\n\tassertLoadedColumnCoverage,\n\tCONTENT_TABLE_PREFIX,\n\tcontentColumnSpecs,\n\tgetPortableTableSpecForKind,\n\ttype ColumnSpec,\n} from \"../format/columns.js\";\nimport {\n\tcompareStreamOrder,\n\tsyntheticId,\n\tisRecordOfKind,\n\tvalidateRecord,\n\ttype RecordKind,\n\ttype SitePackageRecord,\n\ttype RecordOfKind,\n\ttype StreamOrderKey,\n} from \"../format/kinds.js\";\nimport { PORTABLE_SETTING_NAMES } from \"../format/settings.js\";\nimport type { ExportTransformationCode } from \"../format/transformations.js\";\n\ntype Db = Kysely<Database>;\ntype Row = Record<string, unknown>;\n\nexport interface ReadRow<K extends RecordKind> {\n\tkey: StreamOrderKey;\n\t/** `null` when the row is left out of the package. */\n\trecord: RecordOfKind<K> | null;\n\t/** In-record changes made while reading (e.g. a nulled avatar reference). */\n\tadjustments: ReadAdjustment[];\n}\n\nexport interface ReadAdjustment {\n\tcode: ExportTransformationCode;\n\tcount: number;\n}\n\nexport interface ReadPage<K extends RecordKind> {\n\trows: Array<ReadRow<K>>;\n\t/** No rows follow the last row of this page. */\n\tdone: boolean;\n}\n\nexport interface KindReader<K extends RecordKind> {\n\treadonly kind: K;\n\t/** Up to `limit` rows after `after` in stream order. */\n\tpage(after: StreamOrderKey | null, limit: number): Promise<ReadPage<K>>;\n\t/**\n\t * Records by id, without export-only filtering. Missing ids are absent.\n\t * `collections` maps entry ids to the collection each is looked up in;\n\t * an entry id it does not name is looked up in every collection.\n\t */\n\tbyIds(\n\t\tids: readonly string[],\n\t\tcollections?: ReadonlyMap<string, string>,\n\t): Promise<Map<string, RecordOfKind<K>>>;\n\t/** Rows stored for this kind, or null when the kind has no table of its own. */\n\tcountRows(): Promise<number | null>;\n}\n\nexport interface ReaderOptions {\n\t/**\n\t * Export operation whose hashed media (`_emdash_transfer_media_blobs`)\n\t * defines the exported media set. Without it every media row is read and\n\t * no reference is nulled.\n\t */\n\texportOperationId?: string;\n\t/** Blob digest per media id; media records carry it as `blob`. */\n\tmediaBlobs: (mediaIds: readonly string[]) => Promise<ReadonlyMap<string, string>>;\n\t/** Whether comments exist for the principal reader. Defaults to true. */\n\tcomments?: boolean;\n}\n\n// ── SQL helpers ─────────────────────────────────────────────────\n\nfunction bytewiseExpr(db: Db, expr: RawBuilder<unknown>): RawBuilder<string> {\n\treturn isPostgres(db) ? sql<string>`(${expr}) COLLATE \"C\"` : sql<string>`${expr}`;\n}\n\nfunction count(value: unknown): number {\n\treturn Number(value ?? 0);\n}\n\nfunction invalidRecord(kind: RecordKind, id: string, field: string, reason: string): TransferError {\n\treturn new TransferError(\"TRANSFER_EXPORT_ERROR\", \"Stored row does not form a valid record\", {\n\t\tdetail: { kind, id, field, reason },\n\t});\n}\n\nfunction toRecord<K extends RecordKind>(kind: K, raw: Row): RecordOfKind<K> {\n\tconst result = validateRecord(kind, raw);\n\tif (!result.success) {\n\t\tconst issue = result.issues[0];\n\t\tthrow invalidRecord(\n\t\t\tkind,\n\t\t\ttypeof raw.id === \"string\" ? raw.id : \"\",\n\t\t\tissue?.path ?? \"\",\n\t\t\tissue?.message ?? \"invalid\",\n\t\t);\n\t}\n\treturn result.record;\n}\n\nfunction stringOf(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\n/** Rows of `table` whose group (`translation_group`, else `id`) is one of `groups`. */\nasync function existingGroups(\n\tdb: Db,\n\ttable: string,\n\tgroups: readonly string[],\n): Promise<Set<string>> {\n\tconst found = new Set<string>();\n\t// Each value is bound twice.\n\tfor (const batch of chunks([...new Set(groups)], Math.floor(SQL_BATCH_SIZE / 2))) {\n\t\tconst result = await sql<{ id: string; translation_group: string | null }>`\n\t\t\tSELECT id, translation_group FROM ${sql.ref(table)}\n\t\t\tWHERE translation_group IN (${sql.join(batch)})\n\t\t\t\tOR (translation_group IS NULL AND id IN (${sql.join(batch)}))\n\t\t`.execute(db);\n\t\tfor (const row of result.rows) found.add(row.translation_group ?? row.id);\n\t}\n\treturn found;\n}\n\nasync function collectionSlugs(db: Db): Promise<string[]> {\n\tconst rows = await db.selectFrom(\"_emdash_collections\").select(\"slug\").execute();\n\treturn rows.map((row) => row.slug).toSorted();\n}\n\nfunction contentTable(slug: string): string {\n\tvalidateIdentifier(slug, \"collection slug\");\n\treturn `${CONTENT_TABLE_PREFIX}${slug}`;\n}\n\n/**\n * A collection slug as an SQL literal. Filters compare against every\n * collection slug; as bound parameters they exceed D1's 100-parameter limit\n * on sites with many collections.\n */\nfunction slugLiteral(slug: string): RawBuilder<unknown> {\n\tvalidateIdentifier(slug, \"collection slug\");\n\treturn sql.lit(slug);\n}\n\ninterface FilterContext {\n\tdb: Db;\n\toptions: ReaderOptions;\n\t/** Every collection slug, sorted. */\n\tslugs: readonly string[];\n}\n\nconst NEVER = sql<boolean>`1 = 0`;\n\nfunction anyOf(parts: ReadonlyArray<RawBuilder<boolean>>): RawBuilder<boolean> {\n\treturn parts.length === 0 ? NEVER : sql<boolean>`(${sql.join(parts, sql` OR `)})`;\n}\n\n/** An entry with id `id` exists in the content table of collection `collection`. */\nfunction entryExists(\n\tcontext: FilterContext,\n\tcollection: RawBuilder<unknown>,\n\tid: RawBuilder<unknown>,\n): RawBuilder<boolean> {\n\treturn anyOf(\n\t\tcontext.slugs.map(\n\t\t\t(slug) => sql<boolean>`(${collection} = ${slugLiteral(slug)} AND EXISTS (\n\t\t\t\tSELECT 1 FROM ${sql.ref(contentTable(slug))} AS __entry WHERE __entry.id = ${id}\n\t\t\t))`,\n\t\t),\n\t);\n}\n\n/** A row of `table` has translation group (or, without one, id) `group`. */\nfunction groupExists(table: string, group: RawBuilder<unknown>): RawBuilder<boolean> {\n\treturn sql<boolean>`EXISTS (\n\t\tSELECT 1 FROM ${sql.ref(table)} AS __grouped\n\t\tWHERE __grouped.translation_group = ${group}\n\t\t\tOR (__grouped.translation_group IS NULL AND __grouped.id = ${group})\n\t)`;\n}\n\n/** An entry of collection `collection` has translation group `group`. */\nfunction entryGroupExists(\n\tcontext: FilterContext,\n\tcollection: RawBuilder<unknown>,\n\tgroup: RawBuilder<unknown>,\n): RawBuilder<boolean> {\n\treturn anyOf(\n\t\tcontext.slugs.map(\n\t\t\t(slug) =>\n\t\t\t\tsql<boolean>`(${collection} = ${slugLiteral(slug)} AND ${groupExists(contentTable(slug), group)})`,\n\t\t),\n\t);\n}\n\nfunction col(table: string, column: string): RawBuilder<unknown> {\n\treturn sql`${sql.ref(`${table}.${column}`)}`;\n}\n\n/**\n * Ids of `table` reachable from a root (`parentColumn IS NULL`) through rows\n * that each satisfy `valid`: the tree rows an export keeps.\n */\nfunction treeIds(\n\ttable: string,\n\tparentColumn: string,\n\tvalid: RawBuilder<boolean>,\n): RawBuilder<unknown> {\n\treturn sql`(\n\t\tWITH RECURSIVE __kept(__node) AS (\n\t\t\tSELECT ${col(table, \"id\")} FROM ${sql.ref(table)}\n\t\t\tWHERE ${col(table, parentColumn)} IS NULL AND ${valid}\n\t\t\tUNION ALL\n\t\t\tSELECT ${col(table, \"id\")} FROM ${sql.ref(table)}\n\t\t\tINNER JOIN __kept ON ${col(table, parentColumn)} = __kept.__node\n\t\t\tWHERE ${valid}\n\t\t)\n\t\tSELECT __node FROM __kept\n\t)`;\n}\n\nfunction commentValid(context: FilterContext): RawBuilder<boolean> {\n\treturn entryExists(\n\t\tcontext,\n\t\tcol(\"_emdash_comments\", \"collection\"),\n\t\tcol(\"_emdash_comments\", \"content_id\"),\n\t);\n}\n\nfunction revisionValid(context: FilterContext): RawBuilder<boolean> {\n\treturn entryExists(context, col(\"revisions\", \"collection\"), col(\"revisions\", \"entry_id\"));\n}\n\n/** Media ids among `ids` that the export operation hashed. */\nasync function exportedMediaIds(\n\tdb: Db,\n\toperationId: string,\n\tids: readonly string[],\n): Promise<Set<string>> {\n\tconst found = new Set<string>();\n\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\tconst rows = await db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select(\"media_id\")\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"media_id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of rows) found.add(row.media_id);\n\t}\n\treturn found;\n}\n\n// ── Table readers ───────────────────────────────────────────────\n\ninterface TransformContext {\n\tdb: Db;\n\toptions: ReaderOptions;\n\t/** True when reading pages for an export (not `byIds`). */\n\tpaging: boolean;\n}\n\ninterface TransformResult<K extends RecordKind = RecordKind> {\n\trecords: Array<RecordOfKind<K> | null>;\n\t/** Per record, parallel to `records`; absent when nothing was adjusted. */\n\tadjustments?: Array<ReadAdjustment[]>;\n}\n\ntype Transform = (\n\trecords: SitePackageRecord[],\n\tcontext: TransformContext,\n) => Promise<TransformResult>;\n\n/** Adapt a transform written for one kind to the reader's record list. */\nfunction forKind<K extends RecordKind>(\n\tkind: K,\n\ttransform: (\n\t\trecords: Array<RecordOfKind<K>>,\n\t\tcontext: TransformContext,\n\t) => Promise<TransformResult<K>>,\n): Transform {\n\treturn (records, context) => {\n\t\tconst typed = records.filter((record): record is RecordOfKind<K> =>\n\t\t\tisRecordOfKind(record, kind),\n\t\t);\n\t\tif (typed.length !== records.length) throw new Error(`Expected only ${kind} records`);\n\t\treturn transform(typed, context);\n\t};\n}\n\ninterface TableReaderConfig {\n\tkind: RecordKind;\n\ttable: string;\n\t/** Key expression; defaults to the `id` column. */\n\tkey?: (db: Db) => RawBuilder<unknown>;\n\t/** Rows kept when paging. */\n\tfilter?: (context: FilterContext) => RawBuilder<boolean> | null;\n\t/** Rows `countRows` counts (defaults to every row). */\n\tcountFilter?: () => RawBuilder<boolean>;\n\t/** Tree kinds: parent column; pages are ordered by `(depth, id)`. */\n\tparentColumn?: string;\n\t/** Tree kinds: rows kept when paging; a row below a dropped row is dropped too. */\n\ttreeValid?: (context: FilterContext) => RawBuilder<boolean>;\n\t/** Adds properties that do not come from columns, before validation. */\n\tprepare?: (raws: Row[], options: ReaderOptions) => Promise<void>;\n\t/** Post-processing of decoded records (may drop rows or change properties). */\n\ttransform?: Transform;\n}\n\nclass TableReader implements KindReader<RecordKind> {\n\treadonly kind: RecordKind;\n\treadonly #db: Db;\n\treadonly #config: TableReaderConfig;\n\treadonly #options: ReaderOptions;\n\treadonly #columns: Readonly<Record<string, ColumnSpec>>;\n\t#covered = false;\n\t#slugs: readonly string[] = [];\n\n\tconstructor(db: Db, config: TableReaderConfig, options: ReaderOptions) {\n\t\tconst spec = getPortableTableSpecForKind(config.kind);\n\t\tif (!spec) throw new Error(`No table for kind ${config.kind}`);\n\t\tthis.kind = config.kind;\n\t\tthis.#db = db;\n\t\tthis.#config = config;\n\t\tthis.#options = options;\n\t\tthis.#columns = spec.columns;\n\t}\n\n\tprivate async ensureCoverage(): Promise<void> {\n\t\tif (this.#covered) return;\n\t\tawait assertColumnCoverage(this.#db, this.#config.table);\n\t\tthis.#slugs = await collectionSlugs(this.#db);\n\t\tthis.#covered = true;\n\t}\n\n\tprivate keyExpr(): RawBuilder<unknown> {\n\t\treturn this.#config.key?.(this.#db) ?? sql`${sql.ref(`${this.#config.table}.id`)}`;\n\t}\n\n\tprivate selectList(): RawBuilder<unknown> {\n\t\treturn sql.join(selectExportedColumns(this.#db, this.#columns));\n\t}\n\n\tprivate decodeRaw(row: Row): Row {\n\t\tconst properties = decodeRow(this.#db, this.#columns, row);\n\t\tconst raw: Row = { kind: this.kind, ...properties };\n\t\tif (\n\t\t\tthis.kind === \"content_term\" ||\n\t\t\tthis.kind === \"seo\" ||\n\t\t\tthis.kind === \"byline_field_value\" ||\n\t\t\tthis.kind === \"byline_field_group_value\"\n\t\t) {\n\t\t\traw.id = syntheticId(toSyntheticParts(this.kind, raw));\n\t\t}\n\t\treturn raw;\n\t}\n\n\tprivate async decode(rows: Row[]): Promise<Array<SitePackageRecord>> {\n\t\tconst raws = rows.map((row) => this.decodeRaw(row));\n\t\tawait this.#config.prepare?.(raws, this.#options);\n\t\treturn raws.map((raw) => toRecord(this.kind, raw));\n\t}\n\n\tprivate async finish(\n\t\trecords: Array<SitePackageRecord>,\n\t\tpaging: boolean,\n\t): Promise<TransformResult> {\n\t\tif (!this.#config.transform) return { records };\n\t\treturn this.#config.transform(records, { db: this.#db, options: this.#options, paging });\n\t}\n\n\tasync page(after: StreamOrderKey | null, limit: number): Promise<ReadPage<RecordKind>> {\n\t\tawait this.ensureCoverage();\n\t\tconst db = this.#db;\n\t\tconst table = sql.ref(this.#config.table);\n\t\tconst context: FilterContext = { db, options: this.#options, slugs: this.#slugs };\n\t\tconst filter = this.#config.filter?.(context) ?? null;\n\t\tconst conditions: Array<RawBuilder<unknown>> = [];\n\t\tif (filter) conditions.push(filter);\n\n\t\tlet result: { rows: Row[] };\n\t\tif (this.#config.parentColumn) {\n\t\t\tconst parent = sql.ref(`${this.#config.table}.${this.#config.parentColumn}`);\n\t\t\tconst idRef = sql.ref(`${this.#config.table}.id`);\n\t\t\tconst valid = this.#config.treeValid?.(context) ?? sql<boolean>`1 = 1`;\n\t\t\tif (after) {\n\t\t\t\tconst depth = after.depth ?? 0;\n\t\t\t\tconditions.push(\n\t\t\t\t\tsql`(__tree.__level > ${depth} OR (__tree.__level = ${depth} AND ${bytewiseExpr(db, idRef)} > ${after.id}))`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst where = conditions.length > 0 ? sql`WHERE ${sql.join(conditions, sql` AND `)}` : sql``;\n\t\t\tresult = await sql<Row>`\n\t\t\t\tWITH RECURSIVE __tree(__node, __level) AS (\n\t\t\t\t\tSELECT ${idRef}, 0 FROM ${table} WHERE ${parent} IS NULL AND ${valid}\n\t\t\t\t\tUNION ALL\n\t\t\t\t\tSELECT ${idRef}, __tree.__level + 1 FROM ${table}\n\t\t\t\t\tINNER JOIN __tree ON ${parent} = __tree.__node\n\t\t\t\t\tWHERE ${valid}\n\t\t\t\t)\n\t\t\t\tSELECT ${this.selectList()}, __tree.__level AS __depth\n\t\t\t\tFROM ${table} INNER JOIN __tree ON __tree.__node = ${idRef}\n\t\t\t\t${where}\n\t\t\t\tORDER BY __tree.__level, ${bytewiseExpr(db, idRef)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t} else {\n\t\t\tconst key = this.keyExpr();\n\t\t\tif (after) conditions.push(sql`${bytewiseExpr(db, key)} > ${after.id}`);\n\t\t\tconst where = conditions.length > 0 ? sql`WHERE ${sql.join(conditions, sql` AND `)}` : sql``;\n\t\t\tresult = await sql<Row>`\n\t\t\t\tSELECT ${this.selectList()}\n\t\t\t\tFROM ${table}\n\t\t\t\t${where}\n\t\t\t\tORDER BY ${bytewiseExpr(db, key)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t}\n\n\t\tconst done = result.rows.length <= limit;\n\t\tconst rows = result.rows.slice(0, limit);\n\t\tconst records = await this.decode(rows);\n\t\tconst keys = rows.map((row, index) => {\n\t\t\tconst id = records[index]?.id ?? \"\";\n\t\t\treturn this.#config.parentColumn ? { id, depth: count(row.__depth) } : { id };\n\t\t});\n\t\tconst transformed = await this.finish(records, true);\n\t\treturn {\n\t\t\trows: keys.map((key, index) => ({\n\t\t\t\tkey,\n\t\t\t\trecord: transformed.records[index] ?? null,\n\t\t\t\tadjustments: transformed.adjustments?.[index] ?? [],\n\t\t\t})),\n\t\t\tdone,\n\t\t};\n\t}\n\n\tasync byIds(ids: readonly string[]): Promise<Map<string, SitePackageRecord>> {\n\t\tawait this.ensureCoverage();\n\t\tconst db = this.#db;\n\t\tconst result = new Map<string, SitePackageRecord>();\n\t\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await sql<Row>`\n\t\t\t\tSELECT ${this.selectList()}\n\t\t\t\tFROM ${sql.ref(this.#config.table)}\n\t\t\t\tWHERE ${this.keyExpr()} IN (${sql.join(batch)})\n\t\t\t`.execute(db);\n\t\t\tconst records = await this.decode(rows.rows);\n\t\t\tconst transformed = await this.finish(records, false);\n\t\t\tfor (const record of transformed.records) {\n\t\t\t\tif (record) result.set(record.id, record);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync countRows(): Promise<number> {\n\t\tconst filter = this.#config.countFilter?.() ?? null;\n\t\tconst where = filter ? sql`WHERE ${filter}` : sql``;\n\t\tconst result = await sql<{ n: unknown }>`\n\t\t\tSELECT COUNT(*) AS n FROM ${sql.ref(this.#config.table)} ${where}\n\t\t`.execute(this.#db);\n\t\treturn count(result.rows[0]?.n);\n\t}\n}\n\nfunction toSyntheticParts(kind: RecordKind, raw: Row): Parameters<typeof syntheticId>[0] {\n\tconst part = (name: string) => stringOf(raw[name]) ?? \"\";\n\tswitch (kind) {\n\t\tcase \"content_term\":\n\t\t\treturn {\n\t\t\t\tkind,\n\t\t\t\tcollection: part(\"collection\"),\n\t\t\t\tentryGroup: part(\"entryGroup\"),\n\t\t\t\ttermGroup: part(\"termGroup\"),\n\t\t\t};\n\t\tcase \"seo\":\n\t\t\treturn { kind, collection: part(\"collection\"), entryId: part(\"entryId\") };\n\t\tcase \"byline_field_value\":\n\t\t\treturn { kind, bylineId: part(\"bylineId\"), fieldId: part(\"fieldId\") };\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tkind: \"byline_field_group_value\",\n\t\t\t\tbylineGroup: part(\"bylineGroup\"),\n\t\t\t\tfieldId: part(\"fieldId\"),\n\t\t\t};\n\t}\n}\n\nfunction concatKey(...parts: string[]): (db: Db) => RawBuilder<unknown> {\n\treturn () =>\n\t\tsql.join(\n\t\t\tparts.flatMap((part, index) =>\n\t\t\t\tindex === 0 ? [sql.ref(part)] : [sql.lit(\":\"), sql.ref(part)],\n\t\t\t),\n\t\t\tsql` || `,\n\t\t);\n}\n\n// ── Transforms ──────────────────────────────────────────────────\n\nasync function nullUnexportedMedia<K extends \"byline\" | \"section\">(\n\trecords: Array<RecordOfKind<K>>,\n\tcontext: TransformContext,\n\tproperty: \"avatarMediaId\" | \"previewMediaId\",\n): Promise<TransformResult<K>> {\n\tconst operationId = context.options.exportOperationId;\n\tif (!operationId || !context.paging) return { records };\n\tconst ids = records.flatMap((record) => {\n\t\tconst value: unknown = Reflect.get(record, property);\n\t\treturn typeof value === \"string\" ? [value] : [];\n\t});\n\tif (ids.length === 0) return { records };\n\tconst exported = await exportedMediaIds(context.db, operationId, ids);\n\tconst adjustments: Array<ReadAdjustment[]> = [];\n\tconst next = records.map((record) => {\n\t\tconst value: unknown = Reflect.get(record, property);\n\t\tif (typeof value !== \"string\" || exported.has(value)) {\n\t\t\tadjustments.push([]);\n\t\t\treturn record;\n\t\t}\n\t\tadjustments.push([{ code: \"avatar_nulled\", count: 1 }]);\n\t\tconst copy = { ...record };\n\t\tReflect.deleteProperty(copy, property);\n\t\treturn copy;\n\t});\n\treturn { records: next, adjustments };\n}\n\nasync function nullMissingFolders(\n\trecords: Array<RecordOfKind<\"media\">>,\n\tcontext: TransformContext,\n): Promise<TransformResult<\"media\">> {\n\tif (!context.paging) return { records };\n\tconst ids = [...new Set(records.flatMap((r) => (r.folderId === undefined ? [] : [r.folderId])))];\n\tif (ids.length === 0) return { records };\n\tconst found = new Set<string>();\n\tfor (const batch of chunks(ids, SQL_BATCH_SIZE)) {\n\t\tconst rows = await context.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of rows) found.add(row.id);\n\t}\n\tconst adjustments: Array<ReadAdjustment[]> = [];\n\tconst next = records.map((record) => {\n\t\tif (record.folderId === undefined || found.has(record.folderId)) {\n\t\t\tadjustments.push([]);\n\t\t\treturn record;\n\t\t}\n\t\tadjustments.push([{ code: \"orphan_reference_nulled\", count: 1 }]);\n\t\tconst { folderId: _missing, ...rest } = record;\n\t\treturn rest;\n\t});\n\treturn { records: next, adjustments };\n}\n\nasync function filterTaxonomyCollections(\n\trecords: Array<RecordOfKind<\"taxonomy_def\">>,\n\tcontext: TransformContext,\n): Promise<TransformResult<\"taxonomy_def\">> {\n\tif (!context.paging) return { records };\n\tconst slugs = new Set(await collectionSlugs(context.db));\n\tconst adjustments: Array<ReadAdjustment[]> = [];\n\tconst next = records.map((record) => {\n\t\tconst kept = record.collections?.filter((slug) => slugs.has(slug));\n\t\tif (!record.collections || !kept || kept.length === record.collections.length) {\n\t\t\tadjustments.push([]);\n\t\t\treturn record;\n\t\t}\n\t\tadjustments.push([\n\t\t\t{ code: \"soft_orphan_dropped\", count: record.collections.length - kept.length },\n\t\t]);\n\t\treturn { ...record, collections: kept };\n\t});\n\treturn { records: next, adjustments };\n}\n\nasync function attachBlobs(raws: Row[], options: ReaderOptions): Promise<void> {\n\tconst ids = raws.flatMap((raw) => (typeof raw.id === \"string\" ? [raw.id] : []));\n\tif (ids.length === 0) return;\n\tconst blobs = await options.mediaBlobs(ids);\n\tfor (const raw of raws) {\n\t\tconst blob = typeof raw.id === \"string\" ? blobs.get(raw.id) : undefined;\n\t\tif (blob !== undefined) raw.blob = blob;\n\t}\n}\n\n// ── Reader table ────────────────────────────────────────────────\n\nconst PORTABLE_SETTINGS_FILTER = (): RawBuilder<boolean> =>\n\tsql<boolean>`${sql.ref(\"options.name\")} IN (${sql.join(PORTABLE_SETTING_NAMES.map((name) => sql.lit(name)))})`;\n\nconst REDIRECT_FILTER = (): RawBuilder<boolean> => sql<boolean>`(\n\t_emdash_redirects.source_guard = 1\n\tOR (\n\t\tNOT EXISTS (\n\t\t\tSELECT 1 FROM _emdash_redirects AS guarded\n\t\t\tWHERE guarded.source = _emdash_redirects.source AND guarded.source_guard = 1\n\t\t)\n\t\tAND _emdash_redirects.id = (\n\t\t\tSELECT MIN(first.id) FROM _emdash_redirects AS first\n\t\t\tWHERE first.source = _emdash_redirects.source\n\t\t)\n\t)\n)`;\n\nconst COLLECTION_SLUGS = sql`(SELECT slug FROM _emdash_collections)`;\n\nfunction tableConfig(kind: RecordKind): TableReaderConfig {\n\tconst spec = getPortableTableSpecForKind(kind);\n\tif (!spec) throw new Error(`No table for kind ${kind}`);\n\treturn { kind, table: spec.table };\n}\n\nfunction configFor(kind: RecordKind): TableReaderConfig {\n\tswitch (kind) {\n\t\tcase \"block_type_version\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: () =>\n\t\t\t\t\tsql<boolean>`_emdash_block_type_versions.block_type_id IN (SELECT id FROM _emdash_block_types)`,\n\t\t\t};\n\t\tcase \"field\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: () =>\n\t\t\t\t\tsql<boolean>`_emdash_fields.collection_id IN (SELECT id FROM _emdash_collections)`,\n\t\t\t};\n\t\tcase \"taxonomy_def\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\ttransform: forKind(\"taxonomy_def\", filterTaxonomyCollections),\n\t\t\t};\n\t\tcase \"relation\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t_emdash_relations.parent_collection IN ${COLLECTION_SLUGS}\n\t\t\t\t\tAND _emdash_relations.child_collection IN ${COLLECTION_SLUGS}\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"media\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"media\"),\n\t\t\t\tfilter: ({ options }) =>\n\t\t\t\t\toptions.exportOperationId === undefined\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: sql<boolean>`media.id IN (\n\t\t\t\t\t\t\tSELECT media_id FROM _emdash_transfer_media_blobs\n\t\t\t\t\t\t\tWHERE operation_id = ${options.exportOperationId}\n\t\t\t\t\t\t)`,\n\t\t\t\tprepare: attachBlobs,\n\t\t\t\ttransform: forKind(\"media\", nullMissingFolders),\n\t\t\t};\n\t\tcase \"term\":\n\t\t\treturn { ...tableConfig(\"term\"), parentColumn: \"parent_id\" };\n\t\tcase \"comment\":\n\t\t\treturn { ...tableConfig(\"comment\"), parentColumn: \"parent_id\", treeValid: commentValid };\n\t\tcase \"comment_reaction\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: (context) =>\n\t\t\t\t\tsql<boolean>`_emdash_comment_reactions.comment_id IN ${treeIds(\n\t\t\t\t\t\t\"_emdash_comments\",\n\t\t\t\t\t\t\"parent_id\",\n\t\t\t\t\t\tcommentValid(context),\n\t\t\t\t\t)}`,\n\t\t\t};\n\t\tcase \"menu_item\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"menu_item\"),\n\t\t\t\tparentColumn: \"parent_id\",\n\t\t\t\ttreeValid: (context) => {\n\t\t\t\t\tconst reference = col(\"_emdash_menu_items\", \"reference_id\");\n\t\t\t\t\treturn sql<boolean>`(\n\t\t\t\t\t\t_emdash_menu_items.menu_id IN (SELECT id FROM _emdash_menus)\n\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\t${reference} IS NULL\n\t\t\t\t\t\t\tOR ${groupExists(\"taxonomies\", reference)}\n\t\t\t\t\t\t\tOR ${anyOf(context.slugs.map((slug) => groupExists(contentTable(slug), reference)))}\n\t\t\t\t\t\t)\n\t\t\t\t\t)`;\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"byline\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"byline\"),\n\t\t\t\ttransform: forKind(\"byline\", (records, context) =>\n\t\t\t\t\tnullUnexportedMedia(records, context, \"avatarMediaId\"),\n\t\t\t\t),\n\t\t\t};\n\t\tcase \"section\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"section\"),\n\t\t\t\ttransform: forKind(\"section\", (records, context) =>\n\t\t\t\t\tnullUnexportedMedia(records, context, \"previewMediaId\"),\n\t\t\t\t),\n\t\t\t};\n\t\tcase \"byline_field_value\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: concatKey(\"byline_id\", \"field_id\"),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t_emdash_byline_field_values.byline_id IN (SELECT id FROM _emdash_bylines)\n\t\t\t\t\tAND _emdash_byline_field_values.field_id IN (SELECT id FROM _emdash_byline_fields)\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"byline_field_group_value\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: concatKey(\"translation_group\", \"field_id\"),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t${groupExists(\"_emdash_bylines\", col(\"_emdash_byline_field_group_values\", \"translation_group\"))}\n\t\t\t\t\tAND _emdash_byline_field_group_values.field_id IN (SELECT id FROM _emdash_byline_fields)\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"revision\":\n\t\t\treturn { ...tableConfig(kind), filter: revisionValid };\n\t\tcase \"content_term\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"content_term\"),\n\t\t\t\tkey: concatKey(\"collection\", \"entry_id\", \"taxonomy_id\"),\n\t\t\t\tfilter: (context) => sql<boolean>`(\n\t\t\t\t\t${entryGroupExists(context, col(\"content_taxonomies\", \"collection\"), col(\"content_taxonomies\", \"entry_id\"))}\n\t\t\t\t\tAND ${groupExists(\"taxonomies\", col(\"content_taxonomies\", \"taxonomy_id\"))}\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"content_byline\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: (context) => sql<boolean>`(\n\t\t\t\t\t${entryExists(context, col(\"_emdash_content_bylines\", \"collection_slug\"), col(\"_emdash_content_bylines\", \"content_id\"))}\n\t\t\t\t\tAND ${groupExists(\"_emdash_bylines\", col(\"_emdash_content_bylines\", \"byline_id\"))}\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"content_reference\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"content_reference\"),\n\t\t\t\tfilter: (context) => {\n\t\t\t\t\tconst references = \"_emdash_content_references\";\n\t\t\t\t\treturn sql<boolean>`EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM _emdash_relations AS __relation\n\t\t\t\t\t\tWHERE (\n\t\t\t\t\t\t\t__relation.translation_group = ${col(references, \"relation_group\")}\n\t\t\t\t\t\t\tOR (__relation.translation_group IS NULL AND __relation.id = ${col(references, \"relation_group\")})\n\t\t\t\t\t\t)\n\t\t\t\t\t\tAND ${entryGroupExists(context, sql`__relation.parent_collection`, col(references, \"parent_group\"))}\n\t\t\t\t\t\tAND ${entryGroupExists(context, sql`__relation.child_collection`, col(references, \"child_group\"))}\n\t\t\t\t\t)`;\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"seo\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: concatKey(\"collection\", \"content_id\"),\n\t\t\t\tfilter: (context) =>\n\t\t\t\t\tentryExists(context, col(\"_emdash_seo\", \"collection\"), col(\"_emdash_seo\", \"content_id\")),\n\t\t\t};\n\t\tcase \"widget\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"widget\"),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t_emdash_widgets.area_id IN (SELECT id FROM _emdash_widget_areas)\n\t\t\t\t\tAND (\n\t\t\t\t\t\t_emdash_widgets.menu_name IS NULL\n\t\t\t\t\t\tOR _emdash_widgets.menu_name IN (SELECT name FROM _emdash_menus)\n\t\t\t\t\t)\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"redirect\":\n\t\t\treturn { ...tableConfig(kind), filter: REDIRECT_FILTER };\n\t\tcase \"setting\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: () => sql`${sql.ref(\"options.name\")}`,\n\t\t\t\tfilter: PORTABLE_SETTINGS_FILTER,\n\t\t\t\tcountFilter: PORTABLE_SETTINGS_FILTER,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn tableConfig(kind);\n\t}\n}\n\n// ── Entries ─────────────────────────────────────────────────────\n\ninterface ContentCollection {\n\tslug: string;\n\ttable: string;\n\tcolumns: Readonly<Record<string, ColumnSpec>>;\n}\n\ntype FieldColumns = ReadonlyArray<{ slug: string; column_type: string }>;\n\nclass EntryReader implements KindReader<\"entry\"> {\n\treadonly kind = \"entry\";\n\treadonly #db: Db;\n\t#fields: Promise<ReadonlyMap<string, FieldColumns>> | null = null;\n\treadonly #collections = new Map<string, Promise<ContentCollection>>();\n\n\tconstructor(db: Db) {\n\t\tthis.#db = db;\n\t}\n\n\t/** Registered fields of every collection, by collection slug, in one query. */\n\tprivate fields(): Promise<ReadonlyMap<string, FieldColumns>> {\n\t\tthis.#fields ??= this.#db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.leftJoin(\"_emdash_fields\", \"_emdash_fields.collection_id\", \"_emdash_collections.id\")\n\t\t\t.select([\n\t\t\t\t\"_emdash_collections.slug as collection\",\n\t\t\t\t\"_emdash_fields.slug as slug\",\n\t\t\t\t\"_emdash_fields.column_type as column_type\",\n\t\t\t])\n\t\t\t.execute()\n\t\t\t.then((rows) => {\n\t\t\t\tconst fields = new Map<string, Array<{ slug: string; column_type: string }>>();\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\tconst list = fields.get(row.collection) ?? [];\n\t\t\t\t\tif (row.slug !== null && row.column_type !== null) {\n\t\t\t\t\t\tlist.push({ slug: row.slug, column_type: row.column_type });\n\t\t\t\t\t}\n\t\t\t\t\tfields.set(row.collection, list);\n\t\t\t\t}\n\t\t\t\treturn fields;\n\t\t\t});\n\t\treturn this.#fields;\n\t}\n\n\tprivate async slugs(): Promise<string[]> {\n\t\treturn [...(await this.fields()).keys()].toSorted();\n\t}\n\n\t/** A collection's table and column specs, loaded once and checked for coverage. */\n\tprivate collection(slug: string): Promise<ContentCollection> {\n\t\tlet pending = this.#collections.get(slug);\n\t\tif (!pending) {\n\t\t\tpending = (async () => {\n\t\t\t\tconst table = contentTable(slug);\n\t\t\t\tconst fields = (await this.fields()).get(slug) ?? [];\n\t\t\t\tconst tableColumns = await listTableColumns(this.#db, table);\n\t\t\t\tconst columns = contentColumnSpecs(fields, tableColumns);\n\t\t\t\tassertLoadedColumnCoverage(table, columns, tableColumns);\n\t\t\t\treturn { slug, table, columns };\n\t\t\t})();\n\t\t\tthis.#collections.set(slug, pending);\n\t\t}\n\t\treturn pending;\n\t}\n\n\tprivate async collections(): Promise<ContentCollection[]> {\n\t\tconst result = [];\n\t\tfor (const slug of await this.slugs()) result.push(await this.collection(slug));\n\t\treturn result;\n\t}\n\n\tprivate decode(collection: ContentCollection, row: Row): RecordOfKind<\"entry\"> {\n\t\tconst { properties, fields } = decodeContentRow(this.#db, collection.columns, row);\n\t\treturn toRecord(\"entry\", {\n\t\t\tkind: \"entry\",\n\t\t\tcollection: collection.slug,\n\t\t\t...properties,\n\t\t\tfields,\n\t\t});\n\t}\n\n\tprivate selectList(collection: ContentCollection): RawBuilder<unknown> {\n\t\treturn sql.join(selectExportedColumns(this.#db, collection.columns));\n\t}\n\n\tasync page(after: StreamOrderKey | null, limit: number): Promise<ReadPage<\"entry\">> {\n\t\tconst db = this.#db;\n\t\tconst merged: Array<RecordOfKind<\"entry\">> = [];\n\t\tfor (const collection of await this.collections()) {\n\t\t\tconst idRef = sql.ref(`${collection.table}.id`);\n\t\t\tconst where = after ? sql`WHERE ${bytewiseExpr(db, idRef)} > ${after.id}` : sql``;\n\t\t\tconst result = await sql<Row>`\n\t\t\t\tSELECT ${this.selectList(collection)}\n\t\t\t\tFROM ${sql.ref(collection.table)}\n\t\t\t\t${where}\n\t\t\t\tORDER BY ${bytewiseExpr(db, idRef)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t\tfor (const row of result.rows) merged.push(this.decode(collection, row));\n\t\t}\n\t\tmerged.sort((a, b) => compareStreamOrder(\"entry\", a, b));\n\t\tconst page = merged.slice(0, limit);\n\t\tconst nulled = await this.nullMissingReferences(page);\n\t\treturn {\n\t\t\trows: nulled.map(({ record, adjustments }) => ({\n\t\t\t\tkey: { id: record.id },\n\t\t\t\trecord,\n\t\t\t\tadjustments,\n\t\t\t})),\n\t\t\tdone: merged.length <= limit,\n\t\t};\n\t}\n\n\t/**\n\t * Remove revision pointers to revisions an export leaves out and primary\n\t * bylines that do not exist, keeping the entry.\n\t */\n\tprivate async nullMissingReferences(\n\t\trecords: Array<RecordOfKind<\"entry\">>,\n\t): Promise<Array<{ record: RecordOfKind<\"entry\">; adjustments: ReadAdjustment[] }>> {\n\t\tconst db = this.#db;\n\t\tconst revisionIds = [\n\t\t\t...new Set(\n\t\t\t\trecords.flatMap((record) =>\n\t\t\t\t\t[record.liveRevisionId, record.draftRevisionId].filter(\n\t\t\t\t\t\t(id): id is string => id !== undefined,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t];\n\t\tconst revisions = new Set<string>();\n\t\tconst context: FilterContext = {\n\t\t\tdb,\n\t\t\toptions: { mediaBlobs: async () => new Map() },\n\t\t\tslugs: await this.slugs(),\n\t\t};\n\t\tfor (const batch of chunks(revisionIds, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await sql<{ id: string }>`\n\t\t\t\tSELECT id FROM revisions\n\t\t\t\tWHERE id IN (${sql.join(batch)}) AND ${revisionValid(context)}\n\t\t\t`.execute(db);\n\t\t\tfor (const row of rows.rows) revisions.add(row.id);\n\t\t}\n\t\tconst bylineGroups = await existingGroups(\n\t\t\tdb,\n\t\t\t\"_emdash_bylines\",\n\t\t\trecords.flatMap((record) =>\n\t\t\t\trecord.primaryBylineGroup === undefined ? [] : [record.primaryBylineGroup],\n\t\t\t),\n\t\t);\n\t\treturn records.map((record) => {\n\t\t\tconst next: Record<string, unknown> = { ...record };\n\t\t\tlet nulled = 0;\n\t\t\tfor (const property of [\"liveRevisionId\", \"draftRevisionId\"] as const) {\n\t\t\t\tconst id = record[property];\n\t\t\t\tif (id !== undefined && !revisions.has(id)) {\n\t\t\t\t\tdelete next[property];\n\t\t\t\t\tnulled++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (record.primaryBylineGroup !== undefined && !bylineGroups.has(record.primaryBylineGroup)) {\n\t\t\t\tdelete next.primaryBylineGroup;\n\t\t\t\tnulled++;\n\t\t\t}\n\t\t\tif (nulled === 0) return { record, adjustments: [] };\n\t\t\treturn {\n\t\t\t\trecord: toRecord(\"entry\", next),\n\t\t\t\tadjustments: [{ code: \"orphan_reference_nulled\", count: nulled }],\n\t\t\t};\n\t\t});\n\t}\n\n\tasync byIds(\n\t\tids: readonly string[],\n\t\tcollections?: ReadonlyMap<string, string>,\n\t): Promise<Map<string, RecordOfKind<\"entry\">>> {\n\t\tconst slugs = new Set(await this.slugs());\n\t\tconst bySlug = new Map<string, string[]>();\n\t\tconst anywhere: string[] = [];\n\t\tfor (const id of new Set(ids)) {\n\t\t\tconst slug = collections?.get(id);\n\t\t\tif (slug === undefined) {\n\t\t\t\tanywhere.push(id);\n\t\t\t} else if (slugs.has(slug)) {\n\t\t\t\tconst list = bySlug.get(slug) ?? [];\n\t\t\t\tlist.push(id);\n\t\t\t\tbySlug.set(slug, list);\n\t\t\t}\n\t\t}\n\t\tif (anywhere.length > 0) {\n\t\t\tfor (const slug of slugs) bySlug.set(slug, [...(bySlug.get(slug) ?? []), ...anywhere]);\n\t\t}\n\n\t\tconst result = new Map<string, RecordOfKind<\"entry\">>();\n\t\tfor (const [slug, slugIds] of bySlug) {\n\t\t\tconst collection = await this.collection(slug);\n\t\t\tfor (const batch of chunks(slugIds, SQL_BATCH_SIZE)) {\n\t\t\t\tconst rows = await sql<Row>`\n\t\t\t\t\tSELECT ${this.selectList(collection)}\n\t\t\t\t\tFROM ${sql.ref(collection.table)}\n\t\t\t\t\tWHERE ${sql.ref(`${collection.table}.id`)} IN (${sql.join(batch)})\n\t\t\t\t`.execute(this.#db);\n\t\t\t\tfor (const row of rows.rows) {\n\t\t\t\t\tconst record = this.decode(collection, row);\n\t\t\t\t\tresult.set(record.id, record);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync countRows(): Promise<number> {\n\t\tlet total = 0;\n\t\tfor (const collection of await this.collections()) {\n\t\t\tconst result = await sql<{ n: unknown }>`\n\t\t\t\tSELECT COUNT(*) AS n FROM ${sql.ref(collection.table)}\n\t\t\t`.execute(this.#db);\n\t\t\ttotal += count(result.rows[0]?.n);\n\t\t}\n\t\treturn total;\n\t}\n}\n\n// ── Principals ──────────────────────────────────────────────────\n\ninterface PrincipalSource {\n\ttable: string;\n\tcolumn: string;\n\tfilter?: RawBuilder<boolean>;\n}\n\n/**\n * Principals are the origin users referenced by exported rows. Nothing but\n * the id, name, and email of a user ever leaves the `users` table.\n */\nclass PrincipalReader implements KindReader<\"principal\"> {\n\treadonly kind = \"principal\";\n\treadonly #db: Db;\n\treadonly #options: ReaderOptions;\n\n\tconstructor(db: Db, options: ReaderOptions) {\n\t\tthis.#db = db;\n\t\tthis.#options = options;\n\t}\n\n\tprivate async sources(): Promise<PrincipalSource[]> {\n\t\tconst sources: PrincipalSource[] = [];\n\t\tconst slugs = await collectionSlugs(this.#db);\n\t\tconst context: FilterContext = { db: this.#db, options: this.#options, slugs };\n\t\tfor (const slug of slugs) {\n\t\t\tsources.push({ table: contentTable(slug), column: \"author_id\" });\n\t\t}\n\t\tsources.push({ table: \"revisions\", column: \"author_id\", filter: revisionValid(context) });\n\t\tconst operationId = this.#options.exportOperationId;\n\t\tsources.push({\n\t\t\ttable: \"media\",\n\t\t\tcolumn: \"author_id\",\n\t\t\tfilter:\n\t\t\t\toperationId === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: sql<boolean>`media.id IN (\n\t\t\t\t\t\tSELECT media_id FROM _emdash_transfer_media_blobs WHERE operation_id = ${operationId}\n\t\t\t\t\t)`,\n\t\t});\n\t\tsources.push({ table: \"_emdash_bylines\", column: \"user_id\" });\n\t\tif (this.#options.comments ?? true) {\n\t\t\tsources.push({\n\t\t\t\ttable: \"_emdash_comments\",\n\t\t\t\tcolumn: \"author_user_id\",\n\t\t\t\tfilter: sql<boolean>`_emdash_comments.id IN ${treeIds(\n\t\t\t\t\t\"_emdash_comments\",\n\t\t\t\t\t\"parent_id\",\n\t\t\t\t\tcommentValid(context),\n\t\t\t\t)}`,\n\t\t\t});\n\t\t}\n\t\treturn sources;\n\t}\n\n\tasync page(after: StreamOrderKey | null, limit: number): Promise<ReadPage<\"principal\">> {\n\t\tconst db = this.#db;\n\t\tconst ids = new Set<string>();\n\t\tfor (const source of await this.sources()) {\n\t\t\tconst column = sql.ref(`${source.table}.${source.column}`);\n\t\t\tconst conditions: Array<RawBuilder<unknown>> = [sql`${column} IS NOT NULL`];\n\t\t\tif (after) conditions.push(sql`${bytewiseExpr(db, column)} > ${after.id}`);\n\t\t\tif (source.filter) conditions.push(source.filter);\n\t\t\tconst result = await sql<{ id: string }>`\n\t\t\t\tSELECT ${column} AS id FROM ${sql.ref(source.table)}\n\t\t\t\tWHERE ${sql.join(conditions, sql` AND `)}\n\t\t\t\tGROUP BY ${column}\n\t\t\t\tORDER BY ${bytewiseExpr(db, column)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t\tfor (const row of result.rows) ids.add(row.id);\n\t\t}\n\t\tconst sorted = [...ids].toSorted((a, b) =>\n\t\t\tcompareStreamOrder(\"principal\", { id: a }, { id: b }),\n\t\t);\n\t\tconst pageIds = sorted.slice(0, limit);\n\t\tconst records = await this.byIds(pageIds);\n\t\treturn {\n\t\t\trows: pageIds.map((id) => ({\n\t\t\t\tkey: { id },\n\t\t\t\trecord:\n\t\t\t\t\trecords.get(id) ?? toRecord(\"principal\", { kind: \"principal\", id, displayName: \"\" }),\n\t\t\t\tadjustments: [],\n\t\t\t})),\n\t\t\tdone: sorted.length <= limit,\n\t\t};\n\t}\n\n\tasync byIds(ids: readonly string[]): Promise<Map<string, RecordOfKind<\"principal\">>> {\n\t\tconst result = new Map<string, RecordOfKind<\"principal\">>();\n\t\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.#db\n\t\t\t\t.selectFrom(\"users\")\n\t\t\t\t.select([\"id\", \"name\", \"email\"])\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) {\n\t\t\t\tresult.set(\n\t\t\t\t\trow.id,\n\t\t\t\t\ttoRecord(\"principal\", {\n\t\t\t\t\t\tkind: \"principal\",\n\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\tdisplayName: row.name || row.email,\n\t\t\t\t\t\temail: row.email,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync countRows(): Promise<null> {\n\t\treturn null;\n\t}\n}\n\n// ── Factory ─────────────────────────────────────────────────────\n\nexport function createReader(\n\tdb: Db,\n\tkind: RecordKind,\n\toptions: ReaderOptions,\n): KindReader<RecordKind> {\n\tif (kind === \"entry\") return new EntryReader(db);\n\tif (kind === \"principal\") return new PrincipalReader(db, options);\n\treturn new TableReader(db, configFor(kind), options);\n}\n","/**\n * The export operation, advanced in bounded steps.\n *\n * Each `advanceExport` call claims the operation's lease, runs units of work\n * until the step budget is spent, persists the cursor after every unit, and\n * releases the lease. Stages, in order:\n *\n * - fence capture (on the first step), then `export_media`: hash every\n * exported media object from its origin key and record the blob;\n * - `export_records`: every record kind in package order, one chunk per unit;\n * - `export_finalize`: re-check the fence (restart the export on a change,\n * up to the attempt limit), declare dropped rows, write the index chunks\n * and the manifest;\n * - `export_validate`: re-read every record chunk, check digests and scan\n * for storage keys, then run the injected package validator.\n *\n * Media blobs are never copied: the index lists `media/<sha256>` and the\n * bytes are served from the origin object ({@link ExportPackageReader}).\n */\n\nimport type { Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\nimport { z } from \"zod\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { getI18nConfig } from \"../../i18n/config.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { VERSION } from \"../../version.js\";\nimport { TransferError, isTransferError, type TransferErrorCode } from \"../errors.js\";\nimport { compareUtf16 } from \"../format/canonical.js\";\nimport { KIND_FEATURE, requiredFeaturesFor, type SitePackageFeature } from \"../format/features.js\";\nimport { RECORD_KINDS, type RecordKind, type SitePackageRecord } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tindexChunkRefSchema,\n\ttype IndexChunkRef,\n\ttype PackageFileEntry,\n\ttype SitePackageManifest,\n} from \"../format/manifest.js\";\nimport {\n\trewriteMediaRefs,\n\tscanForKeys,\n\tscannableKeys,\n\ttype MediaKeyIndex,\n} from \"../format/media-refs.js\";\nimport { mediaBlobPath, parsePackagePath, recordChunkPath } from \"../format/paths.js\";\nimport type { PlanBlocker, PlanWarning } from \"../format/plan.js\";\nimport { encodeRecordLine } from \"../format/records.js\";\nimport {\n\tEXPORT_TRANSFORMATION_CODES,\n\ttype ExportTransformation,\n\ttype ExportTransformationCode,\n} from \"../format/transformations.js\";\nimport {\n\tSITE_PACKAGE_FORMAT,\n\tSITE_PACKAGE_FORMAT_VERSION,\n\tSITE_PACKAGE_PROFILE,\n} from \"../format/version.js\";\nimport { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferMediaBlobRepository } from \"../ops/media-blobs.js\";\nimport { TransferOperationRepository, type TransferOperation } from \"../ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport type { ExportCursor, ExportFence, TransferCursor, TransferProgress } from \"../ops/states.js\";\nimport { getOrCreateSiteId } from \"../site-id.js\";\nimport { stagingPrefix } from \"../staging/keys.js\";\nimport { StagedPackageReader, StagedPackageWriter } from \"../staging/package.js\";\nimport { TransferStage } from \"../staging/stage.js\";\nimport { captureFence, fencesEqual } from \"./fence.js\";\nimport {\n\thashStoredObject,\n\tlistMediaCandidates,\n\tloadMediaKeyIndex,\n\tunlinkMediaPlaceholders,\n} from \"./media.js\";\nimport { createReader, type KindReader, type ReaderOptions } from \"./readers.js\";\n\ntype Db = Kysely<Database>;\n\nconst encoder = new TextEncoder();\nconst PAGE_ROWS = 250;\nconst MEDIA_CANDIDATES_PER_PAGE = 50;\n/** Sorts after every `index/<seq>.ndjson` path and before `media/`. */\nconst INDEX_PATHS_END = \"index/~\";\n\n// ── Options ─────────────────────────────────────────────────────\n\nexport const exportOptionsSchema = z.strictObject({\n\tcomments: z.boolean().optional(),\n});\n\nexport type ExportOptions = z.infer<typeof exportOptionsSchema>;\n\nexport interface CreateExportInput {\n\tdb: Db;\n\tcreatedBy: string;\n\toptions?: ExportOptions;\n\tidempotencyKey?: string;\n}\n\nfunction includesComments(options: unknown): boolean {\n\treturn exportOptionsSchema.parse(options ?? {}).comments ?? true;\n}\n\n/**\n * Create a pending export operation, or return the existing one for the same\n * idempotency key. Reusing a key with different options fails with\n * `TRANSFER_IDEMPOTENCY_CONFLICT`.\n */\nexport async function createExport(\n\tinput: CreateExportInput,\n): Promise<{ operation: TransferOperation; created: boolean }> {\n\tconst options = exportOptionsSchema.parse(input.options ?? {});\n\tconst result = await new TransferOperationRepository(input.db).create({\n\t\tkind: \"export\",\n\t\tcreatedBy: input.createdBy,\n\t\tidempotencyKey: input.idempotencyKey,\n\t\toptions,\n\t});\n\tif (!result.created && includesComments(result.operation.options) !== includesComments(options)) {\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_IDEMPOTENCY_CONFLICT\",\n\t\t\t\"Idempotency key was already used for an export with different options\",\n\t\t);\n\t}\n\treturn result;\n}\n\n// ── Validator hook ──────────────────────────────────────────────\n\nexport interface ExportPackageValidatorInput {\n\tdb: Db;\n\t/** The finished package; blobs stream from their origin objects. */\n\treader: StagedPackageReader;\n\toperationId: string;\n\t/** Opaque JSON state returned by the previous call, or null on the first. */\n\tstate: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport interface ExportPackageValidatorResult {\n\tdone: boolean;\n\tstate: unknown;\n\tblockers: PlanBlocker[];\n\twarnings: PlanWarning[];\n}\n\n/** Package validation run over the finished export before it completes. */\nexport type ExportPackageValidator = (\n\tinput: ExportPackageValidatorInput,\n) => Promise<ExportPackageValidatorResult>;\n\n// ── Summary carried in the cursor ───────────────────────────────\n\nconst count = z.number().int().nonnegative();\n\nconst exportSummarySchema = z.strictObject({\n\t/** Records per chunk, by kind. */\n\tchunks: z.record(z.string(), z.array(count)),\n\tlocales: z.array(z.string()),\n\ttrash: z.boolean(),\n\t/** `code:kind` → count of declared export transformations. */\n\tadjustments: z.record(z.string(), count),\n\tfenceVerified: z.boolean(),\n\tindex: z.array(indexChunkRefSchema),\n\tfiles: z.strictObject({ count, bytes: count }),\n});\n\ntype ExportSummary = z.infer<typeof exportSummarySchema>;\n\nfunction emptySummary(): ExportSummary {\n\treturn {\n\t\tchunks: {},\n\t\tlocales: [],\n\t\ttrash: false,\n\t\tadjustments: {},\n\t\tfenceVerified: false,\n\t\tindex: [],\n\t\tfiles: { count: 0, bytes: 0 },\n\t};\n}\n\nfunction readSummary(value: unknown): ExportSummary {\n\treturn value === undefined ? emptySummary() : exportSummarySchema.parse(value);\n}\n\nfunction recordsWritten(summary: ExportSummary): number {\n\tlet total = 0;\n\tfor (const counts of Object.values(summary.chunks)) {\n\t\tfor (const records of counts) total += records;\n\t}\n\treturn total;\n}\n\nconst validationSchema = z.strictObject({\n\tphase: z.literal(\"validator\"),\n\tstate: z.json().nullable(),\n});\n\nfunction addAdjustment(\n\tsummary: ExportSummary,\n\tcode: ExportTransformationCode,\n\tkind: RecordKind,\n\tamount: number,\n): void {\n\tif (amount <= 0) return;\n\tconst key = `${code}:${kind}`;\n\tsummary.adjustments[key] = (summary.adjustments[key] ?? 0) + amount;\n}\n\n/** Rows a reader leaves out of each kind, and how the package declares them. */\nconst DROP_CODES: Partial<Record<RecordKind, ExportTransformationCode>> = {\n\tfield: \"orphan_dropped\",\n\trelation: \"orphan_dropped\",\n\tterm: \"orphan_dropped\",\n\tbyline_field_value: \"orphan_dropped\",\n\tbyline_field_group_value: \"orphan_dropped\",\n\trevision: \"orphan_dropped\",\n\tcontent_byline: \"orphan_dropped\",\n\tseo: \"orphan_dropped\",\n\tcomment: \"orphan_dropped\",\n\tcomment_reaction: \"orphan_dropped\",\n\tmenu_item: \"soft_orphan_dropped\",\n\tcontent_term: \"soft_orphan_dropped\",\n\tcontent_reference: \"soft_orphan_dropped\",\n\twidget: \"soft_orphan_dropped\",\n\tredirect: \"redirect_duplicate_dropped\",\n\tmedia: \"media_not_ready_dropped\",\n};\n\n// ── Advancing ───────────────────────────────────────────────────\n\nexport interface AdvanceExportInput {\n\tdb: Db;\n\tstorage: Storage;\n\toperationId: string;\n\t/** A lease the caller already holds; otherwise the step claims one. */\n\tleaseToken?: string;\n\tbudget?: TransferStepBudget;\n\t/** Defaults to the site's configured default locale. */\n\tdefaultLocale?: string;\n\temdashVersion?: string;\n\tvalidatePackage?: ExportPackageValidator;\n}\n\nexport type AdvanceExportOutcome = \"advanced\" | \"complete\" | \"failed\" | \"busy\" | \"finished\";\n\nexport interface AdvanceExportResult {\n\toperation: TransferOperation;\n\t/**\n\t * `advanced`: more steps needed; `complete`/`failed`: this step finished\n\t * the export; `busy`: another caller holds the lease; `finished`: the\n\t * export was already terminal.\n\t */\n\toutcome: AdvanceExportOutcome;\n}\n\n/** Codes a later step may not hit again. */\nconst TRANSIENT_CODES: ReadonlySet<TransferErrorCode> = new Set([\n\t\"TRANSFER_STORAGE_ERROR\",\n\t\"TRANSFER_LEASE_LOST\",\n]);\n\ntype UnitResult =\n\t| { type: \"cursor\"; cursor: ExportCursor; endStep?: boolean }\n\t| { type: \"yield\" }\n\t| { type: \"complete\" }\n\t| { type: \"fail\"; code: TransferErrorCode; detail?: Record<string, string | number | null> };\n\n/**\n * Run one bounded step of an export. Transient failures (storage errors,\n * a lost lease, non-transfer errors) release the lease and rethrow so a\n * later call resumes from the last persisted cursor; any other transfer\n * error fails the operation.\n */\nexport async function advanceExport(input: AdvanceExportInput): Promise<AdvanceExportResult> {\n\tconst operations = new TransferOperationRepository(input.db);\n\tlet operation: TransferOperation;\n\tlet leaseToken = input.leaseToken;\n\tif (leaseToken === undefined) {\n\t\tconst claim = await operations.claim(input.operationId, [\"pending\", \"running\"]);\n\t\tif (claim.outcome === \"lease_active\") return { operation: claim.operation, outcome: \"busy\" };\n\t\tif (claim.outcome === \"invalid_state\") {\n\t\t\treturn { operation: claim.operation, outcome: \"finished\" };\n\t\t}\n\t\toperation = claim.operation;\n\t\tleaseToken = claim.leaseToken;\n\t} else {\n\t\toperation = await operations.require(input.operationId);\n\t\tif (operation.kind !== \"export\" || operation.leaseToken !== leaseToken) {\n\t\t\tthrow new TransferError(\"TRANSFER_LEASE_LOST\", \"Transfer operation lease was lost\");\n\t\t}\n\t}\n\tif (operation.kind !== \"export\") {\n\t\tawait operations.release(operation.id, leaseToken);\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an export\");\n\t}\n\n\tconst step = new ExportStep(input, operation, leaseToken);\n\ttry {\n\t\tconst result = await step.run();\n\t\treturn result;\n\t} catch (error) {\n\t\tif (isTransferError(error) && !TRANSIENT_CODES.has(error.code)) {\n\t\t\tconst failed = await operations.fail(operation.id, leaseToken, {\n\t\t\t\tcode: error.code,\n\t\t\t\tdetail: error.detail,\n\t\t\t});\n\t\t\treturn { operation: failed, outcome: \"failed\" };\n\t\t}\n\t\tif (!(isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\")) {\n\t\t\tawait operations.release(operation.id, leaseToken).catch(() => undefined);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nclass ExportStep {\n\treadonly #input: AdvanceExportInput;\n\treadonly #db: Db;\n\treadonly #operations: TransferOperationRepository;\n\treadonly #stagedFiles: TransferStagedFileRepository;\n\treadonly #blobs: TransferMediaBlobRepository;\n\treadonly #budget: TransferStepBudget;\n\treadonly #stage: TransferStage;\n\treadonly #writer: StagedPackageWriter;\n\treadonly #options: ExportOptions;\n\treadonly #leaseToken: string;\n\t#operation: TransferOperation;\n\t#keys: MediaKeyIndex | null = null;\n\t#scannable: Set<string> | null = null;\n\t#readers = new Map<RecordKind, KindReader<RecordKind>>();\n\t#packageReader: ExportPackageReader | null = null;\n\treadonly #mediaExported = new Map<string, boolean>();\n\n\tconstructor(input: AdvanceExportInput, operation: TransferOperation, leaseToken: string) {\n\t\tthis.#input = input;\n\t\tthis.#db = input.db;\n\t\tthis.#operation = operation;\n\t\tthis.#leaseToken = leaseToken;\n\t\tthis.#operations = new TransferOperationRepository(input.db);\n\t\tthis.#stagedFiles = new TransferStagedFileRepository(input.db);\n\t\tthis.#blobs = new TransferMediaBlobRepository(input.db, operation.id);\n\t\tthis.#budget = input.budget ?? new TransferStepBudget();\n\t\tthis.#stage = new TransferStage(\n\t\t\tinput.storage,\n\t\t\tstagingPrefix(\"export\", operation.id, operation.stagingSecret),\n\t\t);\n\t\tthis.#writer = new StagedPackageWriter(this.#stage);\n\t\tthis.#options = exportOptionsSchema.parse(operation.options ?? {});\n\t}\n\n\tget #comments(): boolean {\n\t\treturn this.#options.comments ?? true;\n\t}\n\n\tasync run(): Promise<AdvanceExportResult> {\n\t\tlet cursor = this.currentCursor();\n\t\tif (cursor === null) {\n\t\t\tcursor = await this.start(1);\n\t\t\tawait this.persist(cursor, \"running\");\n\t\t}\n\t\tfor (;;) {\n\t\t\tconst result = await this.unit(cursor);\n\t\t\tswitch (result.type) {\n\t\t\t\tcase \"yield\": {\n\t\t\t\t\tconst released = await this.#operations.release(this.#operation.id, this.#leaseToken);\n\t\t\t\t\treturn { operation: released, outcome: \"advanced\" };\n\t\t\t\t}\n\t\t\t\tcase \"complete\": {\n\t\t\t\t\tconst total = this.progressTotal();\n\t\t\t\t\tconst last = this.#operation.progress;\n\t\t\t\t\tconst completed = await this.#operations.complete(this.#operation.id, this.#leaseToken, {\n\t\t\t\t\t\tttlSeconds: TRANSFER_LIMITS.exportTtlSeconds,\n\t\t\t\t\t\tprogress: {\n\t\t\t\t\t\t\t...last,\n\t\t\t\t\t\t\tdone: total,\n\t\t\t\t\t\t\ttotal,\n\t\t\t\t\t\t\t...(last?.bytesDone === undefined ? {} : { bytesTotal: last.bytesDone }),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\treturn { operation: completed, outcome: \"complete\" };\n\t\t\t\t}\n\t\t\t\tcase \"fail\": {\n\t\t\t\t\tconst failed = await this.#operations.fail(this.#operation.id, this.#leaseToken, {\n\t\t\t\t\t\tcode: result.code,\n\t\t\t\t\t\tdetail: result.detail,\n\t\t\t\t\t});\n\t\t\t\t\treturn { operation: failed, outcome: \"failed\" };\n\t\t\t\t}\n\t\t\t\tcase \"cursor\":\n\t\t\t\t\tcursor = result.cursor;\n\t\t\t\t\tif (result.endStep) {\n\t\t\t\t\t\tconst released = await this.#operations.release(this.#operation.id, this.#leaseToken, {\n\t\t\t\t\t\t\tcursor,\n\t\t\t\t\t\t\tstage: cursor.stage,\n\t\t\t\t\t\t\tprogress: this.progressFor(cursor),\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn { operation: released, outcome: \"advanced\" };\n\t\t\t\t\t}\n\t\t\t\t\tawait this.persist(cursor);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate currentCursor(): ExportCursor | null {\n\t\tconst cursor: TransferCursor | null = this.#operation.cursor;\n\t\tif (cursor === null) return null;\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"export_records\":\n\t\t\tcase \"export_media\":\n\t\t\tcase \"export_finalize\":\n\t\t\tcase \"export_validate\":\n\t\t\t\treturn cursor;\n\t\t\tdefault:\n\t\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Export cursor is not an export stage\");\n\t\t}\n\t}\n\n\tprivate async persist(cursor: ExportCursor, state?: \"running\"): Promise<void> {\n\t\tthis.#operation = await this.#operations.advance(this.#operation.id, this.#leaseToken, {\n\t\t\tcursor,\n\t\t\tstage: cursor.stage,\n\t\t\tprogress: this.progressFor(cursor),\n\t\t\t...(state ? { state } : {}),\n\t\t});\n\t}\n\n\t/** Media, each exported record kind, finalize, and validate. */\n\tprivate progressTotal(): number {\n\t\treturn this.exportedKinds().length + 3;\n\t}\n\n\tprivate progressFor(cursor: ExportCursor): TransferProgress {\n\t\tconst kinds = this.exportedKinds();\n\t\tconst total = this.progressTotal();\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"export_media\":\n\t\t\t\treturn { done: 0, total, records: 0 };\n\t\t\tcase \"export_records\":\n\t\t\t\treturn {\n\t\t\t\t\tdone: 1 + kinds.indexOf(cursor.kind),\n\t\t\t\t\ttotal,\n\t\t\t\t\trecords: recordsWritten(readSummary(cursor.summary)),\n\t\t\t\t};\n\t\t\tcase \"export_finalize\": {\n\t\t\t\tconst summary = readSummary(cursor.summary);\n\t\t\t\treturn {\n\t\t\t\t\tdone: 1 + kinds.length,\n\t\t\t\t\ttotal,\n\t\t\t\t\trecords: recordsWritten(summary),\n\t\t\t\t\tbytesDone: summary.files.bytes,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"export_validate\":\n\t\t\t\treturn { ...this.#operation.progress, done: 2 + kinds.length, total };\n\t\t}\n\t}\n\n\t/** Capture the fence and start an attempt at the media stage. */\n\tprivate async start(attempt: number): Promise<ExportCursor> {\n\t\tconst fence: ExportFence = await captureFence(this.#db, this.#operation.writeEpoch);\n\t\treturn {\n\t\t\tstage: \"export_media\",\n\t\t\tattempt,\n\t\t\tfence,\n\t\t\tafterMediaId: null,\n\t\t\tsummary: emptySummary(),\n\t\t};\n\t}\n\n\tprivate async unit(cursor: ExportCursor): Promise<UnitResult> {\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"export_media\":\n\t\t\t\treturn this.restartOnChangedFile(cursor.attempt, () => this.mediaUnit(cursor));\n\t\t\tcase \"export_records\":\n\t\t\t\treturn this.restartOnChangedFile(cursor.attempt, () => this.recordsUnit(cursor));\n\t\t\tcase \"export_finalize\":\n\t\t\t\treturn this.finalizeUnit(cursor);\n\t\t\tcase \"export_validate\":\n\t\t\t\treturn this.validateUnit(cursor);\n\t\t}\n\t}\n\n\t/**\n\t * A file this attempt already staged under the same path with other bytes\n\t * means the site changed since it was written (the step that wrote it did\n\t * not persist its cursor): start a new attempt.\n\t */\n\tprivate async restartOnChangedFile(\n\t\tattempt: number,\n\t\trun: () => Promise<UnitResult>,\n\t): Promise<UnitResult> {\n\t\ttry {\n\t\t\treturn await run();\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_FILE_DIGEST_MISMATCH\") {\n\t\t\t\treturn this.restart(attempt);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// ── Media ──\n\n\tprivate async mediaUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_media\" }>,\n\t): Promise<UnitResult> {\n\t\tif (!this.#budget.canStart()) return { type: \"yield\" };\n\t\tthis.#budget.start();\n\t\tconst candidates = await listMediaCandidates(\n\t\t\tthis.#db,\n\t\t\tcursor.afterMediaId,\n\t\t\tMEDIA_CANDIDATES_PER_PAGE,\n\t\t);\n\t\tif (candidates.length === 0) {\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor: {\n\t\t\t\t\tstage: \"export_records\",\n\t\t\t\t\tattempt: cursor.attempt,\n\t\t\t\t\tfence: cursor.fence,\n\t\t\t\t\tkind: RECORD_KINDS[0],\n\t\t\t\t\tafter: null,\n\t\t\t\t\tnextSeq: 0,\n\t\t\t\t\tsummary: cursor.summary,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tlet after = cursor.afterMediaId;\n\t\tfor (const candidate of candidates) {\n\t\t\t// The first object of a step may be any size; later ones must fit what is left.\n\t\t\tconst first = this.#budget.bytesUsed === 0;\n\t\t\tif (!first && !this.#budget.canStart({ queries: 5, bytes: 1 })) break;\n\t\t\tconst hashed = await hashStoredObject(this.#input.storage, candidate.storageKey, {\n\t\t\t\tmaxBytes: first ? undefined : this.#budget.remaining().bytes,\n\t\t\t});\n\t\t\tif (hashed === \"too_large\") break;\n\t\t\tthis.#budget.start(hashed?.bytes ?? 0);\n\t\t\tif (hashed === null) {\n\t\t\t\tif (candidate.status === \"ready\") {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_BLOB_MISSING\",\n\t\t\t\t\t\t\"Media file is missing from storage\",\n\t\t\t\t\t\t{ detail: { mediaId: candidate.id } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait this.#blobs.putMany([\n\t\t\t\t\t{ mediaId: candidate.id, sha256: hashed.sha256, bytes: hashed.bytes },\n\t\t\t\t]);\n\t\t\t\tawait this.#stagedFiles.declareMany(\n\t\t\t\t\tthis.#operation.id,\n\t\t\t\t\t[{ path: mediaBlobPath(hashed.sha256), bytes: hashed.bytes, sha256: hashed.sha256 }],\n\t\t\t\t\t\"verified\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tafter = candidate.id;\n\t\t}\n\t\tif (after === cursor.afterMediaId) return { type: \"yield\" };\n\t\treturn { type: \"cursor\", cursor: { ...cursor, afterMediaId: after } };\n\t}\n\n\t// ── Records ──\n\n\tprivate reader(kind: RecordKind): KindReader<RecordKind> {\n\t\tlet reader = this.#readers.get(kind);\n\t\tif (!reader) {\n\t\t\tconst options: ReaderOptions = {\n\t\t\t\texportOperationId: this.#operation.id,\n\t\t\t\tcomments: this.#comments,\n\t\t\t\tmediaBlobs: async (ids) => {\n\t\t\t\t\tconst entries = await this.#blobs.getMany(ids);\n\t\t\t\t\treturn new Map(Array.from(entries, ([id, entry]) => [id, entry.sha256]));\n\t\t\t\t},\n\t\t\t};\n\t\t\treader = createReader(this.#db, kind, options);\n\t\t\tthis.#readers.set(kind, reader);\n\t\t}\n\t\treturn reader;\n\t}\n\n\t/** Media ids among `ids` that this export did not hash (not in the package). */\n\tprivate async unexportedMedia(ids: readonly string[]): Promise<Set<string>> {\n\t\tconst unknown = ids.filter((id) => !this.#mediaExported.has(id));\n\t\tif (unknown.length > 0) {\n\t\t\tconst exported = await this.#blobs.getMany(unknown);\n\t\t\tfor (const id of unknown) this.#mediaExported.set(id, exported.has(id));\n\t\t}\n\t\treturn new Set(ids.filter((id) => this.#mediaExported.get(id) === false));\n\t}\n\n\tprivate async keyIndex(): Promise<{ keys: MediaKeyIndex; scannable: Set<string> }> {\n\t\tif (!this.#keys || !this.#scannable) {\n\t\t\tthis.#keys = await loadMediaKeyIndex(this.#db);\n\t\t\tthis.#scannable = scannableKeys(this.#keys);\n\t\t}\n\t\treturn { keys: this.#keys, scannable: this.#scannable };\n\t}\n\n\tprivate exportedKinds(): RecordKind[] {\n\t\treturn RECORD_KINDS.filter(\n\t\t\t(kind) => this.#comments || (kind !== \"comment\" && kind !== \"comment_reaction\"),\n\t\t);\n\t}\n\n\tprivate nextKind(kind: RecordKind): RecordKind | null {\n\t\tconst kinds = this.exportedKinds();\n\t\treturn kinds[kinds.indexOf(kind) + 1] ?? null;\n\t}\n\n\tprivate async recordsUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_records\" }>,\n\t): Promise<UnitResult> {\n\t\tif (!this.#budget.canStart({ bytes: 1 })) return { type: \"yield\" };\n\t\tconst summary = readSummary(cursor.summary);\n\t\tconst { keys, scannable } = await this.keyIndex();\n\t\tconst reader = this.reader(cursor.kind);\n\n\t\tconst records: SitePackageRecord[] = [];\n\t\tconst lines: string[] = [];\n\t\tconst locales = new Set(summary.locales);\n\t\tlet bytes = 0;\n\t\tlet after = cursor.after;\n\t\tlet kindDone = false;\n\t\tfill: while (records.length < TRANSFER_LIMITS.chunkRecords) {\n\t\t\tconst page = await reader.page(\n\t\t\t\tafter,\n\t\t\t\tMath.min(PAGE_ROWS, TRANSFER_LIMITS.chunkRecords - records.length),\n\t\t\t);\n\t\t\tfor (const row of page.rows) {\n\t\t\t\tif (row.record === null) {\n\t\t\t\t\tafter = row.key;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst rewritten = rewriteMediaRefs(row.record, {\n\t\t\t\t\tmode: \"export\",\n\t\t\t\t\tkeys,\n\t\t\t\t\trelativize: true,\n\t\t\t\t});\n\t\t\t\tconst error = rewritten.errors[0];\n\t\t\t\tif (error) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_REF_INVALID\",\n\t\t\t\t\t\t\"Record holds a media reference that cannot be exported\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\t\tkind: cursor.kind,\n\t\t\t\t\t\t\t\tid: row.record.id,\n\t\t\t\t\t\t\t\treason: error.code,\n\t\t\t\t\t\t\t\tpath: error.path,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst unlinked = unlinkMediaPlaceholders(\n\t\t\t\t\trewritten.value,\n\t\t\t\t\tawait this.unexportedMedia(rewritten.mediaIds),\n\t\t\t\t);\n\t\t\t\tconst record = unlinked.record;\n\t\t\t\tconst line = encodeRecordLine(record);\n\t\t\t\tif (scanForKeys(line, scannable).length > 0) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_REF_INVALID\",\n\t\t\t\t\t\t\"Record still holds an origin storage key\",\n\t\t\t\t\t\t{ detail: { kind: cursor.kind, id: record.id } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst lineBytes = encoder.encode(line).byteLength + 1;\n\t\t\t\tif (records.length > 0 && bytes + lineBytes > TRANSFER_LIMITS.chunkBytes) break fill;\n\t\t\t\trecords.push(record);\n\t\t\t\tlines.push(line);\n\t\t\t\tbytes += lineBytes;\n\t\t\t\tafter = row.key;\n\t\t\t\tfor (const adjustment of row.adjustments) {\n\t\t\t\t\taddAdjustment(summary, adjustment.code, cursor.kind, adjustment.count);\n\t\t\t\t}\n\t\t\t\taddAdjustment(summary, \"media_url_relativized\", cursor.kind, rewritten.relativized);\n\t\t\t\taddAdjustment(summary, \"media_ref_unlinked\", cursor.kind, unlinked.count);\n\t\t\t\tif (rewritten.warnings.some((warning) => warning.code === \"unknown_storage_key\")) {\n\t\t\t\t\taddAdjustment(summary, \"unknown_storage_key\", cursor.kind, 1);\n\t\t\t\t}\n\t\t\t\tif (\"locale\" in record && typeof record.locale === \"string\") locales.add(record.locale);\n\t\t\t\tif (record.kind === \"entry\" && record.deletedAt !== undefined) summary.trash = true;\n\t\t\t}\n\t\t\tif (page.done) {\n\t\t\t\tkindDone = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (records.length > 0) {\n\t\t\tconst entry = await this.#writer.writeRecordChunk(cursor.kind, cursor.nextSeq, records);\n\t\t\tawait this.#stagedFiles.declareMany(\n\t\t\t\tthis.#operation.id,\n\t\t\t\t[{ path: entry.path, bytes: entry.bytes, sha256: entry.sha256 }],\n\t\t\t\t\"verified\",\n\t\t\t);\n\t\t\tthis.#budget.start(entry.bytes);\n\t\t\tsummary.chunks[cursor.kind] = [...(summary.chunks[cursor.kind] ?? []), records.length];\n\t\t} else {\n\t\t\tthis.#budget.start(0);\n\t\t}\n\t\tsummary.locales = [...locales].toSorted(compareUtf16);\n\n\t\tconst nextSeq = records.length > 0 ? cursor.nextSeq + 1 : cursor.nextSeq;\n\t\tif (!kindDone) {\n\t\t\treturn { type: \"cursor\", cursor: { ...cursor, after, nextSeq, summary } };\n\t\t}\n\t\tconst next = this.nextKind(cursor.kind);\n\t\tif (next === null) {\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor: {\n\t\t\t\t\tstage: \"export_finalize\",\n\t\t\t\t\tattempt: cursor.attempt,\n\t\t\t\t\tfence: cursor.fence,\n\t\t\t\t\tnextIndexSeq: 0,\n\t\t\t\t\tafterPath: null,\n\t\t\t\t\tsummary,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\ttype: \"cursor\",\n\t\t\tcursor: { ...cursor, kind: next, after: null, nextSeq: 0, summary },\n\t\t};\n\t}\n\n\t// ── Finalize ──\n\n\tprivate async finalizeUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_finalize\" }>,\n\t): Promise<UnitResult> {\n\t\tif (!this.#budget.canStart()) return { type: \"yield\" };\n\t\tthis.#budget.start();\n\t\tconst summary = readSummary(cursor.summary);\n\n\t\tif (!summary.fenceVerified) {\n\t\t\tconst current = await this.#operations.require(this.#operation.id);\n\t\t\tconst fence = await captureFence(this.#db, current.writeEpoch);\n\t\t\tif (!fencesEqual(cursor.fence, fence)) return this.restart(cursor.attempt);\n\t\t\tawait this.declareDrops(summary);\n\t\t\tsummary.fenceVerified = true;\n\t\t\treturn { type: \"cursor\", cursor: { ...cursor, summary } };\n\t\t}\n\n\t\tconst files = await this.#stagedFiles.list(this.#operation.id, {\n\t\t\tstate: \"verified\",\n\t\t\tafter: cursor.afterPath ?? INDEX_PATHS_END,\n\t\t\tlimit: TRANSFER_LIMITS.chunkRecords,\n\t\t});\n\t\tconst entries: PackageFileEntry[] = [];\n\t\tlet bytes = 0;\n\t\tfor (const file of files) {\n\t\t\tconst parsed = parsePackagePath(file.path);\n\t\t\tif (!parsed || (parsed.type !== \"records\" && parsed.type !== \"media\")) continue;\n\t\t\tconst entry: PackageFileEntry = { path: file.path, bytes: file.bytes, sha256: file.sha256 };\n\t\t\tif (parsed.type === \"records\") {\n\t\t\t\tconst records = summary.chunks[parsed.kind]?.[parsed.seq];\n\t\t\t\tif (records === undefined) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_EXPORT_ERROR\",\n\t\t\t\t\t\t\"Staged chunk is not part of the export\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdetail: { path: file.path },\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tentry.records = records;\n\t\t\t}\n\t\t\tconst size = encoder.encode(JSON.stringify(entry)).byteLength + 1;\n\t\t\tif (entries.length > 0 && bytes + size > TRANSFER_LIMITS.chunkBytes) break;\n\t\t\tentries.push(entry);\n\t\t\tbytes += size;\n\t\t}\n\n\t\tconst lastEntry = entries.at(-1);\n\t\tif (lastEntry) {\n\t\t\tconst ref: IndexChunkRef = await this.#writer.writeIndexChunk(cursor.nextIndexSeq, entries);\n\t\t\tawait this.#stagedFiles.declareMany(\n\t\t\t\tthis.#operation.id,\n\t\t\t\t[{ path: ref.path, bytes: ref.bytes, sha256: ref.sha256 }],\n\t\t\t\t\"verified\",\n\t\t\t);\n\t\t\tsummary.index = [...summary.index, ref];\n\t\t\tsummary.files = {\n\t\t\t\tcount: summary.files.count + entries.length,\n\t\t\t\tbytes: summary.files.bytes + entries.reduce((sum, entry) => sum + entry.bytes, 0),\n\t\t\t};\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor: {\n\t\t\t\t\t...cursor,\n\t\t\t\t\tnextIndexSeq: cursor.nextIndexSeq + 1,\n\t\t\t\t\tafterPath: lastEntry.path,\n\t\t\t\t\tsummary,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst manifest = await this.buildManifest(summary, cursor.attempt);\n\t\tconst digest = await this.#writer.writeManifest(manifest);\n\t\tthis.#operation = await this.#operations.advance(this.#operation.id, this.#leaseToken, {\n\t\t\tpackageDigest: digest,\n\t\t});\n\t\treturn { type: \"cursor\", cursor: { stage: \"export_validate\", position: null } };\n\t}\n\n\tprivate async declareDrops(summary: ExportSummary): Promise<void> {\n\t\tfor (const kind of this.exportedKinds()) {\n\t\t\tconst rows = await this.reader(kind).countRows();\n\t\t\tif (rows === null) continue;\n\t\t\tconst exported = (summary.chunks[kind] ?? []).reduce((sum, n) => sum + n, 0);\n\t\t\tconst dropped = rows - exported;\n\t\t\tif (dropped === 0) continue;\n\t\t\tconst code = DROP_CODES[kind];\n\t\t\tif (!code || dropped < 0) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_EXPORT_ERROR\", \"Rows could not be exported\", {\n\t\t\t\t\tdetail: { kind, rows, exported },\n\t\t\t\t});\n\t\t\t}\n\t\t\taddAdjustment(summary, code, kind, dropped);\n\t\t}\n\t}\n\n\tprivate async restart(attempt: number): Promise<UnitResult> {\n\t\tif (attempt >= TRANSFER_LIMITS.exportFenceAttempts) {\n\t\t\treturn {\n\t\t\t\ttype: \"fail\",\n\t\t\t\tcode: \"TRANSFER_EXPORT_CONCURRENT_WRITES\",\n\t\t\t\tdetail: { attempts: attempt },\n\t\t\t};\n\t\t}\n\t\tlet deleted: number;\n\t\tdo {\n\t\t\tdeleted = await this.#stagedFiles.deleteForOperation(this.#operation.id);\n\t\t} while (deleted > 0);\n\t\tawait this.#db\n\t\t\t.deleteFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.where(\"operation_id\", \"=\", this.#operation.id)\n\t\t\t.execute();\n\t\tthis.#operation = await this.#operations.require(this.#operation.id);\n\t\treturn { type: \"cursor\", cursor: await this.start(attempt + 1) };\n\t}\n\n\tprivate async buildManifest(\n\t\tsummary: ExportSummary,\n\t\tattempts: number,\n\t): Promise<SitePackageManifest> {\n\t\tconst totals = await this.#blobs.totals();\n\t\tconst features = new Set<SitePackageFeature>();\n\t\tconst records: SitePackageManifest[\"records\"] = {};\n\t\tfor (const kind of RECORD_KINDS) {\n\t\t\tconst chunks = summary.chunks[kind];\n\t\t\tif (!chunks || chunks.length === 0) continue;\n\t\t\trecords[kind] = { count: chunks.reduce((sum, n) => sum + n, 0), chunks: chunks.length };\n\t\t\tfeatures.add(KIND_FEATURE[kind]);\n\t\t}\n\t\tif (this.#comments) features.add(\"comments\");\n\t\tif (totals.blobs > 0) features.add(\"media\");\n\t\tconst defaultLocale =\n\t\t\tthis.#input.defaultLocale ?? getI18nConfig()?.defaultLocale ?? summary.locales[0] ?? \"en\";\n\t\tconst locales = new Set([...summary.locales, defaultLocale]);\n\t\tif (locales.size > 1) features.add(\"i18n\");\n\t\tif (summary.trash) features.add(\"trash\");\n\t\tconst featureList = [...features].toSorted(compareUtf16);\n\n\t\tconst transformations: ExportTransformation[] = [];\n\t\tfor (const [key, amount] of Object.entries(summary.adjustments)) {\n\t\t\tconst [code, kind] = key.split(\":\");\n\t\t\tconst known = EXPORT_TRANSFORMATION_CODES.find((candidate) => candidate === code);\n\t\t\tconst recordKind = RECORD_KINDS.find((candidate) => candidate === kind);\n\t\t\tif (!known || !recordKind || amount === 0) continue;\n\t\t\ttransformations.push({ code: known, kind: recordKind, count: amount });\n\t\t}\n\t\ttransformations.sort((a, b) => compareUtf16(a.code, b.code) || compareUtf16(a.kind, b.kind));\n\n\t\treturn {\n\t\t\tformat: SITE_PACKAGE_FORMAT,\n\t\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\t\tpackageId: ulid(),\n\t\t\toriginSiteId: await getOrCreateSiteId(this.#db),\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\tcreatedByEmDashVersion: this.#input.emdashVersion ?? VERSION,\n\t\t\tprofile: SITE_PACKAGE_PROFILE,\n\t\t\tfeatures: featureList,\n\t\t\trequiredFeatures: requiredFeaturesFor(featureList),\n\t\t\tlocales: { default: defaultLocale, used: [...locales].toSorted(compareUtf16) },\n\t\t\trecords,\n\t\t\tmedia: { count: totals.blobs, totalBytes: totals.blobBytes },\n\t\t\tfiles: { count: summary.files.count, totalBytes: summary.files.bytes },\n\t\t\tindex: summary.index,\n\t\t\ttransformations,\n\t\t\tfence: { attempts },\n\t\t};\n\t}\n\n\t// ── Validate ──\n\n\tprivate packageReader(): ExportPackageReader {\n\t\tthis.#packageReader ??= new ExportPackageReader(\n\t\t\tthis.#stage,\n\t\t\tthis.#db,\n\t\t\tthis.#input.storage,\n\t\t\tthis.#operation.id,\n\t\t);\n\t\treturn this.#packageReader;\n\t}\n\n\tprivate async validateUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_validate\" }>,\n\t): Promise<UnitResult> {\n\t\tconst reader = this.packageReader();\n\t\tif (cursor.validation === undefined) {\n\t\t\tconst manifest = await reader.manifest();\n\t\t\tconst position = cursor.position ?? firstChunk(manifest);\n\t\t\tif (position === null) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"cursor\",\n\t\t\t\t\tcursor: { ...cursor, position: null, validation: { phase: \"validator\", state: null } },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst path = recordChunkPath(position.kind, position.seq);\n\t\t\tconst staged = await this.#stagedFiles.get(this.#operation.id, path);\n\t\t\tif (!staged) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Record chunk was not staged\", {\n\t\t\t\t\tdetail: { path },\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!this.#budget.canStart({ bytes: staged.bytes })) return { type: \"yield\" };\n\t\t\tthis.#budget.start(staged.bytes);\n\t\t\tconst { scannable } = await this.keyIndex();\n\t\t\tconst chunk = await reader.readChunk(position.kind, position.seq, staged);\n\t\t\tfor (const record of chunk) {\n\t\t\t\tif (scanForKeys(record.line, scannable).length > 0) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_REF_INVALID\",\n\t\t\t\t\t\t\"Package holds an origin storage key\",\n\t\t\t\t\t\t{ detail: { kind: position.kind, id: record.record.id } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst next = nextChunk(manifest, position);\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor:\n\t\t\t\t\tnext === null\n\t\t\t\t\t\t? { ...cursor, position: null, validation: { phase: \"validator\", state: null } }\n\t\t\t\t\t\t: { ...cursor, position: next },\n\t\t\t};\n\t\t}\n\n\t\tconst validation = validationSchema.parse(cursor.validation);\n\t\tconst validate = this.#input.validatePackage;\n\t\tif (!validate) return { type: \"complete\" };\n\t\t// The validator gets a fresh step so its first unit can always start.\n\t\tif (this.#budget.units > 0 || !this.#budget.canStart()) return { type: \"yield\" };\n\t\tconst result = await validate({\n\t\t\tdb: this.#db,\n\t\t\treader,\n\t\t\toperationId: this.#operation.id,\n\t\t\tstate: validation.state,\n\t\t\tbudget: this.#budget,\n\t\t});\n\t\tconst blocker = result.blockers[0];\n\t\tif (blocker) {\n\t\t\treturn {\n\t\t\t\ttype: \"fail\",\n\t\t\t\tcode: \"TRANSFER_EXPORT_ERROR\",\n\t\t\t\tdetail: {\n\t\t\t\t\treason: \"package_invalid\",\n\t\t\t\t\tblocker: blocker.code,\n\t\t\t\t\tkind: blocker.kind ?? null,\n\t\t\t\t\tid: blocker.id ?? null,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (result.done) return { type: \"complete\" };\n\t\treturn {\n\t\t\ttype: \"cursor\",\n\t\t\tcursor: {\n\t\t\t\t...cursor,\n\t\t\t\tvalidation: { phase: \"validator\", state: z.json().parse(result.state ?? null) },\n\t\t\t},\n\t\t\tendStep: true,\n\t\t};\n\t}\n}\n\nfunction firstChunk(\n\tmanifest: SitePackageManifest,\n): { kind: RecordKind; seq: number; line: number } | null {\n\tfor (const kind of RECORD_KINDS) {\n\t\tif ((manifest.records[kind]?.chunks ?? 0) > 0) return { kind, seq: 0, line: 0 };\n\t}\n\treturn null;\n}\n\nfunction nextChunk(\n\tmanifest: SitePackageManifest,\n\tposition: { kind: RecordKind; seq: number },\n): { kind: RecordKind; seq: number; line: number } | null {\n\tif (position.seq + 1 < (manifest.records[position.kind]?.chunks ?? 0)) {\n\t\treturn { kind: position.kind, seq: position.seq + 1, line: 0 };\n\t}\n\tfor (const kind of RECORD_KINDS.slice(RECORD_KINDS.indexOf(position.kind) + 1)) {\n\t\tif ((manifest.records[kind]?.chunks ?? 0) > 0) return { kind, seq: 0, line: 0 };\n\t}\n\treturn null;\n}\n\n// ── Reading a finished export ───────────────────────────────────\n\n/**\n * Reader over an export's staging area. Record and index chunks come from\n * staging; `media/<sha256>` streams from the origin object of a media row\n * hashed to that digest.\n */\nexport class ExportPackageReader extends StagedPackageReader {\n\treadonly #db: Db;\n\treadonly #storage: Storage;\n\treadonly #operationId: string;\n\n\tconstructor(stage: TransferStage, db: Db, storage: Storage, operationId: string) {\n\t\tsuper(stage);\n\t\tthis.#db = db;\n\t\tthis.#storage = storage;\n\t\tthis.#operationId = operationId;\n\t}\n\n\toverride async blob(sha256: string): Promise<ReadableStream<Uint8Array>> {\n\t\tconst row = await this.#db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.innerJoin(\"media\", \"media.id\", \"_emdash_transfer_media_blobs.media_id\")\n\t\t\t.select([\"media.storage_key as storage_key\"])\n\t\t\t.where(\"_emdash_transfer_media_blobs.operation_id\", \"=\", this.#operationId)\n\t\t\t.where(\"_emdash_transfer_media_blobs.sha256\", \"=\", sha256)\n\t\t\t.orderBy(\"_emdash_transfer_media_blobs.media_id\")\n\t\t\t.executeTakeFirst();\n\t\tif (!row) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Blob is not part of this export\", {\n\t\t\t\tdetail: { path: mediaBlobPath(sha256) },\n\t\t\t});\n\t\t}\n\t\ttry {\n\t\t\treturn (await this.#storage.download(row.storage_key)).body;\n\t\t} catch (error) {\n\t\t\tthrow new TransferError(\"TRANSFER_MEDIA_BLOB_MISSING\", \"Media file is missing from storage\", {\n\t\t\t\tdetail: { path: mediaBlobPath(sha256) },\n\t\t\t\tcause: error,\n\t\t\t});\n\t\t}\n\t}\n}\n\n/** Open a completed (or finalized) export's package for reading. */\nexport function openExportPackage(input: {\n\tdb: Db;\n\tstorage: Storage;\n\toperation: Pick<TransferOperation, \"id\" | \"stagingSecret\">;\n}): ExportPackageReader {\n\tconst stage = new TransferStage(\n\t\tinput.storage,\n\t\tstagingPrefix(\"export\", input.operation.id, input.operation.stagingSecret),\n\t);\n\treturn new ExportPackageReader(stage, input.db, input.storage, input.operation.id);\n}\n","/**\n * `(operation, kind, portableId) → targetId` mappings for one import.\n *\n * Portable ids are written verbatim whenever possible, and a verbatim id\n * needs no row. Rows exist only for rewritten ids and for derived target\n * values (media storage keys, recorded under kind `media_storage_key`).\n * Mappings are scoped to the import operation, so a later import of the same\n * origin after an abandoned one starts with a clean namespace.\n * `origin_site_id` is recorded for diagnostics only.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { bytewise } from \"./collation.js\";\n\n/** Identity-map kind for a media row's target storage key. */\nexport const MEDIA_STORAGE_KEY_ENTITY = \"media_storage_key\";\n\nexport interface IdentityMapping {\n\tportableId: string;\n\ttargetId: string;\n}\n\nexport class TransferIdentityMapRepository {\n\tconstructor(\n\t\tprivate readonly db: Kysely<Database>,\n\t\tprivate readonly originSiteId: string,\n\t\tprivate readonly operationId: string,\n\t) {}\n\n\t/**\n\t * Record mappings; re-recording the same mapping is a no-op. Throws\n\t * `TRANSFER_REFERENCE_INVALID` if a portable id is already mapped to a\n\t * different target id in this operation.\n\t */\n\tasync putMany(entityKind: string, mappings: readonly IdentityMapping[]): Promise<void> {\n\t\tif (mappings.length === 0) return;\n\t\tfor (const batch of chunks([...mappings], rowsPerInsert(5))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_identity_map\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((mapping) => ({\n\t\t\t\t\t\torigin_site_id: this.originSiteId,\n\t\t\t\t\t\tentity_kind: entityKind,\n\t\t\t\t\t\tportable_id: mapping.portableId,\n\t\t\t\t\t\ttarget_id: mapping.targetId,\n\t\t\t\t\t\toperation_id: this.operationId,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) =>\n\t\t\t\t\tconflict.columns([\"operation_id\", \"entity_kind\", \"portable_id\"]).doNothing(),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t}\n\t\tconst stored = await this.getMany(\n\t\t\tentityKind,\n\t\t\tmappings.map((mapping) => mapping.portableId),\n\t\t);\n\t\tfor (const mapping of mappings) {\n\t\t\tif (stored.get(mapping.portableId) !== mapping.targetId) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_REFERENCE_INVALID\", \"Conflicting identity mapping\", {\n\t\t\t\t\tdetail: { kind: entityKind, id: mapping.portableId },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tasync put(entityKind: string, mapping: IdentityMapping): Promise<void> {\n\t\tawait this.putMany(entityKind, [mapping]);\n\t}\n\n\tasync get(entityKind: string, portableId: string): Promise<string | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t.select(\"target_id\")\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.where(\"entity_kind\", \"=\", entityKind)\n\t\t\t.where(\"portable_id\", \"=\", portableId)\n\t\t\t.executeTakeFirst();\n\t\treturn row?.target_id ?? null;\n\t}\n\n\t/** Mapped target ids by portable id (missing ids are absent from the map). */\n\tasync getMany(entityKind: string, portableIds: readonly string[]): Promise<Map<string, string>> {\n\t\tconst result = new Map<string, string>();\n\t\tfor (const batch of chunks([...new Set(portableIds)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t.select([\"portable_id\", \"target_id\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"entity_kind\", \"=\", entityKind)\n\t\t\t\t.where(\"portable_id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.portable_id, row.target_id);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Portable ids by target id (reverse lookup for verification). */\n\tasync getPortableIds(\n\t\tentityKind: string,\n\t\ttargetIds: readonly string[],\n\t): Promise<Map<string, string>> {\n\t\tconst result = new Map<string, string>();\n\t\tfor (const batch of chunks([...new Set(targetIds)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t.select([\"portable_id\", \"target_id\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"entity_kind\", \"=\", entityKind)\n\t\t\t\t.where(\"target_id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.target_id, row.portable_id);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Mappings of one kind in portable-id order, for bounded iteration. */\n\tasync list(\n\t\tentityKind: string,\n\t\toptions: { after?: string; limit?: number } = {},\n\t): Promise<IdentityMapping[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t.select([\"portable_id\", \"target_id\"])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.where(\"entity_kind\", \"=\", entityKind);\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"portable_id\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"portable_id\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map((row) => ({ portableId: row.portable_id, targetId: row.target_id }));\n\t}\n}\n","/**\n * State shared by one `advanceImport` step.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { isPostgres } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { TransferError } from \"../errors.js\";\nimport {\n\tKIND_REFERENCES,\n\tRECORD_KINDS,\n\ttype RecordKind,\n\ttype RecordOfKind,\n} from \"../format/kinds.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport {\n\tMEDIA_PLACEHOLDER_PREFIX,\n\tPLACEHOLDER_TOKEN,\n\trewriteMediaRefs,\n} from \"../format/media-refs.js\";\nimport type { SiteImportPlan } from \"../format/plan.js\";\nimport type { FieldColumnType } from \"../format/transformations.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { MEDIA_STORAGE_KEY_ENTITY, TransferIdentityMapRepository } from \"../ops/identity-map.js\";\nimport type { TransferOperation, TransferOperationRepository } from \"../ops/operations.js\";\nimport type { StreamPosition } from \"../ops/states.js\";\nimport type { StagedPackageReader, StagedRecord } from \"../staging/package.js\";\n\nconst RECORD_KIND_NAMES: ReadonlySet<string> = new Set(RECORD_KINDS);\n\n/** Identity-map kind marking record-stage units that have started. */\nexport const IMPORT_UNIT_ENTITY = \"import_unit\";\n\ninterface CollectionFields {\n\tcolumns: ReadonlyMap<string, FieldColumnType>;\n\trequired: ReadonlySet<string>;\n}\n\nexport class ImportContext {\n\treadonly float4: boolean;\n\treadonly identity: TransferIdentityMapRepository;\n\treadonly #chunks = new Map<string, Promise<Array<StagedRecord<RecordKind>>>>();\n\treadonly #fields = new Map<string, Promise<CollectionFields>>();\n\t#rewrittenKinds: Promise<Set<string>> | undefined;\n\t/** Whether the running unit is on its first attempt (see `beginUnit`). */\n\tfirstAttempt = false;\n\n\tconstructor(\n\t\treadonly db: Kysely<Database>,\n\t\treadonly storage: Storage,\n\t\treadonly ops: TransferOperationRepository,\n\t\tpublic operation: TransferOperation,\n\t\treadonly leaseToken: string,\n\t\treadonly plan: SiteImportPlan,\n\t\treadonly manifest: SitePackageManifest,\n\t\treadonly reader: StagedPackageReader,\n\t\treadonly budget: TransferStepBudget,\n\t) {\n\t\tthis.float4 = isPostgres(db);\n\t\tthis.identity = new TransferIdentityMapRepository(db, manifest.originSiteId, operation.id);\n\t}\n\n\tget operationId(): string {\n\t\treturn this.operation.id;\n\t}\n\n\tchunkCount(kind: RecordKind): number {\n\t\treturn this.manifest.records[kind]?.chunks ?? 0;\n\t}\n\n\t/** Records of one chunk, parsed once per step. */\n\tasync chunk<K extends RecordKind>(kind: K, seq: number): Promise<Array<StagedRecord<K>>> {\n\t\tconst key = `${kind}/${seq}`;\n\t\tlet pending = this.#chunks.get(key);\n\t\tif (!pending) {\n\t\t\tpending = this.reader.readChunk(kind, seq);\n\t\t\tthis.#chunks.set(key, pending);\n\t\t}\n\t\treturn pending;\n\t}\n\n\t/** Every record of `kind`, for small kinds read as a whole (collections, fields). */\n\tasync allRecords<K extends RecordKind>(kind: K): Promise<Array<RecordOfKind<K>>> {\n\t\tconst records: Array<RecordOfKind<K>> = [];\n\t\tfor (let seq = 0; seq < this.chunkCount(kind); seq++) {\n\t\t\tfor (const staged of await this.chunk(kind, seq)) records.push(staged.record);\n\t\t}\n\t\treturn records;\n\t}\n\n\t/** Target column type of each field of a collection, from the imported schema. */\n\tasync fieldColumns(collection: string): Promise<ReadonlyMap<string, FieldColumnType>> {\n\t\treturn (await this.fields(collection)).columns;\n\t}\n\n\t/** Slugs of a collection's required (NOT NULL) fields, from the imported schema. */\n\tasync requiredFields(collection: string): Promise<ReadonlySet<string>> {\n\t\treturn (await this.fields(collection)).required;\n\t}\n\n\tprivate fields(collection: string): Promise<CollectionFields> {\n\t\tlet pending = this.#fields.get(collection);\n\t\tif (!pending) {\n\t\t\tpending = this.db\n\t\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t\t.innerJoin(\"_emdash_collections\", \"_emdash_collections.id\", \"_emdash_fields.collection_id\")\n\t\t\t\t.select([\n\t\t\t\t\t\"_emdash_fields.slug as slug\",\n\t\t\t\t\t\"_emdash_fields.column_type as column_type\",\n\t\t\t\t\t\"_emdash_fields.required as required\",\n\t\t\t\t])\n\t\t\t\t.where(\"_emdash_collections.slug\", \"=\", collection)\n\t\t\t\t.execute()\n\t\t\t\t.then((rows) => ({\n\t\t\t\t\tcolumns: new Map(\n\t\t\t\t\t\trows.map((row) => [row.slug, toFieldColumnType(row.column_type)] as const),\n\t\t\t\t\t),\n\t\t\t\t\trequired: new Set(\n\t\t\t\t\t\trows.filter((row) => Number(row.required) === 1).map((row) => row.slug),\n\t\t\t\t\t),\n\t\t\t\t}));\n\t\t\tthis.#fields.set(collection, pending);\n\t\t}\n\t\treturn pending;\n\t}\n\n\t/**\n\t * Record that the unit at `position` of `stage` is starting and set\n\t * `firstAttempt`: false when an earlier, interrupted step already started\n\t * it, so rows it finds may be its own partial writes.\n\t */\n\tasync beginUnit(stage: string, position: StreamPosition): Promise<void> {\n\t\tconst result = await this.db\n\t\t\t.insertInto(\"_emdash_transfer_identity_map\")\n\t\t\t.values({\n\t\t\t\torigin_site_id: this.manifest.originSiteId,\n\t\t\t\toperation_id: this.operation.id,\n\t\t\t\tentity_kind: IMPORT_UNIT_ENTITY,\n\t\t\t\tportable_id: `${stage}:${position.kind}:${position.seq}:${position.line}`,\n\t\t\t\ttarget_id: \"started\",\n\t\t\t})\n\t\t\t.onConflict((conflict) =>\n\t\t\t\tconflict.columns([\"operation_id\", \"entity_kind\", \"portable_id\"]).doNothing(),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\t\tthis.firstAttempt = Number(result.numInsertedOrUpdatedRows ?? 0n) > 0;\n\t}\n\n\tprincipalTarget(principal: string | undefined): string | null {\n\t\tif (principal === undefined) return null;\n\t\tconst mappings = this.plan.decisions.principalMappings;\n\t\treturn Object.hasOwn(mappings, principal) ? (mappings[principal] ?? null) : null;\n\t}\n\n\t/**\n\t * Replace every `emdash-media:` placeholder in `records` with the target\n\t * storage key the media stage recorded, and unescape escaped placeholder\n\t * text. Throws `TRANSFER_MEDIA_REF_INVALID` for a placeholder whose media\n\t * was not imported.\n\t */\n\tasync resolveMediaRefs<R extends { kind: RecordKind; id: string }>(\n\t\trecords: readonly R[],\n\t\tlines: readonly string[],\n\t): Promise<R[]> {\n\t\tconst mediaIds = new Set<string>();\n\t\tlet marked = false;\n\t\tfor (const line of lines) {\n\t\t\tif (!line.includes(MEDIA_PLACEHOLDER_PREFIX)) continue;\n\t\t\tmarked = true;\n\t\t\tfor (const match of line.matchAll(PLACEHOLDER_TOKEN)) {\n\t\t\t\tif (match[2] !== undefined) mediaIds.add(match[2]);\n\t\t\t}\n\t\t}\n\t\tif (!marked) return [...records];\n\t\tconst mediaIdToKey = await this.identity.getMany(MEDIA_STORAGE_KEY_ENTITY, [...mediaIds]);\n\t\treturn records.map((record) => {\n\t\t\tconst result = rewriteMediaRefs(record, { mode: \"import\", mediaIdToKey });\n\t\t\tconst error = result.errors[0];\n\t\t\tif (error) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_MEDIA_REF_INVALID\", \"Unresolved media reference\", {\n\t\t\t\t\tdetail: { kind: record.kind, id: record.id, path: error.path },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn result.value;\n\t\t});\n\t}\n\n\t/** Record kinds that have at least one rewritten id in this import. */\n\trewrittenKinds(): Promise<Set<string>> {\n\t\tthis.#rewrittenKinds ??= this.db\n\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t.select(\"entity_kind\")\n\t\t\t.distinct()\n\t\t\t.where(\"operation_id\", \"=\", this.operation.id)\n\t\t\t.execute()\n\t\t\t.then((rows) => new Set(rows.map((row) => row.entity_kind).filter(isRecordKindName)));\n\t\treturn this.#rewrittenKinds;\n\t}\n\n\tnoteRewrite(kind: RecordKind): void {\n\t\tconst current = this.#rewrittenKinds;\n\t\tthis.#rewrittenKinds = (current ?? Promise.resolve(new Set<string>())).then((kinds) =>\n\t\t\tkinds.add(kind),\n\t\t);\n\t}\n\n\t/**\n\t * Target ids for the records' own ids and every `by: \"id\"` reference,\n\t * keyed `kind\\u0000portableId`. Ids without a rewrite are absent.\n\t */\n\tasync rewrittenIds(\n\t\tkind: RecordKind,\n\t\trecords: ReadonlyArray<Record<string, unknown>>,\n\t): Promise<Map<string, string>> {\n\t\tconst rewritten = await this.rewrittenKinds();\n\t\tconst result = new Map<string, string>();\n\t\tif (rewritten.size === 0) return result;\n\t\tconst wanted = new Map<string, Set<string>>();\n\t\tconst want = (targetKind: RecordKind, id: unknown) => {\n\t\t\tif (typeof id !== \"string\" || !rewritten.has(targetKind)) return;\n\t\t\tlet ids = wanted.get(targetKind);\n\t\t\tif (!ids) wanted.set(targetKind, (ids = new Set()));\n\t\t\tids.add(id);\n\t\t};\n\t\tfor (const record of records) {\n\t\t\twant(kind, record.id);\n\t\t\tfor (const reference of KIND_REFERENCES[kind]) {\n\t\t\t\tif (reference.by !== \"id\") continue;\n\t\t\t\tfor (const target of reference.targets) want(target, record[reference.property]);\n\t\t\t}\n\t\t}\n\t\tfor (const [targetKind, ids] of wanted) {\n\t\t\tfor (const [portableId, targetId] of await this.identity.getMany(targetKind, [...ids])) {\n\t\t\t\tresult.set(`${targetKind}\\u0000${portableId}`, targetId);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\nfunction isRecordKindName(value: string): boolean {\n\treturn RECORD_KIND_NAMES.has(value);\n}\n\nfunction toFieldColumnType(value: string): FieldColumnType {\n\tswitch (value) {\n\t\tcase \"REAL\":\n\t\tcase \"INTEGER\":\n\t\tcase \"JSON\":\n\t\t\treturn value;\n\t\tdefault:\n\t\t\treturn \"TEXT\";\n\t}\n}\n\n/** Apply rewritten ids to a record's own id and `by: \"id\"` references. */\nexport function applyRewrittenIds<R extends { kind: RecordKind; id: string }>(\n\trecord: R,\n\trewritten: ReadonlyMap<string, string>,\n): R {\n\tif (rewritten.size === 0) return record;\n\tconst next: Record<string, unknown> = { ...record };\n\tconst own = rewritten.get(`${record.kind}\\u0000${record.id}`);\n\tif (own !== undefined) next.id = own;\n\tfor (const reference of KIND_REFERENCES[record.kind]) {\n\t\tif (reference.by !== \"id\") continue;\n\t\tconst value = next[reference.property];\n\t\tif (typeof value !== \"string\") continue;\n\t\tfor (const target of reference.targets) {\n\t\t\tconst mapped = rewritten.get(`${target}\\u0000${value}`);\n\t\t\tif (mapped !== undefined) {\n\t\t\t\tnext[reference.property] = mapped;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- same record with id-valued properties replaced\n\treturn next as R;\n}\n","/**\n * Deterministic ids and opaque values derived from an import operation, so a\n * replayed batch writes exactly what the interrupted attempt wrote.\n */\n\nimport { sha256Hex } from \"../format/digest.js\";\n\nconst CROCKFORD = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\n\n/**\n * A ULID-shaped id (26 Crockford base32 characters) derived from the SHA-256\n * of `parts`. Stable for the same inputs; the leading character is always in\n * `0`–`7`, as in a real ULID.\n */\nexport async function ulidFromHash(...parts: string[]): Promise<string> {\n\tconst hex = await sha256Hex(parts.join(\"\\u0000\"));\n\tlet bits = BigInt(`0x${hex.slice(0, 32)}`);\n\tlet id = \"\";\n\tfor (let index = 0; index < 26; index++) {\n\t\tid = CROCKFORD[Number(bits & 31n)] + id;\n\t\tbits >>= 5n;\n\t}\n\treturn id;\n}\n\n/** Hex HMAC-SHA-256 of `message` under `secret`. */\nexport async function hmacHex(secret: string, message: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tencoder.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"sign\"],\n\t);\n\tconst signature = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(message));\n\treturn Array.from(new Uint8Array(signature), (byte) => byte.toString(16).padStart(2, \"0\")).join(\n\t\t\"\",\n\t);\n}\n","/**\n * Per-kind writers for every record kind that maps to one row of a fixed\n * table (everything except collections, fields, and entries).\n *\n * A batch is inserted with `ON CONFLICT DO NOTHING` and read back; each\n * stored row must equal the row the importer meant to write, so replaying a\n * batch after an interruption is a no-op. When a row keyed by a portable id\n * already exists with different content, that id belongs to an unrelated\n * target row: the record is written under a deterministic rewritten id,\n * recorded in the identity map, and later `by: \"id\"` references follow it.\n * Any other conflict (another unique constraint, a row that differs after a\n * rewrite) fails the batch with `TRANSFER_IMPORT_ERROR`; where the database\n * has transactions, the failed batch leaves no rows behind.\n */\n\nimport { sql } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { withTransaction } from \"../../database/transaction.js\";\nimport { fingerprintBlockFields } from \"../../schema/block-type-contract.js\";\nimport type { BlockFieldDefinition } from \"../../schema/block-types.js\";\nimport { TransferError } from \"../errors.js\";\nimport { getPortableTableSpecForKind } from \"../format/columns.js\";\nimport type { ColumnCodec } from \"../format/columns.js\";\nimport type { RecordKind, RecordOfKind, SitePackageRecord } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { DECIDED_SETTING_NAMES } from \"../format/settings.js\";\nimport { applyTransformations } from \"../format/transformations.js\";\nimport { applyRewrittenIds, type ImportContext } from \"./context.js\";\nimport { hmacHex, ulidFromHash } from \"./ids.js\";\nimport { encodeRecord, firstDifference, recordCodecs, type Row } from \"./rows.js\";\nimport { estimateStatements, insertRows, selectByKeys, type ConflictAction } from \"./sql.js\";\n\nexport type FlatKind = Exclude<RecordKind, \"principal\" | \"collection\" | \"field\" | \"entry\">;\n\ninterface FlatKindConfig {\n\t/** Columns identifying a row. Only `[\"id\"]` kinds can have their id rewritten. */\n\tkey: readonly string[];\n\tconflict?: ConflictAction;\n\t/** Columns the importer fills that records do not carry. */\n\tderived?: (context: ImportContext, record: SitePackageRecord) => Promise<Row> | Row;\n}\n\nconst ID_KEY = [\"id\"] as const;\n\nasync function blockTypeVersionFingerprint(record: SitePackageRecord): Promise<Row> {\n\tif (record.kind !== \"block_type_version\") throw new Error(\"Expected a block type version\");\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- analysis refuses fields that `validateBlockFields` rejects\n\tconst fields = record.fields as unknown as BlockFieldDefinition[];\n\treturn { fingerprint: await fingerprintBlockFields(fields) };\n}\n\nconst FLAT_KINDS: Readonly<Record<FlatKind, FlatKindConfig>> = {\n\tblock_type: { key: ID_KEY },\n\tblock_type_version: {\n\t\tkey: ID_KEY,\n\t\tderived: (_context, record) => blockTypeVersionFingerprint(record),\n\t},\n\ttaxonomy_def: { key: ID_KEY },\n\trelation: { key: ID_KEY },\n\tbyline_field: { key: ID_KEY },\n\tmedia_folder: { key: ID_KEY },\n\tmedia: { key: ID_KEY },\n\tterm: { key: ID_KEY },\n\tbyline: { key: ID_KEY },\n\tbyline_field_value: { key: [\"byline_id\", \"field_id\"] },\n\tbyline_field_group_value: { key: [\"translation_group\", \"field_id\"] },\n\trevision: { key: ID_KEY },\n\tcontent_term: { key: [\"collection\", \"entry_id\", \"taxonomy_id\"] },\n\tcontent_byline: { key: ID_KEY },\n\tcontent_reference: { key: ID_KEY },\n\tseo: { key: [\"collection\", \"content_id\"] },\n\tmenu: { key: ID_KEY },\n\tmenu_item: { key: ID_KEY },\n\twidget_area: { key: ID_KEY },\n\twidget: { key: ID_KEY },\n\tsection: { key: ID_KEY },\n\tredirect: {\n\t\tkey: ID_KEY,\n\t\tderived: () => ({ config_revision: ulid(), source_guard: 1, write_generation: 0 }),\n\t},\n\tcomment: { key: ID_KEY },\n\tcomment_reaction: {\n\t\tkey: ID_KEY,\n\t\tderived: async (context, record) => ({\n\t\t\tvoter_hash: await hmacHex(context.operation.stagingSecret, `comment_reaction:${record.id}`),\n\t\t}),\n\t},\n\tsetting: {\n\t\tkey: [\"name\"],\n\t\tconflict: { type: \"update\", target: [\"name\"], update: [\"value\", \"revision\"] },\n\t\tderived: () => ({ revision: ulid() }),\n\t},\n};\n\nconst NO_FIELD_COLUMNS = new Map();\n\n/**\n * Identity-map kind recording each redirect the importer wrote disabled\n * because it would close a loop with the redirects written before it.\n * Verification reads it to predict those redirects.\n */\nexport const REDIRECT_LOOP_ENTITY = \"redirect_loop_disabled\";\n\n/** Redirects checked for loops per query: up to three bound parameters each. */\nconst REDIRECT_LOOP_BATCH = rowsPerInsert(3);\n\nexport function isFlatKind(kind: RecordKind): kind is FlatKind {\n\treturn Object.hasOwn(FLAT_KINDS, kind);\n}\n\nfunction tableOf(kind: FlatKind) {\n\tconst spec = getPortableTableSpecForKind(kind);\n\tif (!spec) throw new Error(`No table for kind ${kind}`);\n\treturn spec;\n}\n\n/** Statements one `writeRecords` call for `count` records of `kind` needs. */\nexport function estimateWrite(kind: FlatKind, count: number): number {\n\tconst spec = tableOf(kind);\n\tconst statements = (rows: number) =>\n\t\testimateStatements(rows, Object.keys(spec.columns).length, FLAT_KINDS[kind].key.length) + 3;\n\tif (kind !== \"redirect\") return statements(count);\n\tconst batches = Math.ceil(count / REDIRECT_LOOP_BATCH);\n\treturn batches * (3 + statements(REDIRECT_LOOP_BATCH));\n}\n\nexport interface WriteInput<K extends RecordKind> {\n\trecord: RecordOfKind<K>;\n\t/** The record's canonical line, scanned for media placeholders. */\n\tline: string;\n}\n\nexport interface WriteOptions {\n\t/** Extra columns per portable id, compared like record columns. */\n\textra?: (record: { id: string }) => { row: Row; codecs: Readonly<Record<string, ColumnCodec>> };\n}\n\n/** Records that were actually written (decided settings may be skipped). */\nexport async function writeRecords<K extends FlatKind>(\n\tcontext: ImportContext,\n\tkind: K,\n\tinputs: ReadonlyArray<WriteInput<K>>,\n\toptions: WriteOptions = {},\n): Promise<Array<RecordOfKind<K>>> {\n\tconst skipped = skippedSettings(context);\n\tconst selected = inputs.filter((input) => kind !== \"setting\" || !skipped.has(input.record.id));\n\tif (selected.length === 0) return [];\n\tconst transformed = selected.map((input) =>\n\t\tapplyTransformations(input.record, context.plan, { fieldColumnTypes: NO_FIELD_COLUMNS }),\n\t);\n\tconst resolved = await context.resolveMediaRefs(\n\t\ttransformed,\n\t\tselected.map((input) => input.line),\n\t);\n\tif (kind !== \"redirect\") {\n\t\tawait writeResolved(context, kind, resolved, options, false);\n\t\treturn resolved;\n\t}\n\tconst written: Array<RecordOfKind<K>> = [];\n\tfor (let start = 0; start < resolved.length; start += REDIRECT_LOOP_BATCH) {\n\t\tconst batch = resolved.slice(start, start + REDIRECT_LOOP_BATCH);\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- kind is \"redirect\"\n\t\tconst redirects = await disableLoopClosers(context, batch as Array<RecordOfKind<\"redirect\">>);\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- the same redirect records\n\t\tconst records = redirects as unknown as Array<RecordOfKind<K>>;\n\t\tawait writeResolved(context, kind, records, options, false);\n\t\twritten.push(...records);\n\t}\n\treturn written;\n}\n\n/**\n * The database refuses an enabled redirect that closes a loop of enabled\n * redirects (by exact source and destination). An origin can still hold such\n * a loop, and analysis only finds loops in packages of up to\n * `MAX_LOOP_CHECKED_REDIRECTS` redirects, so each redirect that would close\n * one with the redirects written before it (target rows, then the enabled\n * earlier records of `records`) is written disabled and recorded under\n * {@link REDIRECT_LOOP_ENTITY}. Rows of `records` already in the table (from\n * an interrupted attempt) are ignored, so a replay decides the same way.\n */\nasync function disableLoopClosers(\n\tcontext: ImportContext,\n\trecords: ReadonlyArray<RecordOfKind<\"redirect\">>,\n): Promise<Array<RecordOfKind<\"redirect\">>> {\n\tconst candidates = records.filter((record) => record.enabled && record.destination !== \"\");\n\tif (candidates.length === 0) return [...records];\n\tconst reach = await reachableSources(context, candidates);\n\n\tconst closers = new Set<string>();\n\tcandidates.forEach((record, index) => {\n\t\tconst earlier = candidates.slice(0, index).filter((other) => !closers.has(other.id));\n\t\tconst queue = [{ node: record.destination, moved: false }];\n\t\tconst taken = new Set<string>();\n\t\twhile (queue.length > 0) {\n\t\t\tconst { node, moved } = queue.shift()!;\n\t\t\tfor (const source of reach.get(node) ?? []) {\n\t\t\t\t// Reaching the start node itself without following a redirect is not a loop.\n\t\t\t\tif (source === record.source && (moved || source !== node)) {\n\t\t\t\t\tclosers.add(record.id);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const other of earlier) {\n\t\t\t\t\tif (other.source !== source || taken.has(other.id)) continue;\n\t\t\t\t\ttaken.add(other.id);\n\t\t\t\t\tqueue.push({ node: other.destination, moved: true });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\tif (closers.size === 0) return [...records];\n\tawait context.identity.putMany(\n\t\tREDIRECT_LOOP_ENTITY,\n\t\tArray.from(closers, (id) => ({ portableId: id, targetId: id })),\n\t);\n\treturn records.map((record) => (closers.has(record.id) ? { ...record, enabled: false } : record));\n}\n\n/**\n * For each candidate's destination, the candidate sources reachable from it\n * through enabled target redirects (including the destination itself when it\n * is one). Follows `idx_redirects_source` from each destination only;\n * `enabled <> 0` rather than `enabled = 1` keeps SQLite from choosing\n * `idx_redirects_enabled` and scanning every enabled redirect per step.\n */\nasync function reachableSources(\n\tcontext: ImportContext,\n\tcandidates: ReadonlyArray<RecordOfKind<\"redirect\">>,\n): Promise<Map<string, Set<string>>> {\n\tconst starts = [...new Set(candidates.map((record) => record.destination))];\n\tconst sources = [...new Set(candidates.map((record) => record.source))];\n\tconst result = await sql<{ start: string; node: string }>`\n\t\tWITH RECURSIVE starts(node) AS (VALUES ${sql.join(starts.map((node) => sql`(${node})`))}),\n\t\treach(start, node) AS (\n\t\t\tSELECT node, node FROM starts\n\t\t\tUNION\n\t\t\tSELECT reach.start, redirect.destination\n\t\t\tFROM reach JOIN _emdash_redirects AS redirect ON redirect.source = reach.node\n\t\t\tWHERE redirect.enabled <> 0 AND redirect.destination <> ''\n\t\t\t\tAND redirect.id NOT IN (${sql.join(candidates.map((record) => record.id))})\n\t\t)\n\t\tSELECT start, node FROM reach WHERE node IN (${sql.join(sources)})\n\t`.execute(context.db);\n\tconst reach = new Map<string, Set<string>>();\n\tfor (const row of result.rows) {\n\t\tconst reached = reach.get(row.start) ?? new Set<string>();\n\t\treached.add(row.node);\n\t\treach.set(row.start, reached);\n\t}\n\treturn reach;\n}\n\nfunction skippedSettings(context: ImportContext): ReadonlySet<string> {\n\tconst { decisions } = context.plan;\n\treturn new Set<string>([\n\t\t...(decisions.siteTitle === \"target\" ? DECIDED_SETTING_NAMES.title : []),\n\t\t...(decisions.siteTagline === \"target\" ? DECIDED_SETTING_NAMES.tagline : []),\n\t]);\n}\n\nfunction keyString(key: readonly string[], row: Row): string {\n\treturn key.map((column) => String(row[column])).join(\"\\u0000\");\n}\n\nexport function uniqueConflict(kind: RecordKind, id: string): TransferError {\n\treturn new TransferError(\n\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\"Record conflicts with another target row on a unique key\",\n\t\t{ detail: { kind, id, reason: \"unique_conflict\" } },\n\t);\n}\n\n/**\n * Decide what a stored row that differs from its record means. The row can\n * be one this import wrote in an interrupted attempt of the same unit: then\n * the difference is an importer defect, never a collision, and the import\n * fails with `stored_row_mismatch`. Only on a unit's first attempt can the row\n * predate the import, and only a row keyed by the record's own id can then\n * move aside: the record is rewritten to a new id. Anything else is a\n * `collision` the import cannot resolve.\n */\nexport function assertRewritable(\n\tcontext: ImportContext,\n\trow: { kind: RecordKind; id: string; column: string; idKeyed: boolean; rewritten: boolean },\n): void {\n\tconst detail = { kind: row.kind, id: row.id, column: row.column };\n\tif (!context.firstAttempt) {\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\"A row this import wrote does not read back as its record\",\n\t\t\t{ detail: { ...detail, reason: \"stored_row_mismatch\" } },\n\t\t);\n\t}\n\tif (!row.idKeyed || row.rewritten) {\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\"Record collides with an existing target row\",\n\t\t\t{\n\t\t\t\tdetail: { ...detail, reason: \"collision\" },\n\t\t\t},\n\t\t);\n\t}\n}\n\nasync function writeResolved<K extends FlatKind>(\n\tcontext: ImportContext,\n\tkind: K,\n\trecords: ReadonlyArray<RecordOfKind<K>>,\n\toptions: WriteOptions,\n\tretry: boolean,\n): Promise<void> {\n\tconst spec = tableOf(kind);\n\tconst config = FLAT_KINDS[kind];\n\tconst rewritten = await context.rewrittenIds(kind, records);\n\tconst codecs: Record<string, ColumnCodec> = { ...recordCodecs(spec.columns) };\n\tconst rows: Row[] = [];\n\tfor (const record of records) {\n\t\tconst target = applyRewrittenIds(record, rewritten);\n\t\tconst row = {\n\t\t\t...encodeRecord(context.db, spec.columns, target, { kind, id: record.id }),\n\t\t\t...(config.derived ? await config.derived(context, record) : {}),\n\t\t};\n\t\tconst extra = options.extra?.(record);\n\t\tif (extra) {\n\t\t\tObject.assign(row, extra.row);\n\t\t\tObject.assign(codecs, extra.codecs);\n\t\t}\n\t\trows.push(row);\n\t}\n\tconst columns = Object.keys(rows[0] ?? {});\n\tconst collisions = await withTransaction(context.db, async (trx) => {\n\t\tawait insertRows(trx, spec.table, columns, rows, config.conflict);\n\t\tconst stored = new Map(\n\t\t\t(await selectByKeys(trx, spec.table, config.key, rows)).map((row) => [\n\t\t\t\tkeyString(config.key, row),\n\t\t\t\trow,\n\t\t\t]),\n\t\t);\n\t\tconst found: Array<RecordOfKind<K>> = [];\n\t\trows.forEach((row, index) => {\n\t\t\tconst record = records[index];\n\t\t\tif (!record) return;\n\t\t\tconst existing = stored.get(keyString(config.key, row));\n\t\t\tif (!existing) throw uniqueConflict(kind, record.id);\n\t\t\tconst column = firstDifference(context.db, codecs, row, existing, { float4: context.float4 });\n\t\t\tif (column === null) return;\n\t\t\tassertRewritable(context, {\n\t\t\t\tkind,\n\t\t\t\tid: record.id,\n\t\t\t\tcolumn,\n\t\t\t\tidKeyed: config.key === ID_KEY,\n\t\t\t\trewritten: retry || rewritten.has(`${kind}\\u0000${record.id}`),\n\t\t\t});\n\t\t\tfound.push(record);\n\t\t});\n\t\treturn found;\n\t});\n\tif (collisions.length === 0) return;\n\n\tconst mappings = await Promise.all(\n\t\tcollisions.map(async (record) => ({\n\t\t\tportableId: record.id,\n\t\t\ttargetId: await ulidFromHash(context.operationId, kind, record.id),\n\t\t})),\n\t);\n\tawait context.identity.putMany(kind, mappings);\n\tcontext.noteRewrite(kind);\n\tawait writeResolved(context, kind, collisions, options, true);\n}\n","/**\n * Entry writer: rows of the dynamic `ec_*` content tables.\n *\n * Standard columns come from `CONTENT_TABLE_COLUMNS`, field columns from the\n * imported `_emdash_fields` rows. A row that needs more bound parameters than\n * one D1 statement allows is inserted with its standard columns first and\n * its field columns set by batched `UPDATE`s, after checking that the stored\n * standard columns are the importer's own.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { withTransaction } from \"../../database/transaction.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { validateIdentifier } from \"../../database/validate.js\";\nimport { TransferError } from \"../errors.js\";\nimport {\n\tcodecForColumnType,\n\tCONTENT_TABLE_COLUMNS,\n\tCONTENT_TABLE_PREFIX,\n} from \"../format/columns.js\";\nimport type { ColumnCodec } from \"../format/columns.js\";\nimport type { EntryRecord } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { applyTransformations, type FieldColumnType } from \"../format/transformations.js\";\nimport { applyRewrittenIds, type ImportContext } from \"./context.js\";\nimport { ulidFromHash } from \"./ids.js\";\nimport { encodeRecord, encodeValue, firstDifference, recordCodecs, type Row } from \"./rows.js\";\nimport { estimateStatements, insertRows, selectByKeys, updateColumns } from \"./sql.js\";\nimport { assertRewritable, uniqueConflict, type WriteInput } from \"./writers.js\";\n\nconst STANDARD_CODECS = recordCodecs(CONTENT_TABLE_COLUMNS);\nconst STANDARD_COLUMNS = Object.keys(STANDARD_CODECS);\n\nexport function contentTable(collection: string): string {\n\tvalidateIdentifier(collection, \"collection slug\");\n\treturn `${CONTENT_TABLE_PREFIX}${collection}`;\n}\n\n/** Statements for `count` entries of a collection with `fieldCount` fields. */\nexport function estimateEntryWrite(count: number, fieldCount: number): number {\n\tconst columns = STANDARD_COLUMNS.length + fieldCount;\n\tif (rowsPerInsert(columns) === 0) {\n\t\treturn count * (2 + Math.ceil(fieldCount / 99)) + Math.ceil(count / 100) + 3;\n\t}\n\treturn estimateStatements(count, columns) + 3;\n}\n\nexport async function writeEntries(\n\tcontext: ImportContext,\n\tinputs: ReadonlyArray<WriteInput<\"entry\">>,\n): Promise<void> {\n\tconst byCollection = new Map<string, Array<WriteInput<\"entry\">>>();\n\tfor (const input of inputs) {\n\t\tconst list = byCollection.get(input.record.collection) ?? [];\n\t\tlist.push(input);\n\t\tbyCollection.set(input.record.collection, list);\n\t}\n\tfor (const [collection, group] of byCollection) {\n\t\tconst fieldColumns = await context.fieldColumns(collection);\n\t\tconst fieldColumnTypes = new Map([[collection, fieldColumns]]);\n\t\tconst transformed = group.map((input) =>\n\t\t\tapplyTransformations(input.record, context.plan, { fieldColumnTypes }),\n\t\t);\n\t\tconst resolved = await context.resolveMediaRefs(\n\t\t\ttransformed,\n\t\t\tgroup.map((input) => input.line),\n\t\t);\n\t\tawait writeCollectionEntries(context, collection, fieldColumns, resolved, false);\n\t}\n}\n\nfunction fieldCodecs(\n\tfieldColumns: ReadonlyMap<string, FieldColumnType>,\n): Record<string, ColumnCodec> {\n\tconst codecs: Record<string, ColumnCodec> = {};\n\tfor (const [slug, columnType] of fieldColumns) codecs[slug] = codecForColumnType(columnType);\n\treturn codecs;\n}\n\nfunction entryRow(\n\tdb: Kysely<Database>,\n\trecord: EntryRecord,\n\tcodecs: Readonly<Record<string, ColumnCodec>>,\n\trequired: ReadonlySet<string>,\n): Row {\n\tconst row = encodeRecord(db, CONTENT_TABLE_COLUMNS, record, { kind: \"entry\", id: record.id });\n\tfor (const slug of Object.keys(record.fields)) {\n\t\tif (!Object.hasOwn(codecs, slug)) {\n\t\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Entry has a field its collection lacks\", {\n\t\t\t\tdetail: { kind: \"entry\", id: record.id, field: slug },\n\t\t\t});\n\t\t}\n\t}\n\tfor (const [slug, codec] of Object.entries(codecs)) {\n\t\trow[slug] = encodeValue(\n\t\t\tdb,\n\t\t\tcodec,\n\t\t\trecord.fields[slug],\n\t\t\t{ kind: \"entry\", id: record.id, column: slug },\n\t\t\t{ notNull: required.has(slug) },\n\t\t);\n\t}\n\treturn row;\n}\n\nasync function writeCollectionEntries(\n\tcontext: ImportContext,\n\tcollection: string,\n\tfieldColumns: ReadonlyMap<string, FieldColumnType>,\n\trecords: readonly EntryRecord[],\n\tretry: boolean,\n): Promise<void> {\n\tconst table = contentTable(collection);\n\tconst fields = fieldCodecs(fieldColumns);\n\tconst required = await context.requiredFields(collection);\n\tconst codecs = { ...STANDARD_CODECS, ...fields };\n\tconst rewritten = await context.rewrittenIds(\"entry\", records);\n\tconst rows = records.map((record) =>\n\t\tentryRow(context.db, applyRewrittenIds(record, rewritten), fields, required),\n\t);\n\tconst columns = Object.keys(codecs);\n\tconst wide = rowsPerInsert(columns.length) === 0;\n\n\tconst collisions = await withTransaction(context.db, async (trx) => {\n\t\tawait insertRows(trx, table, wide ? STANDARD_COLUMNS : columns, rows);\n\t\tlet stored = await storedById(trx, table, rows);\n\t\tif (wide) {\n\t\t\tconst fieldSlugs = Object.keys(fields);\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst existing = stored.get(String(row.id));\n\t\t\t\tif (\n\t\t\t\t\t!existing ||\n\t\t\t\t\tfirstDifference(context.db, STANDARD_CODECS, row, existing, {\n\t\t\t\t\t\tfloat4: context.float4,\n\t\t\t\t\t}) !== null\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait updateColumns(trx, table, \"id\", String(row.id), row, fieldSlugs);\n\t\t\t}\n\t\t\tstored = await storedById(trx, table, rows);\n\t\t}\n\n\t\tconst found: EntryRecord[] = [];\n\t\trows.forEach((row, index) => {\n\t\t\tconst record = records[index];\n\t\t\tif (!record) return;\n\t\t\tconst existing = stored.get(String(row.id));\n\t\t\tif (!existing) throw uniqueConflict(\"entry\", record.id);\n\t\t\tconst column = firstDifference(context.db, codecs, row, existing, {\n\t\t\t\tfloat4: context.float4,\n\t\t\t});\n\t\t\tif (column === null) return;\n\t\t\tassertRewritable(context, {\n\t\t\t\tkind: \"entry\",\n\t\t\t\tid: record.id,\n\t\t\t\tcolumn,\n\t\t\t\tidKeyed: true,\n\t\t\t\trewritten: retry || rewritten.has(`entry\\u0000${record.id}`),\n\t\t\t});\n\t\t\tfound.push(record);\n\t\t});\n\t\treturn found;\n\t});\n\tif (collisions.length === 0) return;\n\n\tconst mappings = await Promise.all(\n\t\tcollisions.map(async (record) => ({\n\t\t\tportableId: record.id,\n\t\t\ttargetId: await ulidFromHash(context.operationId, \"entry\", record.id),\n\t\t})),\n\t);\n\tawait context.identity.putMany(\"entry\", mappings);\n\tcontext.noteRewrite(\"entry\");\n\tawait writeCollectionEntries(context, collection, fieldColumns, collisions, true);\n}\n\nasync function storedById(\n\tdb: Kysely<Database>,\n\ttable: string,\n\trows: readonly Row[],\n): Promise<Map<string, Row>> {\n\tconst stored = await selectByKeys(db, table, [\"id\"], rows);\n\treturn new Map(stored.map((row) => [String(row.id), row]));\n}\n","/**\n * Media writer: one target object per media row.\n *\n * Each media row's bytes are copied from its staged blob to a deterministic\n * target key, `${ulidFromHash(operationId, mediaId)}${ext}`, so an\n * interrupted copy is simply repeated. An upload attempt is registered before\n * the copy so media cleanup reclaims the object if the import is abandoned\n * before the row exists. The copy is verified against the blob's declared\n * size and SHA-256, and the row's `content_hash` is recomputed from the bytes\n * exactly as uploads do (SHA-1, only up to `MAX_CONTENT_HASH_BYTES`).\n */\n\nimport mime from \"mime/lite\";\n\nimport { MediaRepository } from \"../../database/repositories/media.js\";\nimport { computeContentHash, MAX_CONTENT_HASH_BYTES } from \"../../utils/hash.js\";\nimport { TransferError } from \"../errors.js\";\nimport type { MediaRecord } from \"../format/kinds.js\";\nimport { mediaBlobPath } from \"../format/paths.js\";\nimport { MEDIA_STORAGE_KEY_ENTITY } from \"../ops/identity-map.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport { putVerified } from \"../staging/stage.js\";\nimport type { ImportContext } from \"./context.js\";\nimport { ulidFromHash } from \"./ids.js\";\nimport { writeRecords, type WriteInput } from \"./writers.js\";\n\nconst EXTENSION = /\\.[A-Za-z0-9]{1,16}$/;\nconst MIME_EXTENSION = /^[a-z0-9]{1,16}$/;\n\nexport function mediaExtension(record: Pick<MediaRecord, \"filename\" | \"mimeType\">): string {\n\tconst fromName = EXTENSION.exec(record.filename)?.[0];\n\tif (fromName) return fromName.toLowerCase();\n\tconst fromType = mime.getExtension(record.mimeType);\n\treturn fromType && MIME_EXTENSION.test(fromType) ? `.${fromType}` : \"\";\n}\n\nexport async function mediaStorageKey(\n\tcontext: ImportContext,\n\trecord: MediaRecord,\n): Promise<string> {\n\treturn `${await ulidFromHash(context.operationId, \"media\", record.id)}${mediaExtension(record)}`;\n}\n\n/** Declared size of a media row's staged blob. */\nexport async function blobBytes(context: ImportContext, record: MediaRecord): Promise<number> {\n\tconst staged = await new TransferStagedFileRepository(context.db).get(\n\t\tcontext.operationId,\n\t\tmediaBlobPath(record.blob),\n\t);\n\tif (!staged || staged.state !== \"verified\") {\n\t\tthrow new TransferError(\"TRANSFER_MEDIA_BLOB_MISSING\", \"Media blob is not staged\", {\n\t\t\tdetail: { kind: \"media\", id: record.id },\n\t\t});\n\t}\n\treturn staged.bytes;\n}\n\n/** Statements `writeMedia` needs for one row. */\nexport const MEDIA_ROW_STATEMENTS = 12;\n\nexport async function writeMedia(\n\tcontext: ImportContext,\n\tinput: WriteInput<\"media\">,\n\tbytes: number,\n): Promise<void> {\n\tconst record = input.record;\n\tconst storageKey = await mediaStorageKey(context, record);\n\tawait context.identity.put(MEDIA_STORAGE_KEY_ENTITY, {\n\t\tportableId: record.id,\n\t\ttargetId: storageKey,\n\t});\n\n\tconst rewritten = await context.rewrittenIds(\"media\", [record]);\n\tconst targetId = rewritten.get(`media\\u0000${record.id}`) ?? record.id;\n\tconst existing = await context.db\n\t\t.selectFrom(\"media\")\n\t\t.select([\"storage_key\", \"status\"])\n\t\t.where(\"id\", \"=\", targetId)\n\t\t.executeTakeFirst();\n\n\tlet contentHash: string | null = null;\n\tconst ours = existing?.storage_key === storageKey;\n\tif (ours) {\n\t\tconst stored = await context.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.select(\"content_hash\")\n\t\t\t.where(\"id\", \"=\", targetId)\n\t\t\t.executeTakeFirstOrThrow();\n\t\tcontentHash = stored.content_hash;\n\t} else {\n\t\tconst media = new MediaRepository(context.db);\n\t\tif (!(await media.hasUploadAttempt(storageKey))) {\n\t\t\tawait media.createUploadAttempt(targetId, storageKey);\n\t\t}\n\t\tcontentHash = await copyBlob(context, record, storageKey, bytes);\n\t}\n\n\tawait writeRecords(context, \"media\", [input], {\n\t\textra: () => ({\n\t\t\trow: { storage_key: storageKey, content_hash: contentHash, status: \"ready\" },\n\t\t\tcodecs: { storage_key: \"text\", status: \"text\" },\n\t\t}),\n\t});\n\tif (!ours) await new MediaRepository(context.db).deleteUploadAttempt(storageKey);\n}\n\nasync function copyBlob(\n\tcontext: ImportContext,\n\trecord: MediaRecord,\n\tstorageKey: string,\n\tbytes: number,\n): Promise<string | null> {\n\tconst retained: Uint8Array[] = [];\n\tlet retainedBytes = 0;\n\tconst keepForHash = bytes > 0 && bytes <= MAX_CONTENT_HASH_BYTES;\n\tconst tap = new TransformStream<Uint8Array, Uint8Array>({\n\t\ttransform(chunk, controller) {\n\t\t\tif (keepForHash && retainedBytes + chunk.byteLength <= MAX_CONTENT_HASH_BYTES) {\n\t\t\t\tretained.push(chunk.slice());\n\t\t\t\tretainedBytes += chunk.byteLength;\n\t\t\t}\n\t\t\tcontroller.enqueue(chunk);\n\t\t},\n\t});\n\tconst body = (await context.reader.blob(record.blob)).pipeThrough(tap);\n\tawait putVerified(\n\t\tcontext.storage,\n\t\tstorageKey,\n\t\tbody,\n\t\t{ bytes, sha256: record.blob },\n\t\t{ contentType: record.mimeType },\n\t);\n\tif (!keepForHash || retainedBytes !== bytes) return null;\n\tconst all = new Uint8Array(retainedBytes);\n\tlet offset = 0;\n\tfor (const part of retained) {\n\t\tall.set(part, offset);\n\t\toffset += part.byteLength;\n\t}\n\treturn computeContentHash(all);\n}\n","/**\n * The record stages of an import: each walks its kinds' package streams in\n * order and writes them in bounded units, checkpointing the stream position\n * after every unit.\n */\n\nimport { sql } from \"kysely\";\n\nimport { SchemaError, SchemaRegistry } from \"../../schema/registry.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport {\n\tIMPORT_STAGE_KINDS,\n\tinferredCreditId,\n\ttype ContentBylineRecord,\n\ttype EntryRecord,\n\ttype ImportRecordStage,\n\ttype RecordKind,\n\ttype RecordOfKind,\n} from \"../format/kinds.js\";\nimport type { StreamPosition } from \"../ops/states.js\";\nimport type { StagedRecord } from \"../staging/package.js\";\nimport { applyRewrittenIds, type ImportContext } from \"./context.js\";\nimport { estimateEntryWrite, writeEntries } from \"./entries.js\";\nimport { blobBytes, MEDIA_ROW_STATEMENTS, writeMedia } from \"./media.js\";\nimport { estimateWrite, isFlatKind, writeRecords, type WriteInput } from \"./writers.js\";\n\n/** Identity-map kind linking an unmapped principal's byline, per locale, to its group. */\nexport const PRINCIPAL_BYLINE_ENTITY = \"principal_byline\";\n\n/**\n * Identity-map kind recording each materialized inferred credit: the\n * `content_byline` row id (`inferredCreditId`) mapped to its byline group.\n * Only these rows are materialized credits; a package's own `inferred:` rows\n * are explicit credits like any other.\n */\nexport const INFERRED_CREDIT_ENTITY = \"inferred_credit\";\n\n/**\n * Streams walked by each record stage. Fields are written together with\n * their collection. The relations stage walks the entry stream a second\n * time, after explicit credits exist, to materialize inferred credits.\n */\nexport const STAGE_STREAMS: Readonly<Record<ImportRecordStage, readonly RecordKind[]>> = {\n\t...IMPORT_STAGE_KINDS,\n\tschema: IMPORT_STAGE_KINDS.schema.filter((kind) => kind !== \"field\"),\n\trelations: IMPORT_STAGE_KINDS.relations.flatMap((kind): RecordKind[] =>\n\t\tkind === \"content_byline\" ? [kind, \"entry\"] : [kind],\n\t),\n};\n\nconst DEFAULT_BATCH = 100;\nconst ENTRY_BATCH = 50;\nconst COLLECTION_STATEMENTS = 80;\n\n/** Thrown out of a stage when the operation was asked to cancel. */\nexport class ImportCancelledSignal extends Error {}\n\nexport type Checkpoint = (position: StreamPosition) => Promise<void>;\n\nexport function firstPosition(stage: ImportRecordStage): StreamPosition {\n\tconst kind = STAGE_STREAMS[stage][0];\n\tif (!kind) throw new Error(`Stage ${stage} has no streams`);\n\treturn { kind, seq: 0, line: 0 };\n}\n\n/**\n * Run units of `stage` from `position` until the stage is done (returns\n * null) or the step budget is spent (returns the next position).\n */\nexport async function runRecordStage(\n\tcontext: ImportContext,\n\tstage: ImportRecordStage,\n\tstart: StreamPosition,\n\tcheckpoint: Checkpoint,\n): Promise<StreamPosition | null> {\n\tconst streams = STAGE_STREAMS[stage];\n\tlet position: StreamPosition | null = start;\n\twhile (position) {\n\t\tconst kindIndex = streams.indexOf(position.kind);\n\t\tif (kindIndex === -1) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cursor names an unknown stream\");\n\t\t}\n\t\tif (position.seq >= context.chunkCount(position.kind)) {\n\t\t\tconst next = streams[kindIndex + 1];\n\t\t\tposition = next ? { kind: next, seq: 0, line: 0 } : null;\n\t\t\tcontinue;\n\t\t}\n\t\tconst chunk = await context.chunk(position.kind, position.seq);\n\t\tif (position.line >= chunk.length) {\n\t\t\tposition = { kind: position.kind, seq: position.seq + 1, line: 0 };\n\t\t\tcontinue;\n\t\t}\n\t\tconst unit = await planUnit(context, stage, position, chunk);\n\t\tif (!context.budget.canStart({ queries: unit.queries + 3, bytes: unit.bytes })) {\n\t\t\treturn position;\n\t\t}\n\t\tcontext.budget.start(unit.bytes);\n\t\tawait context.beginUnit(stage, position);\n\t\tawait unit.run();\n\t\tconst line = position.line + unit.count;\n\t\tposition =\n\t\t\tline >= chunk.length\n\t\t\t\t? { kind: position.kind, seq: position.seq + 1, line: 0 }\n\t\t\t\t: { kind: position.kind, seq: position.seq, line };\n\t\tawait checkpoint(position);\n\t}\n\treturn null;\n}\n\ninterface Unit {\n\tcount: number;\n\tqueries: number;\n\tbytes: number;\n\trun: () => Promise<void>;\n}\n\nasync function planUnit(\n\tcontext: ImportContext,\n\tstage: ImportRecordStage,\n\tposition: StreamPosition,\n\tchunk: ReadonlyArray<StagedRecord<RecordKind>>,\n): Promise<Unit> {\n\tconst kind = position.kind;\n\tconst rest = chunk.slice(position.line);\n\n\tif (kind === \"collection\") {\n\t\tconst [staged] = rest;\n\t\tif (!staged || staged.record.kind !== \"collection\") throw new Error(\"Expected a collection\");\n\t\tconst record = staged.record;\n\t\treturn {\n\t\t\tcount: 1,\n\t\t\tqueries: COLLECTION_STATEMENTS,\n\t\t\tbytes: 0,\n\t\t\trun: () => importCollection(context, record),\n\t\t};\n\t}\n\n\tif (kind === \"media\") {\n\t\tconst [staged] = rest;\n\t\tif (!staged || staged.record.kind !== \"media\") throw new Error(\"Expected a media record\");\n\t\tconst input = { record: staged.record, line: staged.line };\n\t\tconst bytes = await blobBytes(context, staged.record);\n\t\treturn {\n\t\t\tcount: 1,\n\t\t\tqueries: MEDIA_ROW_STATEMENTS,\n\t\t\tbytes,\n\t\t\trun: () => writeMedia(context, input, bytes),\n\t\t};\n\t}\n\n\tif (kind === \"entry\") {\n\t\tconst batch = inputsOf(\"entry\", rest.slice(0, ENTRY_BATCH));\n\t\tif (stage === \"relations\") {\n\t\t\treturn {\n\t\t\t\tcount: batch.length,\n\t\t\t\tqueries:\n\t\t\t\t\t4 +\n\t\t\t\t\tMath.ceil(batch.length / SQL_BATCH_SIZE) * 2 +\n\t\t\t\t\testimateWrite(\"content_byline\", batch.length),\n\t\t\t\tbytes: 0,\n\t\t\t\trun: () => materializeInferredCredits(context, batch),\n\t\t\t};\n\t\t}\n\t\tlet queries = 3;\n\t\tconst perCollection = new Map<string, number>();\n\t\tfor (const input of batch) {\n\t\t\tperCollection.set(\n\t\t\t\tinput.record.collection,\n\t\t\t\t(perCollection.get(input.record.collection) ?? 0) + 1,\n\t\t\t);\n\t\t}\n\t\tfor (const [collection, count] of perCollection) {\n\t\t\tconst fields = await context.fieldColumns(collection);\n\t\t\tqueries += estimateEntryWrite(count, fields.size);\n\t\t}\n\t\treturn { count: batch.length, queries, bytes: 0, run: () => writeEntries(context, batch) };\n\t}\n\n\tif (!isFlatKind(kind)) {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cursor names an unknown stream\");\n\t}\n\tconst batch = rest.slice(0, DEFAULT_BATCH);\n\treturn {\n\t\tcount: batch.length,\n\t\tqueries: estimateWrite(kind, batch.length),\n\t\tbytes: 0,\n\t\trun: async () => {\n\t\t\tconst inputs = batch.map((staged) => ({ record: staged.record, line: staged.line }));\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- records of one chunk share its kind\n\t\t\tawait writeRecords(context, kind, inputs as Array<WriteInput<typeof kind>>);\n\t\t\tif (kind === \"byline\") {\n\t\t\t\tawait recordUnmappedBylines(context, inputsOf(\"byline\", batch));\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction inputsOf<K extends RecordKind>(\n\tkind: K,\n\tstaged: ReadonlyArray<StagedRecord<RecordKind>>,\n): Array<WriteInput<K>> {\n\treturn staged.map((item) => {\n\t\tif (item.record.kind !== kind) throw new Error(`Expected ${kind} records`);\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- kind checked above\n\t\treturn { record: item.record as RecordOfKind<K>, line: item.line };\n\t});\n}\n\nasync function importCollection(\n\tcontext: ImportContext,\n\trecord: RecordOfKind<\"collection\">,\n): Promise<void> {\n\tconst fields = (await context.allRecords(\"field\")).filter(\n\t\t(field) => field.collectionId === record.id,\n\t);\n\ttry {\n\t\tawait new SchemaRegistry(context.db).importCollection(record, fields, { resume: true });\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\tthrow new TransferError(\"TRANSFER_IMPORT_ERROR\", \"Collection could not be imported\", {\n\t\t\t\tdetail: { kind: \"collection\", id: record.id, reason: error.code },\n\t\t\t\tcause: error,\n\t\t\t});\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Remember which byline an unmapped principal owns in each locale, so the\n * relations stage can keep that principal's inferred author credits.\n */\nasync function recordUnmappedBylines(\n\tcontext: ImportContext,\n\tinputs: ReadonlyArray<WriteInput<\"byline\">>,\n): Promise<void> {\n\tconst mappings = inputs.flatMap(({ record }) =>\n\t\trecord.userPrincipal !== undefined && context.principalTarget(record.userPrincipal) === null\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tportableId: `${record.locale}:${record.userPrincipal}`,\n\t\t\t\t\t\ttargetId: record.translationGroup ?? record.id,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [],\n\t);\n\tawait context.identity.putMany(PRINCIPAL_BYLINE_ENTITY, mappings);\n}\n\n/**\n * Explicit `content_byline` rows for entries whose author credit would\n * otherwise be inferred from an unmapped principal and vanish on the target:\n * the author is unmapped, the entry has no explicit credit, and the author\n * has a byline in the entry's locale.\n */\nasync function materializeInferredCredits(\n\tcontext: ImportContext,\n\tinputs: ReadonlyArray<WriteInput<\"entry\">>,\n): Promise<void> {\n\tconst candidates = inputs\n\t\t.map((input) => input.record)\n\t\t.filter(\n\t\t\t(record): record is EntryRecord & { authorPrincipal: string } =>\n\t\t\t\trecord.authorPrincipal !== undefined &&\n\t\t\t\trecord.primaryBylineGroup === undefined &&\n\t\t\t\tcontext.principalTarget(record.authorPrincipal) === null,\n\t\t);\n\tif (candidates.length === 0) return;\n\tconst groups = await context.identity.getMany(\n\t\tPRINCIPAL_BYLINE_ENTITY,\n\t\tcandidates.map((record) => `${record.locale}:${record.authorPrincipal}`),\n\t);\n\tconst credited = candidates.filter((record) =>\n\t\tgroups.has(`${record.locale}:${record.authorPrincipal}`),\n\t);\n\tif (credited.length === 0) return;\n\n\tconst rewritten = await context.rewrittenIds(\"entry\", credited);\n\tconst targetIds = credited.map((record) => applyRewrittenIds(record, rewritten).id);\n\tconst explicit = new Set<string>();\n\tfor (const batch of chunks(targetIds, SQL_BATCH_SIZE)) {\n\t\tconst rows = await context.db\n\t\t\t.selectFrom(\"_emdash_content_bylines\")\n\t\t\t.select([\"collection_slug\", \"content_id\"])\n\t\t\t.where(\"content_id\", \"in\", batch)\n\t\t\t.where(({ exists, not, selectFrom }) =>\n\t\t\t\tnot(\n\t\t\t\t\texists(\n\t\t\t\t\t\tselectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t.where(\"_emdash_transfer_identity_map.operation_id\", \"=\", context.operationId)\n\t\t\t\t\t\t\t.where(\"_emdash_transfer_identity_map.entity_kind\", \"=\", INFERRED_CREDIT_ENTITY)\n\t\t\t\t\t\t\t.whereRef(\n\t\t\t\t\t\t\t\t\"_emdash_transfer_identity_map.portable_id\",\n\t\t\t\t\t\t\t\t\"=\",\n\t\t\t\t\t\t\t\t\"_emdash_content_bylines.id\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.execute();\n\t\tfor (const row of rows) explicit.add(`${row.collection_slug}\\u0000${row.content_id}`);\n\t}\n\n\tconst credits: Array<WriteInput<\"content_byline\">> = [];\n\tcredited.forEach((record, index) => {\n\t\tif (explicit.has(`${record.collection}\\u0000${targetIds[index]}`)) return;\n\t\tconst bylineGroup = groups.get(`${record.locale}:${record.authorPrincipal}`);\n\t\tif (bylineGroup === undefined) return;\n\t\tconst credit: ContentBylineRecord = {\n\t\t\tkind: \"content_byline\",\n\t\t\tid: inferredCreditId(record.collection, record.id),\n\t\t\tcollection: record.collection,\n\t\t\tentryId: record.id,\n\t\t\tbylineGroup,\n\t\t\tsortOrder: 0,\n\t\t\t...(record.createdAt === undefined ? {} : { createdAt: record.createdAt }),\n\t\t};\n\t\tcredits.push({ record: credit, line: \"\" });\n\t});\n\tif (credits.length === 0) return;\n\t// Recorded before writing: a resumed unit must still see a written credit as materialized.\n\tawait context.identity.putMany(\n\t\tINFERRED_CREDIT_ENTITY,\n\t\tcredits.map(({ record }) => ({ portableId: record.id, targetId: record.bylineGroup })),\n\t);\n\tawait writeRecords(context, \"content_byline\", credits);\n}\n","/**\n * Import verification: re-read the target through the exporter's readers and\n * compare it to the package, in bounded steps.\n *\n * For every package record chunk (except principals, which are never\n * written), each record's predicted target form is\n * `applyTransformations(record, plan)`. The target row is read with the same\n * reader the exporter uses, rewritten ids are mapped back to portable ids\n * through the identity map, and target storage keys become placeholders\n * again (`rewriteMediaRefs` verify mode). A record verifies when both forms\n * have the same canonical JSON. Each chunk's logical hash is stored on its\n * staged file; the logical digest is computed from those at the end.\n *\n * Redirects the importer disabled because they would close a loop (listed\n * in the identity map) are predicted disabled.\n *\n * After the records, every inferred credit this import materialized (listed\n * in the identity map) must exist as recorded, the number of target rows per\n * kind must equal the package count (plus those credits for\n * `content_byline`), and every media object is downloaded again and must hash\n * to its blob.\n */\n\nimport type { Kysely } from \"kysely\";\nimport { z } from \"zod\";\n\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { isTransferError, TransferError } from \"../errors.js\";\nimport { canonicalJson } from \"../format/canonical.js\";\nimport {\n\tchunkLogicalSha256,\n\tlogicalDigest,\n\trecordSha256,\n\ttype Sha256Digest,\n} from \"../format/digest.js\";\nimport {\n\tKIND_REFERENCES,\n\tRECORD_KINDS,\n\tsyntheticId,\n\tSYNTHETIC_ID_KINDS,\n\ttype RecordKind,\n\ttype SitePackageRecord,\n} from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tbuildMediaKeyIndex,\n\trelativizePlaceholderUrls,\n\trewriteMediaRefs,\n\ttype MediaKeyIndex,\n} from \"../format/media-refs.js\";\nimport { recordChunkPath } from \"../format/paths.js\";\nimport type { SiteImportPlan } from \"../format/plan.js\";\nimport { DECIDED_SETTING_NAMES } from \"../format/settings.js\";\nimport {\n\tapplyTransformations,\n\ttype FieldColumnType,\n\ttype TransformationContext,\n} from \"../format/transformations.js\";\nimport { INFERRED_CREDIT_ENTITY } from \"../import/stages.js\";\nimport { REDIRECT_LOOP_ENTITY } from \"../import/writers.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferIdentityMapRepository } from \"../ops/identity-map.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport { StagedPackageReader } from \"../staging/package.js\";\nimport { hashStoredObject, loadMediaKeyRows } from \"./media.js\";\nimport { createReader, type KindReader, type ReaderOptions } from \"./readers.js\";\n\ntype Db = Kysely<Database>;\n\nexport interface VerifyImportStepInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/**\n\t * The staged package being imported. Record chunks are read from its\n\t * stage and checked against the digests they were verified with.\n\t */\n\treader: StagedPackageReader;\n\tplan: SiteImportPlan;\n\t/** The cursor returned by the previous step, or null on the first. */\n\tcursor: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport interface VerificationMismatch {\n\tkind: string;\n\tid: string;\n\treason: string;\n}\n\nexport type VerifyImportStepResult =\n\t| { done: false; cursor: unknown }\n\t| {\n\t\t\tdone: true;\n\t\t\tlogicalDigest: Sha256Digest;\n\t\t\tcounts: Record<string, number>;\n\t\t\tmismatches: VerificationMismatch[];\n\t };\n\nconst recordKindSchema = z.enum(RECORD_KINDS);\nconst nonNegative = z.number().int().nonnegative();\n\nconst verifyCursorSchema = z.strictObject({\n\tphase: z.enum([\"records\", \"credits\", \"counts\", \"media\", \"digest\"]),\n\tkind: recordKindSchema,\n\tseq: nonNegative,\n\tline: nonNegative,\n\tcounts: z.record(z.string(), nonNegative),\n\t/** Inferred credits checked so far, and the last one checked. */\n\tcredits: z.strictObject({ checked: nonNegative, after: z.string().nullable() }),\n\tmismatches: z\n\t\t.array(z.strictObject({ kind: z.string(), id: z.string(), reason: z.string() }))\n\t\t.max(TRANSFER_LIMITS.verificationMismatches),\n});\n\ntype VerifyCursor = z.infer<typeof verifyCursorSchema>;\n\n/** Kinds that are written to a target, in package order. */\nconst VERIFIED_KINDS: readonly RecordKind[] = RECORD_KINDS.filter((kind) => kind !== \"principal\");\n\n/** Kinds whose target row count must equal the package count. */\nconst COUNTED_KINDS: readonly RecordKind[] = VERIFIED_KINDS.filter((kind) => kind !== \"setting\");\n\nconst CREDITS_PER_UNIT = 500;\n\n/**\n * Run one bounded verification step. Returns `done: false` with a cursor to\n * pass to the next call, or the logical digest, verified counts per kind, and\n * at most `TRANSFER_LIMITS.verificationMismatches` mismatches.\n */\nexport async function verifyImportStep(\n\tinput: VerifyImportStepInput,\n): Promise<VerifyImportStepResult> {\n\treturn new VerifyStep(input).run();\n}\n\nfunction initialCursor(): VerifyCursor {\n\treturn {\n\t\tphase: \"records\",\n\t\tkind: VERIFIED_KINDS[0] ?? \"collection\",\n\t\tseq: 0,\n\t\tline: 0,\n\t\tcounts: {},\n\t\tcredits: { checked: 0, after: null },\n\t\tmismatches: [],\n\t};\n}\n\nclass VerifyStep {\n\treadonly #input: VerifyImportStepInput;\n\treadonly #db: Db;\n\treadonly #identity: TransferIdentityMapRepository;\n\treadonly #reader: StagedPackageReader;\n\treadonly #readers = new Map<RecordKind, KindReader<RecordKind>>();\n\t#cursor: VerifyCursor;\n\t#rewrites: boolean | null = null;\n\t#keys: MediaKeyIndex | null = null;\n\t#context: TransformationContext | null = null;\n\t#packageBlobs = new Map<string, string>();\n\n\tconstructor(input: VerifyImportStepInput) {\n\t\tthis.#input = input;\n\t\tthis.#db = input.db;\n\t\tthis.#reader = new StagedPackageReader(\n\t\t\tinput.reader.stage,\n\t\t\tnew TransferStagedFileRepository(input.db).verifiedDigests(input.operationId),\n\t\t);\n\t\tthis.#identity = new TransferIdentityMapRepository(\n\t\t\tinput.db,\n\t\t\tinput.plan.origin.siteId,\n\t\t\tinput.operationId,\n\t\t);\n\t\tthis.#cursor =\n\t\t\tinput.cursor === null || input.cursor === undefined\n\t\t\t\t? initialCursor()\n\t\t\t\t: verifyCursorSchema.parse(input.cursor);\n\t}\n\n\tasync run(): Promise<VerifyImportStepResult> {\n\t\tif ((await this.#reader.digest()) !== this.#input.plan.packageDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Staged package does not match\");\n\t\t}\n\t\tfor (;;) {\n\t\t\tconst progressed = await this.unit();\n\t\t\tif (progressed === \"done\") return this.finish();\n\t\t\tif (progressed === \"yield\") return { done: false, cursor: this.#cursor };\n\t\t}\n\t}\n\n\tprivate mismatch(kind: string, id: string, reason: string): void {\n\t\tif (this.#cursor.mismatches.length < TRANSFER_LIMITS.verificationMismatches) {\n\t\t\tthis.#cursor.mismatches.push({ kind, id, reason });\n\t\t}\n\t}\n\n\tprivate async unit(): Promise<\"continue\" | \"yield\" | \"done\"> {\n\t\tconst budget = this.#input.budget;\n\t\tif (!budget.canStart({ bytes: 1 })) return \"yield\";\n\t\tswitch (this.#cursor.phase) {\n\t\t\tcase \"records\":\n\t\t\t\tbudget.start(1);\n\t\t\t\tawait this.recordsUnit();\n\t\t\t\treturn \"continue\";\n\t\t\tcase \"credits\":\n\t\t\t\tbudget.start(1);\n\t\t\t\tawait this.creditsUnit();\n\t\t\t\treturn \"continue\";\n\t\t\tcase \"counts\":\n\t\t\t\tbudget.start(1);\n\t\t\t\tawait this.countsUnit();\n\t\t\t\treturn \"continue\";\n\t\t\tcase \"media\":\n\t\t\t\treturn this.mediaUnit();\n\t\t\tcase \"digest\":\n\t\t\t\treturn \"done\";\n\t\t}\n\t}\n\n\t// ── Shared ──\n\n\tprivate reader(kind: RecordKind): KindReader<RecordKind> {\n\t\tlet reader = this.#readers.get(kind);\n\t\tif (!reader) {\n\t\t\tconst options: ReaderOptions = {\n\t\t\t\tmediaBlobs: async (ids) => {\n\t\t\t\t\tconst portable = await this.portableIds(\"media\", ids);\n\t\t\t\t\tconst found = new Map<string, string>();\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tconst blob = this.#packageBlobs.get(portable.get(id) ?? id);\n\t\t\t\t\t\tif (blob !== undefined) found.set(id, blob);\n\t\t\t\t\t}\n\t\t\t\t\treturn found;\n\t\t\t\t},\n\t\t\t};\n\t\t\treader = createReader(this.#db, kind, options);\n\t\t\tthis.#readers.set(kind, reader);\n\t\t}\n\t\treturn reader;\n\t}\n\n\t/** Whether any record id was rewritten on import. */\n\tprivate async hasRewrites(): Promise<boolean> {\n\t\tif (this.#rewrites === null) {\n\t\t\tconst row = await this.#db\n\t\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t.select(\"portable_id\")\n\t\t\t\t.where(\"operation_id\", \"=\", this.#input.operationId)\n\t\t\t\t.where(\"entity_kind\", \"in\", [...RECORD_KINDS])\n\t\t\t\t.limit(1)\n\t\t\t\t.executeTakeFirst();\n\t\t\tthis.#rewrites = row !== undefined;\n\t\t}\n\t\treturn this.#rewrites;\n\t}\n\n\tprivate async targetIds(kind: RecordKind, ids: readonly string[]): Promise<Map<string, string>> {\n\t\tif (!(await this.hasRewrites()) || ids.length === 0) return new Map();\n\t\treturn this.#identity.getMany(kind, ids);\n\t}\n\n\tprivate async portableIds(\n\t\tkind: RecordKind,\n\t\tids: readonly string[],\n\t): Promise<Map<string, string>> {\n\t\tif (!(await this.hasRewrites()) || ids.length === 0) return new Map();\n\t\treturn this.#identity.getPortableIds(kind, ids);\n\t}\n\n\t/** Map a record's own id and its `by: \"id\"` references through `lookup`. */\n\tprivate async mapIds(\n\t\trecords: SitePackageRecord[],\n\t\tlookup: (kind: RecordKind, ids: readonly string[]) => Promise<Map<string, string>>,\n\t): Promise<SitePackageRecord[]> {\n\t\tif (!(await this.hasRewrites()) || records.length === 0) return records;\n\t\tconst kind = records[0]?.kind;\n\t\tif (!kind) return records;\n\t\tconst properties: Array<{ property: string; target: RecordKind }> = [];\n\t\tif (!isSyntheticKind(kind) && kind !== \"setting\")\n\t\t\tproperties.push({ property: \"id\", target: kind });\n\t\tfor (const reference of KIND_REFERENCES[kind]) {\n\t\t\tconst target = reference.targets[0];\n\t\t\tif (reference.by !== \"id\" || !target || target === \"principal\") continue;\n\t\t\tproperties.push({ property: reference.property, target });\n\t\t}\n\t\tconst maps = new Map<string, Map<string, string>>();\n\t\tfor (const { property, target } of properties) {\n\t\t\tconst values = records.flatMap((record) => {\n\t\t\t\tconst value: unknown = Reflect.get(record, property);\n\t\t\t\treturn typeof value === \"string\" ? [value] : [];\n\t\t\t});\n\t\t\tmaps.set(property, await lookup(target, values));\n\t\t}\n\t\treturn records.map((record) => {\n\t\t\tconst next: Record<string, unknown> = { ...record };\n\t\t\tfor (const { property } of properties) {\n\t\t\t\tconst value = next[property];\n\t\t\t\tconst mapped = typeof value === \"string\" ? maps.get(property)?.get(value) : undefined;\n\t\t\t\tif (mapped !== undefined) next[property] = mapped;\n\t\t\t}\n\t\t\tif (isSyntheticRecord(next)) next.id = syntheticId(next);\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- same record with id-valued properties replaced by other ids\n\t\t\treturn next as SitePackageRecord;\n\t\t});\n\t}\n\n\tprivate async keyIndex(): Promise<MediaKeyIndex> {\n\t\tif (!this.#keys) {\n\t\t\tconst rows = await loadMediaKeyRows(this.#db);\n\t\t\tconst portable = await this.portableIds(\n\t\t\t\t\"media\",\n\t\t\t\trows.map((row) => row.id),\n\t\t\t);\n\t\t\tthis.#keys = buildMediaKeyIndex(\n\t\t\t\trows.map((row) => ({ id: portable.get(row.id) ?? row.id, storageKey: row.storageKey })),\n\t\t\t);\n\t\t}\n\t\treturn this.#keys;\n\t}\n\n\tprivate async transformationContext(): Promise<TransformationContext> {\n\t\tif (this.#context) return this.#context;\n\t\tconst reader = this.#reader;\n\t\tconst collections = new Map<string, string>();\n\t\tfor await (const { record } of reader.records(\"collection\")) {\n\t\t\tcollections.set(record.id, record.slug);\n\t\t}\n\t\tconst types = new Map<string, Map<string, FieldColumnType>>();\n\t\tfor await (const { record } of reader.records(\"field\")) {\n\t\t\tconst slug = collections.get(record.collectionId);\n\t\t\tif (slug === undefined) continue;\n\t\t\tconst fields = types.get(slug) ?? new Map<string, FieldColumnType>();\n\t\t\tfields.set(record.slug, record.columnType);\n\t\t\ttypes.set(slug, fields);\n\t\t}\n\t\tthis.#context = { fieldColumnTypes: types };\n\t\treturn this.#context;\n\t}\n\n\tprivate excludedSettings(): ReadonlySet<string> {\n\t\tconst excluded = new Set<string>();\n\t\tconst { decisions } = this.#input.plan;\n\t\tif (decisions.siteTitle === \"target\") {\n\t\t\tfor (const name of DECIDED_SETTING_NAMES.title) excluded.add(name);\n\t\t}\n\t\tif (decisions.siteTagline === \"target\") {\n\t\t\tfor (const name of DECIDED_SETTING_NAMES.tagline) excluded.add(name);\n\t\t}\n\t\treturn excluded;\n\t}\n\n\tprivate chunkCount(\n\t\tkind: RecordKind,\n\t\tmanifest: Awaited<ReturnType<StagedPackageReader[\"manifest\"]>>,\n\t) {\n\t\treturn manifest.records[kind]?.chunks ?? 0;\n\t}\n\n\t// ── Records ──\n\n\tprivate async recordsUnit(): Promise<void> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst { kind, seq } = this.#cursor;\n\t\tif (seq >= this.chunkCount(kind, manifest)) {\n\t\t\tthis.advanceKind();\n\t\t\treturn;\n\t\t}\n\n\t\tconst chunk = await this.#reader.readChunk(kind, seq);\n\t\tconst context = await this.transformationContext();\n\t\tconst excluded = kind === \"setting\" ? this.excludedSettings() : new Set<string>();\n\t\tconst packageRecords = chunk\n\t\t\t.map((staged) => staged.record)\n\t\t\t.filter((record) => !excluded.has(record.id));\n\t\tif (kind === \"media\") {\n\t\t\tfor (const record of packageRecords) {\n\t\t\t\tif (record.kind === \"media\") this.#packageBlobs.set(record.id, record.blob);\n\t\t\t}\n\t\t}\n\t\tconst predicted = await this.disabledLoopClosers(\n\t\t\tpackageRecords.map((record) =>\n\t\t\t\tpredictRelativeMediaUrls(applyTransformations(record, this.#input.plan, context)),\n\t\t\t),\n\t\t);\n\n\t\tconst forward = await this.mapIds(predicted, (target, ids) => this.targetIds(target, ids));\n\t\tconst lookup = forward.map((record) => record.id);\n\t\tconst collections = new Map(\n\t\t\tforward.flatMap((record) =>\n\t\t\t\trecord.kind === \"entry\" ? [[record.id, record.collection] as const] : [],\n\t\t\t),\n\t\t);\n\t\tconst found = await this.readTargets(kind, lookup, collections);\n\t\tconst targets = await this.mapIds(\n\t\t\tlookup.flatMap((id) => {\n\t\t\t\tconst record = found.get(id);\n\t\t\t\treturn record ? [record] : [];\n\t\t\t}),\n\t\t\t(target, ids) => this.portableIds(target, ids),\n\t\t);\n\t\tconst byPortableId = new Map(targets.map((record) => [record.id, record]));\n\t\tconst keys = await this.keyIndex();\n\n\t\tconst hashes: Array<[string, string]> = [];\n\t\tlet verified = 0;\n\t\tfor (const expected of predicted) {\n\t\t\tconst target = byPortableId.get(expected.id);\n\t\t\tif (!target) {\n\t\t\t\tthis.mismatch(kind, expected.id, \"missing\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst rewritten = rewriteMediaRefs(target, { mode: \"verify\", keys, relativize: true });\n\t\t\tif (rewritten.errors.length > 0) {\n\t\t\t\tthis.mismatch(kind, expected.id, `media_ref_${rewritten.errors[0]?.code ?? \"invalid\"}`);\n\t\t\t}\n\t\t\tconst actual =\n\t\t\t\trewritten.value.kind === \"media\" && expected.kind === \"media\"\n\t\t\t\t\t? { ...rewritten.value, blob: expected.blob }\n\t\t\t\t\t: rewritten.value;\n\t\t\thashes.push([expected.id, await recordSha256(actual)]);\n\t\t\tif (canonicalJson(actual) === canonicalJson(expected)) verified++;\n\t\t\telse this.mismatch(kind, expected.id, \"different\");\n\t\t}\n\n\t\tawait new TransferStagedFileRepository(this.#db).setLogicalSha256(\n\t\t\tthis.#input.operationId,\n\t\t\trecordChunkPath(kind, seq),\n\t\t\tawait chunkLogicalSha256(hashes),\n\t\t);\n\t\tthis.#cursor.counts[kind] = (this.#cursor.counts[kind] ?? 0) + verified;\n\t\tthis.#cursor.seq = seq + 1;\n\t}\n\n\t/** Redirects the importer wrote disabled because they would close a loop. */\n\tprivate async disabledLoopClosers(records: SitePackageRecord[]): Promise<SitePackageRecord[]> {\n\t\tconst redirects = records.flatMap((record) => (record.kind === \"redirect\" ? [record.id] : []));\n\t\tif (redirects.length === 0) return records;\n\t\tconst closers = await this.#identity.getMany(REDIRECT_LOOP_ENTITY, redirects);\n\t\tif (closers.size === 0) return records;\n\t\treturn records.map((record) =>\n\t\t\trecord.kind === \"redirect\" && closers.has(record.id) ? { ...record, enabled: false } : record,\n\t\t);\n\t}\n\n\tprivate async readTargets(\n\t\tkind: RecordKind,\n\t\tids: readonly string[],\n\t\tcollections: ReadonlyMap<string, string>,\n\t) {\n\t\ttry {\n\t\t\treturn await this.reader(kind).byIds(ids, collections);\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_EXPORT_ERROR\") {\n\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\"TRANSFER_VERIFICATION_FAILED\",\n\t\t\t\t\t\"Target row is not a valid record\",\n\t\t\t\t\t{\n\t\t\t\t\t\tdetail: { ...error.detail, kind },\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate advanceKind(): void {\n\t\tconst next = VERIFIED_KINDS[VERIFIED_KINDS.indexOf(this.#cursor.kind) + 1];\n\t\tif (next) {\n\t\t\tthis.#cursor.kind = next;\n\t\t\tthis.#cursor.seq = 0;\n\t\t\treturn;\n\t\t}\n\t\tthis.#cursor.phase = \"credits\";\n\t\tthis.#cursor.seq = 0;\n\t}\n\n\t// ── Inferred credits ──\n\n\tprivate async creditsUnit(): Promise<void> {\n\t\tconst mappings = await this.#identity.list(INFERRED_CREDIT_ENTITY, {\n\t\t\tafter: this.#cursor.credits.after ?? undefined,\n\t\t\tlimit: CREDITS_PER_UNIT,\n\t\t});\n\t\tconst rows = new Map<\n\t\t\tstring,\n\t\t\t{ byline_id: string; sort_order: unknown; role_label: string | null }\n\t\t>();\n\t\tfor (const batch of chunks(\n\t\t\tmappings.map((mapping) => mapping.portableId),\n\t\t\tSQL_BATCH_SIZE,\n\t\t)) {\n\t\t\tconst found = await this.#db\n\t\t\t\t.selectFrom(\"_emdash_content_bylines\")\n\t\t\t\t.select([\"id\", \"byline_id\", \"sort_order\", \"role_label\"])\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of found) rows.set(row.id, row);\n\t\t}\n\t\tfor (const mapping of mappings) {\n\t\t\tconst row = rows.get(mapping.portableId);\n\t\t\tif (!row) this.mismatch(\"content_byline\", mapping.portableId, \"inferred_credit_missing\");\n\t\t\telse if (\n\t\t\t\trow.byline_id !== mapping.targetId ||\n\t\t\t\tNumber(row.sort_order) !== 0 ||\n\t\t\t\trow.role_label !== null\n\t\t\t) {\n\t\t\t\tthis.mismatch(\"content_byline\", mapping.portableId, \"inferred_credit_different\");\n\t\t\t}\n\t\t}\n\t\tthis.#cursor.credits.checked += mappings.length;\n\t\tconst last = mappings.at(-1);\n\t\tif (last && mappings.length === CREDITS_PER_UNIT) {\n\t\t\tthis.#cursor.credits.after = last.portableId;\n\t\t\treturn;\n\t\t}\n\t\tthis.#cursor.phase = \"counts\";\n\t\tthis.#cursor.kind = COUNTED_KINDS[0] ?? \"collection\";\n\t}\n\n\t// ── Counts ──\n\n\tprivate async countsUnit(): Promise<void> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst kind = this.#cursor.kind;\n\t\tconst rows = await this.reader(kind).countRows();\n\t\tlet expected = manifest.records[kind]?.count ?? 0;\n\t\tif (kind === \"content_byline\") expected += this.#cursor.credits.checked;\n\t\tif (rows !== null && rows !== expected) {\n\t\t\tthis.mismatch(kind, \"*\", `row_count expected=${expected} actual=${rows}`);\n\t\t}\n\n\t\tconst next = COUNTED_KINDS[COUNTED_KINDS.indexOf(kind) + 1];\n\t\tif (next) {\n\t\t\tthis.#cursor.kind = next;\n\t\t\treturn;\n\t\t}\n\t\tthis.#cursor.phase = \"media\";\n\t\tthis.#cursor.kind = \"media\";\n\t\tthis.#cursor.seq = 0;\n\t\tthis.#cursor.line = 0;\n\t}\n\n\t// ── Media ──\n\n\t#mediaChunk: { seq: number; records: SitePackageRecord[]; keys: Map<string, string> } | null =\n\t\tnull;\n\n\tprivate async mediaUnit(): Promise<\"continue\" | \"yield\" | \"done\"> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst { seq, line } = this.#cursor;\n\t\tif (seq >= this.chunkCount(\"media\", manifest)) {\n\t\t\tthis.#cursor.phase = \"digest\";\n\t\t\treturn \"continue\";\n\t\t}\n\t\tif (this.#mediaChunk?.seq !== seq) {\n\t\t\tconst records = (await this.#reader.readChunk(\"media\", seq)).map((s) => s.record);\n\t\t\tconst targetIds = await this.targetIds(\n\t\t\t\t\"media\",\n\t\t\t\trecords.map((record) => record.id),\n\t\t\t);\n\t\t\tconst ids = records.map((record) => targetIds.get(record.id) ?? record.id);\n\t\t\tconst keys = new Map<string, string>();\n\t\t\tfor (const row of await this.targetMediaKeys(ids)) keys.set(row.id, row.storageKey);\n\t\t\tconst mapped = new Map<string, string>();\n\t\t\trecords.forEach((record, index) => {\n\t\t\t\tconst key = keys.get(ids[index] ?? record.id);\n\t\t\t\tif (key !== undefined) mapped.set(record.id, key);\n\t\t\t});\n\t\t\tthis.#mediaChunk = { seq, records, keys: mapped };\n\t\t}\n\n\t\tconst record = this.#mediaChunk.records[line];\n\t\tif (!record || record.kind !== \"media\") {\n\t\t\tthis.#cursor.seq = seq + 1;\n\t\t\tthis.#cursor.line = 0;\n\t\t\treturn \"continue\";\n\t\t}\n\t\tconst budget = this.#input.budget;\n\t\t// The first object of a step may be any size; later ones must fit what is left.\n\t\tconst first = budget.bytesUsed === 0;\n\t\tif (!first && !budget.canStart({ bytes: 1 })) return \"yield\";\n\n\t\tconst key = this.#mediaChunk.keys.get(record.id);\n\t\tif (key === undefined) {\n\t\t\tbudget.start(1);\n\t\t\tthis.mismatch(\"media\", record.id, \"missing\");\n\t\t} else {\n\t\t\tconst hashed = await hashStoredObject(this.#input.storage, key, {\n\t\t\t\tmaxBytes: first ? undefined : budget.remaining().bytes,\n\t\t\t});\n\t\t\tif (hashed === \"too_large\") return \"yield\";\n\t\t\tbudget.start(Math.max(hashed?.bytes ?? 0, 1));\n\t\t\tif (hashed === null) this.mismatch(\"media\", record.id, \"blob_missing\");\n\t\t\telse if (hashed.sha256 !== record.blob) this.mismatch(\"media\", record.id, \"blob_mismatch\");\n\t\t}\n\t\tthis.#cursor.line = line + 1;\n\t\treturn \"continue\";\n\t}\n\n\tprivate async targetMediaKeys(ids: readonly string[]) {\n\t\tconst rows: Array<{ id: string; storageKey: string }> = [];\n\t\tfor (const batch of chunks([...ids], SQL_BATCH_SIZE)) {\n\t\t\tconst found = await this.#db\n\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t.select([\"id\", \"storage_key\"])\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of found) rows.push({ id: row.id, storageKey: row.storage_key });\n\t\t}\n\t\treturn rows;\n\t}\n\n\t// ── Digest ──\n\n\tprivate async finish(): Promise<VerifyImportStepResult> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst staged = new TransferStagedFileRepository(this.#db);\n\t\tconst recordChunks: Array<[string, number]> = [];\n\t\tfor (const kind of VERIFIED_KINDS) {\n\t\t\tfor (let seq = 0; seq < this.chunkCount(kind, manifest); seq++) {\n\t\t\t\trecordChunks.push([kind, seq]);\n\t\t\t}\n\t\t}\n\t\tconst files = await staged.getMany(\n\t\t\tthis.#input.operationId,\n\t\t\trecordChunks.map(([kind, seq]) => recordChunkPath(kindOf(kind), seq)),\n\t\t);\n\t\tconst tuples: Array<[string, number, string]> = [];\n\t\tfor (const [kind, seq] of recordChunks) {\n\t\t\tconst hash = files.get(recordChunkPath(kindOf(kind), seq))?.logicalSha256;\n\t\t\tif (!hash) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_IMPORT_ERROR\", \"Chunk was not verified\", {\n\t\t\t\t\tdetail: { kind, seq },\n\t\t\t\t});\n\t\t\t}\n\t\t\ttuples.push([kind, seq, hash]);\n\t\t}\n\t\treturn {\n\t\t\tdone: true,\n\t\t\tlogicalDigest: await logicalDigest(tuples),\n\t\t\tcounts: { ...this.#cursor.counts },\n\t\t\tmismatches: [...this.#cursor.mismatches],\n\t\t};\n\t}\n}\n\n/**\n * The importer writes a placeholder media URL relative to the target, so an\n * absolute one in a package record is predicted without its scheme and host.\n */\nfunction predictRelativeMediaUrls(record: SitePackageRecord): SitePackageRecord {\n\tconst text = canonicalJson(record);\n\tconst relative = relativizePlaceholderUrls(text);\n\tif (relative === text) return record;\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- the same record with some URL prefixes removed\n\treturn JSON.parse(relative) as SitePackageRecord;\n}\n\nfunction kindOf(kind: string): RecordKind {\n\tconst found = RECORD_KINDS.find((candidate) => candidate === kind);\n\tif (!found) throw new Error(`Unknown record kind ${kind}`);\n\treturn found;\n}\n\nconst SYNTHETIC: ReadonlySet<string> = new Set(SYNTHETIC_ID_KINDS);\n\nfunction isSyntheticKind(kind: RecordKind): boolean {\n\treturn SYNTHETIC.has(kind);\n}\n\nfunction isSyntheticRecord(\n\trecord: Record<string, unknown>,\n): record is Parameters<typeof syntheticId>[0] & Record<string, unknown> {\n\treturn typeof record.kind === \"string\" && SYNTHETIC.has(record.kind);\n}\n","/**\n * The `rebuild` stage: derived state the importer does not write row by row.\n *\n * - `search`: full-text indexes for collections whose package search config\n * is enabled, populated in rowid ranges, then the collection's final\n * `search_config` (SQLite only; the plan declares `search_unsupported`\n * elsewhere).\n * - `media_usage`: every imported collection is marked stale so the\n * media-usage maintenance engine re-indexes it.\n * - `options`: `POST_IMPORT_OPTION_RESETS`.\n * - `taxonomies`: each taxonomy's structure group, rebuilt from its imported\n * definitions; a group whose name no definition has any more is deleted.\n * - `caches`: isolate caches and every object-cache namespace.\n */\n\nimport { sql } from \"kysely\";\n\nimport { isSqlite } from \"../../database/dialect-helpers.js\";\nimport { parseTaxonomyCollections } from \"../../database/repositories/taxonomy-def.js\";\nimport { markContentMediaUsageCollectionStale } from \"../../media/usage/content-refresh.js\";\nimport {\n\tCacheNamespace,\n\tinvalidateCollectionCache,\n\tinvalidateObjectCache,\n} from \"../../object-cache/index.js\";\nimport { resetRegisteredCollectionsCache } from \"../../schema/collection-slugs-cache.js\";\nimport { invalidateSchemaCache } from \"../../schema/zod-generator.js\";\nimport { FTSManager } from \"../../search/fts-manager.js\";\nimport type { SearchTokenizer } from \"../../search/types.js\";\nimport { SEARCH_TOKENIZERS } from \"../../search/types.js\";\nimport { invalidateSiteSettingsCache } from \"../../settings/index.js\";\nimport { TransferError } from \"../errors.js\";\nimport { compareIds, type CollectionRecord } from \"../format/kinds.js\";\nimport { POST_IMPORT_OPTION_RESETS } from \"../format/settings.js\";\nimport { applyTransformations } from \"../format/transformations.js\";\nimport { REBUILD_STEPS, type RebuildStep } from \"../ops/states.js\";\nimport type { ImportContext } from \"./context.js\";\nimport { ulidFromHash } from \"./ids.js\";\n\nconst FTS_ROWS_PER_UNIT = 500;\nconst FTS_SETUP_STATEMENTS = 20;\nconst FTS_POPULATE_STATEMENTS = 4;\nconst STALE_STATEMENTS = 4;\nconst OPTION_STATEMENTS = 4;\nconst TAXONOMY_STATEMENTS = 4;\n/** Cache invalidation runs no queries; its checkpoint does. */\nconst CACHE_STATEMENTS = 1;\n\nexport interface RebuildPosition {\n\tstep: RebuildStep;\n\tafter: string | null;\n}\n\nexport type RebuildCheckpoint = (position: RebuildPosition) => Promise<void>;\n\n/** Run rebuild units from `position`; returns null when the stage is done. */\nexport async function runRebuild(\n\tcontext: ImportContext,\n\tstart: RebuildPosition,\n\tcheckpoint: RebuildCheckpoint,\n): Promise<RebuildPosition | null> {\n\tlet position: RebuildPosition | null = start;\n\twhile (position) {\n\t\tconst next: RebuildPosition | null | \"budget\" = await runUnit(context, position);\n\t\tif (next === \"budget\") return position;\n\t\tif (next) await checkpoint(next);\n\t\tposition = next;\n\t}\n\treturn null;\n}\n\nfunction nextStep(step: RebuildStep): RebuildPosition | null {\n\tconst following = REBUILD_STEPS[REBUILD_STEPS.indexOf(step) + 1];\n\treturn following ? { step: following, after: null } : null;\n}\n\nasync function collections(context: ImportContext): Promise<CollectionRecord[]> {\n\treturn (await context.allRecords(\"collection\")).toSorted((a, b) => compareIds(a.slug, b.slug));\n}\n\nasync function runUnit(\n\tcontext: ImportContext,\n\tposition: RebuildPosition,\n): Promise<RebuildPosition | null | \"budget\"> {\n\tswitch (position.step) {\n\t\tcase \"search\":\n\t\t\treturn searchUnit(context, position.after);\n\t\tcase \"media_usage\": {\n\t\t\tconst collection = (await collections(context)).find(\n\t\t\t\t(candidate) => position.after === null || compareIds(candidate.slug, position.after) > 0,\n\t\t\t);\n\t\t\tif (!collection) return nextStep(\"media_usage\");\n\t\t\tif (!context.budget.canStart({ queries: STALE_STATEMENTS })) return \"budget\";\n\t\t\tcontext.budget.start();\n\t\t\tawait markContentMediaUsageCollectionStale(\n\t\t\t\tcontext.db,\n\t\t\t\tcollection.slug,\n\t\t\t\t\"CONTENT_USAGE_STALE\",\n\t\t\t);\n\t\t\treturn { step: \"media_usage\", after: collection.slug };\n\t\t}\n\t\tcase \"options\": {\n\t\t\tif (!context.budget.canStart({ queries: OPTION_STATEMENTS })) return \"budget\";\n\t\t\tcontext.budget.start();\n\t\t\tfor (const name of POST_IMPORT_OPTION_RESETS.bumpVersion) {\n\t\t\t\tawait sql`\n\t\t\t\t\tINSERT INTO options (name, value)\n\t\t\t\t\tVALUES (${name}, '2')\n\t\t\t\t\tON CONFLICT(name) DO UPDATE SET value = CASE\n\t\t\t\t\t\tWHEN CAST(options.value AS INTEGER) % 2 = 0\n\t\t\t\t\t\t\tTHEN CAST(CAST(options.value AS INTEGER) + 2 AS TEXT)\n\t\t\t\t\t\tELSE CAST(CAST(options.value AS INTEGER) + 1 AS TEXT)\n\t\t\t\t\tEND\n\t\t\t\t`.execute(context.db);\n\t\t\t}\n\t\t\tawait context.db\n\t\t\t\t.deleteFrom(\"options\")\n\t\t\t\t.where(\"name\", \"in\", [...POST_IMPORT_OPTION_RESETS.delete])\n\t\t\t\t.execute();\n\t\t\treturn nextStep(\"options\");\n\t\t}\n\t\tcase \"taxonomies\":\n\t\t\treturn taxonomyUnit(context, position.after);\n\t\tcase \"caches\":\n\t\t\tif (!context.budget.canStart({ queries: CACHE_STATEMENTS })) return \"budget\";\n\t\t\tcontext.budget.start();\n\t\t\tawait invalidateCaches(context);\n\t\t\treturn nextStep(\"caches\");\n\t}\n}\n\nfunction isTokenizer(value: unknown): value is SearchTokenizer {\n\treturn SEARCH_TOKENIZERS.some((tokenizer) => tokenizer === value);\n}\n\ninterface SearchTarget {\n\trecord: CollectionRecord;\n\tconfig: Record<string, unknown>;\n}\n\nasync function searchTargets(context: ImportContext): Promise<SearchTarget[]> {\n\tconst targets: SearchTarget[] = [];\n\tfor (const record of await collections(context)) {\n\t\tconst final = applyTransformations(record, context.plan, { fieldColumnTypes: new Map() });\n\t\tconst config = final.searchConfig;\n\t\tif (typeof config !== \"object\" || config === null || Array.isArray(config)) continue;\n\t\tif (config.enabled !== true) continue;\n\t\tif (!isSqlite(context.db)) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\t\"Full-text search is not available on this target\",\n\t\t\t\t{ detail: { kind: \"collection\", id: record.id } },\n\t\t\t);\n\t\t}\n\t\ttargets.push({ record, config });\n\t}\n\treturn targets;\n}\n\n/** `after`: null, `slug` (done), or `slug:rowid` (index created, rows ≤ rowid indexed). */\nasync function searchUnit(\n\tcontext: ImportContext,\n\tafter: string | null,\n): Promise<RebuildPosition | null | \"budget\"> {\n\tconst [doneSlug, rowidText] = after?.split(\":\") ?? [];\n\tconst inProgress = rowidText === undefined ? null : Number(rowidText);\n\tconst target = (await searchTargets(context)).find((candidate) =>\n\t\tinProgress === null\n\t\t\t? doneSlug === undefined || compareIds(candidate.record.slug, doneSlug) > 0\n\t\t\t: candidate.record.slug === doneSlug,\n\t);\n\tif (!target) return nextStep(\"search\");\n\tconst slug = target.record.slug;\n\tconst fts = new FTSManager(context.db);\n\n\tif (inProgress === null) {\n\t\tif (!context.budget.canStart({ queries: FTS_SETUP_STATEMENTS })) return \"budget\";\n\t\tcontext.budget.start();\n\t\tconst fields = await fts.getSearchableFields(slug);\n\t\tif (fields.length > 0) {\n\t\t\tconst weights = target.config.weights;\n\t\t\tawait fts.dropFtsTable(slug);\n\t\t\tawait fts.createFtsTable(\n\t\t\t\tslug,\n\t\t\t\tfields,\n\t\t\t\ttypeof weights === \"object\" && weights !== null\n\t\t\t\t\t? Object.fromEntries(\n\t\t\t\t\t\t\tObject.entries(weights).filter(\n\t\t\t\t\t\t\t\t(entry): entry is [string, number] => typeof entry[1] === \"number\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tisTokenizer(target.config.tokenize) ? target.config.tokenize : undefined,\n\t\t\t);\n\t\t}\n\t\treturn { step: \"search\", after: `${slug}:0` };\n\t}\n\n\tif (!context.budget.canStart({ queries: FTS_POPULATE_STATEMENTS })) return \"budget\";\n\tcontext.budget.start();\n\tconst fields = await fts.getSearchableFields(slug);\n\tconst last =\n\t\tfields.length > 0 ? await fts.populateRange(slug, fields, inProgress, FTS_ROWS_PER_UNIT) : null;\n\tif (last !== null) return { step: \"search\", after: `${slug}:${last}` };\n\tawait context.db\n\t\t.updateTable(\"_emdash_collections\")\n\t\t.set({ search_config: JSON.stringify(target.config) })\n\t\t.where(\"id\", \"=\", target.record.id)\n\t\t.execute();\n\treturn { step: \"search\", after: slug };\n}\n\n/**\n * `after`: the last taxonomy name whose group was rebuilt, or null.\n *\n * The group becomes hierarchical if any definition is and lists every collection\n * any definition lists. The definitions keep the package's values, which the\n * verify stage compares; they differ from the group only where the exporting\n * site's locales disagreed.\n */\nasync function taxonomyUnit(\n\tcontext: ImportContext,\n\tafter: string | null,\n): Promise<RebuildPosition | null | \"budget\"> {\n\tif (!context.budget.canStart({ queries: TAXONOMY_STATEMENTS })) return \"budget\";\n\tcontext.budget.start();\n\tconst db = context.db;\n\tlet nextName = db\n\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t.select((eb) => eb.fn.min(\"name\").as(\"name\"));\n\tif (after !== null) nextName = nextName.where(\"name\", \">\", after);\n\tconst defs = await db\n\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t.select([\"id\", \"name\", \"hierarchical\", \"collections\", \"translation_group\"])\n\t\t.where(\"name\", \"=\", nextName)\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tconst name = defs[0]?.name;\n\tif (name === undefined) {\n\t\tawait db\n\t\t\t.deleteFrom(\"_emdash_taxonomy_def_groups\")\n\t\t\t.where((eb) =>\n\t\t\t\teb.not(\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t.whereRef(\"_emdash_taxonomy_defs.name\", \"=\", \"_emdash_taxonomy_def_groups.name\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.execute();\n\t\treturn nextStep(\"taxonomies\");\n\t}\n\n\tconst groupId = defs\n\t\t.map((def) => def.translation_group ?? def.id)\n\t\t.reduce((lowest, candidate) => (candidate < lowest ? candidate : lowest));\n\tconst collectionSlugs = [\n\t\t...new Set(defs.flatMap((def) => parseTaxonomyCollections(def.collections))),\n\t];\n\tconst hierarchical = defs.some((def) => def.hierarchical === 1) ? 1 : 0;\n\tconst taken = await db\n\t\t.selectFrom(\"_emdash_taxonomy_def_groups\")\n\t\t.select(\"id\")\n\t\t.where(\"id\", \"=\", groupId)\n\t\t.where(\"name\", \"!=\", name)\n\t\t.executeTakeFirst();\n\tconst id = taken ? await ulidFromHash(context.operationId, \"taxonomy_group\", name) : groupId;\n\tawait db\n\t\t.insertInto(\"_emdash_taxonomy_def_groups\")\n\t\t.values({ id, name, hierarchical, collections: JSON.stringify(collectionSlugs) })\n\t\t.onConflict((oc) =>\n\t\t\toc\n\t\t\t\t.column(\"name\")\n\t\t\t\t.doUpdateSet({ id, hierarchical, collections: JSON.stringify(collectionSlugs) }),\n\t\t)\n\t\t.execute();\n\treturn { step: \"taxonomies\", after: name };\n}\n\nasync function invalidateCaches(context: ImportContext): Promise<void> {\n\tfor (const namespace of Object.values(CacheNamespace)) invalidateObjectCache(namespace);\n\tfor (const collection of await collections(context)) {\n\t\tinvalidateCollectionCache(collection.slug);\n\t\tinvalidateSchemaCache(collection.slug);\n\t}\n\tinvalidateSiteSettingsCache();\n\tresetRegisteredCollectionsCache();\n\tconst { invalidateTermCache, invalidateTaxonomyDefsCache } =\n\t\tawait import(\"../../taxonomies/index.js\");\n\tconst { invalidateBylineCache } = await import(\"../../bylines/index.js\");\n\tconst { invalidateRedirectCache } = await import(\"../../redirects/cache.js\");\n\tconst { invalidateUrlPatternCache } = await import(\"../../query.js\");\n\tinvalidateTermCache();\n\tinvalidateTaxonomyDefsCache();\n\tinvalidateBylineCache();\n\tinvalidateRedirectCache();\n\tinvalidateUrlPatternCache();\n}\n","/**\n * The `clear_scaffold` stage: delete the seeded scaffold the plan declared\n * (`seeded_scaffold_removed`), one item per unit, then wait until\n * media-usage collection deletions of removed collections have finished so\n * the package may reuse their slugs.\n */\n\nimport { sql } from \"kysely\";\n\nimport { processDueMediaUsageCollectionDeletions } from \"../../media/usage/collection-deletion-processor.js\";\nimport { SchemaError, SchemaRegistry } from \"../../schema/registry.js\";\nimport { TransferError } from \"../errors.js\";\nimport type { ImportTransformation } from \"../format/transformations.js\";\nimport type { ImportContext } from \"./context.js\";\n\nexport type ScaffoldItemRef = Extract<\n\tImportTransformation,\n\t{ code: \"seeded_scaffold_removed\" }\n>[\"items\"][number];\n\nconst ITEM_STATEMENTS = 40;\n\nexport function declaredScaffold(context: ImportContext): readonly ScaffoldItemRef[] {\n\treturn context.plan.transformations.flatMap((transformation) =>\n\t\ttransformation.code === \"seeded_scaffold_removed\" ? transformation.items : [],\n\t);\n}\n\nexport type ScaffoldProgress =\n\t| { state: \"continue\"; step: number }\n\t| { state: \"wait\"; step: number }\n\t| { state: \"done\" };\n\n/**\n * Delete declared items from `step` on. Each item is removed only if it is\n * still the scaffold it was when analyzed (an unassigned term, an empty menu,\n * an empty widget area, a theme section, a seeded block type); deleting an already-deleted item\n * is a no-op.\n */\nexport async function clearScaffold(\n\tcontext: ImportContext,\n\tstep: number,\n\tcheckpoint: (step: number) => Promise<void>,\n): Promise<ScaffoldProgress> {\n\tconst items = declaredScaffold(context);\n\tlet next = step;\n\twhile (next < items.length) {\n\t\tconst item = items[next];\n\t\tif (!item) break;\n\t\tif (!context.budget.canStart({ queries: ITEM_STATEMENTS })) {\n\t\t\treturn { state: \"continue\", step: next };\n\t\t}\n\t\tcontext.budget.start();\n\t\tawait removeItem(context, item);\n\t\tnext++;\n\t\tawait checkpoint(next);\n\t}\n\n\tconst collectionIds = items.flatMap((item) => (item.type === \"collection\" ? [item.id] : []));\n\twhile (collectionIds.length > 0) {\n\t\tif (!context.budget.canStart({ queries: ITEM_STATEMENTS })) {\n\t\t\treturn { state: \"continue\", step: next };\n\t\t}\n\t\tcontext.budget.start();\n\t\tconst pending = await context.db\n\t\t\t.selectFrom(\"_emdash_media_usage_collection_deletions\")\n\t\t\t.select(\"collection_id\")\n\t\t\t.where(\"collection_id\", \"in\", collectionIds)\n\t\t\t.execute();\n\t\tif (pending.length === 0) break;\n\t\tconst tick = await processDueMediaUsageCollectionDeletions(context.db);\n\t\tif (tick.outcome === \"idle\" || tick.outcome === \"claim_lost\" || tick.outcome === \"retry\") {\n\t\t\treturn { state: \"wait\", step: next };\n\t\t}\n\t\tif (tick.outcome === \"failed\") {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\t\"Removing the seeded scaffold collections failed\",\n\t\t\t);\n\t\t}\n\t}\n\treturn { state: \"done\" };\n}\n\nasync function removeItem(context: ImportContext, item: ScaffoldItemRef): Promise<void> {\n\tconst db = context.db;\n\tswitch (item.type) {\n\t\tcase \"collection\": {\n\t\t\tconst row =\n\t\t\t\t(await db\n\t\t\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t\t\t.select(\"slug\")\n\t\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t\t.executeTakeFirst()) ??\n\t\t\t\t(await db\n\t\t\t\t\t.selectFrom(\"_emdash_media_usage_collection_deletions\")\n\t\t\t\t\t.select(\"collection_slug as slug\")\n\t\t\t\t\t.where(\"collection_id\", \"=\", item.id)\n\t\t\t\t\t.executeTakeFirst());\n\t\t\tif (!row) return;\n\t\t\ttry {\n\t\t\t\tawait new SchemaRegistry(db).deleteCollection(row.slug);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof SchemaError && error.code === \"COLLECTION_NOT_FOUND\") return;\n\t\t\t\tif (error instanceof SchemaError) {\n\t\t\t\t\tthrow new TransferError(\"TRANSFER_TARGET_NOT_EMPTY\", \"Scaffold collection is in use\", {\n\t\t\t\t\t\tdetail: { type: item.type, id: item.id, reason: error.code },\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tcase \"term\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"taxonomies\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.where(\n\t\t\t\t\t\t\t\t\t\"content_taxonomies.taxonomy_id\",\n\t\t\t\t\t\t\t\t\t\"=\",\n\t\t\t\t\t\t\t\t\teb.fn.coalesce(\"taxonomies.translation_group\", \"taxonomies.id\"),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"menu_item\":\n\t\t\tawait db.deleteFrom(\"_emdash_menu_items\").where(\"id\", \"=\", item.id).execute();\n\t\t\treturn;\n\t\tcase \"widget\":\n\t\t\tawait db.deleteFrom(\"_emdash_widgets\").where(\"id\", \"=\", item.id).execute();\n\t\t\treturn;\n\t\tcase \"taxonomy_def\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_taxonomy_defs\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.whereRef(\"taxonomies.name\", \"=\", \"_emdash_taxonomy_defs.name\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"menu\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_menus\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"_emdash_menu_items\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.whereRef(\"_emdash_menu_items.menu_id\", \"=\", \"_emdash_menus.id\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"widget_area\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_widget_areas\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"_emdash_widgets\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.whereRef(\"_emdash_widgets.area_id\", \"=\", \"_emdash_widget_areas.id\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"section\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_sections\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where(\"source\", \"=\", \"theme\")\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"block_type\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_block_type_versions\")\n\t\t\t\t.where(\"block_type_id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"_emdash_block_types\")\n\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t.where(\"_emdash_block_types.id\", \"=\", item.id)\n\t\t\t\t\t\t\t.where(\"_emdash_block_types.source\", \"=\", \"seed\"),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_block_types\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where(\"source\", \"=\", \"seed\")\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tdefault:\n\t\t\tthrow new TransferError(\"TRANSFER_IMPORT_ERROR\", \"Unknown scaffold item type\", {\n\t\t\t\tdetail: { type: item.type, id: item.id },\n\t\t\t});\n\t}\n}\n","/**\n * Import execution: one bounded `advanceImport` step at a time.\n *\n * Stages (`IMPORT_STAGES`): reserve → clear_scaffold → schema → media →\n * terms_bylines → content → relations → presentation → rebuild → verify.\n * Every step claims the operation's lease, runs units until the stage work\n * or the step budget runs out, and checkpoints the typed cursor after each\n * unit through the lease-fenced operation repository. Every unit is\n * idempotent, so an interrupted step is resumed by advancing again (after\n * the lease expires if the interrupted caller still held it). Cancellation\n * requested while a step runs is honored at the next checkpoint.\n */\n\nimport type { Kysely } from \"kysely\";\nimport type { z } from \"zod\";\n\nimport { isPostgres } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { isMissingTableError } from \"../../utils/db-errors.js\";\nimport { VERSION } from \"../../version.js\";\nimport { inspectPortableDomain } from \"../domain.js\";\nimport { isTransferError, TransferError, type TransferErrorCode } from \"../errors.js\";\nimport { planDigest, type Sha256Digest } from \"../format/digest.js\";\nimport { IMPORT_RECORD_STAGES } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport { isPlanExecutable, siteImportPlanSchema, type SiteImportPlan } from \"../format/plan.js\";\nimport { sealReceipt } from \"../format/receipt.js\";\nimport { SITE_PACKAGE_FORMAT_VERSION } from \"../format/version.js\";\nimport { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferOperationRepository, type TransferOperation } from \"../ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport {\n\tEXECUTING_IMPORT_STATES,\n\ttype ImportCursor,\n\tIMPORT_STAGES,\n\ttype ImportStage,\n\tisTerminalState,\n} from \"../ops/states.js\";\nimport { getOrCreateSiteId } from \"../site-id.js\";\nimport { stagingPrefix } from \"../staging/keys.js\";\nimport { StagedPackageReader } from \"../staging/package.js\";\nimport { TransferStage } from \"../staging/stage.js\";\nimport { ImportContext } from \"./context.js\";\nimport { runRebuild } from \"./rebuild.js\";\nimport { clearScaffold, declaredScaffold } from \"./scaffold.js\";\nimport { firstPosition, ImportCancelledSignal, runRecordStage } from \"./stages.js\";\n\n/** Delay the caller should wait before advancing again after a retry-later step. */\nexport const IMPORT_RETRY_MS = 2000;\n\nexport interface VerifyImportStepInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\treader: StagedPackageReader;\n\tplan: SiteImportPlan;\n\t/** The verifier's cursor from its previous step, or null on the first step. */\n\tcursor: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport type VerifyImportStepResult =\n\t| { done: false; cursor: unknown }\n\t| {\n\t\t\tdone: true;\n\t\t\tlogicalDigest: Sha256Digest;\n\t\t\tcounts: Record<string, number>;\n\t\t\tmismatches: Array<{ kind: string; id: string; reason: string }>;\n\t };\n\nexport type VerifyImportStep = (input: VerifyImportStepInput) => Promise<VerifyImportStepResult>;\n\nexport interface AdvanceImportOptions {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/** Verification step (`verifyImportStep` from `transfer/export/verify.ts`). */\n\tverify: VerifyImportStep;\n\t/** Defaults to a budget over the current request's query metrics. */\n\tbudget?: TransferStepBudget;\n}\n\nexport interface AdvanceImportResult {\n\toperation: TransferOperation;\n\t/** When to advance again; null once the operation is terminal. */\n\tnextRequestInMs: number | null;\n\t/** Whether this step moved the import to a terminal state. */\n\tended: boolean;\n}\n\ntype StepResult = Omit<AdvanceImportResult, \"ended\">;\n\n/** Errors another caller's lease explains; the step is abandoned without touching the operation. */\nconst LEASE_CODES: ReadonlySet<TransferErrorCode> = new Set([\n\t\"TRANSFER_LEASE_LOST\",\n\t\"TRANSFER_LEASE_ACTIVE\",\n]);\n\n/**\n * Failures a later step may not hit again, and how many consecutive steps\n * may fail without progress before the import fails. A staged file that\n * cannot be read is usually gone for good, so it gets few attempts; storage\n * and database errors are more often passing. Every other transfer error\n * fails the import at once.\n */\nconst RETRY_LIMITS: Readonly<Partial<Record<TransferErrorCode, number>>> = {\n\tTRANSFER_FILE_MISSING: 3,\n\tTRANSFER_STORAGE_ERROR: 8,\n\tTRANSFER_IMPORT_ERROR: 8,\n};\n\nconst MAX_RETRY_DELAY_MS = 60_000;\n\n/** Delay before the `attempts`th retry: doubling from `IMPORT_RETRY_MS`. */\nexport function importRetryDelay(attempts: number): number {\n\treturn Math.min(IMPORT_RETRY_MS * 2 ** Math.max(0, attempts - 1), MAX_RETRY_DELAY_MS);\n}\n\nconst EXECUTABLE_STATES = [\"planned\", \"running\", \"verifying\"] as const;\n\nfunction result(operation: TransferOperation, nextRequestInMs: number): StepResult {\n\treturn {\n\t\toperation,\n\t\tnextRequestInMs: isTerminalState(operation.kind, operation.state) ? null : nextRequestInMs,\n\t};\n}\n\n/**\n * Mark a planned import for execution. Requires the digests the caller\n * reviewed; the first `advanceImport` then reserves the target. Repeating\n * the request for an import that already started returns it unchanged, with\n * `requested` false.\n */\nexport async function requestImportExecution(input: {\n\tdb: Kysely<Database>;\n\toperationId: string;\n\tpackageDigest: Sha256Digest;\n\tplanDigest: Sha256Digest;\n}): Promise<{ operation: TransferOperation; requested: boolean }> {\n\tconst ops = new TransferOperationRepository(input.db);\n\tconst operation = await ops.require(input.operationId);\n\tif (operation.kind !== \"import\") {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an import\");\n\t}\n\tif (operation.packageDigest !== input.packageDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Package digest does not match\");\n\t}\n\tif (operation.planDigest === null || operation.planDigest !== input.planDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan digest does not match\");\n\t}\n\tif (operation.state !== \"planned\" || operation.stage === \"reserve\") {\n\t\tconst started =\n\t\t\t(EXECUTING_IMPORT_STATES as readonly string[]).includes(operation.state) ||\n\t\t\toperation.mutationStartedAt !== null;\n\t\tif (operation.state === \"planned\" || started) return { operation, requested: false };\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be executed in its state\");\n\t}\n\tconst claim = await ops.claim(operation.id, [\"planned\"]);\n\tif (claim.outcome === \"lease_active\") {\n\t\tthrow new TransferError(\"TRANSFER_LEASE_ACTIVE\", \"Import is busy; try again\");\n\t}\n\tif (claim.outcome === \"invalid_state\") {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be executed in its state\");\n\t}\n\tconst requested = await ops.release(operation.id, claim.leaseToken, {\n\t\tstage: \"reserve\",\n\t\tcursor: { stage: \"reserve\" },\n\t});\n\treturn { operation: requested, requested: true };\n}\n\nexport async function advanceImport(options: AdvanceImportOptions): Promise<AdvanceImportResult> {\n\tconst ops = new TransferOperationRepository(options.db);\n\tconst claim = await ops.claim(options.operationId, EXECUTABLE_STATES);\n\tif (claim.outcome !== \"claimed\") {\n\t\tif (claim.operation.kind !== \"import\") {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an import\");\n\t\t}\n\t\treturn { ...result(claim.operation, IMPORT_RETRY_MS), ended: false };\n\t}\n\t// Only the lease holder moves a claimed import to a terminal state.\n\tconst step = await advanceClaimed(options, ops, claim.operation, claim.leaseToken);\n\treturn { ...step, ended: isTerminalState(step.operation.kind, step.operation.state) };\n}\n\nasync function advanceClaimed(\n\toptions: AdvanceImportOptions,\n\tops: TransferOperationRepository,\n\toperation: TransferOperation,\n\tleaseToken: string,\n): Promise<StepResult> {\n\tif (\n\t\toperation.kind !== \"import\" ||\n\t\t(operation.state === \"planned\" && operation.stage !== \"reserve\")\n\t) {\n\t\tawait ops.release(operation.id, leaseToken);\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\"Import has not been requested for execution\",\n\t\t);\n\t}\n\n\ttry {\n\t\tif (await mediaUsageActivating(options.db)) {\n\t\t\treturn result(await ops.release(operation.id, leaseToken), IMPORT_RETRY_MS);\n\t\t}\n\t\tconst context = await loadContext(options, ops, operation, leaseToken);\n\t\treturn await runStep(context, options.verify);\n\t} catch (error) {\n\t\tif (error instanceof ImportCancelledSignal) {\n\t\t\treturn result(await ops.finishCancelled(operation.id, leaseToken), 0);\n\t\t}\n\t\tif (isTransferError(error) && LEASE_CODES.has(error.code)) throw error;\n\t\tconst code: TransferErrorCode = isTransferError(error) ? error.code : \"TRANSFER_IMPORT_ERROR\";\n\t\tconst detail = isTransferError(error) ? error.detail : undefined;\n\t\tconst limit = RETRY_LIMITS[code];\n\t\tif (limit === undefined || (isTransferError(error) && code === \"TRANSFER_IMPORT_ERROR\")) {\n\t\t\treturn result(await ops.fail(operation.id, leaseToken, { code, detail }), 0);\n\t\t}\n\t\tif (!isTransferError(error)) console.error(\"[transfer] import step failed:\", error);\n\t\tconst latest = await ops.require(operation.id);\n\t\tconst attempts = retryAttempts(latest) + 1;\n\t\tconst retryDetail = { ...detail, attempts };\n\t\tif (attempts >= limit) {\n\t\t\treturn result(await ops.fail(operation.id, leaseToken, { code, detail: retryDetail }), 0);\n\t\t}\n\t\tconst released = await ops.release(operation.id, leaseToken, {\n\t\t\tretryError: { code, detail: retryDetail },\n\t\t});\n\t\treturn result(released, importRetryDelay(attempts));\n\t}\n}\n\n/** Consecutive failed steps recorded since the import last made progress. */\nfunction retryAttempts(operation: TransferOperation): number {\n\tif (operation.errorCode === null || isTerminalState(operation.kind, operation.state)) return 0;\n\tconst attempts = operation.errorDetail?.attempts;\n\treturn typeof attempts === \"number\" ? attempts : 0;\n}\n\nasync function mediaUsageActivating(db: Kysely<Database>): Promise<boolean> {\n\ttry {\n\t\tconst row = await db\n\t\t\t.selectFrom(\"_emdash_media_usage_activation\")\n\t\t\t.select(\"state\")\n\t\t\t.where(\"task_key\", \"=\", \"incremental_capture\")\n\t\t\t.executeTakeFirst();\n\t\treturn row?.state === \"activating\";\n\t} catch (error) {\n\t\tif (isMissingTableError(error)) return false;\n\t\tthrow error;\n\t}\n}\n\nasync function loadContext(\n\toptions: AdvanceImportOptions,\n\tops: TransferOperationRepository,\n\toperation: TransferOperation,\n\tleaseToken: string,\n): Promise<ImportContext> {\n\tconst stage = new TransferStage(\n\t\toptions.storage,\n\t\tstagingPrefix(\"import\", operation.id, operation.stagingSecret),\n\t);\n\tconst reader = new StagedPackageReader(\n\t\tstage,\n\t\tnew TransferStagedFileRepository(options.db).verifiedDigests(operation.id),\n\t);\n\tconst manifest = await reader.manifest();\n\tconst packageDigest = await reader.digest();\n\tif (operation.packageDigest !== packageDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Staged package does not match\");\n\t}\n\tconst planText = await stage.readAux(\"plan\", TRANSFER_LIMITS.manifestBytes);\n\tif (planText === null) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Import plan is missing\");\n\t}\n\tconst parsed = siteImportPlanSchema.safeParse(JSON.parse(planText));\n\tif (!parsed.success || (await planDigest(parsed.data)) !== operation.planDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Import plan does not match\");\n\t}\n\tconst plan = parsed.data;\n\tif (plan.packageDigest !== packageDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan is for another package\");\n\t}\n\tif (!isPlanExecutable(plan)) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_BLOCKED\", \"Import plan has blockers\");\n\t}\n\treturn new ImportContext(\n\t\toptions.db,\n\t\toptions.storage,\n\t\tops,\n\t\toperation,\n\t\tleaseToken,\n\t\tplan,\n\t\tmanifest,\n\t\treader,\n\t\toptions.budget ?? new TransferStepBudget(),\n\t);\n}\n\nfunction stageProgress(stage: ImportStage) {\n\treturn { done: IMPORT_STAGES.indexOf(stage), total: IMPORT_STAGES.length };\n}\n\nasync function checkpoint(\n\tcontext: ImportContext,\n\tcursor: ImportCursor,\n\tpatch: { state?: \"running\" | \"verifying\"; markMutationStarted?: true } = {},\n): Promise<void> {\n\tconst operation = await context.ops.advance(context.operationId, context.leaseToken, {\n\t\t...patch,\n\t\t...(context.operation.errorCode === null ? {} : { retryError: null }),\n\t\tstage: cursor.stage,\n\t\tcursor,\n\t\tprogress: stageProgress(cursor.stage),\n\t});\n\tcontext.operation = operation;\n\tif (operation.cancelRequestedAt !== null) throw new ImportCancelledSignal();\n}\n\nfunction currentCursor(operation: TransferOperation): ImportCursor {\n\tconst cursor = operation.cursor;\n\tif (cursor === null) return { stage: \"reserve\" };\n\tif (!(IMPORT_STAGES as readonly string[]).includes(cursor.stage)) {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation cursor is not an import cursor\");\n\t}\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- stage checked against IMPORT_STAGES\n\treturn cursor as ImportCursor;\n}\n\nfunction nextRecordStageCursor(stage: ImportStage): ImportCursor {\n\tconst next = IMPORT_STAGES[IMPORT_STAGES.indexOf(stage) + 1];\n\tif (next === \"rebuild\") return { stage: \"rebuild\", step: \"search\", after: null };\n\tconst recordStage = IMPORT_RECORD_STAGES.find((candidate: string) => candidate === next);\n\tif (!recordStage) throw new Error(`No record stage follows ${stage}`);\n\treturn { stage: recordStage, position: firstPosition(recordStage) };\n}\n\n/** The checkpoint that moves the cursor to the next stage. */\nconst TRANSITION_STATEMENTS = 1;\n\nasync function yieldStep(context: ImportContext, nextRequestInMs: number): Promise<StepResult> {\n\treturn result(\n\t\tawait context.ops.release(context.operationId, context.leaseToken),\n\t\tnextRequestInMs,\n\t);\n}\n\nasync function runStep(context: ImportContext, verify: VerifyImportStep): Promise<StepResult> {\n\tfor (;;) {\n\t\tconst cursor = currentCursor(context.operation);\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"reserve\":\n\t\t\t\tawait reserve(context);\n\t\t\t\tbreak;\n\t\t\tcase \"clear_scaffold\": {\n\t\t\t\tconst progress = await clearScaffold(context, cursor.step, (step) =>\n\t\t\t\t\tcheckpoint(context, { stage: \"clear_scaffold\", step }),\n\t\t\t\t);\n\t\t\t\tif (progress.state === \"continue\") return yieldStep(context, 0);\n\t\t\t\tif (progress.state === \"wait\") return yieldStep(context, IMPORT_RETRY_MS);\n\t\t\t\tif (!context.budget.canStart({ queries: TRANSITION_STATEMENTS })) {\n\t\t\t\t\treturn yieldStep(context, 0);\n\t\t\t\t}\n\t\t\t\tawait checkpoint(context, { stage: \"schema\", position: firstPosition(\"schema\") });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"schema\":\n\t\t\tcase \"media\":\n\t\t\tcase \"terms_bylines\":\n\t\t\tcase \"content\":\n\t\t\tcase \"relations\":\n\t\t\tcase \"presentation\": {\n\t\t\t\tconst stage = cursor.stage;\n\t\t\t\tconst remaining = await runRecordStage(context, stage, cursor.position, (position) =>\n\t\t\t\t\tcheckpoint(context, { stage, position }),\n\t\t\t\t);\n\t\t\t\tif (remaining || !context.budget.canStart({ queries: TRANSITION_STATEMENTS })) {\n\t\t\t\t\treturn yieldStep(context, 0);\n\t\t\t\t}\n\t\t\t\tawait checkpoint(context, nextRecordStageCursor(stage));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"rebuild\": {\n\t\t\t\tconst remaining = await runRebuild(\n\t\t\t\t\tcontext,\n\t\t\t\t\t{ step: cursor.step, after: cursor.after },\n\t\t\t\t\t(position) => checkpoint(context, { stage: \"rebuild\", ...position }),\n\t\t\t\t);\n\t\t\t\tif (remaining) return yieldStep(context, 0);\n\t\t\t\tawait checkpoint(\n\t\t\t\t\tcontext,\n\t\t\t\t\t{ stage: \"verify\", position: null, mediaAfter: null, mismatches: 0 },\n\t\t\t\t\t{ state: \"verifying\" },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"verify\":\n\t\t\t\treturn runVerify(context, verify, cursor.verifier ?? null);\n\t\t}\n\t}\n}\n\nasync function reserve(context: ImportContext): Promise<void> {\n\t// Running fences site writes before the checks below, so none can slip in\n\t// between them and the first write; a failed check leaves no fence behind\n\t// because the mutation has not started.\n\tawait checkpoint(context, { stage: \"reserve\" }, { state: \"running\" });\n\tconst siteId = await getOrCreateSiteId(context.db);\n\tconst dialect = isPostgres(context.db) ? \"postgres\" : \"sqlite\";\n\tif (siteId !== context.plan.target.siteId || dialect !== context.plan.target.dialect) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan was made for another target\");\n\t}\n\tawait assertMappedUsersExist(context);\n\tconst domain = await inspectPortableDomain(context.db);\n\tconst declared = new Set(declaredScaffold(context).map((item) => `${item.type}:${item.id}`));\n\tconst undeclared = domain.seededScaffold.filter(\n\t\t(item) => !declared.has(`${item.type}:${item.id}`),\n\t);\n\tif (!domain.empty || undeclared.length > 0) {\n\t\tthrow new TransferError(\"TRANSFER_TARGET_NOT_EMPTY\", \"The target site is not empty\", {\n\t\t\tdetail: { blockers: domain.blockers.length, undeclaredScaffold: undeclared.length },\n\t\t});\n\t}\n\tawait checkpoint(context, { stage: \"clear_scaffold\", step: 0 }, { markMutationStarted: true });\n}\n\nasync function assertMappedUsersExist(context: ImportContext): Promise<void> {\n\tconst mappings = Object.entries(context.plan.decisions.principalMappings);\n\tconst userIds = [...new Set(mappings.flatMap(([, userId]) => (userId === null ? [] : [userId])))];\n\tconst found = new Set<string>();\n\tfor (const batch of chunks(userIds, SQL_BATCH_SIZE)) {\n\t\tconst rows = await context.db\n\t\t\t.selectFrom(\"users\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of rows) found.add(row.id);\n\t}\n\tconst missing = mappings.find(([, userId]) => userId !== null && !found.has(userId));\n\tif (missing) {\n\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"A mapped target user no longer exists\", {\n\t\t\tdetail: { principal: missing[0] },\n\t\t});\n\t}\n}\n\nasync function runVerify(\n\tcontext: ImportContext,\n\tverify: VerifyImportStep,\n\tstart: unknown,\n): Promise<StepResult> {\n\tconst step = await verify({\n\t\tdb: context.db,\n\t\tstorage: context.storage,\n\t\toperationId: context.operationId,\n\t\treader: context.reader,\n\t\tplan: context.plan,\n\t\tcursor: start,\n\t\tbudget: context.budget,\n\t});\n\t// The verifier runs until its budget is spent, so an unfinished step ends this one.\n\tif (!step.done) {\n\t\tawait checkpoint(context, {\n\t\t\tstage: \"verify\",\n\t\t\tposition: null,\n\t\t\tmediaAfter: null,\n\t\t\tmismatches: 0,\n\t\t\tverifier: toJson(step.cursor),\n\t\t});\n\t\treturn yieldStep(context, 0);\n\t}\n\tif (step.mismatches.length > 0) {\n\t\tconst detail: Record<string, string | number> = { mismatches: step.mismatches.length };\n\t\tstep.mismatches.slice(0, TRANSFER_LIMITS.verificationMismatches).forEach((mismatch, index) => {\n\t\t\tdetail[`mismatch_${index}`] = `${mismatch.kind}:${mismatch.id}:${mismatch.reason}`.slice(\n\t\t\t\t0,\n\t\t\t\t512,\n\t\t\t);\n\t\t});\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_VERIFICATION_FAILED\",\n\t\t\t\"Imported site does not match the package\",\n\t\t\t{\n\t\t\t\tdetail,\n\t\t\t},\n\t\t);\n\t}\n\tconst operation = context.operation;\n\tif (operation.packageDigest === null || operation.planDigest === null) {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import digests are missing\");\n\t}\n\tconst receipt = await sealReceipt({\n\t\toperationId: operation.id,\n\t\tpackageDigest: operation.packageDigest,\n\t\tplanDigest: operation.planDigest,\n\t\ttargetSiteId: context.plan.target.siteId,\n\t\toriginSiteId: context.manifest.originSiteId,\n\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\timporterEmDashVersion: VERSION,\n\t\tcompletedAt: new Date().toISOString(),\n\t\tlogicalDigest: step.logicalDigest,\n\t\tcounts: step.counts,\n\t\twarnings: context.plan.warnings\n\t\t\t.slice(0, 500)\n\t\t\t.map((warning) => ({ code: warning.code, message: warning.message })),\n\t\tverification: \"verified\",\n\t});\n\tconst completed = await context.ops.complete(operation.id, context.leaseToken, {\n\t\treceipt,\n\t\tprogress: { done: IMPORT_STAGES.length, total: IMPORT_STAGES.length },\n\t});\n\treturn result(completed, 0);\n}\n\nfunction toJson(value: unknown): z.infer<ReturnType<typeof z.json>> {\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- the verifier's cursor is plain JSON by contract; the cursor schema validates it on write\n\treturn value as z.infer<ReturnType<typeof z.json>>;\n}\n","/**\n * Site transfer handlers: capabilities, exports and their downloads, staged\n * import uploads, analysis, execution, operation status and control, and MCP\n * approval grants.\n *\n * Operations are always serialized with `toPublicOperation`, which drops the\n * staging secret and lease token.\n *\n * Import upload flow: `POST imports` with the manifest stages it and declares\n * the index chunks the manifest pins. Each index chunk upload declares every\n * file that chunk lists. A client uploads whatever `missing` lists, then asks\n * for `missing` again, until it is empty; index paths sort before record and\n * media paths, so they are listed first.\n */\n\nimport type { Permission, RoleLevel } from \"@emdash-cms/auth\";\nimport { hasPermission } from \"@emdash-cms/auth\";\nimport type { Kysely } from \"kysely\";\n\nimport {\n\tdecodeCursor,\n\tencodeCursor,\n\tInvalidCursorError,\n} from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { DownloadResult, Storage } from \"../../storage/types.js\";\nimport { analyzeImportStep, finalizePlan, loadImportPlan } from \"../../transfer/analyze/step.js\";\nimport type { AnalysisTargetContext } from \"../../transfer/analyze/target.js\";\nimport { validateStagedPackageStep } from \"../../transfer/analyze/validate.js\";\nimport { recordTransferAudit } from \"../../transfer/audit.js\";\nimport type { TransferApprovalAction } from \"../../transfer/auth.js\";\nimport { packSitePackage, type PackageFileSource } from \"../../transfer/container/tar.js\";\nimport { inspectPortableDomain } from \"../../transfer/domain.js\";\nimport { isTransferError, TransferError } from \"../../transfer/errors.js\";\nimport {\n\tadvanceExport,\n\tcreateExport,\n\texportOptionsSchema,\n\topenExportPackage,\n\ttype ExportOptions,\n\ttype ExportPackageValidator,\n} from \"../../transfer/export/exporter.js\";\nimport { verifyImportStep } from \"../../transfer/export/verify.js\";\nimport {\n\tcanonicalDigest,\n\tcreateHashingStream,\n\tcreateSha256,\n\tpackageDigest,\n\tsha256Hex,\n\ttype Sha256Digest,\n} from \"../../transfer/format/digest.js\";\nimport { OPTIONAL_FEATURES, SITE_PACKAGE_FEATURES } from \"../../transfer/format/features.js\";\nimport { TRANSFER_LIMITS } from \"../../transfer/format/limits.js\";\nimport { parseManifest, type SitePackageManifest } from \"../../transfer/format/manifest.js\";\nimport { MANIFEST_PATH, parsePackagePath } from \"../../transfer/format/paths.js\";\nimport {\n\tisPlanExecutable,\n\ttype SiteImportDecisionsInput,\n\ttype SiteImportPlan,\n} from \"../../transfer/format/plan.js\";\nimport type { SiteImportReceipt } from \"../../transfer/format/receipt.js\";\nimport { SUPPORTED_FORMAT_VERSIONS } from \"../../transfer/format/version.js\";\nimport { advanceImport, requestImportExecution } from \"../../transfer/import/index.js\";\nimport {\n\tTransferApprovalRepository,\n\ttype ApprovalStatus,\n\ttype TransferApproval,\n} from \"../../transfer/ops/approvals.js\";\nimport { TransferStepBudget } from \"../../transfer/ops/budget.js\";\nimport {\n\ttoPublicOperation,\n\tTransferOperationRepository,\n\ttype PublicTransferOperation,\n\ttype TransferOperation,\n} from \"../../transfer/ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../../transfer/ops/staged-files.js\";\nimport { stagingPrefix } from \"../../transfer/staging/keys.js\";\nimport { StagedPackageReader } from \"../../transfer/staging/package.js\";\nimport { TransferStage } from \"../../transfer/staging/stage.js\";\nimport type { ApiResult } from \"../types.js\";\n\n/** Poll delay suggested while another request holds an operation's lease. */\nconst LEASE_RETRY_MS = 1000;\n\nfunction isLeaseError(error: unknown): boolean {\n\treturn (\n\t\tisTransferError(error) &&\n\t\t(error.code === \"TRANSFER_LEASE_LOST\" || error.code === \"TRANSFER_LEASE_ACTIVE\")\n\t);\n}\n\nconst PAGE_LIMIT_DEFAULT = 50;\nconst PAGE_LIMIT_MAX = 100;\n\ntype ErrorResult = Extract<ApiResult<never>, { success: false }>;\n\nfunction failure(code: string, message: string, details?: Record<string, unknown>): ErrorResult {\n\treturn {\n\t\tsuccess: false,\n\t\terror: details === undefined ? { code, message } : { code, message, details },\n\t};\n}\n\nfunction errorResult(error: unknown, fallbackCode: string, fallbackMessage: string): ErrorResult {\n\tif (isTransferError(error)) {\n\t\treturn failure(error.code, error.message, error.detail ? { ...error.detail } : undefined);\n\t}\n\tif (error instanceof InvalidCursorError) {\n\t\treturn failure(\"INVALID_CURSOR\", \"Invalid pagination cursor\");\n\t}\n\tconsole.error(`[transfer] ${fallbackMessage}:`, error);\n\treturn failure(fallbackCode, fallbackMessage);\n}\n\nfunction pageLimit(limit: number | undefined): number {\n\treturn Math.min(Math.max(Math.trunc(limit ?? PAGE_LIMIT_DEFAULT), 1), PAGE_LIMIT_MAX);\n}\n\nfunction decodeTimeCursor(\n\tcursor: string | undefined,\n): { createdAt: string; id: string } | undefined {\n\tif (cursor === undefined) return undefined;\n\tconst { orderValue, id } = decodeCursor(cursor);\n\treturn { createdAt: orderValue, id };\n}\n\nfunction stageFor(storage: Storage, operation: TransferOperation): TransferStage {\n\treturn new TransferStage(\n\t\tstorage,\n\t\tstagingPrefix(operation.kind, operation.id, operation.stagingSecret),\n\t);\n}\n\nasync function requireImport(\n\toperations: TransferOperationRepository,\n\toperationId: string,\n): Promise<TransferOperation> {\n\tconst operation = await operations.get(operationId);\n\tif (!operation || operation.kind !== \"import\") {\n\t\tthrow new TransferError(\"TRANSFER_OPERATION_NOT_FOUND\", \"Transfer operation not found\");\n\t}\n\treturn operation;\n}\n\n// ── Capabilities ────────────────────────────────────────────────\n\nexport interface TransferCapabilities {\n\tformatVersions: string[];\n\tfeatures: string[];\n\toptionalFeatures: string[];\n\tlimits: {\n\t\tmanifestBytes: number;\n\t\trecordLineBytes: number;\n\t\tchunkBytes: number;\n\t\tchunkRecords: number;\n\t\ttotalRecords: number;\n\t\ttotalFiles: number;\n\t\tindexChunks: number;\n\t\tjsonDepth: number;\n\t\tmaxBlobBytes: number;\n\t};\n\tportableDomain: {\n\t\tempty: boolean;\n\t\tblockers: Array<Record<string, string>>;\n\t\tseededScaffold: Array<Record<string, string>>;\n\t};\n}\n\nexport async function handleTransferCapabilities(\n\tdb: Kysely<Database>,\n\ttarget: AnalysisTargetContext,\n): Promise<ApiResult<TransferCapabilities>> {\n\ttry {\n\t\tconst domain = await inspectPortableDomain(db);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\tformatVersions: [...SUPPORTED_FORMAT_VERSIONS],\n\t\t\t\tfeatures: [...SITE_PACKAGE_FEATURES],\n\t\t\t\toptionalFeatures: [...OPTIONAL_FEATURES].toSorted(),\n\t\t\t\tlimits: {\n\t\t\t\t\tmanifestBytes: TRANSFER_LIMITS.manifestBytes,\n\t\t\t\t\trecordLineBytes: TRANSFER_LIMITS.recordLineBytes,\n\t\t\t\t\tchunkBytes: TRANSFER_LIMITS.chunkBytes,\n\t\t\t\t\tchunkRecords: TRANSFER_LIMITS.chunkRecords,\n\t\t\t\t\ttotalRecords: TRANSFER_LIMITS.totalRecords,\n\t\t\t\t\ttotalFiles: TRANSFER_LIMITS.totalFiles,\n\t\t\t\t\tindexChunks: TRANSFER_LIMITS.indexChunks,\n\t\t\t\t\tjsonDepth: TRANSFER_LIMITS.jsonDepth,\n\t\t\t\t\tmaxBlobBytes: target.maxUploadSize,\n\t\t\t\t},\n\t\t\t\tportableDomain: {\n\t\t\t\t\tempty: domain.empty,\n\t\t\t\t\tblockers: domain.blockers.map((blocker) => ({ ...blocker })),\n\t\t\t\t\tseededScaffold: domain.seededScaffold.map((item) => ({ ...item })),\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_ANALYZE_ERROR\", \"Failed to read transfer capabilities\");\n\t}\n}\n\n// ── Imports: creation and uploads ───────────────────────────────\n\nexport interface TransferMissingFiles {\n\titems: Array<{ path: string; bytes: number; sha256: string }>;\n\tnextCursor?: string;\n}\n\nasync function listMissing(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\toptions: { cursor?: string; limit?: number },\n): Promise<TransferMissingFiles> {\n\tconst limit = pageLimit(options.limit);\n\tconst after = options.cursor === undefined ? undefined : decodeCursor(options.cursor).orderValue;\n\tconst files = await new TransferStagedFileRepository(db).list(operationId, {\n\t\tstate: \"declared\",\n\t\tafter,\n\t\tlimit: limit + 1,\n\t});\n\tconst items = files\n\t\t.slice(0, limit)\n\t\t.map((file) => ({ path: file.path, bytes: file.bytes, sha256: file.sha256 }));\n\tconst last = items.at(-1);\n\treturn files.length > limit && last\n\t\t? { items, nextCursor: encodeCursor(last.path, last.path) }\n\t\t: { items };\n}\n\nasync function stageManifest(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperation: TransferOperation,\n\tmanifest: SitePackageManifest,\n\tbytes: Uint8Array,\n): Promise<void> {\n\tconst staged = new TransferStagedFileRepository(db);\n\tconst existing = await staged.get(operation.id, MANIFEST_PATH);\n\tif (existing?.state !== \"verified\") {\n\t\tconst sha256 = await sha256Hex(bytes);\n\t\tawait stageFor(storage, operation).putVerified(MANIFEST_PATH, bytes, bytes.byteLength, sha256, {\n\t\t\tcontentType: \"application/json\",\n\t\t\tkeepExistingOnFailure: () => staged.isVerified(operation.id, MANIFEST_PATH),\n\t\t});\n\t\tawait staged.declareMany(\n\t\t\toperation.id,\n\t\t\t[{ path: MANIFEST_PATH, bytes: bytes.byteLength, sha256 }],\n\t\t\t\"verified\",\n\t\t);\n\t}\n\tawait staged.declareMany(\n\t\toperation.id,\n\t\tmanifest.index.map((ref) => ({ path: ref.path, bytes: ref.bytes, sha256: ref.sha256 })),\n\t);\n}\n\nexport interface CreateImportInput {\n\tuserId: string;\n\t/** Raw `manifest.json` bytes (canonical JSON). */\n\tmanifest: Uint8Array;\n\tidempotencyKey?: string;\n}\n\n/**\n * Create an import from a manifest, stage the manifest, and return the first\n * page of files still to upload. The same idempotency key with the same\n * manifest returns the existing operation; with a different manifest it\n * fails with `TRANSFER_IDEMPOTENCY_CONFLICT`.\n */\nexport async function handleImportCreate(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: CreateImportInput,\n): Promise<\n\tApiResult<{ operation: PublicTransferOperation; created: boolean; missing: TransferMissingFiles }>\n> {\n\ttry {\n\t\tconst manifest = parseManifest(input.manifest);\n\t\tconst digest = await packageDigest(manifest);\n\t\tconst domain = await inspectPortableDomain(db);\n\t\tif (!domain.empty) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_TARGET_NOT_EMPTY\",\n\t\t\t\t\"This site already has content; import needs an empty site\",\n\t\t\t\t{ detail: { blockers: domain.blockers.length } },\n\t\t\t);\n\t\t}\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tconst { operation, created } = await operations.create({\n\t\t\tkind: \"import\",\n\t\t\tcreatedBy: input.userId,\n\t\t\tidempotencyKey: input.idempotencyKey,\n\t\t\tpackageDigest: digest,\n\t\t\toriginSiteId: manifest.originSiteId,\n\t\t});\n\t\tif (operation.kind !== \"import\") {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an import\");\n\t\t}\n\t\tif (created) {\n\t\t\tawait recordTransferAudit(db, {\n\t\t\t\tactorId: input.userId,\n\t\t\t\taction: \"transfer_import_create\",\n\t\t\t\tresourceType: \"transfer_operation\",\n\t\t\t\tresourceId: operation.id,\n\t\t\t\tdetails: { packageDigest: digest },\n\t\t\t});\n\t\t}\n\t\tif (operation.state === \"uploading\") {\n\t\t\tawait stageManifest(db, storage, operation, manifest, input.manifest);\n\t\t}\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\toperation: toPublicOperation(operation),\n\t\t\t\tcreated,\n\t\t\t\tmissing: await listMissing(db, operation.id, {}),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to create import\");\n\t}\n}\n\nexport async function handleImportMissing(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\toptions: { cursor?: string; limit?: number },\n): Promise<ApiResult<TransferMissingFiles>> {\n\ttry {\n\t\tawait requireImport(new TransferOperationRepository(db), operationId);\n\t\treturn { success: true, data: await listMissing(db, operationId, options) };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to list missing files\");\n\t}\n}\n\nexport interface UploadImportFileInput {\n\toperationId: string;\n\tpath: string;\n\t/** `Content-Length` of the request. */\n\tcontentLength: number;\n\tbody: ReadableStream<Uint8Array> | null;\n\t/** Largest media blob the site accepts (`maxUploadSize`). */\n\tmaxBlobBytes: number;\n}\n\nexport interface UploadImportFileResult {\n\tpath: string;\n\tbytes: number;\n\t/** True when the path was already verified and the body matched it. */\n\talreadyVerified: boolean;\n\t/** Declared files still to upload. */\n\tremaining: number;\n}\n\nfunction fileLimit(type: \"manifest\" | \"index\" | \"records\" | \"media\", maxBlobBytes: number): number {\n\tswitch (type) {\n\t\tcase \"manifest\":\n\t\t\treturn TRANSFER_LIMITS.manifestBytes;\n\t\tcase \"media\":\n\t\t\treturn maxBlobBytes;\n\t\tcase \"index\":\n\t\tcase \"records\":\n\t\t\treturn TRANSFER_LIMITS.chunkBytes;\n\t}\n}\n\nasync function digestOfBody(body: ReadableStream<Uint8Array> | null, bytes: number) {\n\tconst hasher = await createSha256();\n\tconst hashing = createHashingStream(hasher, {\n\t\tmaxBytes: bytes,\n\t\tonLimitExceeded: () =>\n\t\t\tnew TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"File is larger than declared\"),\n\t});\n\tif (body) await body.pipeThrough(hashing.stream).pipeTo(new WritableStream());\n\treturn { sha256: await hasher.digest(), bytes: hashing.bytes() };\n}\n\n/**\n * Whether the staged object at `path` exists and still holds exactly the\n * bytes it was verified with. A storage error other than a missing object\n * is thrown rather than read as a mismatch.\n */\nasync function stagedFileIntact(\n\tstage: TransferStage,\n\tpath: string,\n\tfile: { bytes: number; sha256: string },\n): Promise<boolean> {\n\tif (!(await stage.exists(path))) return false;\n\tlet download: DownloadResult;\n\ttry {\n\t\tdownload = await stage.storage.download(stage.keyFor(path));\n\t} catch (error) {\n\t\tthrow new TransferError(\"TRANSFER_STORAGE_ERROR\", \"Failed to read a staged file\", {\n\t\t\tcause: error,\n\t\t});\n\t}\n\ttry {\n\t\tconst stored = await digestOfBody(download.body, file.bytes);\n\t\treturn stored.bytes === file.bytes && stored.sha256 === file.sha256;\n\t} catch (error) {\n\t\tif (isTransferError(error) && error.code === \"TRANSFER_FILE_SIZE_MISMATCH\") return false;\n\t\tthrow error;\n\t}\n}\n\n/**\n * Stream one declared package file into staging, verifying its size and\n * digest. Uploading an index chunk declares the files it lists. A path that\n * is already verified is only compared, never written, while its staged\n * object still matches; once that object no longer matches (a failed\n * concurrent upload of the same path overwrote it), an upload replaces it.\n * An upload that is still streaming when analysis starts is refused.\n */\nexport async function handleImportFileUpload(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: UploadImportFileInput,\n): Promise<ApiResult<UploadImportFileResult>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tconst operation = await requireImport(operations, input.operationId);\n\t\tif (operation.state !== \"uploading\") {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\t\"Files can only be uploaded before analysis\",\n\t\t\t);\n\t\t}\n\t\tconst parsed = parsePackagePath(input.path);\n\t\tif (!parsed) {\n\t\t\tthrow new TransferError(\"TRANSFER_PATH_INVALID\", \"Invalid package path\");\n\t\t}\n\t\tconst staged = new TransferStagedFileRepository(db);\n\t\tconst file = await staged.get(operation.id, parsed.path);\n\t\tif (!file) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_NOT_DECLARED\", \"File is not declared by the package\", {\n\t\t\t\tdetail: { path: parsed.path },\n\t\t\t});\n\t\t}\n\t\tconst limit = fileLimit(parsed.type, input.maxBlobBytes);\n\t\tif (file.bytes > limit) {\n\t\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"File is larger than this site accepts\", {\n\t\t\t\tdetail: { path: parsed.path, bytes: file.bytes, limit },\n\t\t\t});\n\t\t}\n\t\tif (input.contentLength !== file.bytes) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_FILE_SIZE_MISMATCH\",\n\t\t\t\t\"Content-Length does not match the declared size\",\n\t\t\t\t{ detail: { path: parsed.path, expected: file.bytes } },\n\t\t\t);\n\t\t}\n\n\t\tconst stage = stageFor(storage, operation);\n\t\tif (file.state === \"verified\" && (await stagedFileIntact(stage, parsed.path, file))) {\n\t\t\tconst received = await digestOfBody(input.body, file.bytes);\n\t\t\tif (received.bytes !== file.bytes) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"File size does not match\", {\n\t\t\t\t\tdetail: { path: parsed.path, expected: file.bytes },\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (received.sha256 !== file.sha256) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_DIGEST_MISMATCH\", \"File digest does not match\", {\n\t\t\t\t\tdetail: { path: parsed.path },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tpath: parsed.path,\n\t\t\t\t\tbytes: file.bytes,\n\t\t\t\t\talreadyVerified: true,\n\t\t\t\t\tremaining: (await staged.countByState(operation.id)).declared,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tawait stage.putVerified(parsed.path, input.body ?? new Uint8Array(0), file.bytes, file.sha256, {\n\t\t\tkeepExistingOnFailure: () => staged.isVerified(operation.id, parsed.path),\n\t\t});\n\t\tif ((await operations.require(operation.id)).state !== \"uploading\") {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\t\"Files can only be uploaded before analysis\",\n\t\t\t);\n\t\t}\n\t\tif (parsed.type === \"index\") {\n\t\t\tconst entries = await new StagedPackageReader(stage).indexChunk(parsed.seq);\n\t\t\tawait staged.declareMany(\n\t\t\t\toperation.id,\n\t\t\t\tentries.map((entry) => ({ path: entry.path, bytes: entry.bytes, sha256: entry.sha256 })),\n\t\t\t);\n\t\t}\n\t\tawait staged.markVerified(operation.id, file);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\tpath: parsed.path,\n\t\t\t\tbytes: file.bytes,\n\t\t\t\talreadyVerified: false,\n\t\t\t\tremaining: (await staged.countByState(operation.id)).declared,\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_STORAGE_ERROR\", \"Failed to store the uploaded file\");\n\t}\n}\n\n// ── Imports: analysis and plan ──────────────────────────────────\n\nexport interface AnalyzeImportInput {\n\toperationId: string;\n\tdecisions?: SiteImportDecisionsInput;\n\ttarget: AnalysisTargetContext;\n\tbudget?: TransferStepBudget;\n}\n\nexport interface AnalyzeImportResult {\n\toperation: PublicTransferOperation;\n\tplan?: SiteImportPlan;\n\tplanDigest?: Sha256Digest;\n\t/** Milliseconds until the client should call again, or null when analysis has ended. */\n\tnextRequestInMs: number | null;\n}\n\n/**\n * Run one bounded analysis step. Once the import is planned, returns the plan\n * and, when `decisions` are given, applies them first. Decisions are refused\n * with `TRANSFER_INVALID_STATE` once execution has been requested.\n */\nexport async function handleImportAnalyze(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: AnalyzeImportInput,\n): Promise<ApiResult<AnalyzeImportResult>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tlet operation = await requireImport(operations, input.operationId);\n\t\tlet plan: SiteImportPlan | null = null;\n\t\tlet digest: Sha256Digest | null = null;\n\n\t\tif (operation.state === \"uploading\") {\n\t\t\tconst { declared } = await new TransferStagedFileRepository(db).countByState(operation.id);\n\t\t\tif (declared > 0) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Some package files are not uploaded\", {\n\t\t\t\t\tdetail: { missing: declared },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (operation.state === \"uploading\" || operation.state === \"analyzing\") {\n\t\t\tconst step = await analyzeImportStep({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: operation.id,\n\t\t\t\tbudget: input.budget ?? new TransferStepBudget(),\n\t\t\t\ttargetContext: input.target,\n\t\t\t}).catch((error: unknown) => {\n\t\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_LEASE_ACTIVE\") return null;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\t\tif (!step) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: toPublicOperation(await operations.require(operation.id)),\n\t\t\t\t\t\tnextRequestInMs: LEASE_RETRY_MS,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\toperation = step.operation;\n\t\t\tif (!step.done) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: { operation: toPublicOperation(operation), nextRequestInMs: 0 },\n\t\t\t\t};\n\t\t\t}\n\t\t\tplan = step.plan;\n\t\t\tdigest = step.planDigest;\n\t\t} else if (operation.state === \"planned\") {\n\t\t\tplan = await loadImportPlan(storage, operation);\n\t\t\tdigest = operation.planDigest;\n\t\t} else {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import is past analysis\");\n\t\t}\n\n\t\tif (operation.state === \"planned\" && input.decisions !== undefined) {\n\t\t\tconst finalized = await finalizePlan({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: operation.id,\n\t\t\t\tdecisions: input.decisions,\n\t\t\t});\n\t\t\tplan = finalized.plan;\n\t\t\tdigest = finalized.planDigest;\n\t\t\toperation = await operations.require(operation.id);\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\toperation: toPublicOperation(operation),\n\t\t\t\t...(plan ? { plan } : {}),\n\t\t\t\t...(plan && digest ? { planDigest: digest } : {}),\n\t\t\t\tnextRequestInMs: null,\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_ANALYZE_ERROR\", \"Failed to analyze import\");\n\t}\n}\n\nexport async function handleImportPlan(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperationId: string,\n): Promise<ApiResult<{ plan: SiteImportPlan; planDigest: Sha256Digest }>> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), operationId);\n\t\tconst plan = operation.planDigest ? await loadImportPlan(storage, operation) : null;\n\t\tif (!plan || !operation.planDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has not been analyzed\");\n\t\t}\n\t\treturn { success: true, data: { plan, planDigest: operation.planDigest } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_ANALYZE_ERROR\", \"Failed to read import plan\");\n\t}\n}\n\n// ── Imports: status and control ─────────────────────────────────\n\nexport async function handleImportGet(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<\n\tApiResult<{\n\t\toperation: PublicTransferOperation;\n\t\tfiles: { declared: number; verified: number };\n\t}>\n> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), operationId);\n\t\tconst files = await new TransferStagedFileRepository(db).countByState(operation.id);\n\t\treturn { success: true, data: { operation: toPublicOperation(operation), files } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to read import\");\n\t}\n}\n\nexport async function handleImportList(\n\tdb: Kysely<Database>,\n\toptions: { cursor?: string; limit?: number },\n): Promise<ApiResult<{ items: PublicTransferOperation[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst page = await new TransferOperationRepository(db).list({\n\t\t\tkind: \"import\",\n\t\t\tlimit: pageLimit(options.limit),\n\t\t\tcursor: decodeTimeCursor(options.cursor),\n\t\t});\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: page.next\n\t\t\t\t? { items: page.items, nextCursor: encodeCursor(page.next.createdAt, page.next.id) }\n\t\t\t\t: { items: page.items },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to list imports\");\n\t}\n}\n\n/** Cancel an import; a step in flight stops after its current batch. */\nexport async function handleImportCancel(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\tuserId: string,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireImport(operations, operationId);\n\t\tconst operation = await operations.requestCancel(operationId);\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_cancel\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operationId,\n\t\t});\n\t\treturn { success: true, data: { operation: toPublicOperation(operation) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to cancel import\");\n\t}\n}\n\n/**\n * Abandon a failed or cancelled import. Lifts the site write fence; imported\n * data stays in place.\n */\nexport async function handleImportAbandon(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\tuserId: string,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireImport(operations, operationId);\n\t\tconst operation = await operations.abandon(operationId);\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_abandon\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operationId,\n\t\t});\n\t\treturn { success: true, data: { operation: toPublicOperation(operation) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to abandon import\");\n\t}\n}\n\n// ── Exports ─────────────────────────────────────────────────────\n\nasync function requireExport(\n\toperations: TransferOperationRepository,\n\toperationId: string,\n): Promise<TransferOperation> {\n\tconst operation = await operations.get(operationId);\n\tif (!operation || operation.kind !== \"export\") {\n\t\tthrow new TransferError(\"TRANSFER_OPERATION_NOT_FOUND\", \"Transfer operation not found\");\n\t}\n\treturn operation;\n}\n\nasync function requireCompleteExport(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<TransferOperation> {\n\tconst operation = await requireExport(new TransferOperationRepository(db), operationId);\n\tif (operation.state !== \"complete\") {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Export is not complete\");\n\t}\n\tif (operation.stagingCollectedAt !== null) {\n\t\tthrow new TransferError(\"TRANSFER_EXPIRED\", \"Export files are no longer available\");\n\t}\n\treturn operation;\n}\n\n/**\n * Run `start` after a grant was consumed for it, handing the grant back when\n * the operation does not start so the caller can retry with it.\n */\nasync function withGrantRestoredOnFailure<T>(\n\tapprovals: TransferApprovalRepository,\n\tapproval: TransferApprovalGrant | undefined,\n\tstart: () => Promise<T>,\n): Promise<T> {\n\ttry {\n\t\treturn await start();\n\t} catch (error) {\n\t\tif (approval) {\n\t\t\tawait approvals.restore(approval.id).catch((restoreError: unknown) => {\n\t\t\t\tconsole.error(\"[transfer] Failed to restore an approval grant:\", restoreError);\n\t\t\t});\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Digest an export approval grant binds: the export options, normalized. */\nexport async function exportParamsDigest(options: ExportOptions): Promise<Sha256Digest> {\n\treturn canonicalDigest(exportOptionsSchema.parse(options));\n}\n\n/** A one-time approval grant a caller without the transfer scope presents. */\nexport interface TransferApprovalGrant {\n\tid: string;\n\t/** The API token the caller is authenticated with, if any. */\n\ttokenId?: string;\n}\n\nexport interface CreateExportInput {\n\tuserId: string;\n\toptions: ExportOptions;\n\tidempotencyKey?: string;\n\t/**\n\t * Consumed before the export is created, and restored if creation fails;\n\t * bound to the user and the options digest.\n\t */\n\tapproval?: TransferApprovalGrant;\n}\n\n/**\n * Create an export, or return the existing one for the same idempotency key.\n * With `approval`, the grant must be approved, unexpired, and bound to this\n * user, action `export`, these options, and the caller's token.\n */\nexport async function handleExportCreate(\n\tdb: Kysely<Database>,\n\tinput: CreateExportInput,\n): Promise<ApiResult<{ operation: PublicTransferOperation; created: boolean }>> {\n\ttry {\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tif (input.approval) {\n\t\t\tawait approvals.consume(input.approval.id, {\n\t\t\t\tuserId: input.userId,\n\t\t\t\taction: \"export\",\n\t\t\t\tparamsDigest: await exportParamsDigest(input.options),\n\t\t\t\ttokenId: input.approval.tokenId,\n\t\t\t});\n\t\t}\n\t\tconst { operation, created } = await withGrantRestoredOnFailure(approvals, input.approval, () =>\n\t\t\tcreateExport({\n\t\t\t\tdb,\n\t\t\t\tcreatedBy: input.userId,\n\t\t\t\toptions: input.options,\n\t\t\t\tidempotencyKey: input.idempotencyKey,\n\t\t\t}),\n\t\t);\n\t\tif (input.approval) await approvals.linkOperation(input.approval.id, operation.id);\n\t\tif (created) {\n\t\t\tawait recordTransferAudit(db, {\n\t\t\t\tactorId: input.userId,\n\t\t\t\taction: \"transfer_export_create\",\n\t\t\t\tresourceType: \"transfer_operation\",\n\t\t\t\tresourceId: operation.id,\n\t\t\t});\n\t\t}\n\t\treturn { success: true, data: { operation: toPublicOperation(operation), created } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to create export\");\n\t}\n}\n\nexport interface AdvanceExportRouteInput {\n\toperationId: string;\n\tdefaultLocale?: string;\n\tbudget?: TransferStepBudget;\n}\n\nconst validatePackage: ExportPackageValidator = (input) => validateStagedPackageStep(input);\n\n/** Run one bounded export step. */\nexport async function handleExportAdvance(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: AdvanceExportRouteInput,\n): Promise<ApiResult<{ operation: PublicTransferOperation; nextRequestInMs: number | null }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireExport(operations, input.operationId);\n\t\tlet step;\n\t\ttry {\n\t\t\tstep = await advanceExport({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tbudget: input.budget,\n\t\t\t\tdefaultLocale: input.defaultLocale,\n\t\t\t\tvalidatePackage,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\") {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: toPublicOperation(await operations.require(input.operationId)),\n\t\t\t\t\t\tnextRequestInMs: LEASE_RETRY_MS,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst nextRequestInMs =\n\t\t\tstep.outcome === \"advanced\" ? 0 : step.outcome === \"busy\" ? LEASE_RETRY_MS : null;\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { operation: toPublicOperation(step.operation), nextRequestInMs },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to advance export\");\n\t}\n}\n\nexport async function handleExportGet(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operation = await requireExport(new TransferOperationRepository(db), operationId);\n\t\treturn { success: true, data: { operation: toPublicOperation(operation) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to read export\");\n\t}\n}\n\nexport async function handleExportList(\n\tdb: Kysely<Database>,\n\toptions: { cursor?: string; limit?: number },\n): Promise<ApiResult<{ items: PublicTransferOperation[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst page = await new TransferOperationRepository(db).list({\n\t\t\tkind: \"export\",\n\t\t\tlimit: pageLimit(options.limit),\n\t\t\tcursor: decodeTimeCursor(options.cursor),\n\t\t});\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: page.next\n\t\t\t\t? { items: page.items, nextCursor: encodeCursor(page.next.createdAt, page.next.id) }\n\t\t\t\t: { items: page.items },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to list exports\");\n\t}\n}\n\n/** A package file ready to stream: its size and a body verified as it streams. */\nexport interface ExportFileStream {\n\tpath: string;\n\tbytes: number;\n\tsha256: string;\n\tbody: ReadableStream<Uint8Array>;\n}\n\nfunction exportFileMismatch(): TransferError {\n\treturn new TransferError(\n\t\t\"TRANSFER_FILE_DIGEST_MISMATCH\",\n\t\t\"Stored file no longer matches the export\",\n\t);\n}\n\n/**\n * Pass `body` through, failing the stream if it does not carry exactly\n * `bytes` bytes hashing to `sha256`, so a changed source object never\n * reaches the client as a complete file.\n */\nfunction verifyingStream(\n\tbody: ReadableStream<Uint8Array>,\n\texpected: { bytes: number; sha256: string },\n): ReadableStream<Uint8Array> {\n\tlet hasher: Awaited<ReturnType<typeof createSha256>> | undefined;\n\tlet total = 0;\n\treturn body.pipeThrough(\n\t\tnew TransformStream<Uint8Array, Uint8Array>({\n\t\t\tasync start() {\n\t\t\t\thasher = await createSha256();\n\t\t\t},\n\t\t\ttransform(chunk, controller) {\n\t\t\t\ttotal += chunk.byteLength;\n\t\t\t\tif (total > expected.bytes) throw exportFileMismatch();\n\t\t\t\thasher?.update(chunk);\n\t\t\t\tcontroller.enqueue(chunk);\n\t\t\t},\n\t\t\tasync flush() {\n\t\t\t\tif (total !== expected.bytes || (await hasher?.digest()) !== expected.sha256) {\n\t\t\t\t\tthrow exportFileMismatch();\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\t);\n}\n\nasync function openExportFile(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperation: TransferOperation,\n\tpath: string,\n): Promise<ExportFileStream> {\n\tconst parsed = parsePackagePath(path);\n\tif (!parsed) throw new TransferError(\"TRANSFER_PATH_INVALID\", \"Invalid package path\");\n\tconst reader = openExportPackage({ db, storage, operation });\n\tif (parsed.type === \"manifest\") {\n\t\tconst bytes = await reader.stage.readBytes(MANIFEST_PATH, TRANSFER_LIMITS.manifestBytes);\n\t\treturn {\n\t\t\tpath: MANIFEST_PATH,\n\t\t\tbytes: bytes.byteLength,\n\t\t\tsha256: await sha256Hex(bytes),\n\t\t\tbody: new ReadableStream<Uint8Array>({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.enqueue(bytes);\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t}),\n\t\t};\n\t}\n\tconst file = await new TransferStagedFileRepository(db).get(operation.id, parsed.path);\n\tif (!file || file.state !== \"verified\") {\n\t\tthrow new TransferError(\"TRANSFER_FILE_NOT_DECLARED\", \"File is not part of this export\", {\n\t\t\tdetail: { path: parsed.path },\n\t\t});\n\t}\n\tconst source =\n\t\tparsed.type === \"media\"\n\t\t\t? await reader.blob(parsed.sha256)\n\t\t\t: (await reader.stage.open(parsed.path)).body;\n\treturn {\n\t\tpath: file.path,\n\t\tbytes: file.bytes,\n\t\tsha256: file.sha256,\n\t\tbody: verifyingStream(source, file),\n\t};\n}\n\n/**\n * Open one file of a complete export: `manifest.json`, an index or record\n * chunk from staging, or a media blob streamed from the origin object. The\n * body errors if the bytes no longer match the export's digest.\n */\nexport async function handleExportFile(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperationId: string,\n\tpath: string,\n): Promise<ApiResult<ExportFileStream>> {\n\ttry {\n\t\tconst operation = await requireCompleteExport(db, operationId);\n\t\treturn { success: true, data: await openExportFile(db, storage, operation, path) };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to read export file\");\n\t}\n}\n\nasync function* exportArchiveFiles(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperation: TransferOperation,\n): AsyncGenerator<PackageFileSource> {\n\tconst manifest = await openExportFile(db, storage, operation, MANIFEST_PATH);\n\tyield { path: manifest.path, bytes: manifest.bytes, body: () => manifest.body };\n\tconst staged = new TransferStagedFileRepository(db);\n\tlet after: string | undefined;\n\tfor (;;) {\n\t\tconst page = await staged.list(operation.id, { state: \"verified\", after, limit: 500 });\n\t\tfor (const file of page) {\n\t\t\tif (file.path === MANIFEST_PATH) continue;\n\t\t\tyield {\n\t\t\t\tpath: file.path,\n\t\t\t\tbytes: file.bytes,\n\t\t\t\tbody: async () => (await openExportFile(db, storage, operation, file.path)).body,\n\t\t\t};\n\t\t}\n\t\tconst last = page.at(-1);\n\t\tif (!last || page.length < 500) return;\n\t\tafter = last.path;\n\t}\n}\n\n/**\n * Stream a complete export as one tar container: the manifest first, then\n * every index chunk, media blob, and record chunk in path order. Each file is\n * read and verified as it is written, so a failure mid-archive ends the\n * stream with an error rather than a short archive. On Workers the whole\n * archive must stream within one request's limits; large sites should\n * download files individually.\n */\nexport async function handleExportArchive(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperationId: string,\n): Promise<ApiResult<{ body: ReadableStream<Uint8Array> }>> {\n\ttry {\n\t\tconst operation = await requireCompleteExport(db, operationId);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { body: packSitePackage(exportArchiveFiles(db, storage, operation)) },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to read export archive\");\n\t}\n}\n\n// ── Imports: execution ──────────────────────────────────────────\n\nexport interface ExecuteImportInput {\n\toperationId: string;\n\tuserId: string;\n\tpackageDigest: Sha256Digest;\n\tplanDigest: Sha256Digest;\n\t/**\n\t * Consumed before execution starts, and restored if it cannot start;\n\t * bound to the user, action `import`, this operation, both digests, and\n\t * the caller's token.\n\t */\n\tapproval?: TransferApprovalGrant;\n}\n\n/**\n * Request execution of a planned import. The digests must match the staged\n * package and the current plan (`TRANSFER_PACKAGE_DIGEST_MISMATCH` /\n * `TRANSFER_PLAN_DIGEST_MISMATCH`), and the plan must have no blockers.\n * Repeating the request for an import already executing returns it.\n */\nexport async function handleImportExecute(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: ExecuteImportInput,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), input.operationId);\n\t\tif (operation.packageDigest !== input.packageDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Package digest does not match\");\n\t\t}\n\t\tif (operation.planDigest === null || operation.planDigest !== input.planDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan digest does not match\");\n\t\t}\n\t\tif (operation.state === \"planned\") {\n\t\t\tconst plan = await loadImportPlan(storage, operation);\n\t\t\tif (!plan || !isPlanExecutable(plan)) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_PLAN_BLOCKED\", \"The import plan has blockers\", {\n\t\t\t\t\tdetail: { blockers: plan?.blockers.length ?? 0 },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tif (input.approval) {\n\t\t\tawait approvals.consume(input.approval.id, {\n\t\t\t\tuserId: input.userId,\n\t\t\t\taction: \"import\",\n\t\t\t\toperationId: operation.id,\n\t\t\t\tpackageDigest: input.packageDigest,\n\t\t\t\tplanDigest: input.planDigest,\n\t\t\t\ttokenId: input.approval.tokenId,\n\t\t\t});\n\t\t}\n\t\tconst { operation: requested, requested: newlyRequested } = await withGrantRestoredOnFailure(\n\t\t\tapprovals,\n\t\t\tinput.approval,\n\t\t\t() =>\n\t\t\t\trequestImportExecution({\n\t\t\t\t\tdb,\n\t\t\t\t\toperationId: operation.id,\n\t\t\t\t\tpackageDigest: input.packageDigest,\n\t\t\t\t\tplanDigest: input.planDigest,\n\t\t\t\t}),\n\t\t);\n\t\tif (newlyRequested) {\n\t\t\tawait recordTransferAudit(db, {\n\t\t\t\tactorId: input.userId,\n\t\t\t\taction: \"transfer_import_execute\",\n\t\t\t\tresourceType: \"transfer_operation\",\n\t\t\t\tresourceId: operation.id,\n\t\t\t\tdetails: { packageDigest: input.packageDigest, planDigest: input.planDigest },\n\t\t\t});\n\t\t}\n\t\treturn { success: true, data: { operation: toPublicOperation(requested) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to execute import\");\n\t}\n}\n\n/**\n * Run one bounded import step. Retryable failures are recorded on the\n * operation and reported through `nextRequestInMs`, as is a step that lost\n * its lease to another caller; it is null once the import has ended. The\n * step that completes or fails the import records it in the audit log as\n * `userId`'s.\n */\nexport async function handleImportAdvance(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: { operationId: string; userId: string; budget?: TransferStepBudget },\n): Promise<ApiResult<{ operation: PublicTransferOperation; nextRequestInMs: number | null }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireImport(operations, input.operationId);\n\t\tlet step;\n\t\ttry {\n\t\t\tstep = await advanceImport({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tverify: verifyImportStep,\n\t\t\t\tbudget: input.budget,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (isLeaseError(error)) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: toPublicOperation(await operations.require(input.operationId)),\n\t\t\t\t\t\tnextRequestInMs: LEASE_RETRY_MS,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tif (step.ended) await auditImportEnd(db, step.operation, input.userId);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { operation: toPublicOperation(step.operation), nextRequestInMs: step.nextRequestInMs },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to advance import\");\n\t}\n}\n\nasync function auditImportEnd(\n\tdb: Kysely<Database>,\n\toperation: TransferOperation,\n\tuserId: string,\n): Promise<void> {\n\tif (operation.state === \"complete\") {\n\t\tconst counts = operation.receipt?.counts ?? {};\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_complete\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operation.id,\n\t\t\tdetails: {\n\t\t\t\tpackageDigest: operation.packageDigest,\n\t\t\t\tplanDigest: operation.planDigest,\n\t\t\t\trecords: Object.values(counts).reduce((sum, count) => sum + count, 0),\n\t\t\t},\n\t\t});\n\t} else if (operation.state === \"failed\") {\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_fail\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operation.id,\n\t\t\tdetails: { errorCode: operation.errorCode },\n\t\t\tstatus: \"failure\",\n\t\t});\n\t}\n}\n\nexport async function handleImportReceipt(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<ApiResult<{ receipt: SiteImportReceipt }>> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), operationId);\n\t\tif (operation.state !== \"complete\" || !operation.receipt) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has no receipt\");\n\t\t}\n\t\treturn { success: true, data: { receipt: operation.receipt } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to read import receipt\");\n\t}\n}\n\n// ── Approvals ───────────────────────────────────────────────────\n\nconst APPROVAL_PERMISSION: Readonly<Record<TransferApprovalAction, Permission>> = {\n\texport: \"transfer:export\",\n\timport: \"transfer:import\",\n};\n\nexport async function handleApprovalList(\n\tdb: Kysely<Database>,\n\toptions: { status?: ApprovalStatus; cursor?: string; limit?: number },\n): Promise<ApiResult<{ items: TransferApproval[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst page = await new TransferApprovalRepository(db).list({\n\t\t\tstatus: options.status,\n\t\t\tlimit: pageLimit(options.limit),\n\t\t\tcursor: decodeTimeCursor(options.cursor),\n\t\t});\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: page.next\n\t\t\t\t? { items: page.items, nextCursor: encodeCursor(page.next.createdAt, page.next.id) }\n\t\t\t\t: { items: page.items },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to list approvals\");\n\t}\n}\n\n/**\n * Approve or deny a pending grant. The deciding user needs the permission\n * for the grant's action. Callers must only reach this from a session, never\n * with a bearer token.\n */\nexport async function handleApprovalDecide(\n\tdb: Kysely<Database>,\n\tinput: {\n\t\tapprovalId: string;\n\t\tdecision: \"approve\" | \"deny\";\n\t\tuser: { id: string; role: RoleLevel };\n\t},\n): Promise<ApiResult<{ approval: TransferApproval }>> {\n\ttry {\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tconst approval = await approvals.get(input.approvalId);\n\t\tif (!approval) {\n\t\t\tthrow new TransferError(\"TRANSFER_APPROVAL_INVALID\", \"Approval not found\");\n\t\t}\n\t\tif (!hasPermission(input.user, APPROVAL_PERMISSION[approval.action])) {\n\t\t\treturn failure(\"FORBIDDEN\", \"Insufficient permissions\");\n\t\t}\n\t\tconst decided =\n\t\t\tinput.decision === \"approve\"\n\t\t\t\t? await approvals.approve(approval.id, input.user.id)\n\t\t\t\t: await approvals.deny(approval.id, input.user.id);\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: input.user.id,\n\t\t\taction: input.decision === \"approve\" ? \"transfer_approval_approve\" : \"transfer_approval_deny\",\n\t\t\tresourceType: \"transfer_approval\",\n\t\t\tresourceId: approval.id,\n\t\t\tdetails: {\n\t\t\t\taction: approval.action,\n\t\t\t\tuserId: approval.userId,\n\t\t\t\t...(approval.operationId === null ? {} : { operationId: approval.operationId }),\n\t\t\t},\n\t\t});\n\t\treturn { success: true, data: { approval: decided } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to decide approval\");\n\t}\n}\n\nexport interface RequestTransferApprovalInput {\n\t/** The user the grant is for: the caller that will consume it. */\n\tuserId: string;\n\taction: TransferApprovalAction;\n\t/** The API token the caller is authenticated with, if any. */\n\trequestedByTokenId?: string;\n\toperationId?: string;\n\tparamsDigest?: Sha256Digest;\n\tpackageDigest?: Sha256Digest;\n\tplanDigest?: Sha256Digest;\n}\n\n/**\n * Create a pending approval grant for a caller that lacks the transfer scope\n * for `action`, and fail with `TRANSFER_APPROVAL_REQUIRED` carrying its id.\n * An unexpired pending grant with the same binding is returned instead of a\n * new one. An admin approves it in a session; the caller then retries with\n * the id and consumes the grant with `TransferApprovalRepository.consume`.\n */\nexport async function requestTransferApproval(\n\tdb: Kysely<Database>,\n\tinput: RequestTransferApprovalInput,\n): Promise<ErrorResult> {\n\ttry {\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tconst approval =\n\t\t\t(await approvals.findPending({ ...input, tokenId: input.requestedByTokenId })) ??\n\t\t\t(await approvals.createPending(input));\n\t\treturn failure(\"TRANSFER_APPROVAL_REQUIRED\", \"An admin must approve this transfer\", {\n\t\t\tapprovalId: approval.id,\n\t\t\texpiresAt: approval.expiresAt,\n\t\t});\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to request approval\");\n\t}\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAWA,SAAgB,SAAS,IAAsB,QAAoC;AAClF,QAAO,WAAW,GAAG,GAClB,GAAW,GAAG,IAAI,IAAI,OAAO,CAAC,gBAC9B,GAAW,GAAG,IAAI,IAAI,OAAO;;;AAIjC,SAAgB,WAAW,QAAwB;AAClD,QAAO,GAAG,OAAO,WAAW,MAAM,OAAO,CAAC,WAAW,KAAK,MAAM,CAAC,WAAW,KAAK,MAAM,CAAC;;;;;;;;;;;;;;;ACmBzF,SAAS,aAAa,KAOP;AACd,QAAO;EACN,MAAM,IAAI;EACV,OAAO,OAAO,IAAI,MAAM;EACxB,QAAQ,IAAI;EACZ,OAAO,IAAI,UAAU,aAAa,aAAa;EAC/C,YAAY,IAAI;EAChB,eAAe,IAAI;EACnB;;;AAIF,MAAM,oBAAoB;AAE1B,IAAa,+BAAb,MAA0C;CACzC,YAAY,AAAiB,IAAsB;EAAtB;;;;;;;CAO7B,MAAM,YACL,aACA,OACA,QAAyB,YACT;AAChB,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,MAAM,EAAE,cAAc,kBAAkB,CAAC,CACvE,OAAM,KAAK,GACT,WAAW,gCAAgC,CAC3C,OACA,MAAM,KAAK,UAAU;GACpB,cAAc;GACd,MAAM,KAAK;GACX,OAAO,KAAK;GACZ,QAAQ,KAAK;GACb;GACA,aAAa,UAAU,aAAa,aAAa,KAAK,GAAG,GAAG;GAC5D,gBAAgB;GAChB,EAAE,CACH,CACA,YAAY,aAAa,SAAS,QAAQ,CAAC,gBAAgB,OAAO,CAAC,CAAC,WAAW,CAAC,CAChF,SAAS;AAEZ,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,MAAM,EAAE,eAAe,EAAE;GACvD,MAAM,SAAS,MAAM,KAAK,QACzB,aACA,MAAM,KAAK,SAAS,KAAK,KAAK,CAC9B;AACD,QAAK,MAAM,QAAQ,OAAO;IACzB,MAAM,WAAW,OAAO,IAAI,KAAK,KAAK;AACtC,QAAI,CAAC,YAAY,SAAS,UAAU,KAAK,SAAS,SAAS,WAAW,KAAK,OAC1E,OAAM,IAAI,cACT,iCACA,6DACA,EAAE,QAAQ,EAAE,MAAM,KAAK,MAAM,EAAE,CAC/B;;;;;CAOL,MAAM,aAAa,aAAqB,MAAsC;EAC7E,MAAM,SAAS,MAAM,KAAK,GACxB,YAAY,gCAAgC,CAC5C,IAAI;GAAE,OAAO;GAAY,aAAa,aAAa,KAAK,GAAG;GAAE,CAAC,CAC9D,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,QAAQ,KAAK,KAAK,KAAK,CAC7B,MAAM,SAAS,KAAK,KAAK,MAAM,CAC/B,MAAM,UAAU,KAAK,KAAK,OAAO,CACjC,kBAAkB;AACpB,SAAO,OAAO,OAAO,kBAAkB,GAAG,GAAG;;;;;;;CAQ9C,gBAAgB,aAAqE;AACpF,SAAO,OAAO,SAAS;GACtB,MAAM,OAAO,MAAM,KAAK,IAAI,aAAa,KAAK;AAC9C,UAAO,MAAM,UAAU,aAAa;IAAE,OAAO,KAAK;IAAO,QAAQ,KAAK;IAAQ,GAAG;;;CAInF,MAAM,WAAW,aAAqB,MAAgC;AACrE,UAAQ,MAAM,KAAK,IAAI,aAAa,KAAK,GAAG,UAAU;;CAGvD,MAAM,iBAAiB,aAAqB,MAAc,eAAsC;AAC/F,QAAM,KAAK,GACT,YAAY,gCAAgC,CAC5C,IAAI,EAAE,gBAAgB,eAAe,CAAC,CACtC,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,QAAQ,KAAK,KAAK,CACxB,SAAS;;CAGZ,MAAM,IAAI,aAAqB,MAA0C;EACxE,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,gCAAgC,CAC3C,OAAO;GAAC;GAAQ;GAAS;GAAU;GAAS;GAAe;GAAiB,CAAC,CAC7E,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,QAAQ,KAAK,KAAK,CACxB,kBAAkB;AACpB,SAAO,MAAM,aAAa,IAAI,GAAG;;CAGlC,MAAM,QAAQ,aAAqB,OAA4D;EAC9F,MAAM,yBAAS,IAAI,KAAyB;AAC5C,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,EAAE,eAAe,EAAE;GAChE,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,gCAAgC,CAC3C,OAAO;IAAC;IAAQ;IAAS;IAAU;IAAS;IAAe;IAAiB,CAAC,CAC7E,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,QAAQ,MAAM,MAAM,CAC1B,SAAS;AACX,QAAK,MAAM,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,aAAa,IAAI,CAAC;;AAEhE,SAAO;;;CAIR,MAAM,KACL,aACA,UAAwF,EAAE,EAClE;EACxB,IAAI,QAAQ,KAAK,GACf,WAAW,gCAAgC,CAC3C,OAAO;GAAC;GAAQ;GAAS;GAAU;GAAS;GAAe;GAAiB,CAAC,CAC7E,MAAM,gBAAgB,KAAK,YAAY;AACzC,MAAI,QAAQ,MAAO,SAAQ,MAAM,MAAM,SAAS,KAAK,QAAQ,MAAM;AACnE,MAAI,QAAQ,WAAW,OACtB,SAAQ,MAAM,MAAM,GAAY,aAAa,WAAW,QAAQ,OAAO,CAAC,cAAc;EAEvF,MAAM,QAAQ,QAAQ;AACtB,MAAI,UAAU,OACb,SAAQ,MAAM,MAAM,GAAY,GAAG,SAAS,KAAK,IAAI,OAAO,CAAC,KAAK,QAAQ;AAM3E,UAJa,MAAM,MACjB,QAAQ,SAAS,KAAK,IAAI,OAAO,CAAC,CAClC,MAAM,KAAK,IAAI,KAAK,IAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,IAAK,CAAC,CACxD,SAAS,EACC,IAAI,aAAa;;CAG9B,MAAM,aAAa,aAA+D;EACjF,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,gCAAgC,CAC3C,QAAQ,OAAO,CAAC,SAAS,GAAG,GAAG,UAA2B,CAAC,GAAG,QAAQ,CAAC,CAAC,CACxE,MAAM,gBAAgB,KAAK,YAAY,CACvC,QAAQ,QAAQ,CAChB,SAAS;EACX,MAAM,SAA0C;GAAE,UAAU;GAAG,UAAU;GAAG;AAC5E,OAAK,MAAM,OAAO,KACjB,KAAI,IAAI,UAAU,cAAc,IAAI,UAAU,WAC7C,QAAO,IAAI,SAAS,OAAO,IAAI,MAAM;AAEvC,SAAO;;;CAIR,MAAM,mBAAmB,aAAqB,QAAQ,KAAsB;EAC3E,MAAM,QAAQ,MAAM,KAAK,GACvB,WAAW,gCAAgC,CAC3C,OAAO,OAAO,CACd,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,MAAM,CACZ,SAAS;EACX,IAAI,UAAU;AACd,OAAK,MAAM,SAAS,OACnB,MAAM,KAAK,QAAQ,IAAI,KAAK,EAC5B,eACA,EAAE;GACF,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,gCAAgC,CAC3C,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,QAAQ,MAAM,MAAM,CAC1B,kBAAkB;AACpB,cAAW,OAAO,OAAO,kBAAkB,GAAG;;AAE/C,SAAO;;;;;;;;;;AC1NT,MAAa,iBAAiB;;;;;;AAO9B,eAAsB,kBAAkB,IAAuC;CAC9E,MAAM,UAAU,IAAI,kBAAkB,GAAG;CACzC,MAAM,WAAW,MAAM,QAAQ,IAAI,eAAe;AAClD,KAAI,OAAO,aAAa,YAAY,SAAS,SAAS,EAAG,QAAO;CAEhE,MAAM,YAAY,MAAM;AAExB,MADe,MAAM,QAAQ,cAAc,gBAAgB,MAAM,UAAU,EAChE,QAAS,QAAO;CAE3B,MAAM,SAAS,MAAM,QAAQ,IAAI,eAAe;AAChD,KAAI,OAAO,WAAW,YAAY,OAAO,SAAS,EAAG,QAAO;AAC5D,OAAM,IAAI,MAAM,sDAAsD;;;;;;;;;;;;;;ACZvE,MAAMA,YAAU,IAAI,aAAa;;AAGjC,SAAgB,iBAAiB,QAAkD;CAClF,MAAM,OAAO,cAAc,OAAO;CAClC,MAAM,QAAQA,UAAQ,OAAO,KAAK,CAAC;AACnC,KAAI,QAAQ,gBAAgB,gBAC3B,OAAM,IAAI,cAAc,2BAA2B,sCAAsC,EACxF,QAAQ;EAAE,MAAM,OAAO;EAAM,IAAI,OAAO;EAAI;EAAO,OAAO,gBAAgB;EAAiB,EAC3F,CAAC;AAEH,QAAO;;;;;;AAaR,SAAgBC,mBACf,MACA,MACA,UACmB;AACnB,KAAID,UAAQ,OAAO,KAAK,CAAC,aAAa,gBAAgB,gBACrD,OAAM,IAAI,cAAc,2BAA2B,sCAAsC,EACxF,QAAQ;EAAE,MAAM,SAAS;EAAM,MAAM,SAAS;EAAM,EACpD,CAAC;CAEH,IAAI;AACJ,KAAI;AACH,QAAM,mBAAmB,KAAK;UACtB,OAAO;AACf,QAAM,IAAI,cAAc,2BAA2B,gCAAgC,EAClF,QAAQ;GACP,MAAM,SAAS;GACf,MAAM,SAAS;GACf,QAAQ,iBAAiB,qBAAqB,MAAM,UAAU;GAC9D,EACD,CAAC;;CAEH,MAAM,SAAS,eAAe,MAAM,IAAI;AACxC,KAAI,CAAC,OAAO,SAAS;EACpB,MAAM,QAAQ,OAAO,OAAO;AAC5B,QAAM,IAAI,cAAc,2BAA2B,4BAA4B,EAC9E,QAAQ;GACP,MAAM,SAAS;GACf,MAAM,SAAS;GACf,OAAO,OAAO,QAAQ;GACtB,QAAQ,OAAO,WAAW;GAC1B,EACD,CAAC;;AAEH,QAAO;EAAE,QAAQ,OAAO;EAAQ;EAAM;;;;;;AAOvC,SAAgB,gBAAgB,OAAmB,MAAwB;AAC1E,KAAI,MAAM,aAAa,gBAAgB,WACtC,OAAM,IAAI,cAAc,2BAA2B,gCAAgC,EAClF,QAAQ;EAAE;EAAM,OAAO,gBAAgB;EAAY,EACnD,CAAC;CAEH,MAAM,OAAO,WAAW,OAAO,0BAA0B;AACzD,KAAI,KAAK,WAAW,EACnB,OAAM,IAAI,cAAc,2BAA2B,kBAAkB,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAE3F,KAAI,CAAC,KAAK,SAAS,KAAK,CACvB,OAAM,IAAI,cAAc,2BAA2B,iCAAiC,EACnF,QAAQ,EAAE,MAAM,EAChB,CAAC;CAEH,MAAM,QAAQ,KAAK,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK;AAC3C,KAAI,MAAM,SAAS,gBAAgB,aAClC,OAAM,IAAI,cAAc,2BAA2B,4BAA4B,EAC9E,QAAQ;EAAE;EAAM,OAAO,gBAAgB;EAAc,EACrD,CAAC;AAEH,OAAM,SAAS,MAAM,UAAU;AAC9B,MAAI,KAAK,WAAW,EACnB,OAAM,IAAI,cAAc,2BAA2B,+BAA+B,EACjF,QAAQ;GAAE;GAAM,MAAM,QAAQ;GAAG,EACjC,CAAC;GAEF;AACF,QAAO;;;AAIR,SAAgB,YAAY,OAA0B,MAA0B;AAC/E,KAAI,MAAM,WAAW,KAAK,MAAM,SAAS,gBAAgB,aACxD,OAAM,IAAI,cAAc,2BAA2B,iCAAiC,EACnF,QAAQ;EAAE;EAAM,OAAO,MAAM;EAAQ,EACrC,CAAC;CAEH,MAAM,QAAQA,UAAQ,OAAO,GAAG,MAAM,KAAK,KAAK,CAAC,IAAI;AACrD,KAAI,MAAM,aAAa,gBAAgB,WACtC,OAAM,IAAI,cAAc,2BAA2B,gCAAgC,EAClF,QAAQ;EAAE;EAAM,OAAO,MAAM;EAAY,EACzC,CAAC;AAEH,QAAO;;;;;;;;;;;;;AC9FR,MAAME,YAAU,IAAI,aAAa;AAEjC,IAAa,sBAAb,MAAiC;CAChC,YAAY,AAAS,OAAsB;EAAtB;;;CAGrB,MAAM,UAAU,MAAc,OAA8C;EAC3E,MAAM,SAAS,MAAM,UAAU,MAAM;AACrC,QAAM,KAAK,MAAM,YAAY,MAAM,OAAO,MAAM,YAAY,OAAO;AACnE,SAAO;GAAE;GAAM,OAAO,MAAM;GAAY;GAAQ;;;CAIjD,MAAM,iBACL,MACA,KACA,SAC4B;EAC5B,MAAM,OAAO,gBAAgB,MAAM,IAAI;AACvC,OAAK,MAAM,UAAU,QACpB,KAAI,OAAO,SAAS,KACnB,OAAM,IAAI,cAAc,2BAA2B,wCAAwC,EAC1F,QAAQ;GAAE;GAAM,IAAI,OAAO;GAAI,EAC/B,CAAC;EAGJ,MAAM,QAAQ,QAAQ,KAAK,WAAW,iBAAiB,OAAO,CAAC;AAE/D,SAAO;GAAE,GADK,MAAM,KAAK,UAAU,MAAM,YAAY,OAAO,KAAK,CAAC;GAC/C,SAAS,QAAQ;GAAQ;;;CAI7C,MAAM,gBAAgB,KAAa,SAA8D;EAChG,MAAM,OAAO,eAAe,IAAI;EAChC,MAAM,QAAQ,QAAQ,KAAK,UAAU,cAAc,MAAM,CAAC;EAC1D,MAAM,OAAO,MAAM,KAAK,UAAU,MAAM,YAAY,OAAO,KAAK,CAAC;AACjE,SAAO;GAAE;GAAM,OAAO,KAAK;GAAO,QAAQ,KAAK;GAAQ,SAAS,QAAQ;GAAQ;;;CAIjF,MAAM,UACL,QACA,MACA,OAC4B;EAC5B,MAAM,OAAO,cAAc,OAAO;AAClC,QAAM,KAAK,MAAM,YAAY,MAAM,MAAM,OAAO,OAAO;AACvD,SAAO;GAAE;GAAM;GAAO;GAAQ;;;CAI/B,MAAM,cAAc,UAAsD;EACzE,MAAM,OAAO,kBAAkB,cAAc,kBAAkB,SAAS,CAAC,CAAC;EAC1E,MAAM,QAAQA,UAAQ,OAAO,KAAK;AAClC,QAAM,KAAK,MAAM,YAAY,eAAe,OAAO,MAAM,YAAY,MAAM,UAAU,MAAM,CAAC;AAC5F,SAAO,cAAc,SAAS;;;AAgBhC,IAAa,sBAAb,MAAiC;CAChC;;;;;CAMA,YACC,AAAS,OACT,AAAiB,SAChB;EAFQ;EACQ;;;CAIlB,MAAM,WAAyC;AAC9C,MAAI,CAAC,MAAKC,SAET,OAAKA,WAAY,cADH,MAAM,KAAK,MAAM,UAAU,eAAe,gBAAgB,cAAc,CACjD;AAEtC,SAAO,MAAKA;;CAGb,MAAM,SAAgC;AACrC,SAAO,cAAc,MAAM,KAAK,UAAU,CAAC;;;CAI5C,MAAM,WAAW,KAA0C;EAE1D,MAAM,OADW,MAAM,KAAK,UAAU,EACjB,MAAM;AAC3B,MAAI,CAAC,IACJ,OAAM,IAAI,cAAc,yBAAyB,+BAA+B,EAC/E,QAAQ,EAAE,KAAK,EACf,CAAC;EAGH,MAAM,UAAU,gBADF,MAAM,KAAK,aAAa,IAAI,MAAM,IAAI,EACb,IAAI,KAAK,CAAC,KAAK,SAAS,eAAe,KAAK,CAAC;AACpF,MAAI,QAAQ,WAAW,IAAI,QAC1B,OAAM,IAAI,cAAc,6BAA6B,oCAAoC,EACxF,QAAQ,EAAE,MAAM,IAAI,MAAM,EAC1B,CAAC;AAEH,SAAO;;;CAIR,OAAO,MAAM,UAAU,GAA6D;EACnF,MAAM,WAAW,MAAM,KAAK,UAAU;AACtC,OAAK,IAAI,MAAM,SAAS,MAAM,SAAS,MAAM,QAAQ,MACpD,MAAK,MAAM,SAAS,MAAM,KAAK,WAAW,IAAI,CAAE,OAAM;GAAE;GAAK;GAAO;;;;;;;CAStE,MAAM,UACL,MACA,KACA,UACkC;EAClC,MAAM,OAAO,gBAAgB,MAAM,IAAI;EACvC,MAAM,OAAO,YAAa,MAAM,KAAK,aAAa,KAAK;AAIvD,SAAO,gBAHO,OACX,MAAM,KAAK,aAAa,MAAM,KAAK,GACnC,MAAM,KAAK,MAAM,UAAU,MAAM,gBAAgB,WAAW,EACjC,KAAK,CAAC,KAAK,MAAM,UAAU;GACxD,MAAM,UAAUC,mBAAiB,MAAM,MAAM;IAAE;IAAM,MAAM,QAAQ;IAAG,CAAC;AACvE,UAAO;IAAE,QAAQ,QAAQ;IAAQ,MAAM,QAAQ;IAAM;IAAK;IAAO;IAChE;;;CAIH,OAAO,QAA8B,MAAS,UAAU,GAAoC;EAE3F,MAAM,UADW,MAAM,KAAK,UAAU,EACd,QAAQ,OAAO,UAAU;AACjD,OAAK,IAAI,MAAM,SAAS,MAAM,QAAQ,MACrC,QAAO,MAAM,KAAK,UAAU,MAAM,IAAI;;CAIxC,MAAM,KAAK,QAAqD;AAC/D,UAAQ,MAAM,KAAK,MAAM,KAAK,cAAc,OAAO,CAAC,EAAE;;CAGvD,MAAc,aAAa,MAAiD;AAC3E,MAAI,CAAC,KAAK,QAAS,QAAO;EAC1B,MAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AACzC,MAAI,CAAC,SACJ,OAAM,IAAI,cAAc,yBAAyB,+BAA+B,EAC/E,QAAQ,EAAE,MAAM,EAChB,CAAC;AAEH,SAAO;;CAGR,MAAc,aAAa,MAAc,UAA6C;EACrF,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,KAAK;EACxC,IAAI;AACJ,MAAI;AACH,WAAQ,MAAM,gBAAgB,KAAK,MAAM,KAAK,IAAI,SAAS,OAAO,EAAE,CAAC;WAC7D,OAAO;AACf,OAAI,iBAAiB,iBAAiB,MAAM,SAAS,0BACpD,OAAM,IAAI,cAAc,+BAA+B,mCAAmC,EACzF,QAAQ,EAAE,MAAM,EAChB,CAAC;AAEH,SAAM;;AAEP,MAAI,MAAM,eAAe,SAAS,MACjC,OAAM,IAAI,cAAc,+BAA+B,mCAAmC,EACzF,QAAQ,EAAE,MAAM,EAChB,CAAC;AAEH,MAAK,MAAM,UAAU,MAAM,KAAM,SAAS,OACzC,OAAM,IAAI,cACT,iCACA,qCACA,EACC,QAAQ,EAAE,MAAM,EAChB,CACD;AAEF,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5KT,MAAM,gBAAgB;CACrB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAED,SAAS,eAAe,QAAgC;AACvD,QAAO,WAAW,WAAW,QAAQ,WAAW,YAAY,IAAI;;AAGjE,SAAS,iBAAiB,OAAuC;AAChE,KAAI,UAAU,KAAM,QAAO,EAAE;AAC7B,KAAI;EACH,MAAM,SAAkB,KAAK,MAAM,MAAM;AACzC,MAAI,CAAC,MAAM,QAAQ,OAAO,CAAE,QAAO;AACnC,SAAO,OAAO,OAAO,SAAyB,OAAO,SAAS,SAAS,GAAG,SAAS;SAC5E;AACP,SAAO;;;AAIT,eAAsB,sBACrB,IACoC;CACpC,MAAM,WAA4B,EAAE;CACpC,MAAM,iBAAiC,EAAE;CAEzC,MAAM,SAAS,cAAc,KAC3B,OAAO,UAAU,GAAG,kBAAkB,IAAI,IAAI,MAAM,CAAC,eAAe,IAAI,IAAI,IAAI,QAAQ,GACzF;AACD,QAAO,KACN,GAAG,uEAAuE,IAAI,IAAI,gBAAgB,GAClG;CAED,MAAM,SADW,MAAM,GAA4B,UAAU,IAAI,KAAK,OAAO,GAAG,QAAQ,GAAG,EACpE,KAAK,MAAM,EAAE;AACpC,eAAc,SAAS,OAAO,UAAU;AACvC,MAAI,MAAM,IAAI,YAAY,KAAM,UAAS,KAAK;GAAE,MAAM;GAAmB;GAAO,CAAC;GAChF;AACF,KAAI,MAAM,iBAAiB,KAC1B,UAAS,KAAK;EAAE,MAAM;EAAmB,OAAO;EAAoB,CAAC;CAEtE,MAAM,cAAc,MAAM,GACxB,WAAW,sBAAsB,CACjC,OAAO;EAAC;EAAM;EAAQ;EAAS,CAAC,CAChC,QAAQ,OAAO,CACf,SAAS;CACX,MAAM,SAAS,YAAY,QAAQ,eAAe,eAAe,WAAW,OAAO,CAAC;AACpF,MAAK,MAAM,cAAc,YACxB,KAAI,CAAC,eAAe,WAAW,OAAO,CACrC,UAAS,KAAK;EAAE,MAAM;EAAyB,IAAI,WAAW;EAAI,MAAM,WAAW;EAAM,CAAC;AAI5F,KAAI,OAAO,SAAS,GAAG;EACtB,MAAM,gBAAgB,OAAO,KAAK,YAAY,UAAU;AACvD,sBAAmB,WAAW,MAAM,kBAAkB;AACtD,UAAO,GAAG,kBAAkB,IAAI,IAAI,MAAM,WAAW,OAAO,CAAC,eAAe,IAAI,IAAI,IAAI,QAAQ;IAC/F;EAIF,MAAM,gBAHU,MAAM,GAA4B,UAAU,IAAI,KAAK,cAAc,GAAG,QACrF,GACA,EAC4B,KAAK,MAAM,EAAE;AAC1C,SAAO,SAAS,YAAY,UAAU;AACrC,OAAI,aAAa,IAAI,YAAY,KAChC,UAAS,KAAK;IAAE,MAAM;IAA0B,IAAI,WAAW;IAAI,MAAM,WAAW;IAAM,CAAC;OAE3F,gBAAe,KAAK;IAAE,MAAM;IAAc,IAAI,WAAW;IAAI,MAAM,WAAW;IAAM,CAAC;IAErF;;CAGH,MAAM,gBAAgB,IAAI,IACzB,eAAe,SAAS,SAAU,KAAK,SAAS,eAAe,CAAC,KAAK,KAAK,GAAG,EAAE,CAAE,CACjF;CACD,MAAM,gBAAgB,IAAI,IAAI,YAAY,KAAK,eAAe,WAAW,KAAK,CAAC;CAC/E,MAAM,eAAe,MAAM,GACzB,WAAW,wBAAwB,CACnC,OAAO;EAAC;EAAM;EAAQ;EAAU;EAAc,CAAC,CAC/C,QAAQ,KAAK,CACb,SAAS;CACX,MAAM,eAA+B,EAAE;AACvC,MAAK,MAAM,OAAO,aAEjB,KADiB,iBAAiB,IAAI,YAAY,EACpC,OAAO,SAAS,cAAc,IAAI,KAAK,IAAI,CAAC,cAAc,IAAI,KAAK,CAAC,CACjF,cAAa,KAAK;EAAE,MAAM;EAAgB,IAAI,IAAI;EAAI,MAAM,IAAI;EAAM,QAAQ,IAAI;EAAQ,CAAC;KAE3F,UAAS,KAAK;EAAE,MAAM;EAA6B,IAAI,IAAI;EAAI,MAAM,IAAI;EAAM,CAAC;CAIlF,MAAM,aAAa,MAAM,GACvB,WAAW,sBAAsB,CACjC,OAAO;EAAC;EAAM;EAAQ;EAAS,CAAC,CAChC,QAAQ,OAAO,CACf,SAAS;AACX,MAAK,MAAM,aAAa,WACvB,KAAI,UAAU,WAAW,OACxB,UAAS,KAAK;EAAE,MAAM;EAAyB,IAAI,UAAU;EAAI,MAAM,UAAU;EAAM,CAAC;AAM1F,KAAI,SAAS,SAAS,EAAG,QAAO;EAAE,OAAO;EAAO;EAAgB;EAAU;CAE1E,MAAM,QAAQ,MAAM,GAClB,WAAW,aAAa,CACxB,OAAO;EAAC;EAAM;EAAQ;EAAQ;EAAS,CAAC,CACxC,QAAQ,KAAK,CACb,SAAS;AACX,MAAK,MAAM,QAAQ,MAClB,gBAAe,KAAK;EACnB,MAAM;EACN,IAAI,KAAK;EACT,MAAM,KAAK;EACX,MAAM,KAAK;EACX,QAAQ,KAAK;EACb,CAAC;AAEH,gBAAe,KAAK,GAAG,aAAa;CAEpC,MAAM,YAAY,MAAM,GACtB,WAAW,qBAAqB,CAChC,OAAO;EAAC;EAAM;EAAW;EAAQ,CAAC,CAClC,QAAQ,KAAK,CACb,SAAS;AACX,MAAK,MAAM,QAAQ,UAClB,gBAAe,KAAK;EACnB,MAAM;EACN,IAAI,KAAK;EACT,QAAQ,KAAK;EACb,OAAO,KAAK;EACZ,CAAC;CAGH,MAAM,QAAQ,MAAM,GAClB,WAAW,gBAAgB,CAC3B,OAAO;EAAC;EAAM;EAAQ;EAAS,CAAC,CAChC,QAAQ,KAAK,CACb,SAAS;AACX,MAAK,MAAM,QAAQ,MAClB,gBAAe,KAAK;EAAE,MAAM;EAAQ,IAAI,KAAK;EAAI,MAAM,KAAK;EAAM,QAAQ,KAAK;EAAQ,CAAC;CAGzF,MAAM,UAAU,MAAM,GACpB,WAAW,kBAAkB,CAC7B,OAAO;EAAC;EAAM;EAAW;EAAO,CAAC,CACjC,QAAQ,KAAK,CACb,SAAS;AACX,MAAK,MAAM,UAAU,QACpB,gBAAe,KAAK;EACnB,MAAM;EACN,IAAI,OAAO;EACX,QAAQ,OAAO;EACf,YAAY,OAAO;EACnB,CAAC;CAGH,MAAM,QAAQ,MAAM,GAClB,WAAW,uBAAuB,CAClC,OAAO,CAAC,MAAM,OAAO,CAAC,CACtB,QAAQ,KAAK,CACb,SAAS;AACX,MAAK,MAAM,QAAQ,MAClB,gBAAe,KAAK;EAAE,MAAM;EAAe,IAAI,KAAK;EAAI,MAAM,KAAK;EAAM,CAAC;CAE3E,MAAM,WAAW,MAAM,GACrB,WAAW,mBAAmB,CAC9B,OAAO,CAAC,MAAM,OAAO,CAAC,CACtB,MAAM,UAAU,KAAK,QAAQ,CAC7B,QAAQ,KAAK,CACb,SAAS;AACX,MAAK,MAAM,WAAW,SACrB,gBAAe,KAAK;EAAE,MAAM;EAAW,IAAI,QAAQ;EAAI,MAAM,QAAQ;EAAM,CAAC;AAG7E,MAAK,MAAM,aAAa,WACvB,gBAAe,KAAK;EAAE,MAAM;EAAc,IAAI,UAAU;EAAI,MAAM,UAAU;EAAM,CAAC;AAGpF,QAAO;EAAE,OAAO;EAAM;EAAgB;EAAU;;;;;;;;;;ACvOjD,MAAMC,YAAU,IAAI,aAAa;AAEjC,MAAM,iBAEF;CACH,yBAAyB;EAAE,MAAM;EAAkB,SAAS;EAAgC;CAC5F,uBAAuB;EAAE,MAAM;EAAgB,SAAS;EAA2B;CACnF,6BAA6B;EAC5B,MAAM;EACN,SAAS;EACT;CACD,+BAA+B;EAC9B,MAAM;EACN,SAAS;EACT;CACD,6BAA6B;EAC5B,MAAM;EACN,SAAS;EACT;CACD,8BAA8B;EAC7B,MAAM;EACN,SAAS;EACT;CACD,yBAAyB;EAAE,MAAM;EAAkB,SAAS;EAA6B;CACzF,uBAAuB;EAAE,MAAM;EAAmB,SAAS;EAA2B;CACtF;;;;;AAMD,SAAgB,gBACf,OACA,WAA6C,EAAE,EACjC;CACd,MAAM,SAAS,eAAe,MAAM,SAAS;EAC5C,MAAM;EACN,SAAS;EACT;CACD,MAAM,SAA0C,EAAE;AAClD,KAAI,SAAS,SAAS,OAAW,QAAO,OAAO,SAAS;AACxD,KAAI,SAAS,SAAS,OAAW,QAAO,OAAO,SAAS;AACxD,QAAO;EAAE,MAAM,OAAO;EAAM,SAAS,OAAO;EAAS;EAAQ;;;AAI9D,eAAsB,kBACrB,OACA,MACA,UACoB;CACpB,MAAM,OAAO,MAAM,MAAM,KAAK,KAAK;CACnC,IAAI;AACJ,KAAI;AACH,UAAQ,MAAM,gBAAgB,KAAK,MAAM,SAAS,MAAM;UAChD,OAAO;AACf,MAAI,iBAAiB,iBAAiB,MAAM,SAAS,0BACpD,OAAM,IAAI,cAAc,+BAA+B,kCAAkC;AAE1F,QAAM;;AAEP,KAAI,MAAM,eAAe,SAAS,MACjC,OAAM,IAAI,cAAc,+BAA+B,kCAAkC;AAE1F,KAAK,MAAM,UAAU,MAAM,KAAM,SAAS,OACzC,OAAM,IAAI,cAAc,iCAAiC,oCAAoC;AAE9F,QAAO,gBAAgB,OAAO,KAAK;;;;;;AAWpC,SAAgB,iBACf,MACA,MACA,UACiB;CACjB,MAAM,SAAS;EAAE,MAAM,SAAS;EAAM,MAAM,SAAS;EAAM;AAC3D,KAAIA,UAAQ,OAAO,KAAK,CAAC,aAAa,gBAAgB,gBACrD,QAAO;EACN,IAAI;EACJ,SAAS;GACR,MAAM;GACN,SAAS;GACT;GACA;GACA;EACD;CAEF,IAAI;AACJ,KAAI;AACH,QAAM,mBAAmB,KAAK;SACvB;AACP,SAAO;GACN,IAAI;GACJ,SAAS;IAAE,MAAM;IAAkB,SAAS;IAAgC;IAAM;IAAQ;GAC1F;;CAEF,MAAM,SAAS,eAAe,MAAM,IAAI;AACxC,KAAI,CAAC,OAAO,SAAS;EACpB,MAAM,QAAQ,OAAO,OAAO,IAAI,QAAQ;AACxC,SAAO;GACN,IAAI;GACJ,SAAS;IACR,MAAM;IACN,SAAS;IACT;IACA,QAAQ,UAAU,SAAY,SAAS;KAAE,GAAG;KAAQ;KAAO;IAC3D;GACD;;AAEF,QAAO;EAAE,IAAI;EAAM,QAAQ,OAAO;EAAQ;;;;;;;;;;AC7F3C,SAAS,SAAS,UAAkB,SAA6B;AAChE,QAAO;EAAE,MAAM;EAA8B;EAAS;EAAU;;AAGjE,MAAM,yBAAiD;CACtD,QAAQ;CACR,aAAa;CACb,MAAM;CACN;AAED,SAAS,eAAe,QAAsC;CAC7D,MAAM,SAAuB,EAAE;CAC/B,MAAM,OAAO,mBAAmB,UAAU;EACzC,QAAQ,OAAO;EACf,aAAa,OAAO;EACpB,MAAM,OAAO;EACb,CAAC;AACF,KAAI,CAAC,KAAK,SAAS;EAClB,MAAM,aAAa,IAAI,IAAI,KAAK,MAAM,OAAO,KAAK,UAAU,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC;AACnF,OAAK,MAAM,CAAC,UAAU,YAAY,OAAO,QAAQ,uBAAuB,CACvE,KAAI,WAAW,IAAI,SAAS,CAAE,QAAO,KAAK,SAAS,UAAU,QAAQ,CAAC;;CAGxE,MAAM,UAAU,UAAU,OAAO,OAAO;AACxC,KAAI,OAAO,cAAc,QACxB,QAAO,KAAK,SAAS,aAAa,kDAAkD,CAAC;AAEtF,KAAI,SACH;MAAI,gBAAgB,OAAO,OAAO,KAAK,KACtC,QAAO,KAAK,SAAS,UAAU,yCAAyC,CAAC;WAEzE,CAAC,iBAAiB,OAAO,KAAK,IAC9B,0BAA0B,OAAO,QAAQ,OAAO,YAAY,KAAK,KAEjE,QAAO,KACN,SACC,eACA,oEACA,CACD;;AAGH,QAAO;;;AAIR,SAAgB,qBAAqB,QAAiC;AACrE,QAAO,eAAe,OAAO,CAAC,WAAW;;AAG1C,MAAM,8BAA+D;CACpE,QAAQ;CACR,MAAM;CACN,KAAK;CACL,SAAS;CACT,QAAQ;CACR;AAED,SAAS,uBAAuB,OAAqC,OAA8B;AAClG,KAAI,CAAC,MAAO,QAAO,EAAE;AACrB,KAAI;AACH,mBACC;GAAE,MAAM;GAAI,MAAM,MAAM;GAAM,YAAY,EAAE,SAAS,MAAM,SAAS;GAAE,EACtE,SAAS,KACT;AACD,SAAO,EAAE;UACD,OAAO;AACf,MAAI,iBAAiB,sBACpB,QAAO,CAAC,SAAS,SAAS,4BAA4B,MAAM,MAAM,CAAC;AAEpE,QAAM;;;AAIR,SAAS,kBAAkB,SAA0B;AACpD,KAAI;AACH,oBAAkB,QAAQ;AAC1B,SAAO;SACA;AACP,SAAO;;;AAIT,MAAM,aAAa;;;;;AAMnB,SAAS,iBAAiB,WAA4B;AACrD,KAAI,WAAW,KAAK,UAAU,IAAI,UAAU,WAAW,KAAK,CAC3D,QAAO,QAAQ,UAAU,UAAU,CAAC;AAErC,QAAO;;AAGR,MAAM,4BAAiD,IAAI,IAAI,qBAAqB;AACpF,MAAM,uBAAuB;AAE7B,SAAS,gBAAgB,QAAuC;CAC/D,MAAM,SAAuB,EAAE;AAC/B,KAAI,0BAA0B,IAAI,OAAO,KAAK,CAC7C,QAAO,KAAK,SAAS,QAAQ,8BAA8B,CAAC;AAE7D,KAAI,OAAO,MAAM,MAAM,CAAC,WAAW,KAAK,OAAO,MAAM,SAAS,qBAC7D,QAAO,KAAK,SAAS,SAAS,wCAAwC,CAAC;AAExE,KAAI,OAAO,WAAW,UAAU,OAAO,WAAW,OACjD,QAAO,KAAK,SAAS,UAAU,qCAAqC,CAAC;AAEtE,QAAO;;AAGR,SAAS,uBAAuB,QAA8C;CAC7E,MAAM,SAAuB,EAAE;AAC/B,KAAI,OAAO,UAAU,EAAG,QAAO,KAAK,SAAS,WAAW,qCAAqC,CAAC;AAC9F,KAAI;AAEH,sBAAoB,OAAO,OAA4C;UAC/D,OAAO;AACf,MAAI,EAAE,iBAAiB,aAAc,OAAM;AAC3C,SAAO,KAAK,SAAS,UAAU,+CAA+C,CAAC;;AAEhF,QAAO;;AAGR,SAAgB,gBAAgB,QAA2B,OAAqC;AAC/F,SAAQ,OAAO,MAAf;EACC,KAAK,aACJ,QAAO,gBAAgB,OAAO;EAC/B,KAAK,qBACJ,QAAO,uBAAuB,OAAO;EACtC,KAAK,WACJ,QAAO,eAAe,OAAO;EAC9B,KAAK,aACJ,QAAO,OAAO,eAAe,UAAa,CAAC,kBAAkB,OAAO,WAAW,GAC5E,CAAC,SAAS,cAAc,oCAAoC,CAAC,GAC7D,EAAE;EACN,KAAK,SACJ,QAAO,OAAO,eAAe,UAAa,CAAC,QAAQ,UAAU,OAAO,WAAW,CAAC,UAC7E,CAAC,SAAS,cAAc,6CAA6C,CAAC,GACtE,EAAE;EACN,KAAK;EACL,KAAK,2BACJ,QAAO,uBAAuB,MAAM,aAAa,IAAI,OAAO,QAAQ,EAAE,OAAO,MAAM;EACpF,KAAK,MACJ,QAAO,OAAO,iBAAiB,UAAa,CAAC,iBAAiB,OAAO,aAAa,GAC/E,CAAC,SAAS,gBAAgB,2DAA2D,CAAC,GACtF,EAAE;EACN,KAAK,YACJ,QAAO,OAAO,cAAc,UAAa,CAAC,SAAS,UAAU,OAAO,UAAU,CAAC,UAC5E,CAAC,SAAS,aAAa,iDAAiD,CAAC,GACzE,EAAE;EACN,QACC,QAAO,EAAE;;;;;;;;;;ACzJZ,SAAgB,sBAAsB,QAIZ;AACzB,QAAO;EACN,SAAS,OAAO,OAAO,CAAC,GAAG,OAAO,KAAK,QAAQ,GAAG,CAAC,KAAK;EACxD,eAAe,OAAO,iBAAiB,gBAAgB;EACvD,eAAe,OAAO,iBAAiB;EACvC;;AAGF,MAAM,0BAAiE;CACtE,iBAAiB;CACjB,uBAAuB;CACvB,wBAAwB;CACxB,2BAA2B;CAC3B,uBAAuB;CACvB;AAED,SAAS,cAAc,SAAqC;CAC3D,MAAM,SAAiC,EAAE,QAAQ,QAAQ,MAAM;AAC/D,KAAI,QAAQ,SAAS,kBAAmB,QAAO,QAAQ,QAAQ;UACtD,QAAQ,SAAS,4BAA6B,QAAO,WAAW,QAAQ;UACxE,QAAQ,SAAS,wBAAyB,QAAO,YAAY,QAAQ;KACzE,QAAO,aAAa,QAAQ;AACjC,QAAO;EACN,MAAM;EACN,SAAS,wBAAwB,QAAQ;EACzC;EACA;;;;;;;AAaF,eAAsB,oBACrB,IACA,iBAC0B;CAC1B,MAAM,aAAa,MAAM,sBAAsB,GAAG;CAClD,MAAM,WAAW,WAAW,SAAS,IAAI,cAAc;CACvD,MAAM,WAAW,IAAI,IAAI,gBAAgB;AACzC,KAAI,SAAS,OAAO,EACnB,MAAK,MAAM,UAAU,MAAM,IAAI,eAAe,GAAG,CAAC,wBAAwB,EAAE;AAC3E,MAAI,CAAC,SAAS,IAAI,OAAO,KAAK,CAAE;AAChC,WAAS,KAAK;GACb,MAAM;GACN,SAAS;GACT,QAAQ;IAAE,QAAQ;IAAkB,OAAO,OAAO;IAAW;GAC7D,CAAC;;AAGJ,QAAO;EAAE;EAAU,UAAU,WAAW;EAAgB;;;AAIzD,SAAS,iBAAiB,QAAgB,QAAmD;AAC5F,KAAI,OAAO,QAAQ,SAAS,OAAO,CAAE,QAAO;CAC5C,MAAM,SAAS,OAAO,aAAa;AACnC,QAAO,OAAO,QAAQ,MAAM,cAAc,UAAU,aAAa,KAAK,OAAO;;;;;;;AAQ9E,SAAgB,aACf,UACA,QACgB;CAChB,MAAM,WAA0B,EAAE;CAClC,MAAM,UAAU,IAAI,IACnB,SAAS,QAAQ,KAAK,QAAQ,WAAW,OAAO,QAAQ,SAAS,OAAO,CAAC,CACzE;AACD,MAAK,MAAM,UAAU,SAAS,QAAQ,MAAM;AAC3C,MAAI,OAAO,QAAQ,SAAS,OAAO,CAAE;EACrC,MAAM,aAAa,iBAAiB,QAAQ,OAAO;AACnD,MAAI,eAAe,UAAa,CAAC,QAAQ,IAAI,WAAW,EAAE;AACzD,WAAQ,IAAI,WAAW;AACvB;;AAED,WAAS,KAAK;GACb,MAAM;GACN,SACC,eAAe,SACZ,8DACA;GACJ,GAAI,kBAAkB,OAAO,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE;GAC3D,CAAC;;AAEH,QAAO;;;AAIR,SAAgB,eACf,UACA,QACsC;AACtC,QAAO,SAAS,QAAQ,KAAK,SAAS,WAAW;EAChD,MAAM,aAAa,iBAAiB,QAAQ,OAAO;AACnD,SAAO,eAAe,UAAa,eAAe,SAC/C,EAAE,GACF,CAAC;GAAE,MAAM;GAAQ,IAAI;GAAY,CAAC;GACpC;;;AAIH,MAAa,6BAA6B;;;;;;;AAQ1C,eAAsB,kBACrB,UACA,OACA,aACA,aACoB;CACpB,MAAM,UAAU,SAAS,QAAQ;AACjC,KAAI,CAAC,WAAW,QAAQ,QAAQ,2BAA4B,QAAO,EAAE;CACrE,MAAM,QAAwB,EAAE;AAChC,MAAK,IAAI,MAAM,GAAG,MAAM,QAAQ,QAAQ,OAAO;EAC9C,MAAM,OAAO,gBAAgB,YAAY,IAAI;EAC7C,MAAM,OAAO,MAAM,YAAY,IAAI,aAAa,KAAK;AACrD,MAAI,CAAC,QAAQ,KAAK,UAAU,WAAY;EACxC,IAAI;AACJ,MAAI;AACH,WAAQ,MAAM,kBAAkB,OAAO,MAAM,KAAK;WAC1C,OAAO;AACf,OAAI,gBAAgB,MAAM,CAAE;AAC5B,SAAM;;AAEP,QAAM,SAAS,MAAM,UAAU;GAC9B,MAAM,UAAU,iBAAiB,YAAY,MAAM;IAAE;IAAM,MAAM,QAAQ;IAAG,CAAC;AAC7E,OAAI,CAAC,QAAQ,MAAM,CAAC,qBAAqB,QAAQ,OAAO,CAAE;GAC1D,MAAM,EAAE,WAAW;AACnB,SAAM,KAAK;IACV,IAAI,OAAO;IACX,QAAQ,OAAO;IACf,aAAa,OAAO;IACpB,SAAS,OAAO;IAChB,WAAW,OAAO;IAClB,CAAC;IACD;;AAEH,QAAO,YAAY,MAAM,CAAC,SAAS,WAAW;;;AAI/C,MAAM,iBAAiB;;;;;AAMvB,SAAgB,UAAU,OAAuB;AAChD,QAAO,MAAM,UAAU,MAAM,CAAC,aAAa;;;;;;;AAQ5C,eAAsB,sBACrB,IACA,YAC+B;CAC/B,MAAM,SAAS,IAAI,IAClB,WAAW,SAAS,cAAe,UAAU,QAAQ,CAAC,UAAU,UAAU,MAAM,CAAC,GAAG,EAAE,CAAE,CACxF;CACD,MAAM,+BAAe,IAAI,KAAuB;AAChD,KAAI,OAAO,OAAO,GAAG;EACpB,IAAI,QAAuB;AAC3B,WAAS;GACR,IAAI,QAAQ,GACV,WAAW,QAAQ,CACnB,OAAO,CAAC,MAAM,QAAQ,CAAC,CACvB,QAAQ,KAAK,CACb,MAAM,eAAe;AACvB,OAAI,UAAU,KAAM,SAAQ,MAAM,MAAM,MAAM,KAAK,MAAM;GACzD,MAAM,OAAO,MAAM,MAAM,SAAS;AAClC,QAAK,MAAM,OAAO,MAAM;IACvB,MAAM,SAAS,UAAU,IAAI,MAAM;AACnC,QAAI,CAAC,OAAO,IAAI,OAAO,CAAE;IACzB,MAAM,OAAO,aAAa,IAAI,OAAO,IAAI,EAAE;AAC3C,SAAK,KAAK,IAAI,GAAG;AACjB,iBAAa,IAAI,QAAQ,KAAK;;GAE/B,MAAM,OAAO,KAAK,GAAG,GAAG;AACxB,OAAI,KAAK,SAAS,kBAAkB,CAAC,KAAM;AAC3C,WAAQ,KAAK;;;CAGf,MAAM,8BAAc,IAAI,KAAqB;AAC7C,MAAK,MAAM,aAAa,YAAY;AACnC,MAAI,CAAC,UAAU,MAAO;EACtB,MAAM,UAAU,aAAa,IAAI,UAAU,UAAU,MAAM,CAAC,IAAI,EAAE;EAClE,MAAM,CAAC,QAAQ;AACf,MAAI,QAAQ,WAAW,KAAK,SAAS,OAAW,aAAY,IAAI,UAAU,IAAI,KAAK;;AAEpF,QAAO;;;AAIR,eAAsB,iBACrB,IACA,SACoB;CACpB,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,QAAQ,CAAC;CACpC,MAAM,wBAAQ,IAAI,KAAa;AAC/B,MAAK,MAAM,SAAS,OAAO,QAAQ,eAAe,EAAE;EACnD,MAAM,OAAO,MAAM,GAAG,WAAW,QAAQ,CAAC,OAAO,KAAK,CAAC,MAAM,MAAM,MAAM,MAAM,CAAC,SAAS;AACzF,OAAK,MAAM,OAAO,KAAM,OAAM,IAAI,IAAI,GAAG;;AAE1C,QAAO,OAAO,QAAQ,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,WAAW;;;;;AC3OlE,MAAM,iBAAiB;AACvB,MAAM,wBAAwB;;AAG9B,MAAM,qBAAqB;AAE3B,MAAM,yBAA8C,IAAI,IAAI,CAAC,qBAAqB,CAAC;AACnF,MAAM,gCAAqD,IAAI,IAA8B,CAC5F,oBACA,qBACA,CAAC;AAsCF,MAAM,uBAA0C,CAC/C,GAAG,6BACH,GAAG,4BACH;;AAGD,SAAS,oBAAoB,iBAA6D;AACzF,QAAO,gBAAgB,UACrB,GAAG,MAAM,qBAAqB,QAAQ,EAAE,KAAK,GAAG,qBAAqB,QAAQ,EAAE,KAAK,CACrF;;AAGF,SAAS,yBAAyB,SAA2C;AAC5E,QAAO,CAAC,GAAG,QAAQ,kBAAkB,CAAC,MAAM,GAAG,sBAAsB,CAAC,KAAK,CAAC,UAAU,WAAW;EAChG,MAAM;EACN,SAAS;EACT,OAAO;EACP,QAAQ,EAAE,UAAU;EACpB,EAAE;;AAGJ,SAAS,0BAA0B,UAA8C;CAChF,MAAM,QAAQ,SAAS,QAAQ,UAAU,SAAS;AAClD,KAAI,SAAS,2BAA4B,QAAO,EAAE;AAClD,QAAO,CACN;EACC,MAAM;EACN,SACC;EACD,MAAM;EACN;EACA,CACD;;AAGF,SAAS,cAAc,UAAuC;CAC7D,IAAI,SAAS;AACb,MAAK,MAAM,WAAW,OAAO,OAAO,SAAS,QAAQ,CAAE,WAAU,SAAS,UAAU;AACpF,QACC,qBAAqB,SAAS,KAAK,KAAK,SAAS,MAAM,aAAa,gBAAgB,UAAU;;AAIhG,SAAgB,iBACf,YACsB;AACtB,QAAO;EACN,mBAAmB,OAAO,YACzB,WAAW,KAAK,cAAc,CAAC,UAAU,IAAI,UAAU,mBAAmB,KAAK,CAAC,CAChF;EACD,WAAW;EACX,aAAa;EACb;;AAGF,SAAS,eAAe,cAAuB,aAAsB;AACpE,QAAO;EACN,GAAI,iBAAiB,SAAY,EAAE,GAAG,EAAE,SAAS,cAAc;EAC/D,GAAI,gBAAgB,SAAY,EAAE,GAAG,EAAE,QAAQ,YAAY,MAAM,GAAG,KAAK,EAAE;EAC3E;;;AAIF,SAAgB,UAAU,QAAoB,SAA2C;CACxF,MAAM,EAAE,UAAU,YAAY;CAE9B,MAAM,aAA8B,QAAQ,WAAW,KAAK,cAAc;EACzE,MAAM,kBAAkB,OAAO,YAAY,IAAI,UAAU,GAAG;AAC5D,SAAO;GACN,IAAI,UAAU;GACd,aAAa,UAAU;GACvB,GAAI,UAAU,UAAU,SAAY,EAAE,GAAG,EAAE,OAAO,UAAU,OAAO;GACnE,YAAY,QAAQ,oBAAoB,IAAI,UAAU,GAAG,IAAI;GAC7D,GAAI,oBAAoB,SAAY,EAAE,GAAG,EAAE,iBAAiB;GAC5D;GACA;CAEF,MAAM,kBAAwC,CAAC,GAAG,SAAS,gBAAgB;AAC3E,KAAI,OAAO,SAAS,SAAS,EAC5B,iBAAgB,KAAK;EACpB,MAAM;EACN,OAAO,OAAO,SAAS;EACvB,OAAO,OAAO,SACZ,MAAM,GAAG,eAAe,CACxB,KAAK,UAAU;GAAE,MAAM,KAAK;GAAM,IAAI,KAAK;GAAI,EAAE;EACnD,CAAC;AAEH,KAAI,OAAO,cAAc,SAAS,EACjC,iBAAgB,KAAK;EACpB,MAAM;EACN,MAAM;EACN,KAAK,OAAO,cAAc,MAAM,GAAG,eAAe;EAClD,CAAC;AAEH,KAAI,OAAO,eAAe,SAAS,EAClC,iBAAgB,KAAK;EAAE,MAAM;EAAkB,SAAS,CAAC,GAAG,OAAO,eAAe;EAAE,CAAC;AAEtF,KAAI,OAAO,OAAO,YAAY,YAAY;AACzC,MAAI,QAAQ,yBAAyB,SAAS,EAC7C,iBAAgB,KAAK;GACpB,MAAM;GACN,MAAM;GACN,KAAK,QAAQ,yBAAyB,MAAM,GAAG,eAAe;GAC9D,CAAC;AAEH,MAAI,QAAQ,gBAAgB,EAC3B,iBAAgB,KAAK;GAAE,MAAM;GAAkB,OAAO,QAAQ;GAAe,CAAC;;CAIhF,MAAM,OAAuB;EAC5B,eAAe;EACf,eAAe,OAAO;EACtB,QAAQ;GACP,QAAQ,SAAS;GACjB,WAAW,SAAS;GACpB,WAAW,SAAS;GACpB,wBAAwB,SAAS;GACjC;EACD,QAAQ,OAAO;EACf,QAAQ,OAAO,YACd,OAAO,QAAQ,SAAS,QAAQ,CAAC,KAAK,CAAC,MAAM,YAAY,CAAC,MAAM,OAAO,MAAM,CAAC,CAC9E;EACD,OAAO;GAAE,SAAS,QAAQ;GAAa,OAAO,SAAS,MAAM;GAAY;EACzE;EACA,UAAU;GACT,OAAO,eAAe,QAAQ,SAAS,OAAO,OAAO,eAAe,MAAM;GAC1E,SAAS,eAAe,QAAQ,SAAS,SAAS,OAAO,eAAe,QAAQ;GAChF;EACD,WAAW,iBAAiB,WAAW;EACvC;EACA,UAAU;GACT,GAAG,OAAO;GACV,GAAG,yBAAyB,QAAQ;GACpC,GAAG,0BAA0B,SAAS;GACtC;EACD,UAAU,CAAC,GAAG,OAAO,oBAAoB,GAAG,OAAO,eAAe;EAClE,gBAAgB,cAAc,SAAS;EACvC;AACD,QAAO,eAAe,MAAM,KAAK,WAAW,QAAQ;;;;;;AAOrD,SAAgB,iBAAiB,OAMd;AAClB,QAAO,qBAAqB,MAAM;EACjC,eAAe;EACf,eAAe,MAAM;EACrB,QAAQ,MAAM;EACd,QAAQ,MAAM;EACd,QAAQ,EAAE;EACV,OAAO;GAAE,SAAS;GAAG,OAAO;GAAG;EAC/B,YAAY,EAAE;EACd,UAAU;GAAE,OAAO,EAAE;GAAE,SAAS,EAAE;GAAE;EACpC,WAAW,iBAAiB,EAAE,CAAC;EAC/B,iBAAiB,EAAE;EACnB,UAAU,CAAC,GAAG,MAAM,SAAS;EAC7B,UAAU,CAAC,GAAG,MAAM,SAAS;EAC7B,gBAAgB;EAChB,CAAC;;;;;;AAOH,SAAgB,eACf,MACA,WACA,SACiB;CACjB,IAAI,mBAAmB;CACvB,IAAI,qBAAqB;CACzB,MAAM,mCAAmB,IAAI,KAAuB;CACpD,MAAM,YAA2B,EAAE;AACnC,MAAK,MAAM,aAAa,KAAK,YAAY;EACxC,MAAM,SAAS,OAAO,OAAO,UAAU,mBAAmB,UAAU,GAAG,GACpE,UAAU,kBAAkB,UAAU,MACtC;AACH,MAAI,WAAW,QAAQ,WAAW,QAAW;AAC5C,yBAAsB,UAAU;AAChC;;AAED,sBAAoB,UAAU;AAC9B,MAAI,QAAQ,aAAa,IAAI,UAAU,GAAG,CACzC,WAAU,KAAK;GACd,MAAM;GACN,SAAS;GACT,MAAM;GACN,IAAI,UAAU;GACd,QAAQ,EAAE,MAAM,QAAQ;GACxB,CAAC;EAEH,MAAM,OAAO,iBAAiB,IAAI,OAAO,IAAI,EAAE;AAC/C,OAAK,KAAK,UAAU,GAAG;AACvB,mBAAiB,IAAI,QAAQ,KAAK;;AAGnC,MAAK,MAAM,CAAC,QAAQ,iBAAiB,iBACpC,MAAK,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,IACxC,MAAK,IAAI,IAAI,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;EACjD,MAAM,QAAQ,aAAa;EAC3B,MAAM,SAAS,aAAa;AAC5B,MAAI,UAAU,UAAa,WAAW,OAAW;EACjD,MAAM,eAAe,QAAQ,QAAQ,IAAI,MAAM;EAC/C,MAAM,gBAAgB,QAAQ,QAAQ,IAAI,OAAO;AACjD,MAAI,CAAC,gBAAgB,CAAC,cAAe;AACrC,MAAI,CAAC,CAAC,GAAG,aAAa,CAAC,MAAM,WAAW,cAAc,IAAI,OAAO,CAAC,CAAE;AACpE,YAAU,KAAK;GACd,MAAM;GACN,SAAS;GACT,MAAM;GACN,IAAI;GACJ,QAAQ;IAAE,WAAW;IAAO,MAAM;IAAQ;GAC1C,CAAC;;CAKL,MAAM,kBAAkB,KAAK,gBAAgB,QAC3C,mBAAmB,CAAC,8BAA8B,IAAI,eAAe,KAAK,CAC3E;AACD,KAAI,mBAAmB,EACtB,iBAAgB,KAAK;EAAE,MAAM;EAAoB,OAAO;EAAkB,CAAC;AAE5E,KAAI,qBAAqB,EACxB,iBAAgB,KAAK;EAAE,MAAM;EAAsB,OAAO;EAAoB,CAAC;AAGhF,QAAO,qBAAqB,MAAM;EACjC,GAAG;EACH;EACA,iBAAiB,oBAAoB,gBAAgB;EACrD,UAAU,CACT,GAAG,KAAK,SAAS,QAAQ,YAAY,CAAC,uBAAuB,IAAI,QAAQ,KAAK,CAAC,EAC/E,GAAG,UACH;EACD,CAAC;;;;;;;;;;;;;;;;;;ACvSH,MAAM,aAAa;CAClB,IAAI;CACJ,OAAO;CACP,MAAM;CACN,MAAM;CACN;AAED,IAAa,iCAAb,MAA4C;CAC3C,YACC,AAAiB,IACjB,AAAiB,aAChB;EAFgB;EACA;;;CAIlB,MAAM,WAAW,SAAsD;AACtE,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,QAAQ,EAAE,cAAc,EAAE,CAAC,CACzD,OAAM,KAAK,GACT,WAAW,iCAAiC,CAC5C,OACA,MAAM,KAAK,WAAW;GACrB,cAAc,KAAK;GACnB,MAAM,MAAM;GACZ,IAAI,MAAM;GACV,UAAU,MAAM,WAAW;GAC3B,WAAW,MAAM,YAAY;GAC7B,UAAU,MAAM,WAAW;GAC3B,OAAO,MAAM,SAAS;GACtB,EAAE,CACH,CACA,YAAY,aAAa,SAAS,QAAQ;GAAC;GAAgB;GAAQ;GAAK,CAAC,CAAC,WAAW,CAAC,CACtF,SAAS;;CAIb,MAAM,IAAI,MAAkB,IAA+C;EAC1E,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,iCAAiC,CAC5C,WAAW,CACX,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,QAAQ,KAAK,KAAK,CACxB,MAAM,MAAM,KAAK,GAAG,CACpB,kBAAkB;AACpB,MAAI,CAAC,OAAO,CAAC,aAAa,IAAI,KAAK,CAAE,QAAO;AAC5C,SAAO;GACN,MAAM,IAAI;GACV,IAAI,IAAI;GACR,SAAS,IAAI;GACb,UAAU,IAAI;GACd,SAAS,IAAI;GACb,OAAO,OAAO,IAAI,MAAM;GACxB;;;;;;CAOF,MAAM,YACL,OACA,KACA,QACoB;EACpB,MAAM,SAAS,WAAW;EAC1B,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC;EACnC,MAAM,wBAAQ,IAAI,KAAa;AAC/B,OAAK,MAAM,SAAS,OAAO,QAAQ,eAAe,EAAE;GACnD,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,iCAAiC,CAC5C,OAAO,GAAW,GAAG,IAAI,IAAI,OAAO,GAAG,GAAG,QAAQ,CAAC,CACnD,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,QAAQ,MAAM,CAAC,GAAG,MAAM,CAAC,CAC/B,MAAM,IAAI,IAAI,OAAO,EAAE,MAAM,MAAM,CACnC,SAAS;AACX,QAAK,MAAM,OAAO,KAAM,OAAM,IAAI,IAAI,MAAM;;AAE7C,SAAO,OAAO,QAAQ,UAAU,CAAC,MAAM,IAAI,MAAM,CAAC,CAAC,SAAS,WAAW;;;CAIxE,MAAM,OAAO,MAAkB,KAAsD;EACpF,MAAM,yBAAS,IAAI,KAAqB;AACxC,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,EAAE,eAAe,EAAE;GAC9D,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,iCAAiC,CAC5C,OAAO,CAAC,MAAM,QAAQ,CAAC,CACvB,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,QAAQ,KAAK,KAAK,CACxB,MAAM,MAAM,MAAM,MAAM,CACxB,SAAS;AACX,QAAK,MAAM,OAAO,KAAM,QAAO,IAAI,IAAI,IAAI,OAAO,IAAI,MAAM,CAAC;;AAE9D,SAAO;;CAGR,MAAM,MAAM,MAAoC;EAC/C,IAAI,QAAQ,KAAK,GACf,WAAW,iCAAiC,CAC5C,QAAQ,OAAO,GAAG,GAAG,UAA2B,CAAC,GAAG,QAAQ,CAAC,CAC7D,MAAM,gBAAgB,KAAK,KAAK,YAAY;AAC9C,MAAI,KAAM,SAAQ,MAAM,MAAM,QAAQ,KAAK,KAAK;EAChD,MAAM,MAAM,MAAM,MAAM,yBAAyB;AACjD,SAAO,OAAO,IAAI,MAAM;;;CAIzB,MAAM,WAAW,QAAQ,KAAsB;EAC9C,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,iCAAiC,CAC5C,OAAO,CAAC,QAAQ,KAAK,CAAC,CACtB,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,MAAM,CACZ,SAAS;EACX,IAAI,UAAU;EACd,MAAM,yBAAS,IAAI,KAAuB;AAC1C,OAAK,MAAM,OAAO,KAAM,QAAO,IAAI,IAAI,MAAM,CAAC,GAAI,OAAO,IAAI,IAAI,KAAK,IAAI,EAAE,EAAG,IAAI,GAAG,CAAC;AACvF,OAAK,MAAM,CAAC,MAAM,QAAQ,OACzB,MAAK,MAAM,SAAS,OAAO,KAAK,eAAe,EAAE;GAChD,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,iCAAiC,CAC5C,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,QAAQ,KAAK,KAAK,CACxB,MAAM,MAAM,MAAM,MAAM,CACxB,kBAAkB;AACpB,cAAW,OAAO,OAAO,kBAAkB,GAAG;;AAGhD,SAAO;;;;;;;;;;;;;;ACzIT,MAAa,mBAAmB,EAAE,aAAa;CAC9C,UAAU,EAAE,MAAM,kBAAkB;CACpC,UAAU,EAAE,MAAM,kBAAkB;CACpC,iBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;CAC/C,iBAAiB,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;CAC/C,CAAC;AAIF,SAAgB,cAA0B;AACzC,QAAO;EAAE,UAAU,EAAE;EAAE,UAAU,EAAE;EAAE,iBAAiB;EAAG,iBAAiB;EAAG;;AAG9E,SAAgB,WAAW,QAAoB,SAA4B;AAC1E,KAAI,OAAO,SAAS,SAAS,gBAAgB,WAAY,QAAO,SAAS,KAAK,QAAQ;KACjF,QAAO;;AAGb,SAAgB,WAAW,QAAoB,SAA4B;AAC1E,KAAI,OAAO,SAAS,SAAS,gBAAgB,WAAY,QAAO,SAAS,KAAK,QAAQ;KACjF,QAAO;;;AAIb,SAAgB,cAAc,QAAmC;AAChE,KAAI,OAAO,oBAAoB,KAAK,OAAO,oBAAoB,EAAG,QAAO,CAAC,GAAG,OAAO,SAAS;AAC7F,QAAO,CACN,GAAG,OAAO,UACV;EACC,MAAM;EACN,SAAS;EACT,OAAO,OAAO,kBAAkB,OAAO;EACvC,QAAQ;GAAE,UAAU,OAAO;GAAiB,UAAU,OAAO;GAAiB;EAC9E,CACD;;;;;;ACPF,MAAM,kBAAkB;AAOxB,SAAS,IAAI,YAA8B,GAAG,OAA4B;AACzE,QAAO;EAAE;EAAY;EAAO;;;;;;AAO7B,SAAS,YAAY,QAAwB;AAC5C,QAAO,OAAO,aAAa;;;AAI5B,SAAgB,aAAa,QAAwC;AACpE,SAAQ,OAAO,MAAf;EACC,KAAK,aACJ,QAAO,CAAC,IAAI,mBAAmB,OAAO,KAAK,CAAC;EAC7C,KAAK,qBACJ,QAAO,CAAC,IAAI,sBAAsB,OAAO,aAAa,OAAO,OAAO,QAAQ,CAAC,CAAC;EAC/E,KAAK,SAAS;GACb,MAAM,OAAoB,EAAE;AAC5B,OAAI,OAAO,SAAS,OACnB,MAAK,KAAK,IAAI,qBAAqB,OAAO,YAAY,OAAO,MAAM,OAAO,OAAO,CAAC;AAEnF,OAAI,OAAO,cAAc,UAAa,OAAO,qBAAqB,OACjE,MAAK,KACJ,IACC,6BACA,OAAO,YACP,OAAO,kBACP,YAAY,OAAO,OAAO,CAC1B,CACD;AAEF,UAAO;;EAER,KAAK,QAAQ;GACZ,MAAM,OAAO,CAAC,IAAI,yBAAyB,OAAO,MAAM,OAAO,MAAM,OAAO,OAAO,CAAC;AACpF,OAAI,OAAO,qBAAqB,OAC/B,MAAK,KAAK,IAAI,qBAAqB,OAAO,kBAAkB,OAAO,OAAO,CAAC;AAE5E,UAAO;;EAER,KAAK,eACJ,QAAO,CAAC,IAAI,4BAA4B,OAAO,MAAM,OAAO,OAAO,CAAC;EACrE,KAAK,UAAU;GACd,MAAM,OAAO,CAAC,IAAI,sBAAsB,OAAO,MAAM,OAAO,OAAO,CAAC;AACpE,OAAI,OAAO,qBAAqB,OAC/B,MAAK,KAAK,IAAI,uBAAuB,OAAO,kBAAkB,OAAO,OAAO,CAAC;AAE9E,OAAI,OAAO,kBAAkB,OAC5B,MAAK,KAAK,IAAI,2BAA2B,OAAO,eAAe,OAAO,OAAO,CAAC;AAE/E,UAAO;;EAER,KAAK,eACJ,QAAO,CAAC,IAAI,qBAAqB,OAAO,KAAK,CAAC;EAC/C,KAAK,OACJ,QAAO,CAAC,IAAI,oBAAoB,OAAO,MAAM,OAAO,OAAO,CAAC;EAC7D,KAAK,WACJ,QAAO,CACN,IAAI,wBAAwB,OAAO,MAAM,OAAO,OAAO,EACvD,IAAI,yBAAyB,OAAO,kBAAkB,OAAO,OAAO,CACpE;EACF,KAAK,cACJ,QAAO,CAAC,IAAI,oBAAoB,OAAO,KAAK,CAAC;EAC9C,KAAK,UACJ,QAAO,CAAC,IAAI,gBAAgB,OAAO,KAAK,CAAC;EAC1C,KAAK,oBACJ,QAAO,CACN,IACC,4BACA,OAAO,eACP,OAAO,aACP,OAAO,WACP,CACD;EACF,KAAK,iBACJ,QAAO,CACN,IAAI,+BAA+B,OAAO,YAAY,OAAO,SAAS,OAAO,YAAY,CACzF;EACF,KAAK,eACJ,QAAO,CAAC,IAAI,yBAAyB,OAAO,QAAQ,CAAC;EACtD,QACC,QAAO,EAAE;;;;AAkBZ,MAAa,qBAAqB;;AAGlC,MAAa,uBACZ,KAAK,KAAK,qBAAqB,cAAc,EAAE,CAAC,GAAG,KAAK,KAAK,qBAAqB,eAAe;;;;;AAMlG,eAAsB,qBACrB,IACA,aACA,SACgC;CAChC,MAAM,OAMD,EAAE;AACP,MAAK,MAAM,UAAU,QACpB,MAAK,MAAM,UAAU,OAAO,KAC3B,MAAK,KAAK;EACT,MAAM,GAAG,kBAAkB,OAAO;EAClC,IAAI,MAAM,UAAU,cAAc,OAAO,MAAM,CAAC;EAChD,SAAS,OAAO;EAChB,MAAM,OAAO;EACb,YAAY,OAAO;EACnB,CAAC;AAGJ,KAAI,KAAK,WAAW,EAAG,QAAO,EAAE;AAEhC,MAAK,MAAM,SAAS,OAAO,MAAM,cAAc,EAAE,CAAC,CACjD,OAAM,GACJ,WAAW,iCAAiC,CAC5C,OACA,MAAM,KAAK,SAAS;EACnB,cAAc;EACd,MAAM,IAAI;EACV,IAAI,IAAI;EACR,UAAU,IAAI;EACd,EAAE,CACH,CACA,YAAY,aAAa,SAAS,QAAQ;EAAC;EAAgB;EAAQ;EAAK,CAAC,CAAC,WAAW,CAAC,CACtF,SAAS;CAGZ,MAAM,0BAAU,IAAI,KAAqB;AACzC,MAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,KAAK,KAAK,QAAQ,IAAI,GAAG,CAAC,CAAC,EAAE,eAAe,EAAE;EACpF,MAAM,SAAS,MAAM,GACnB,WAAW,iCAAiC,CAC5C,OAAO;GAAC;GAAQ;GAAM;GAAW,CAAC,CAClC,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,QAAQ,QAAQ,GAAG,gBAAgB,GAAG,CAC5C,MAAM,MAAM,MAAM,MAAM,CACxB,SAAS;AACX,OAAK,MAAM,OAAO,OACjB,KAAI,IAAI,aAAa,KAAM,SAAQ,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAI,MAAM,IAAI,SAAS;;CAIpF,MAAM,aAAmC,EAAE;AAC3C,MAAK,MAAM,OAAO,MAAM;EACvB,MAAM,WAAW,QAAQ,IAAI,GAAG,IAAI,KAAK,QAAQ,IAAI,KAAK;AAC1D,MAAI,aAAa,UAAa,aAAa,IAAI,QAC9C,YAAW,KAAK;GAAE,YAAY,IAAI;GAAY,MAAM,IAAI;GAAM;GAAU,CAAC;;AAG3E,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACxLR,MAAa,2BAA2B;AACxC,MAAa,kBAAkB;AAE/B,MAAM,yBAAyB;AAC/B,MAAM,qBAAqB,GAAG,yBAAyB;AACvD,MAAM,cAAc;AACpB,MAAM,iBAAiB;AACvB,MAAM,mBAAmB;AACzB,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAC1B,MAAM,oBAAoB;AAC1B,MAAM,wBAAwB;;AAE9B,MAAM,gBAAgB;AAEtB,SAAS,QAAQ,MAAuB;AACvC,QAAO,QAAQ,MAAM,QAAQ;;AAG9B,SAAS,SAAS,MAAuB;CACxC,MAAM,QAAQ,OAAO;AACrB,QAAO,SAAS,MAAM,SAAS;;;AAIhC,SAAS,WAAW,MAAuB;AAC1C,QAAO,SAAS,KAAK,IAAI,QAAQ,KAAK,IAAI,SAAS,MAAM,SAAS;;;AAInE,SAAS,aAAa,MAAuB;AAC5C,QAAO,WAAW,KAAK,IAAI,SAAS;;;AAIrC,SAAS,oBAAoB,MAAuB;AACnD,QAAO,SAAS,KAAK,IAAI,QAAQ,KAAK,IAAI,SAAS,MAAM,SAAS;;;;;;;AAQnE,MAAa,oBAAoB;;AAGjC,SAAgB,sBAAsB,OAAuB;AAC5D,QAAO,MAAM,SAAS,yBAAyB,GAC5C,MAAM,WAAW,0BAA0B,mBAAmB,GAC9D;;AAGJ,SAAgB,kBAAkB,SAA0B;AAC3D,QAAO,uBAAuB,KAAK,QAAQ;;AAwB5C,SAAgB,mBACf,MACgB;CAChB,MAAM,+BAAe,IAAI,KAAqB;CAC9C,MAAM,2BAAW,IAAI,KAAa;AAClC,MAAK,MAAM,OAAO,MAAM;AACvB,WAAS,IAAI,IAAI,GAAG;EACpB,MAAM,WAAW,aAAa,IAAI,IAAI,WAAW;AACjD,MAAI,aAAa,UAAa,WAAW,IAAI,IAAI,SAAS,GAAG,EAC5D,cAAa,IAAI,IAAI,YAAY,IAAI,GAAG;;AAG1C,QAAO;EAAE;EAAc;EAAU;;;;;;AA8DlC,SAAgB,iBACf,QACA,SAC4B;CAC5B,MAAM,UAAuB;EAC5B;EACA,MAAM,OAAO;EACb,0BAAU,IAAI,KAAK;EACnB,UAAU,EAAE;EACZ,QAAQ,EAAE;EACV,aAAa;EACb,cAAc;EACd;CACD,MAAM,OAAO,mBAAmB,OAAO,KAAK;CAC5C,MAAM,UAAmC,EAAE;CAC3C,IAAI,UAAU;AACd,MAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,OAAO,EAAE;AACvD,MAAI,KAAK,IAAI,SAAS,CAAE;EACxB,MAAM,OAAO,KAAK,OAAO,SAAS,UAAU,CAAC,SAAS,CAAC;AACvD,MAAI,SAAS,OAAO;AACnB,WAAQ,YAAY;AACpB,aAAU;;;AAGZ,QAAO;EACN,OAAO,UAAU;GAAE,GAAG;GAAQ,GAAG;GAAS,GAAG;EAC7C;EACA,UAAU,CAAC,GAAG,QAAQ,SAAS,CAAC,SAAS,WAAW;EACpD,UAAU,QAAQ;EAClB,QAAQ,QAAQ;EAChB,aAAa,QAAQ;EACrB;;AAGF,SAAS,OAAO,MAAuB,OAA4B;AAClE,KAAI,KAAK,SAAS,sBAAuB,MAAK,KAAK,MAAM;;AAG1D,SAASC,gBAAc,OAAkD;AACxE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,SAAS,kBAAkB,MAAkB,UAAsC;AAClF,KAAI,SAAS,MAAO,QAAO,SAAS,WAAW,KAAK,SAAS,OAAO;AACpE,KAAI,SAAS,QAAS,QAAO,SAAS,WAAW,KAAK,SAAS,OAAO;AACtE,QAAO;;AAGR,SAAS,KAAK,OAAgB,SAAsB,MAAc,UAA6B;AAC9F,KAAI,OAAO,UAAU,SAAU,QAAO,cAAc,OAAO,SAAS,MAAM,SAAS;AACnF,KAAI,MAAM,QAAQ,MAAM,EAAE;EACzB,IAAI,UAAU;EACd,MAAM,OAAO,MAAM,KAAK,MAAM,UAAU;GACvC,MAAM,YAAY,KAAK,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,IAAI,CAAC,GAAG,UAAU,OAAO,MAAM,CAAC,CAAC;AACxF,OAAI,cAAc,KAAM,WAAU;AAClC,UAAO;IACN;AACF,SAAO,UAAU,OAAO;;AAEzB,KAAIA,gBAAc,MAAM,CAAE,QAAO,cAAc,OAAO,SAAS,MAAM,SAAS;AAC9E,QAAO;;AAGR,SAAS,cACR,OACA,SACA,MACA,UAC0B;CAC1B,IAAI,UAAU;CACd,MAAM,OAAgC,EAAE;AACxC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,EAAE;EACjD,MAAM,YAAY,KAAK,OAAO,SAAS,GAAG,KAAK,GAAG,OAAO,CAAC,GAAG,UAAU,IAAI,CAAC;AAC5E,MAAI,cAAc,MAAO,WAAU;AACnC,OAAK,OAAO;;AAGb,KAAI,QAAQ,QAAQ,SAAS,UAAU;EACtC,MAAM,EAAE,SAAS,QAAQ;EACzB,MAAM,WAAW,MAAM;EACvB,MAAM,UAAU,aAAa,UAAa,aAAa,QAAQ,aAAa;EAE5E,MAAM,OAAO,MAAM;AACnB,MAAI,WAAWA,gBAAc,KAAK,IAAI,OAAO,KAAK,eAAe,UAAU;GAC1E,MAAM,aAAa,KAAK;GACxB,MAAM,cAAc,kBAAkB,YAAY,MAAM,SAAS,GAAG,KAAK,kBAAkB;AAC3F,OAAI,gBAAgB,MAAM;AAEzB,SAAK,OAAO;KAAE,GADGA,gBAAc,KAAK,KAAK,GAAG,KAAK,OAAO;KAC7B,YAAY;KAAa;AACpD,cAAU;cACA,CAAC,KAAK,SAAS,IAAI,WAAW,CACxC,QAAO,QAAQ,UAAU;IACxB,MAAM;IACN,MAAM,GAAG,KAAK;IACd,OAAO;IACP,CAAC;;EAIJ,MAAM,KAAK,MAAM;AACjB,MAAI,WAAW,OAAO,OAAO,YAAY,CAAC,KAAK,SAAS,IAAI,GAAG,EAAE;GAChE,MAAM,cAAc,kBAAkB,IAAI,MAAM,SAAS,GAAG,KAAK,KAAK;AACtE,OAAI,gBAAgB,MAAM;AACzB,SAAK,KAAK;AACV,cAAU;;;;AAKb,QAAO,UAAU,OAAO;;;AAIzB,SAAS,kBACR,KACA,MACA,SACA,MACgB;AAChB,KAAI,KAAK,SAAS,IAAI,IAAI,CAAE,QAAO;CACnC,MAAM,UAAU,KAAK,aAAa,IAAI,IAAI;AAC1C,KAAI,YAAY,OAAW,QAAO;AAClC,KAAI,CAAC,kBAAkB,QAAQ,EAAE;AAChC,SAAO,QAAQ,QAAQ;GAAE,MAAM;GAAgC;GAAM,OAAO;GAAS,CAAC;AACtF,SAAO;;AAER,SAAQ,SAAS,IAAI,QAAQ;AAC7B,SAAQ;AACR,QAAO,GAAG,2BAA2B;;AAGtC,SAAS,cACR,OACA,SACA,MACA,UACS;AACT,KAAI,QAAQ,QAAQ,SAAS,SAC5B,QAAO,oBAAoB,OAAO,QAAQ,QAAQ,cAAc,SAAS,KAAK;CAE/E,MAAM,EAAE,SAAS,QAAQ;AAEzB,KAAI,kBAAkB,QAAQ,MAAM,SAAS,EAAE;EAC9C,MAAM,cAAc,kBAAkB,OAAO,MAAM,SAAS,KAAK;AACjE,MAAI,gBAAgB,KAAM,QAAO;;CAGlC,MAAM,UAAU,MAAM,WAAW;AACjC,KAAI,QAAQ,WAAW,IAAI,IAAI,QAAQ,WAAW,IAAI,EAAE;EACvD,MAAM,SAASC,oBAAkB,MAAM;AACvC,MAAI,WAAW,QAAW;GACzB,MAAM,eAAe,QAAQ;GAC7B,MAAM,YAAY,KAAK,QAAQ,SAAS,MAAM,SAAS;AAEvD,UAAO,QAAQ,iBAAiB,eAC7B,sBAAsB,MAAM,GAC5B,KAAK,UAAU,UAAU;;;CAI9B,MAAM,UAAU,sBAAsB,MAAM;AAC5C,KAAI,CAAC,QAAQ,SAAS,gBAAgB,CAAE,QAAO;AAC/C,QAAO,qBAAqB,SAAS,MAAM,SAAS,MAAM,QAAQ,QAAQ,eAAe,KAAK;;AAG/F,SAAS,cAAc,SAAgC;AACtD,KAAI,CAAC,QAAQ,SAAS,IAAI,CAAE,QAAO;AACnC,KAAI;AACH,SAAO,mBAAmB,QAAQ;SAC3B;AACP,SAAO;;;;;;;;AAST,SAAS,UAAU,OAAe,SAA4C;CAC7E,IAAI,QAAQ;AACZ,SAAQ,UAAU;AACjB,MAAI,SAAS,MAAO,QAAO;AAC3B,UAAQ,YAAY;EACpB,MAAM,QAAQ,QAAQ,KAAK,MAAM;AACjC,UAAQ,QAAQ,MAAM,QAAQ,MAAM;AACpC,SAAO;;;;;;;;AAST,SAAS,YAAY,OAAe,MAAc,IAAoB;CACrE,MAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,cAAc;CAChD,MAAM,MAAM,MAAiC,UAC5C,SAAS,SAAS,KAAK,MAAM,WAAW,MAAM,CAAC;CAChD,IAAI,MAAM;CACV,IAAI,SAAS;AACb,QAAO,GAAG,SAAS,SAAS,EAAE,CAAE;AAChC,KAAI,SAAS,OAAO,MAAM,SAAS,OAAO,OAAO,SAAS,KAAK,MAAO,OAAM,SAAS;CACrF,IAAI,OAAO;AACX,QAAO,GAAG,YAAY,OAAO,EAAE,CAAE;AACjC,KAAI,SAAS,OAAO,OAAO,IAAI,SAAS,MAAM,OAAO,OAAO,OAAO,MAAM,OAAO,OAAO,IACtF,QAAO;CAER,MAAM,UAAU,OAAO;AACvB,KAAI,UAAU,IAAI,SAAS,MAAM,UAAU,OAAO,IAAK,QAAO;CAC9D,IAAI,SAAS,UAAU;AACvB,QAAO,GAAG,cAAc,SAAS,EAAE,CAAE;AACrC,MAAK,IAAI,QAAQ,QAAQ,QAAQ,UAAU,GAAG,QAC7C,KAAI,SAAS,MAAM,WAAW,MAAM,CAAC,CAAE,QAAO;AAE/C,QAAO;;;;;;;;;;;;AAaR,SAAS,qBACR,OACA,MACA,SACA,MACA,YACS;CACT,MAAM,eAAe,aAAa,KAAK,GAAG;CAC1C,MAAM,UAAU,UAAU,OAAO,iBAAiB;CAClD,MAAM,UAAU,UAAU,OAAO,iBAAiB;CAClD,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,KAAK,MAAM,QAAQ,gBAAgB;AACvC,QAAO,OAAO,IAAI;EACjB,MAAM,QAAQ,KAAK;EAEnB,MAAM,QAAQ,iBADI,MAAM,MAAM,OAAO,KAAK,IAAI,QAAQ,MAAM,EAAE,QAAQ,aAAa,CAAC,EAC1C,KAAK;EAC/C,MAAM,cAAc,QAAQ,kBAAkB,MAAM,KAAK,MAAM,SAAS,KAAK,GAAG;AAEhF,MAAI,SAAS,gBAAgB,MAAM;GAClC,MAAM,SAAS,aAAa,YAAY,OAAO,QAAQ,GAAG,GAAG;AAC7D,OAAI,WAAW,GAAI,SAAQ;AAC3B,aAAU,MAAM,MAAM,QAAQ,WAAW,KAAK,KAAK,OAAO;AAC1D,aAAU,kBAAkB;AAC5B,YAAS,QAAQ,MAAM;SACjB;AACN,aAAU,MAAM,MAAM,QAAQ,MAAM;AACpC,YAAS;;AAEV,MAAI,CAAC,SAAS,QAAQ,SAAS,SAAS,uBAAuB;GAC9D,MAAM,MAAM,KAAK,IAAI,QAAQ,MAAM,EAAE,QAAQ,MAAM,EAAE,QAAQ,qBAAqB;GAClF,MAAM,UAAU,MAAM,MAAM,OAAO,IAAI;GACvC,MAAM,UAAU,cAAc,QAAQ;AACtC,OACC,QAAQ,SAAS,KACjB,CAAC,KAAK,SAAS,IAAI,QAAQ,IAC3B,EAAE,YAAY,QAAQ,KAAK,SAAS,IAAI,QAAQ,EAEhD,QAAO,QAAQ,UAAU;IAAE,MAAM;IAAuB;IAAM,OAAO;IAAS,CAAC;;AAGjF,OAAK,MAAM,QAAQ,iBAAiB,KAAK,IAAI,QAAQ,MAAM,CAAC;;AAE7D,QAAO,SAAS,MAAM,MAAM,OAAO;;AAGpC,SAAS,iBACR,WACA,MACyC;CACzC,MAAM,UAAU,WAAW,KAAK;CAChC,MAAM,cAAc,qBAAqB,WAAW,KAAK;CACzD,MAAM,aACL,YAAY,SAAS,IAClB,iBAAiB,KAAK,GACtB,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,SAAS,GAAG,YAAY,CAAC,CAAC,CAAC,UAAU,GAAG,MAAM,IAAI,EAAE;AACxE,MAAK,MAAM,UAAU,YAAY;AAChC,MAAI,SAAS,UAAU,UAAU,WAAW,EAAG;AAC/C,MAAI,QAAQ,IAAI,OAAO,EAAE;GACxB,MAAM,SAAS,UAAU,MAAM,GAAG,OAAO;AACzC,OAAI,KAAK,aAAa,IAAI,OAAO,IAAI,CAAC,KAAK,SAAS,IAAI,OAAO,CAC9D,QAAO;IAAE,KAAK;IAAQ;IAAQ;;AAGhC,MAAI,YAAY,IAAI,OAAO,EAAE;GAC5B,MAAM,UAAU,cAAc,UAAU,MAAM,GAAG,OAAO,CAAC;AACzD,OAAI,YAAY,QAAQ,KAAK,aAAa,IAAI,QAAQ,IAAI,CAAC,KAAK,SAAS,IAAI,QAAQ,CACpF,QAAO;IAAE,KAAK;IAAS;IAAQ;;;AAIlC,QAAO;;AAGR,SAAS,SAAS,MAAsB;AACvC,KAAI,QAAQ,MAAM,QAAQ,GAAI,QAAO,OAAO;CAC5C,MAAM,QAAQ,OAAO;AACrB,QAAO,SAAS,MAAM,SAAS,MAAM,QAAQ,KAAK;;;;;;;;AASnD,SAAS,qBAAqB,WAAmB,MAAkC;CAClF,MAAM,UAAU,WAAW,KAAK;CAChC,MAAM,uBAAO,IAAI,KAAa;CAC9B,IAAI,QAAQ,UAAU,QAAQ,IAAI;AAClC,KAAI,UAAU,GAAI,QAAO;CACzB,MAAM,UAAU,iBAAiB,KAAK,CAAC,MAAM;CAC7C,IAAI,UAAU;CACd,IAAI,UAAU;CACd,IAAI,QAAQ;AACZ,QAAO,QAAQ,UAAU,UAAU,WAAW,SAAS;AACtD,MAAI,UAAU,WAAW,KAAK;GAC7B,MAAM,OAAO,SAAS,UAAU,WAAW,QAAQ,EAAE,CAAC;GACtD,MAAM,MAAM,SAAS,UAAU,WAAW,QAAQ,EAAE,CAAC;AACrD,OAAI,SAAS,MAAM,QAAQ,GAAI;GAC/B,MAAM,OAAO,OAAO,KAAK;AACzB,YAAS;AACT,OAAI,UAAU,GAAG;AAChB,SAAK,OAAO,SAAU,IAAM;AAC5B;AACA,QAAI,YAAY,EAAG,YAAW;cACpB,OAAO,IACjB;aACW,OAAO,SAAU,KAAM;AAClC,cAAU;AACV,YAAQ;eACG,OAAO,SAAU,KAAM;AAClC,cAAU;AACV,YAAQ;eACG,OAAO,SAAU,KAAM;AAClC,cAAU;AACV,YAAQ;SAER;SAEK;AACN,OAAI,UAAU,EAAG;AACjB;AACA;;AAED,MAAI,YAAY,KAAK,QAAQ,IAAI,QAAQ,CAAE,MAAK,IAAI,MAAM;;AAE3D,QAAO;;;AAIR,MAAM,6BAA6B;;AAGnC,MAAM,uBAAuB,gBAAgB,WAAW;AAExD,MAAM,kCAAkB,IAAI,SAA6C;AAEzE,SAAS,WAAW,MAA0C;CAC7D,IAAI,UAAU,gBAAgB,IAAI,KAAK;AACvC,KAAI,YAAY,QAAW;AAC1B,YAAU,IAAI,IAAI,MAAM,KAAK,KAAK,aAAa,MAAM,GAAG,QAAQ,IAAI,OAAO,CAAC;AAC5E,kBAAgB,IAAI,MAAM,QAAQ;;AAEnC,QAAO;;AAGR,MAAM,wCAAwB,IAAI,SAA2C;;AAG7E,SAAS,iBAAiB,MAAwC;CACjE,IAAI,SAAS,sBAAsB,IAAI,KAAK;AAC5C,KAAI,WAAW,QAAW;AACzB,WAAS,CAAC,GAAG,WAAW,KAAK,CAAC,CAAC,UAAU,GAAG,MAAM,IAAI,EAAE;AACxD,wBAAsB,IAAI,MAAM,OAAO;;AAExC,QAAO;;AAGR,SAAS,aAAa,MAA6B;AAClD,QAAO,iBAAiB,KAAK,CAAC,MAAM;;AAGrC,SAASA,oBAAkB,OAAwB;AAClD,KAAI,iBAAiB,OAAO,gBAAgB,UAAU,GAAG,gBAAgB,UACxE;AAED,KAAI;EACH,MAAM,SAAkB,KAAK,MAAM,MAAM;AACzC,SAAO,OAAO,WAAW,YAAY,WAAW,OAAO,SAAS;SACzD;AACP;;;AAIF,MAAM,wBAAwB,GAAG,kBAAkB;;;;;;;AAQnD,SAAgB,0BAA0B,OAAuB;CAChE,IAAI,SAAS;CACb,IAAI,SAAS;CACb,IAAI,KAAK,MAAM,QAAQ,sBAAsB;AAC7C,QAAO,OAAO,IAAI;EACjB,MAAM,OAAO,KAAK,sBAAsB;AACxC,MAAI,oBAAoB,MAAM,WAAW,KAAK,CAAC,EAAE;GAChD,MAAM,SAAS,YAAY,OAAO,QAAQ,GAAG;AAC7C,OAAI,WAAW,IAAI;AAClB,cAAU,MAAM,MAAM,QAAQ,OAAO;AACrC,aAAS;;;AAGX,OAAK,MAAM,QAAQ,uBAAuB,KAAK;;AAEhD,QAAO,WAAW,IAAI,QAAQ,SAAS,MAAM,MAAM,OAAO;;AAG3D,SAAS,oBACR,OACA,cACA,SACA,MACS;AACT,KAAI,CAAC,MAAM,SAAS,yBAAyB,CAAE,QAAO;AACtD,QAAO,0BAA0B,MAAM,CAAC,QACvC,oBACC,OAAO,QAA4B,YAAgC;AACnE,MAAI,WAAW,OAAW,QAAO;AACjC,MAAI,YAAY,OAAW,QAAO;EAClC,MAAM,MAAM,aAAa,IAAI,QAAQ;AACrC,MAAI,QAAQ,QAAW;AACtB,UAAO,QAAQ,QAAQ;IAAE,MAAM;IAA0B;IAAM,OAAO;IAAS,CAAC;AAChF,UAAO;;AAER,UAAQ,SAAS,IAAI,QAAQ;AAC7B,SAAO;GAER;;;;;;AAOF,SAAgB,cAAc,MAAkC;CAC/D,MAAM,yBAAS,IAAI,KAAa;AAChC,MAAK,MAAM,OAAO,KAAK,aAAa,MAAM,CACzC,KAAI,CAAC,KAAK,SAAS,IAAI,IAAI,CAAE,QAAO,IAAI,IAAI;AAE7C,QAAO;;;;;;;;AASR,SAAgB,YAAY,MAAc,MAAqC;AAC9E,KAAI,KAAK,SAAS,KAAK,KAAK,WAAW,EAAG,QAAO,EAAE;CACnD,MAAM,wBAAQ,IAAI,KAAa;CAC/B,MAAM,0BAAU,IAAI,KAAa;CACjC,MAAM,YAAsB,EAAE;AAC9B,MAAK,MAAM,OAAO,KACjB,KAAI,kBAAkB,KAAK,IAAI,CAAE,SAAQ,IAAI,IAAI,OAAO;UAC/C,IAAI,SAAS,EAAG,WAAU,KAAK,IAAI;CAE7C,MAAM,gBAAgB,CAAC,GAAG,QAAQ,CAAC,UAAU,GAAG,MAAM,IAAI,EAAE;CAC5D,MAAM,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,MAAM,kBAAkB,KAAK,CAAC,GAAG,CAAC,KAAK;AAC3E,MAAK,MAAM,iBAAiB,OAAO;AAClC,OAAK,MAAM,SAAS,cAAc,SAAS,kBAAkB,EAAE;GAC9D,MAAM,QAAQ,MAAM;AACpB,QAAK,MAAM,UAAU,eAAe;AACnC,QAAI,SAAS,MAAM,OAAQ;AAC3B,SAAK,IAAI,QAAQ,GAAG,QAAQ,UAAU,MAAM,QAAQ,SAAS;KAC5D,MAAM,YAAY,MAAM,MAAM,OAAO,QAAQ,OAAO;AACpD,SAAI,KAAK,IAAI,UAAU,CAAE,OAAM,IAAI,UAAU;;;;AAIhD,OAAK,MAAM,OAAO,UACjB,KAAI,SAAS,IAAI,CAAC,MAAM,SAAS,cAAc,SAAS,KAAK,CAAC,CAAE,OAAM,IAAI,IAAI;;AAGhF,QAAO,CAAC,GAAG,MAAM,CAAC,SAAS,WAAW;;AAGvC,SAAS,SAAS,KAAuB;CACxC,MAAM,UAAU,mBAAmB,IAAI;AACvC,QAAO,CACN,GAAG,IAAI,IAAI;EACV;EACA,KAAK,UAAU,IAAI,CAAC,MAAM,GAAG,GAAG;EAChC;EACA,QAAQ,QAAQ,iBAAiB,WAAW,OAAO,aAAa,CAAC;EACjE,UAAU,IAAI;EACd,CAAC,CACF;;;AAIF,SAAS,kBAAkB,MAAsB;AAChD,QAAO,KAAK,QAAQ,cAAc,QAAQ;AACzC,MAAI;AACH,UAAO,mBAAmB,IAAI;UACvB;AACP,UAAO;;GAEP;;;;;;;;;;ACnrBH,MAAM,sBAAsB;;AAG5B,MAAa,iBAAiB;AAE9B,MAAM,WAAW;AACjB,MAAM,WAAW;;;;;AAMjB,MAAM,kBAAuC,IAAI,IAAI;CACpD;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA,CAAC;;AAGF,MAAM,kBAAuC,IAAI,IAAI,CAAC,UAAU,SAAS,CAAC;AAW1E,SAAS,cAAc,OAAkD;AACxE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;AAG5E,SAAS,kBAAkB,OAAwB;CAClD,MAAM,UAAU,MAAM,WAAW;AACjC,KAAI,CAAC,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,WAAW,IAAI,CAAE,QAAO;AACjE,KAAI,iBAAiB,MAAM,GAAG,gBAAgB,UAAW,QAAO;AAChE,KAAI;AACH,SAAO,KAAK,MAAM,MAAM;SACjB;AACP;;;AAIF,SAAS,UAAU,OAAgB,MAAkB,UAAyB;AAC7E,KAAI,OAAO,UAAU,UAAU;AAC9B,MAAI,CAAC,UAAU;AACd,QAAK,MAAM,SAAS,MAAM,SAAS,kBAAkB,CACpD,KAAI,MAAM,OAAO,OAAW,MAAK,aAAa,IAAI,MAAM,GAAG;YAClD,MAAM,OAAO,OAAW,MAAK;GAEvC,MAAM,SAAS,kBAAkB,MAAM;AACvC,OAAI,WAAW,OAAW,WAAU,QAAQ,MAAM,KAAK;;AAExD;;AAED,KAAI,MAAM,QAAQ,MAAM,EAAE;AACzB,OAAK,MAAM,QAAQ,MAAO,WAAU,MAAM,MAAM,SAAS;AACzD;;AAED,KAAI,CAAC,cAAc,MAAM,CAAE;CAC3B,MAAM,WAAW,MAAM;AACvB,KAAI,OAAO,aAAa,YAAY,aAAa,WAAW,OAAO,MAAM,OAAO,UAAU;EACzF,MAAM,MAAM,oBAAoB,KAAK,SAAS,GAAG,WAAW;AAC5D,OAAK,UAAU,IAAI,MAAM,KAAK,UAAU,IAAI,IAAI,IAAI,KAAK,EAAE;;AAE5D,MAAK,MAAM,SAAS,OAAO,OAAO,MAAM,CAAE,WAAU,OAAO,MAAM,SAAS;;;;;;;AAQ3E,SAAgB,iBAAiB,QAAuC;CACvE,MAAM,OAAmB;EAAE,8BAAc,IAAI,KAAK;EAAE,WAAW;EAAG,2BAAW,IAAI,KAAK;EAAE;CACxF,MAAM,OAAO,mBAAmB,OAAO,KAAK;AAC5C,MAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,OAAO,CACrD,KAAI,CAAC,KAAK,IAAI,SAAS,CAAE,WAAU,OAAO,MAAM,MAAM;AAEvD,QAAO;;AAgBR,SAAS,OAAO,OAAwB;AACvC,QAAO,SAAS,YAAY,SAAS;;AAGtC,SAAS,eAAe,OAAwB;AAC/C,QAAO,KAAK,OAAO,MAAM,KAAK;;;;;;AAO/B,SAAgB,mBACf,QACA,SACmB;CACnB,MAAM,SAA2B;EAAE,QAAQ,EAAE;EAAE,eAAe;EAAG;AACjE,KAAI,YAAY,WAAY,QAAO;AACnC,MAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,OAAO,EAAE;AACvD,MAAI,OAAO,UAAU,YAAY,gBAAgB,IAAI,SAAS,CAAE;AAChE,MAAI,gBAAgB,IAAI,SAAS,EAChC;OAAI,eAAe,MAAM,CAAE,QAAO;aACxB,CAAC,OAAO,MAAM,CACxB,QAAO,OAAO,KAAK;GAClB,MAAM;GACN,SAAS;GACT;GACA,CAAC;;AAGJ,QAAO;;AAGR,SAAS,SAAS,OAAe,SAA6B;AAC7D,QAAO;EAAE,MAAM;EAA8B;EAAS,UAAU;EAAU;EAAO;;;;;;;;;;AAWlF,SAAgB,iBACf,OACA,QACA,SACmB;CACnB,MAAM,SAA2B;EAAE,QAAQ,EAAE;EAAE,eAAe;EAAG;AACjE,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,MAAM,OAAO,EAAE;EACzD,MAAM,OAAO,OAAO,IAAI,KAAK;AAC7B,MAAI,CAAC,MAAM;AACV,UAAO,OAAO,KAAK,SAAS,MAAM,qDAAqD,CAAC;AACxF;;AAED,MAAI;AACH,gBAAa,SAAS,mBAAmB,KAAK,WAAW,EAAE,MAAM;WACzD,OAAO;AACf,OAAI,CAAC,gBAAgB,MAAM,CAAE,OAAM;AACnC,UAAO,OAAO,KAAK,SAAS,MAAM,6CAA6C,CAAC;AAChF;;AAED,MAAI,YAAY,cAAc,OAAO,UAAU,SAAU;AACzD,MAAI,KAAK,eAAe,aAAa,CAAC,OAAO,MAAM,CAClD,QAAO,OAAO,KAAK;GAClB,MAAM;GACN,SAAS;GACT,UAAU;GACV,OAAO;GACP,CAAC;WACQ,KAAK,eAAe,UAAU,eAAe,MAAM,CAC7D,QAAO;;AAGT,MAAK,MAAM,CAAC,MAAM,SAAS,OAC1B,KAAI,KAAK,YAAY,KAAK,eAAe,UAAU,CAAC,OAAO,OAAO,MAAM,QAAQ,KAAK,CACpF,QAAO,OAAO,KAAK,SAAS,MAAM,8BAA8B,CAAC;AAGnE,QAAO;;;AAIR,SAAgB,aAAa,QAA+C;CAC3E,MAAM,SAAkB,QAAQ,IAAI,QAAQ,SAAS;AACrD,QAAO,OAAO,WAAW,WAAW,SAAS;;AAG9C,SAAgB,qBACf,QACA,UACqB;AACrB,KAAI,CAAC,OAAO,OAAO,QAAQ,SAAS,CAAE,QAAO;CAC7C,MAAM,QAAiB,QAAQ,IAAI,QAAQ,SAAS;AACpD,QAAO,OAAO,UAAU,WAAW,QAAQ;;;;;AC7I5C,MAAMC,UAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;AAC5C,MAAM,aAAa,EAAE,KAAK,aAAa;AACvC,MAAM,aAAa,EAAE,MAAM,EAAE,MAAM,CAAC,YAAYA,QAAM,CAAC,CAAC;AAExD,MAAa,oBAAoB;CAAC;CAAa;CAAW;CAAc;CAAO;;;;;AAO/E,MAAa,wBAAwB,EAAE,aAAa;CACnD,SAAS,EAAE,QAAQ,EAAE;CACrB,OAAO,EAAE,KAAK,kBAAkB;CAChC,cAAcA;CACd,eAAe,EAAE,QAAQ,CAAC,UAAU;CACpC,eAAe;CACf,gBAAgB;CAChB,cAAcA;CACd,cAAcA;CACd,cAAcA;CACd,kBAAkBA;CAClB,aAAaA;CACb,WAAWA;CACX,KAAKA;CACL,SAAS,EAAE,aAAa;EAAE,IAAI,EAAE,QAAQ;EAAE,OAAOA,QAAM,UAAU;EAAE,CAAC,CAAC,UAAU;CAC/E,aAAa;CACb,iBAAiB,EAAE,MAAM,WAAW;CACpC,aAAa,EAAE,MACd,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,aAAa;EAAE,IAAI,EAAE,QAAQ;EAAE,eAAe,EAAE,SAAS;EAAE,CAAC,CAAC,CAAC,CACrF;CACD,QAAQ,EAAE,MACT,EAAE,MAAM,CACP,EAAE,QAAQ,EACV,EAAE,MACD,EAAE,MAAM,CACP,EAAE,QAAQ,EACV,EAAE,aAAa;EACd,YAAY,EAAE,KAAK;GAAC;GAAQ;GAAQ;GAAW;GAAO,CAAC;EACvD,UAAU,EAAE,SAAS;EACrB,CAAC,CACF,CAAC,CACF,CACD,CAAC,CACF;CACD,YAAY,EAAE,MACb,EAAE,aAAa;EAAE,IAAI,EAAE,QAAQ;EAAE,aAAa,EAAE,QAAQ;EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU;EAAE,CAAC,CACzF;CACD,qBAAqB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAEA,QAAM,CAAC,CAAC;CAC1D,wBAAwB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CAC3E,mCAAmC,EAAE,MAAM,EAAE,QAAQ,CAAC;CACtD,UAAU,EAAE,aAAa;EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU;EAAE,SAAS,EAAE,QAAQ,CAAC,UAAU;EAAE,CAAC;CAC1F,cAAc,EAAE,MACf,EAAE,MAAM,CACP,EAAE,QAAQ,EACV,EAAE,aAAa;EACd,MAAM,EAAE,OAAwB,kBAAkB;EAClD,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,UAAU;EACvC,CAAC,CACF,CAAC,CACF;CACD,eAAeA;CACf,mBAAmB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAEA,QAAM,CAAC,CAAC;CACxD,QAAQ;CACR,CAAC;AAqEF,SAAgB,yBAA0C;AACzD,QAAO,UAAU,qBAAqB,CAAC;;AAGxC,SAAS,sBAAoC;AAC5C,QAAO;EACN,OAAO;EACP,cAAc;EACd,eAAe;EACf,+BAAe,IAAI,KAAK;EACxB,gCAAgB,IAAI,KAAK;EACzB,cAAc;EACd,cAAc;EACd,cAAc;EACd,kBAAkB;EAClB,aAAa;EACb,WAAW;EACX,KAAK;EACL,SAAS;EACT,6BAAa,IAAI,KAAK;EACtB,iCAAiB,IAAI,KAAK;EAC1B,6BAAa,IAAI,KAAK;EACtB,wBAAQ,IAAI,KAAK;EACjB,YAAY,EAAE;EACd,qCAAqB,IAAI,KAAK;EAC9B,wCAAwB,IAAI,KAAK;EACjC,mDAAmC,IAAI,KAAK;EAC5C,UAAU,EAAE;EACZ,8BAAc,IAAI,KAAK;EACvB,eAAe;EACf,mCAAmB,IAAI,KAAK;EAC5B,QAAQ,aAAa;EACrB;;AAGF,SAAS,cAAiB,KAAiD;AAC1E,QAAO,CAAC,GAAG,IAAI,SAAS,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,WAAW,GAAG,EAAE,CAAC;;AAGnE,SAAS,UAAU,OAAsC;AACxD,QAAO;EACN,SAAS;EACT,OAAO,MAAM;EACb,cAAc,MAAM;EACpB,eAAe,MAAM;EACrB,eAAe,CAAC,GAAG,MAAM,cAAc,SAAS,CAAC;EACjD,gBAAgB,CAAC,GAAG,MAAM,eAAe,SAAS,CAAC;EACnD,cAAc,MAAM;EACpB,cAAc,MAAM;EACpB,cAAc,MAAM;EACpB,kBAAkB,MAAM;EACxB,aAAa,MAAM;EACnB,WAAW,MAAM;EACjB,KAAK,MAAM;EACX,SAAS,MAAM,UACZ;GACA,IAAI,MAAM,QAAQ;GAClB,GAAI,MAAM,QAAQ,UAAU,SAAY,EAAE,GAAG,EAAE,OAAO,MAAM,QAAQ,OAAO;GAC3E,GACA;EACH,aAAa,CAAC,GAAG,MAAM,YAAY,SAAS,CAAC;EAC7C,iBAAiB,CAAC,GAAG,MAAM,gBAAgB;EAC3C,aAAa,cAAc,MAAM,YAAY;EAC7C,QAAQ,cAAc,MAAM,OAAO,CAAC,KAAK,CAAC,MAAM,YAAY,CAAC,MAAM,cAAc,OAAO,CAAC,CAAC;EAC1F,YAAY,MAAM;EAClB,qBAAqB,cAAc,MAAM,oBAAoB;EAC7D,wBAAwB,cAAc,MAAM,uBAAuB,CAAC,KAAK,CAAC,IAAI,aAAa,CAC1F,IACA,CAAC,GAAG,QAAQ,CAAC,SAAS,WAAW,CACjC,CAAC;EACF,mCAAmC,CAAC,GAAG,MAAM,kCAAkC,CAAC,SAC/E,WACA;EACD,UAAU,MAAM;EAChB,cAAc,cAAc,MAAM,aAAa;EAC/C,eAAe,MAAM;EACrB,mBAAmB,cAAc,MAAM,kBAAkB;EACzD,QAAQ,MAAM;EACd;;AAGF,SAAS,YAAY,OAAsC;AAC1D,QAAO;EACN,OAAO,MAAM;EACb,cAAc,MAAM;EACpB,eAAe,MAAM;EACrB,eAAe,IAAI,IAAI,MAAM,cAAc;EAC3C,gBAAgB,IAAI,IAAI,MAAM,eAAe;EAC7C,cAAc,MAAM;EACpB,cAAc,MAAM;EACpB,cAAc,MAAM;EACpB,kBAAkB,MAAM;EACxB,aAAa,MAAM;EACnB,WAAW,MAAM;EACjB,KAAK,MAAM;EACX,SAAS,MAAM;EACf,aAAa,IAAI,IAAI,MAAM,YAAY;EACvC,iBAAiB,IAAI,IAAI,MAAM,gBAAgB;EAC/C,aAAa,IAAI,IAAI,MAAM,YAAY;EACvC,QAAQ,IAAI,IAAI,MAAM,OAAO,KAAK,CAAC,MAAM,YAAY,CAAC,MAAM,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;EAC9E,YAAY,MAAM;EAClB,qBAAqB,IAAI,IAAI,MAAM,oBAAoB;EACvD,wBAAwB,IAAI,IAC3B,MAAM,uBAAuB,KAAK,CAAC,IAAI,aAAa,CAAC,IAAI,IAAI,IAAI,QAAQ,CAAC,CAAC,CAC3E;EACD,mCAAmC,IAAI,IAAI,MAAM,kCAAkC;EACnF,UAAU,MAAM;EAChB,cAAc,IAAI,IAAI,MAAM,aAAa;EACzC,eAAe,MAAM;EACrB,mBAAmB,IAAI,IAAI,MAAM,kBAAkB;EACnD,QAAQ,MAAM;EACd;;AAGF,SAAgB,qBAAqB,OAAiC;CACrE,MAAM,SAAS,sBAAsB,UAAU,MAAM;AACrD,KAAI,CAAC,OAAO,QACX,OAAM,IAAI,cAAc,0BAA0B,8BAA8B;AAEjF,QAAO,OAAO;;;;;;;AAmBf,eAAsB,0BACrB,OACgC;AAChC,QAAO,kBAAkB,OAAO,EAAE,CAAC;;AAqBpC,eAAsB,kBACrB,OACA,SACgC;CAChC,MAAM,QAAQ,YACb,MAAM,UAAU,QAAQ,MAAM,UAAU,SACrC,wBAAwB,GACxB,qBAAqB,MAAM,MAAM,CACpC;CAED,IAAI,WAAuC;AAC3C,KAAI,MAAM,UAAU,OACnB,KAAI;AACH,aAAW,MAAM,MAAM,OAAO,UAAU;UAChC,OAAO;AACf,MAAI,CAAC,gBAAgB,MAAM,CAAE,OAAM;AACnC,aAAW,MAAM,QAAQ,gBAAgB,OAAO,EAAE,MAAM,iBAAiB,CAAC,CAAC;AAC3E,QAAM,QAAQ;;AAIhB,KAAI,YAAY,MAAM,UAAU,QAAQ;EACvC,MAAM,UAAmB;GACxB,IAAI,MAAM;GACV,QAAQ,MAAM;GACd,aAAa,MAAM;GACnB;GACA;GACA,aAAa,IAAI,6BAA6B,MAAM,GAAG;GACvD,OAAO,IAAI,+BAA+B,MAAM,IAAI,MAAM,YAAY;GACtE,QAAQ,QAAQ;GAChB;AACD,SAAO,QAAQ,MAAM,UAAU,QAAQ;GACtC,MAAM,QAAQ,MAAM,cAAc,QAAQ;AAC1C,OAAI,CAAC,MAAM,OAAO,SAAS;IAAE;IAAO,SAAS,YAAY,QAAQ,MAAM,MAAM;IAAE,CAAC,CAAE;AAClF,SAAM,OAAO,MAAM,MAAM;AACzB,SAAMC,UAAQ,QAAQ;;;CAIxB,MAAM,aAAa,UAAU,MAAM;AACnC,QAAO;EACN,MAAM,MAAM,UAAU;EACtB,OAAO;EACP,UAAU,CAAC,GAAG,MAAM,OAAO,SAAS;EACpC,UAAU,cAAc,MAAM,OAAO;EACrC;;AAKF,SAAS,OAAO,OAAuC;AACtD,QAAO,aAAa;;;AAIrB,SAAS,iBAAiB,UAA+B,MAAsB;AAC9E,MAAK,IAAI,QAAQ,MAAM,QAAQ,aAAa,QAAQ,SAAS;EAC5D,MAAM,OAAO,OAAO,MAAM;AAC1B,MAAI,QAAQ,SAAS,QAAQ,MAAO,QAAO;;AAE5C,QAAO;;;;;;;AAQR,SAAS,YAAY,OAAgC;AACpD,SAAQ,OAAR;EACC,KAAK,UACJ,QACC,KAAK,KAAK,gBAAgB,eAAe,cAAc,EAAE,CAAC,GAC1D,IAAI,KAAK,KAAK,gBAAgB,eAAe,eAAe,GAC5D,uBACA;EAEF,KAAK,aACJ,QAAO,IAAI,KAAK,KAAK,gBAAgB,eAAe,eAAe,GAAG;EACvE,QACC,QAAO;;;AAIV,eAAe,cAAc,SAAmC;CAC/D,MAAM,EAAE,OAAO,aAAa;AAC5B,KAAI,MAAM,UAAU,YACnB,QAAO,SAAS,MAAM,MAAM,eAAe,SAAS;AAErD,KAAI,MAAM,UAAU,aAAa,MAAM,UAAU,cAAc;EAC9D,MAAM,OAAO,OAAO,MAAM,UAAU;AACpC,MAAI,CAAC,KAAM,QAAO;AAKlB,UAJa,MAAM,QAAQ,YAAY,IACtC,QAAQ,aACR,gBAAgB,MAAM,MAAM,IAAI,CAChC,GACY,SAAS;;AAEvB,QAAO;;AAGR,eAAeA,UAAQ,SAAiC;CACvD,MAAM,EAAE,OAAO,aAAa;AAC5B,SAAQ,MAAM,OAAd;EACC,KAAK;AACJ,OAAI,MAAM,eAAe,SAAS,MAAM,OAAQ,OAAM,eAAe,QAAQ;QACxE;AACJ,UAAM,gBAAgB,QAAQ;AAC9B,cAAU,SAAS,UAAU;;AAE9B;EACD,KAAK;EACL,KAAK,cAAc;GAClB,MAAM,OAAO,OAAO,MAAM,UAAU;AACpC,OAAI,CAAC,MAAM;AACV,UAAM,QAAQ,MAAM,UAAU,YAAY,eAAe;AACzD,QAAI,MAAM,UAAU,aAAc,WAAU,SAAS,aAAa;AAClE;;AAED,OAAI,MAAM,UAAU,UAAW,OAAM,aAAa,SAAS,KAAK;OAC3D,OAAM,gBAAgB,SAAS,KAAK;AACzC,gBAAa,SAAS,KAAK;AAC3B;;EAED,KAAK,OACJ;;;AAIH,SAAS,UAAU,SAAkB,OAAuC;CAC3E,MAAM,EAAE,OAAO,aAAa;CAC5B,MAAM,QAAQ,iBAAiB,UAAU,EAAE;AAC3C,OAAM,QAAQ,UAAU,KAAM,UAAU,YAAY,eAAe,SAAU;AAC7E,OAAM,YAAY,UAAU,KAAK,aAAa,SAAS;AACvD,OAAM,MAAM;AACZ,OAAM,UAAU;AAChB,KAAI,UAAU,MAAM,UAAU,UAAW,WAAU,SAAS,aAAa;;AAG1E,SAAS,aAAa,SAAkB,MAAwB;CAC/D,MAAM,EAAE,OAAO,aAAa;AAC5B,OAAM;AACN,KAAI,MAAM,OAAO,SAAS,QAAQ,OAAO,UAAU,GAAI;AACvD,KAAI,MAAM,UAAU,UAAW,mBAAkB,SAAS,KAAK;CAC/D,MAAM,OAAO,iBAAiB,UAAU,MAAM,YAAY,EAAE;AAC5D,OAAM,YAAY,SAAS,KAAK,aAAa,SAAS;AACtD,OAAM,MAAM;AACZ,OAAM,UAAU;AAChB,KAAI,SAAS,GACZ,KAAI,MAAM,UAAU,UAAW,WAAU,SAAS,aAAa;KAC1D,OAAM,QAAQ;;AAMrB,SAAS,UAAa,KAAqB,KAAQ,KAAK,GAAS;AAChE,KAAI,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,KAAK,GAAG;;AAGvC,eAAe,eAAe,SAAiC;CAC9D,MAAM,EAAE,OAAO,aAAa;CAC5B,MAAM,MAAM,MAAM;AAClB,OAAM;CACN,MAAM,YAAY,SAAS,MAAM,MAAM;CAEvC,IAAI;AACJ,KAAI;AACH,YAAU,MAAM,QAAQ,OAAO,WAAW,IAAI;UACtC,OAAO;AACf,MAAI,CAAC,gBAAgB,MAAM,CAAE,OAAM;AACnC,aAAW,MAAM,QAAQ,gBAAgB,OAAO,EAAE,MAAM,WAAW,CAAC,CAAC;AACrE;;AAGD,MAAK,MAAM,SAAS,SAAS;AAC5B,MAAI,MAAM,kBAAkB,QAAQ,WAAW,MAAM,eAAe,MAAM,KAAK,IAAI,EAClF,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT,QAAQ,EAAE,MAAM,MAAM,MAAM;GAC5B,CAAC;AAEH,QAAM,gBAAgB,MAAM;AAC5B,QAAM;AACN,QAAM,gBAAgB,MAAM;EAE5B,MAAM,SAAS,iBAAiB,MAAM,KAAK;AAC3C,MAAI,QAAQ,SAAS,WAAW;GAC/B,MAAM,UAAU,SAAS,QAAQ,OAAO;AACxC,OAAI,CAAC,WAAW,OAAO,OAAO,QAAQ,OACrC,YAAW,MAAM,QAAQ;IACxB,MAAM;IACN,SAAS;IACT,MAAM,OAAO;IACb,QAAQ,EAAE,MAAM,MAAM,MAAM;IAC5B,CAAC;AAEH,aAAU,MAAM,eAAe,OAAO,KAAK;AAC3C,aAAU,MAAM,gBAAgB,OAAO,MAAM,MAAM,WAAW,EAAE;AAChE,SAAM,eAAe,MAAM;aACjB,QAAQ,SAAS,SAAS;AACpC,SAAM;AACN,SAAM,oBAAoB,MAAM;AAChC,OAAI,QAAQ,UAAU,MAAM,QAAQ,QAAQ,OAAO,aAClD,YAAW,MAAM,QAAQ;IACxB,MAAM;IACN,SAAS;IACT,QAAQ;KAAE,MAAM,MAAM;KAAM,OAAO,MAAM;KAAO,OAAO,QAAQ,OAAO;KAAc;IACpF,CAAC;;;CAKL,MAAM,SAAS,MAAM,QAAQ,YAAY,QACxC,QAAQ,aACR,QAAQ,KAAK,UAAU,MAAM,KAAK,CAClC;AACD,MAAK,MAAM,SAAS,SAAS;EAC5B,MAAM,OAAO,OAAO,IAAI,MAAM,KAAK;AACnC,MAAI,CAAC,KACJ,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT,QAAQ,EAAE,MAAM,MAAM,MAAM;GAC5B,CAAC;WACQ,KAAK,UAAU,MAAM,SAAS,KAAK,WAAW,MAAM,OAC9D,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT,QAAQ,EAAE,MAAM,MAAM,MAAM;GAC5B,CAAC;WACQ,KAAK,UAAU,WACzB,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT,QAAQ,EAAE,MAAM,MAAM,MAAM;GAC5B,CAAC;;;AAKL,eAAe,wBAAwB,SAAmC;CACzE,MAAM,MAAM,MAAM,QAAQ,GACxB,WAAW,gCAAgC,CAC3C,QAAQ,OAAO,GAAG,GAAG,UAA2B,CAAC,GAAG,QAAQ,CAAC,CAC7D,MAAM,gBAAgB,KAAK,QAAQ,YAAY,CAC/C,OAAO,OAAO,GAAG,GAAG,CAAC,GAAG,QAAQ,QAAQ,YAAY,EAAE,GAAG,QAAQ,QAAQ,UAAU,CAAC,CAAC,CAAC,CACtF,yBAAyB;AAC3B,QAAO,OAAO,IAAI,MAAM;;AAGzB,eAAe,gBAAgB,SAAiC;CAC/D,MAAM,EAAE,OAAO,aAAa;AAC5B,MAAK,MAAM,QAAQ,cAAc;EAChC,MAAM,UAAU,SAAS,QAAQ;EACjC,MAAM,SAAS,MAAM,cAAc,IAAI,KAAK,IAAI;EAChD,MAAM,UAAU,MAAM,eAAe,IAAI,KAAK,IAAI;AAClD,OAAK,SAAS,UAAU,OAAO,OAC9B,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT;GACA,QAAQ;IAAE,UAAU,SAAS,UAAU;IAAG,SAAS;IAAQ;GAC3D,CAAC;YACS,SAAS,SAAS,OAAO,QACpC,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT;GACA,QAAQ;IAAE,UAAU,SAAS,SAAS;IAAG,SAAS;IAAS;GAC3D,CAAC;;AAGJ,KACC,MAAM,iBAAiB,SAAS,MAAM,SACtC,MAAM,qBAAqB,SAAS,MAAM,WAE1C,YAAW,MAAM,QAAQ;EACxB,MAAM;EACN,SAAS;EACT,CAAC;AAEH,KACC,MAAM,iBAAiB,SAAS,MAAM,SACtC,MAAM,iBAAiB,SAAS,MAAM,WAEtC,YAAW,MAAM,QAAQ;EACxB,MAAM;EACN,SAAS;EACT,CAAC;CAEH,MAAM,SAAS,MAAM,wBAAwB,QAAQ;AACrD,KAAI,SAAS,MAAM,aAClB,YAAW,MAAM,QAAQ;EACxB,MAAM;EACN,SAAS;EACT,OAAO,SAAS,MAAM;EACtB,CAAC;;;;;;;AAgBJ,eAAe,UACd,SACA,MACA,QAC0E;CAC1E,MAAM,OAAO,gBAAgB,MAAM,QAAQ,MAAM,IAAI;CACrD,MAAM,OAAO,MAAM,QAAQ,YAAY,IAAI,QAAQ,aAAa,KAAK;AACrE,KAAI,CAAC,QAAQ,KAAK,UAAU,WAAY,QAAO;CAC/C,IAAI;AACJ,KAAI;AACH,UAAQ,MAAM,kBAAkB,QAAQ,OAAO,OAAO,MAAM,KAAK;UACzD,OAAO;AACf,MAAI,CAAC,gBAAgB,MAAM,CAAE,OAAM;AACnC,MAAI,OAAQ,YAAW,QAAQ,MAAM,QAAQ,gBAAgB,OAAO,EAAE,MAAM,CAAC,CAAC;AAC9E,SAAO;;CAER,MAAM,UAAyB,EAAE;AACjC,OAAM,SAAS,MAAM,UAAU;EAC9B,MAAM,UAAU,iBAAiB,MAAM,MAAM;GAAE;GAAM,MAAM,QAAQ;GAAG,CAAC;AACvE,MAAI,QAAQ,GAAI,SAAQ,KAAK;GAAE,QAAQ,QAAQ;GAAQ,MAAM,QAAQ;GAAG,CAAC;WAChE,OAAQ,YAAW,QAAQ,MAAM,QAAQ,QAAQ,QAAQ;GACjE;AACF,QAAO;EAAE;EAAS,OAAO,MAAM;EAAQ;EAAM;;AAG9C,SAAS,UAAU,QAAmC;AACrD,QAAO,qBAAqB,QAAQ,mBAAmB,IAAI,OAAO;;AAGnE,SAAS,UAAU,QAA0C;AAC5D,KAAI,OAAO,SAAS,gBAAgB,OAAO,SAAS,aAAc,QAAO,OAAO;AAChF,KAAI,OAAO,SAAS,OAAQ,QAAO,OAAO;AAC1C,KAAI,OAAO,SAAS,qBACnB,QAAO,oBAAoB,OAAO,aAAa,OAAO,QAAQ;AAE/D,QAAO;;AAGR,SAAS,kBAAkB,MAA2C;AACrE,QAAO,OAAO,OAAO,6BAA6B,KAAK;;AAGxD,SAAS,SAAS,MAAkB,QAA+C;AAClF,KAAI,CAAC,kBAAkB,KAAK,CAAE,QAAO;AACrC,QAAO,qBAAqB,QAAQ,4BAA4B,MAAM;;AAGvE,eAAe,aAAa,SAAkB,MAAiC;CAC9E,MAAM,EAAE,OAAO,aAAa;CAC5B,MAAM,QAAQ,MAAM,UAAU,SAAS,MAAM,KAAK;AAClD,KAAI,CAAC,OAAO;AACX,QAAM,gBAAgB,IAAI,KAAK;AAC/B;;AAED,WAAU,MAAM,aAAa,MAAM,MAAM,MAAM;CAC/C,MAAM,cAAc,cAAc,KAAK,KAAK;CAE5C,MAAM,8BAAc,IAAI,KAAqB;CAC7C,IAAI,8BAAc,IAAI,KAAqB;AAC3C,KAAI,aAAa;EAChB,MAAM,0BAAU,IAAI,KAAa;AACjC,OAAK,MAAM,EAAE,YAAY,MAAM,SAAS;AACvC,WAAQ,IAAI,OAAO,GAAG;GACtB,MAAM,SAAS,SAAS,MAAM,OAAO;AACrC,OAAI,WAAW,OAAW,SAAQ,IAAI,OAAO;;AAE9C,gBAAc,MAAM,QAAQ,MAAM,OAAO,MAAM,CAAC,GAAG,QAAQ,CAAC;;CAG7D,MAAM,cAAc,IAAI,IAAI,SAAS,QAAQ,KAAK;CAClD,MAAM,UAA+B,EAAE;AACvC,MAAK,MAAM,EAAE,QAAQ,UAAU,MAAM,SAAS;EAC7C,MAAM,WAAW;GAAE,MAAM,MAAM;GAAM;GAAM;EAC3C,IAAI;AACJ,MAAI,aAAa;AAChB,WAAQ;GACR,MAAM,SAAS,SAAS,MAAM,OAAO;AACrC,OAAI,WAAW,OAAO,GACrB,YAAW,MAAM,QAAQ;IACxB,MAAM;IACN,SAAS;IACT;IACA,IAAI,OAAO;IACX,QAAQ;IACR,CAAC;YACQ,WAAW,QAAW;IAChC,MAAM,cAAc,YAAY,IAAI,OAAO,IAAI,YAAY,IAAI,OAAO;AACtE,QAAI,gBAAgB,OACnB,YAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT;KACA,IAAI,OAAO;KACX,QAAQ;KACR,CAAC;QACI,SAAQ,cAAc;;GAE9B,MAAM,SAAS,YAAY,IAAI,OAAO,GAAG;AACzC,OAAI,YAAY,IAAI,OAAO,GAAG,IAAK,WAAW,UAAa,WAAW,MACrE,YAAW,MAAM,QAAQ;IACxB,MAAM;IACN,SAAS;IACT;IACA,IAAI,OAAO;IACX,QAAQ;IACR,CAAC;AAEH,eAAY,IAAI,OAAO,IAAI,MAAM;;EAGlC,MAAM,MAAsB,UAAU,SAAY,EAAE,IAAI,OAAO,IAAI,GAAG;GAAE,IAAI,OAAO;GAAI;GAAO;AAC9F,MAAI,MAAM,WAAW,mBAAmB,MAAM,MAAM,SAAS,IAAI,IAAI,GAAG;GACvE,MAAM,YAAY,MAAM,QAAQ,OAAO,OAAO;AAC9C,cAAW,MAAM,QAAQ;IACxB,MAAM,YAAY,iBAAiB;IACnC,SAAS,YAAY,qCAAqC;IAC1D;IACA,IAAI,OAAO;IACX,QAAQ;IACR,CAAC;;AAEH,QAAM,UAAU;EAEhB,MAAM,SAAS,aAAa,OAAO;AACnC,MAAI,WAAW,UAAa,CAAC,YAAY,IAAI,OAAO,CACnD,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT;GACA,IAAI,OAAO;GACX,QAAQ;GACR,CAAC;AAGH,qBAAmB,SAAS,QAAQ,SAAS;EAE7C,MAAM,SAAS,SAAS,MAAM,OAAO;AACrC,UAAQ,KAAK;GACZ;GACA,IAAI,OAAO;GACX,SAAS,UAAU,OAAO;GAC1B,SAAS,UAAU,OAAO;GAC1B,UAAU,UAAU;GACpB,OAAO,SAAS;GAChB,CAAC;;AAEH,OAAM,QAAQ,MAAM,WAAW,QAAQ;AACvC,OAAM,gBAAgB,SAAS,MAAM,MAAM,SAAS,MAAM,KAAK;;AAGhE,eAAe,gBACd,SACA,MACA,SACA,MACgB;CAChB,MAAM,QAAQ,QAAQ,KAAK,UAAU;EACpC,SAAS,KAAK,OAAO;EACrB,MAAM,aAAa,KAAK,OAAO;EAC/B;EACA,EAAE;CACH,MAAM,aAAa,MAAM,qBAAqB,QAAQ,IAAI,QAAQ,aAAa,MAAM;AACrF,MAAK,MAAM,EAAE,YAAY,MAAM,cAAc,YAAY;AACxD,MAAI,eAAe,2BAA2B;GAC7C,MAAM,YAAY,qBAAqB,KAAK,QAAQ,gBAAgB;AACpE,OAAI,cAAc,OAAW,SAAQ,MAAM,kCAAkC,IAAI,UAAU;AAC3F;;AAED,aAAW,QAAQ,MAAM,QAAQ;GAChC,MAAM;GACN,SAAS;GACT;GACA,IAAI,KAAK,OAAO;GAChB,QAAQ;IAAE;IAAY,eAAe;IAAU;IAAM,MAAM,KAAK;IAAM;GACtE,CAAC;;;AAIJ,MAAM,iBAAsC,IAAI,IAAI,YAAY;AAChE,MAAM,wBAA8C,IAAI,IAAI,mBAAmB;AAE/E,SAAS,kBAAkB,MAAwC;AAClE,QAAO,sBAAsB,IAAI,KAAK;;;AAIvC,SAAS,cAAc,YAA+B;AACrD,KAAI,OAAO,eAAe,YAAY,eAAe,QAAQ,MAAM,QAAQ,WAAW,CACrF,QAAO,EAAE;CAEV,MAAM,UAAmB,QAAQ,IAAI,YAAY,UAAU;AAC3D,QAAO,MAAM,QAAQ,QAAQ,GAC1B,QAAQ,QAAQ,WAA6B,OAAO,WAAW,SAAS,GACxE,EAAE;;AAGN,SAAS,iBAAiB,MAAyD;AAClF,QAAO,eAAe,IAAI,KAAK;;;;;;AAOhC,MAAM,cAAc;CACnB,YAAY;CACZ,aAAa;CACb,QAAQ;CACR,cAAc;CACd,WAAW;CACX;AAED,SAAS,YAAY,OAA6B;CACjD,IAAI,QAAQ;AACZ,MAAK,MAAM,UAAU,MAAM,OAAO,QAAQ,CAAE,UAAS,OAAO;AAC5D,QAAO;;AAGR,SAAS,oBAAoB,OAAqB,MAAwB;CACzE,MAAM,UAAU;AAKhB,KAAI,CAJa,MAAM,OAAO,SAAS,MACrC,YACA,QAAQ,SAAS,oBAAoB,QAAQ,SAAS,QAAQ,QAAQ,YAAY,QACnF,CACc,YAAW,MAAM,QAAQ;EAAE,MAAM;EAAkB;EAAS;EAAM,CAAC;;AAGnF,SAAS,mBACR,SACA,QACA,UACO;CACP,MAAM,EAAE,UAAU;AAClB,SAAQ,OAAO,MAAf;EACC,KAAK;AACJ,OAAI,OAAO,OAAO,aAAa;AAC9B,eAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT,MAAM;KACN,QAAQ;KACR,CAAC;AACF;;AAED,OAAI,MAAM,WAAW,UAAU,YAAY,YAAY;AACtD,wBAAoB,OAAO,YAAY;AACvC;;AAED,SAAM,WAAW,KAAK;IACrB,IAAI,OAAO;IACX,aAAa,OAAO;IACpB,GAAI,OAAO,UAAU,SAAY,EAAE,GAAG,EAAE,OAAO,OAAO,OAAO;IAC7D,CAAC;AACF;EACD,KAAK,cAAc;GAClB,MAAM,WAAW,MAAM,YAAY,IAAI,OAAO,KAAK;AACnD,OAAI,YAAY,SAAS,OAAO,OAAO,IAAI;AAC1C,eAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT,MAAM;KACN,IAAI,OAAO;KACX,QAAQ;KACR,CAAC;AACF;;GAED,MAAM,SAAS,OAAO;GACtB,MAAM,gBACL,OAAO,WAAW,YAClB,WAAW,QACX,CAAC,MAAM,QAAQ,OAAO,IACtB,OAAO,YAAY;AACpB,OAAI,MAAM,YAAY,QAAQ,YAAY,aAAa;AACtD,wBAAoB,OAAO,aAAa;AACxC;;AAED,SAAM,YAAY,IAAI,OAAO,MAAM;IAAE,IAAI,OAAO;IAAI;IAAe,CAAC;AACpE;;EAED,KAAK,SAAS;AACb,OAAI,CAAC,iBAAiB,OAAO,KAAK,EAAE;AACnC,eAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT,MAAM;KACN,IAAI,OAAO;KACX,QAAQ;KACR,CAAC;AACF;;AAED,OAAI,qBAAqB,OAAO,UAAU,OAAO,YAAY;AAC5D,eAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT,MAAM;KACN,IAAI,OAAO;KACX,QAAQ;KACR,CAAC;AACF;;GAED,IAAI;AACJ,QAAK,MAAM,CAAC,MAAM,eAAe,MAAM,YACtC,KAAI,WAAW,OAAO,OAAO,aAAc,kBAAiB;AAE7D,OAAI,mBAAmB,OAAW;AAClC,OAAI,YAAY,MAAM,IAAI,YAAY,QAAQ;AAC7C,wBAAoB,OAAO,QAAQ;AACnC;;GAED,MAAM,SAAS,MAAM,OAAO,IAAI,eAAe,oBAAI,IAAI,KAAwB;AAC/E,OAAI,OAAO,IAAI,OAAO,KAAK,EAAE;AAC5B,eAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT,MAAM;KACN,IAAI,OAAO;KACX,QAAQ;KACR,CAAC;AACF;;AAED,UAAO,IAAI,OAAO,MAAM;IACvB,YAAY,OAAO;IACnB,UAAU,OAAO,aAAa;IAC9B,CAAC;AACF,SAAM,OAAO,IAAI,gBAAgB,OAAO;AACxC;;EAED,KAAK,gBAAgB;AACpB,OAAI,CAAC,kBAAkB,OAAO,KAAK,EAAE;AACpC,eAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT,MAAM;KACN,IAAI,OAAO;KACX,QAAQ;KACR,CAAC;AACF;;GAED,MAAM,UAAU,OAAO,SAAS,WAAW,cAAc,OAAO,WAAW,GAAG;AAC9E,OAAI,YAAY,UAAa,QAAQ,SAAS,oBAAoB;AACjE,eAAW,MAAM,QAAQ;KACxB,MAAM;KACN,SAAS;KACT,MAAM;KACN,IAAI,OAAO;KACX,QAAQ;MAAE,GAAG;MAAU,UAAU;MAAc;KAC/C,CAAC;AACF;;AAED,OAAI,MAAM,aAAa,QAAQ,YAAY,cAAc;AACxD,wBAAoB,OAAO,eAAe;AAC1C;;AAED,SAAM,aAAa,IAAI,OAAO,IAAI;IACjC,MAAM,OAAO;IACb,GAAI,YAAY,SAAY,EAAE,GAAG,EAAE,SAAS;IAC5C,CAAC;AACF;;EAED,KAAK;AACJ,OAAI,OAAO,OAAO,UAAU,UAAU;AACrC,QACC,OAAO,OAAO,gBACb,OAAO,OAAO,uBAAuB,CAAC,MAAM,SAAS,MAEtD,OAAM,SAAS,QAAQ,OAAO,MAAM,MAAM,GAAG,KAAK;AAEnD,QACC,OAAO,OAAO,kBACb,OAAO,OAAO,yBAAyB,CAAC,MAAM,SAAS,QAExD,OAAM,SAAS,UAAU,OAAO,MAAM,MAAM,GAAG,KAAK;;AAGtD;EACD,QACC;;;AAIH,SAAS,kBAAkB,SAAkB,MAAwB;CACpE,MAAM,EAAE,OAAO,aAAa;CAC5B,MAAM,WAAW,SAAS,QAAQ,OAAO,SAAS;CAClD,MAAM,OAAO,MAAM,YAAY,IAAI,KAAK,IAAI;AAC5C,KAAI,aAAa,QAAQ,CAAC,MAAM,gBAAgB,IAAI,KAAK,CACxD,YAAW,MAAM,QAAQ;EACxB,MAAM;EACN,SAAS;EACT;EACA,QAAQ;GAAE;GAAU,OAAO;GAAM;EACjC,CAAC;;AAMJ,SAAS,gBAAgB,QAA2B,UAAkB,MAAyB;AAC9F,KAAI,CAAC,OAAO,OAAO,QAAQ,SAAS,CAAE,QAAO,EAAE;CAC/C,MAAM,MAAe,QAAQ,IAAI,QAAQ,SAAS;AAClD,KAAI,KACH,QAAO,MAAM,QAAQ,IAAI,GACtB,IAAI,QAAQ,UAA2B,OAAO,UAAU,SAAS,GACjE,EAAE;AAEN,QAAO,OAAO,QAAQ,WAAW,CAAC,IAAI,GAAG,EAAE;;AAG5C,eAAe,gBAAgB,SAAkB,MAAiC;CACjF,MAAM,EAAE,UAAU;CAClB,MAAM,QAAQ,MAAM,UAAU,SAAS,MAAM,MAAM;AACnD,KAAI,CAAC,MAAO;CAEZ,MAAM,eAAe,IAAI,IAAI,MAAM,WAAW,KAAK,cAAc,UAAU,GAAG,CAAC;AAC/E,MAAK,MAAM,aAAa,gBAAgB,OAAO;EAC9C,MAAM,yBAAS,IAAI,KAA4B;AAC/C,OAAK,MAAM,QAAQ,MAAM,QACxB,MAAK,MAAM,SAAS,gBACnB,KAAK,QACL,UAAU,UACV,UAAU,SAAS,KACnB,EAAE;GACF,MAAM,OAAO,OAAO,IAAI,MAAM,IAAI,EAAE;AACpC,QAAK,KAAK,KAAK;AACf,UAAO,IAAI,OAAO,KAAK;AACvB,OAAI,UAAU,QAAQ,SAAS,YAAY,IAAI,aAAa,IAAI,MAAM,CACrE,WAAU,MAAM,qBAAqB,MAAM;;AAI9C,MAAI,OAAO,SAAS,EAAG;EACvB,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY,UAAU,SAAS,UAAU,IAAI,CAChF,GAAG,OAAO,MAAM,CAChB,CAAC;AACF,OAAK,MAAM,SAAS,QACnB,MAAK,MAAM,QAAQ,OAAO,IAAI,MAAM,IAAI,EAAE,EAAE;GAC3C,MAAM,SAAS;IAAE,UAAU,UAAU;IAAU,MAAM,MAAM;IAAM,MAAM,KAAK;IAAM;AAClF,OAAI,UAAU,KACb,YAAW,MAAM,QAAQ;IACxB,MAAM;IACN,SAAS;IACT;IACA,IAAI,KAAK,OAAO;IAChB;IACA,CAAC;OAEF,YAAW,MAAM,QAAQ;IACxB,MAAM;IACN,SAAS;IACT;IACA,IAAI,KAAK,OAAO;IAChB;IACA,CAAC;;;AAMN,OAAM,sBAAsB,SAAS,MAAM,MAAM,SAAS,MAAM,KAAK;AACrE,OAAM,qBAAqB,SAAS,MAAM,MAAM,SAAS,MAAM,KAAK;AACpE,KAAI,SAAS,QAAS,OAAM,gBAAgB,SAAS,MAAM,SAAS,MAAM,KAAK;AAE/E,MAAK,MAAM,EAAE,QAAQ,UAAU,MAAM,SAAS;AAC7C,MACC,OAAO,SAAS,YAChB,OAAO,kBAAkB,UACzB,aAAa,IAAI,OAAO,cAAc,EACrC;GACD,MAAM,UAAU,MAAM,uBAAuB,IAAI,OAAO,cAAc,oBAAI,IAAI,KAAa;AAC3F,WAAQ,IAAI,OAAO,OAAO;AAC1B,SAAM,uBAAuB,IAAI,OAAO,eAAe,QAAQ;;AAEhE,MAAI,QAAQ,OAAQ,mBAAkB,SAAS,QAAQ;GAAE,MAAM,MAAM;GAAM;GAAM,CAAC;;;;;;;;AAgBpF,MAAM,oBAAkE;CACvE,OAAO;EACN,UAAU;EACV,SAAS,CAAC,aAAa;EACvB,IAAI;EACJ,SAAS,WAAY,OAAO,SAAS,UAAU,qBAAqB,OAAO,GAAG,EAAE;EAChF;CACD,YAAY;EACX,UAAU;EACV,SAAS,CAAC,qBAAqB;EAC/B,IAAI;EACJ,SAAS,WACR,OAAO,SAAS,eAAe,CAAC,oBAAoB,OAAO,IAAI,OAAO,eAAe,CAAC,GAAG,EAAE;EAC5F;CACD;AAED,eAAe,sBACd,SACA,MACA,SACA,MACgB;CAChB,MAAM,YAAY,kBAAkB;AACpC,KAAI,CAAC,UAAW;CAChB,MAAM,yBAAS,IAAI,KAA4B;AAC/C,MAAK,MAAM,QAAQ,QAClB,MAAK,MAAM,SAAS,UAAU,OAAO,KAAK,OAAO,EAAE;EAClD,MAAM,OAAO,OAAO,IAAI,MAAM,IAAI,EAAE;AACpC,OAAK,KAAK,KAAK;AACf,SAAO,IAAI,OAAO,KAAK;;AAGzB,KAAI,OAAO,SAAS,EAAG;CACvB,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY,UAAU,SAAS,UAAU,IAAI,CAChF,GAAG,OAAO,MAAM,CAChB,CAAC;AACF,MAAK,MAAM,SAAS,QACnB,MAAK,MAAM,QAAQ,OAAO,IAAI,MAAM,IAAI,EAAE,CACzC,YAAW,QAAQ,MAAM,QAAQ;EAChC,MAAM;EACN,SAAS;EACT;EACA,IAAI,KAAK,OAAO;EAChB,QAAQ;GAAE,UAAU,UAAU;GAAU;GAAM,MAAM,KAAK;GAAM;EAC/D,CAAC;;AAKL,eAAe,qBACd,SACA,MACA,SACA,MACgB;CAChB,MAAM,EAAE,UAAU;CAClB,MAAM,oCAAoB,IAAI,KAA4B;CAC1D,MAAM,gCAAgB,IAAI,KAA4B;AACtD,MAAK,MAAM,QAAQ,SAAS;EAC3B,MAAM,OAAO,iBAAiB,KAAK,OAAO;AAC1C,MAAI,KAAK,YAAY,EACpB,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT;GACA,IAAI,KAAK,OAAO;GAChB,QAAQ;IAAE;IAAM,MAAM,KAAK;IAAM;GACjC,CAAC;AAEH,OAAK,MAAM,WAAW,KAAK,cAAc;GACxC,MAAM,OAAO,kBAAkB,IAAI,QAAQ,IAAI,EAAE;AACjD,QAAK,KAAK,KAAK;AACf,qBAAkB,IAAI,SAAS,KAAK;;AAErC,OAAK,MAAM,CAAC,UAAU,SAAS,KAAK,WAAW;GAC9C,MAAM,MACL,MAAM,kBAAkB,IAAI,SAAS,IACrC,MAAM,kBAAkB,OAAO,YAAY,YACxC,WACA;AACJ,aAAU,MAAM,mBAAmB,KAAK,KAAK;;AAE9C,MAAI,KAAK,OAAO,SAAS,UACxB,MAAK,MAAM,WAAW,gBAAgB,KAAK,OAAO,IAAI,KAAK,OAAO,MAAM,EAAE;GACzE,MAAM,OAAO,cAAc,IAAI,QAAQ,IAAI,EAAE;AAC7C,QAAK,KAAK,KAAK;AACf,iBAAc,IAAI,SAAS,KAAK;;;AAInC,KAAI,kBAAkB,OAAO,GAAG;EAC/B,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,kBAAkB,MAAM,CAAC,CAAC;AAC/F,OAAK,MAAM,WAAW,QACrB,MAAK,MAAM,QAAQ,kBAAkB,IAAI,QAAQ,IAAI,EAAE,CACtD,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT;GACA,IAAI,KAAK,OAAO;GAChB,QAAQ;IAAE;IAAM,MAAM,KAAK;IAAM;GACjC,CAAC;;AAIL,KAAI,cAAc,OAAO,GAAG;EAC3B,MAAM,UAAU,MAAM,QAAQ,MAAM,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,GAAG,cAAc,MAAM,CAAC,CAAC;AAC3F,OAAK,MAAM,WAAW,QACrB,MAAK,MAAM,QAAQ,cAAc,IAAI,QAAQ,IAAI,EAAE,CAClD,YAAW,MAAM,QAAQ;GACxB,MAAM;GACN,SAAS;GACT;GACA,IAAI,KAAK,OAAO;GAChB,CAAC;;;AAMN,eAAe,gBACd,SACA,SACA,MACgB;CAChB,MAAM,4BAAY,IAAI,KAA4B;AAClD,MAAK,MAAM,QAAQ,SAAS;AAC3B,MAAI,KAAK,OAAO,SAAS,QAAS;EAClC,MAAM,WAAW,cAAc,KAAK,OAAO,KAAK;EAChD,MAAM,OAAO,UAAU,IAAI,SAAS,IAAI,EAAE;AAC1C,OAAK,KAAK,KAAK;AACf,YAAU,IAAI,UAAU,KAAK;;AAE9B,KAAI,UAAU,SAAS,EAAG;CAC1B,MAAM,SAAS,MAAM,QAAQ,YAAY,QAAQ,QAAQ,aAAa,CAAC,GAAG,UAAU,MAAM,CAAC,CAAC;AAC5F,MAAK,MAAM,CAAC,UAAU,UAAU,WAAW;EAC1C,MAAM,OAAO,OAAO,IAAI,SAAS;AACjC,MAAI,QAAQ,KAAK,UAAU,WAAY;AACvC,OAAK,MAAM,QAAQ,MAClB,YAAW,QAAQ,MAAM,QAAQ;GAChC,MAAM;GACN,SAAS;GACT,MAAM;GACN,IAAI,KAAK,OAAO;GAChB,QAAQ;IAAE;IAAM,MAAM,KAAK;IAAM;GACjC,CAAC;;;AAKL,SAAS,kBACR,SACA,QACA,QACA,UACO;AACP,MAAK,MAAM,SAAS,OACnB,YAAW,QAAQ,MAAM,QAAQ;EAChC,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,MAAM,OAAO;EACb,IAAI,OAAO;EACX,QAAQ;GACP,GAAG;GACH,UAAU,MAAM;GAChB,GAAI,MAAM,UAAU,SAAY,EAAE,GAAG,EAAE,OAAO,MAAM,OAAO;GAC3D;EACD,CAAC;;AAIJ,SAAS,kBACR,SACA,QACA,UACO;CACP,MAAM,SAAS,QAAQ;AACvB,KAAI,CAAC,OAAQ;CACb,MAAM,UAAU,mBAAmB,QAAQ,OAAO,QAAQ;AAC1D,SAAQ,MAAM,iBAAiB,QAAQ;AACvC,mBAAkB,SAAS,QAAQ,QAAQ,QAAQ,SAAS;AAC5D,mBACC,SACA,QACA,gBAAgB,QAAQ,EAAE,cAAc,QAAQ,MAAM,cAAc,CAAC,EACrE,SACA;AACD,KAAI,OAAO,SAAS,SAAS;EAC5B,MAAM,SAAS,QAAQ,MAAM,OAAO,IAAI,OAAO,WAAW;AAC1D,MAAI,CAAC,OAAQ;EACb,MAAM,SAAS,iBAAiB,QAAQ,QAAQ,OAAO,QAAQ;AAC/D,UAAQ,MAAM,iBAAiB,OAAO;AACtC,oBAAkB,SAAS,QAAQ,OAAO,QAAQ,SAAS;;;AAsB7D,SAAgB,oBAAoB,OAA2C;CAC9E,MAAM,UAAU,YAAY,MAAM;AAClC,QAAO;EACN,aAAa,QAAQ;EACrB,YAAY,QAAQ;EACpB,qBAAqB,QAAQ;EAC7B,wBAAwB,QAAQ;EAChC,mCAAmC,QAAQ;EAC3C,UAAU,QAAQ;EAClB,iBAAiB,CAAC,GAAG,QAAQ,YAAY,MAAM,CAAC,CAAC,SAAS,WAAW;EACrE,0BAA0B,CAAC,GAAG,QAAQ,YAAY,QAAQ,CAAC,CACzD,QAAQ,eAAe,WAAW,cAAc,CAChD,KAAK,eAAe,WAAW,GAAG,CAClC,SAAS,WAAW;EACtB,eAAe,QAAQ;EACvB,mBAAmB,QAAQ;EAC3B;;;;;ACl0CF,MAAM,qBAAqB;AAC3B,MAAM,kBAAkB,KAAK,OAAO;AACpC,MAAM,iBAAiB,KAAK,OAAO;AAEnC,MAAM,oBAAoB,CAAC,aAAa,YAAY;AAoBpD,MAAM,wBAAwB,EAAE,aAAa;CAC5C,SAAS,EAAE,QAAQ,EAAE;CACrB,wBAAwB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,QAAQ,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CAC3E,mCAAmC,EAAE,MAAM,EAAE,QAAQ,CAAC;CACtD,CAAC;AAIF,SAASC,WAAS,SAAkB,WAA6C;AAChF,QAAO,IAAI,cAAc,SAAS,cAAc,UAAU,UAAU,IAAI,UAAU,cAAc,CAAC;;AAGlG,eAAe,SAAS,OAAsB,QAAyC;AACtF,QAAO,GAAG,MAAM,SAAS,mBAAmB,QAAQ,MAAM,UAAU,cAAc,OAAO,CAAC,CAAC;;AAG5F,SAAS,WAAW,OAA8B;AACjD,QAAO,GAAG,MAAM,SAAS,mBAAmB;;AAG7C,eAAe,SAAS,SAAkB,KAAa,UAAoC;AAC1F,KAAI,CAAE,MAAM,QAAQ,OAAO,IAAI,CAAG,QAAO;CACzC,MAAM,WAAW,MAAM,QAAQ,SAAS,IAAI;AAC5C,QAAO,KAAK,MAAM,IAAI,aAAa,CAAC,OAAO,MAAM,gBAAgB,SAAS,MAAM,SAAS,CAAC,CAAC;;AAG5F,eAAe,UAAU,SAAkB,KAAa,OAA+B;AACtF,OAAM,QAAQ,OAAO;EACpB;EACA,MAAM,IAAI,aAAa,CAAC,OAAO,KAAK,UAAU,MAAM,CAAC;EACrD,aAAa;EACb,CAAC;;AAGH,SAAS,UAAU,OAAwC;CAC1D,MAAM,OAAO,aAAa,MAAM;AAChC,SAAQ,MAAM,OAAd;EACC,KAAK,YACJ,QAAO;GAAE,OAAO;GAAqB,cAAc,MAAM;GAAc;EACxE,KAAK;AACJ,OAAI,KACH,QAAO;IAAE,OAAO;IAAmB,UAAU;KAAE;KAAM,KAAK,MAAM;KAAK,MAAM;KAAG;IAAE;AAEjF,UAAO;IAAE,OAAO;IAAsB,OAAO,MAAM;IAAW,OAAO;IAAM;EAC5E,KAAK,aACJ,QAAO;GACN,OAAO;GACP,OAAO,MAAM;GACb,OAAO,QAAQ,MAAM,MAAM,IAAI,gBAAgB,MAAM,MAAM,MAAM,EAAE,GAAG;GACtE;EACF,KAAK,OACJ,QAAO,EAAE,OAAO,kBAAkB;;;AAIrC,SAAS,aACR,UACA,WACA,KACoC;CACpC,IAAI,SAAS;CACb,IAAI,QAAQ;AACZ,cAAa,SAAS,MAAM,UAAU;EACrC,MAAM,SAAS,UAAU,QAAQ,OAAO,UAAU;AAClD,WAAS;AACT,MAAI,QAAQ,UAAW,WAAU;GAChC;AACF,QAAO;EAAE,QAAQ,SAAS;EAAK;EAAO;;AAGvC,SAAS,YACR,OACA,UACmB;CACnB,MAAM,cAAc,UAAU,MAAM,UAAU;CAC9C,MAAM,EAAE,QAAQ,OAAO,iBAAiB,aAAa,UAAU,MAAM,WAAW,MAAM,IAAI;CAC1F,MAAM,QAAQ,cAAc,IAAI,eAAe;AAC/C,SAAQ,MAAM,OAAd;EACC,KAAK,YACJ,QAAO;GAAE,MAAM,KAAK,IAAI,MAAM,cAAc,YAAY;GAAE;GAAO;EAClE,KAAK,UACJ,QAAO;GAAE,MAAM,cAAc;GAAQ;GAAO;EAC7C,KAAK,aACJ,QAAO;GAAE,MAAM,cAAc,eAAe;GAAQ;GAAO;EAC5D,KAAK,OACJ,QAAO;GAAE,MAAM,QAAQ;GAAG;GAAO;;;AAIpC,eAAe,oBACd,OACA,QAC2B;CAC3B,MAAM,iBAAiB,qBAAqB,UAAU,OAAO;AAC7D,KAAI,CAAC,eAAe,QAAS,QAAO,wBAAwB;CAC5D,MAAM,MAAM,MAAM,SACjB,MAAM,SACN,MAAM,SAAS,OAAO,eAAe,KAAK,EAC1C,gBACA;AACD,QAAO,QAAQ,OAAO,wBAAwB,GAAG,qBAAqB,IAAI;;AAG3E,eAAe,mBACd,QACsC;AACtC,KAAI;AACH,SAAO,MAAM,OAAO,UAAU;UACtB,OAAO;AACf,MAAI,gBAAgB,MAAM,CAAE,QAAO;AACnC,QAAM;;;AAIR,MAAM,sBAAsB,EAAE,YAAY;CACzC,WAAW;CACX,cAAc;CACd,WAAW,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,GAAG;CACpC,wBAAwB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,IAAI,IAAI;CAClD,CAAC;;;;;AAMF,eAAe,sBAAsB,OAG3B;AACT,KAAI;EACH,MAAM,QAAQ,MAAM,MAAM,UAAU,eAAe,gBAAgB,cAAc;EACjF,MAAM,MAAM,mBAAmB,IAAI,YAAY,SAAS,EAAE,OAAO,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC;EACvF,MAAM,WAAW,oBAAoB,UAAU,IAAI;AACnD,MAAI,CAAC,SAAS,QAAS,QAAO;AAC9B,SAAO;GAAE,QAAQ,MAAM,gBAAgB,IAAI;GAAE,QAAQ,SAAS;GAAM;SAC7D;AACP,SAAO;;;AAIT,eAAe,mBACd,IACgD;CAChD,MAAM,UAAU,IAAI,kBAAkB,GAAG;CACzC,MAAM,QAAQ,MAAM,QAAQ,IAAI,aAAa;CAC7C,MAAM,UAAU,MAAM,QAAQ,IAAI,eAAe;AACjD,QAAO;EACN,GAAI,OAAO,UAAU,WAAW,EAAE,OAAO,GAAG,EAAE;EAC9C,GAAI,OAAO,YAAY,WAAW,EAAE,SAAS,GAAG,EAAE;EAClD;;AAGF,SAAS,qBAAqB,MAA6C;AAC1E,QAAO;EACN,SAAS,IAAI,IAAI,KAAK,uBAAuB,KAAK,CAAC,IAAI,aAAa,CAAC,IAAI,IAAI,IAAI,QAAQ,CAAC,CAAC,CAAC;EAC5F,cAAc,IAAI,IAAI,KAAK,kCAAkC;EAC7D;;AAGF,eAAe,UACd,OACA,MACA,SACwB;AACxB,OAAM,UAAU,MAAM,SAAS,WAAW,MAAM,EAAE,QAAQ;AAC1D,OAAM,MAAM,OAAO,QAAQ,cAAc,KAAK,CAAC;AAC/C,QAAO,WAAW,KAAK;;AAGxB,eAAe,kBACd,OACA,OACA,QACA,YACyE;CACzE,MAAM,EAAE,IAAI,kBAAkB;CAC9B,MAAM,SAAS;EACd,QAAQ,MAAM,kBAAkB,GAAG;EACnC,SAAS,cAAc,GAAG;EAC1B,eAAe,cAAc;EAC7B;CACD,MAAM,WAAW,MAAM,mBAAmB,OAAO;AACjD,KAAI,CAAC,UAAU;EACd,MAAM,WAAW,MAAM,sBAAsB,MAAM;AACnD,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO;GACN,MAAM,iBAAiB;IACtB,eAAe,SAAS;IACxB,QAAQ;KACP,QAAQ,SAAS,OAAO;KACxB,WAAW,SAAS,OAAO;KAC3B,WAAW,SAAS,OAAO;KAC3B,wBAAwB,SAAS,OAAO;KACxC;IACD;IACA,UAAU,WAAW;IACrB,UAAU,WAAW;IACrB,CAAC;GACF,SAAS;IAAE,SAAS;IAAG,wBAAwB,EAAE;IAAE,mCAAmC,EAAE;IAAE;GAC1F;;CAGF,MAAM,UAAU,oBAAoB,WAAW,MAAM;CACrD,MAAM,SAAS,MAAM,oBAAoB,IAAI,QAAQ,gBAAgB;CACrE,MAAM,gBAAgB,MAAM,kBAC3B,UACA,OACA,IAAI,6BAA6B,GAAG,EACpC,MAAM,YACN;CACD,MAAM,UAA+B;EACpC,SAAS;EACT,wBAAwB,MAAM,KAC7B,QAAQ,yBACP,CAAC,IAAI,aAAiC,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC,SAAS,WAAW,CAAC,CAC9E,CAAC,UAAU,CAAC,IAAI,CAAC,OAAO,WAAW,GAAG,EAAE,CAAC;EAC1C,mCAAmC,CAAC,GAAG,QAAQ,kCAAkC,CAAC,SACjF,WACA;EACD;AAkBD,QAAO;EAAE,MAjBI,UACZ;GACC,eAAe,MAAM,OAAO,QAAQ;GACpC;GACA;GACA;GACA,oBAAoB,WAAW;GAC/B,oBAAoB,WAAW;GAC/B,gBAAgB,CAAC,GAAG,OAAO,UAAU,GAAG,aAAa,UAAU,cAAc,CAAC;GAC9E,UAAU,OAAO;GACjB;GACA,gBAAgB,eAAe,UAAU,cAAc;GACvD,aAAa,MAAM,sBAAsB,IAAI,QAAQ,WAAW;GAChE,gBAAgB,MAAM,mBAAmB,GAAG;GAC5C,EACD,qBAAqB,QAAQ,CAC7B;EACc;EAAS;;AAGzB,eAAe,iBACd,MACA,OACiG;AACjG,KAAI,MAAM,eAAe,QAAW;EACnC,MAAM,YAAY,MAAM,KAAK,QAAQ,MAAM,YAAY;AACvD,MAAI,UAAU,eAAe,MAAM,WAClC,OAAM,IAAI,cAAc,uBAAuB,oCAAoC;AAEpF,MAAI,UAAU,SAAS,YAAY,CAAC,aAAa,UAAU,MAAM,CAChE,OAAM,IAAI,cAAc,0BAA0B,0CAA0C;AAE7F,SAAO;GAAE;GAAW,YAAY,MAAM;GAAY;;CAEnD,MAAM,QAAQ,MAAM,KAAK,MAAM,MAAM,aAAa,kBAAkB;AACpE,SAAQ,MAAM,SAAd;EACC,KAAK;AACJ,OAAI,MAAM,UAAU,SAAS,UAAU;AACtC,UAAM,KAAK,QAAQ,MAAM,UAAU,IAAI,MAAM,WAAW;AACxD,UAAM,IAAI,cAAc,0BAA0B,+BAA+B;;AAElF,UAAO;IAAE,WAAW,MAAM;IAAW,YAAY,MAAM;IAAY;EACpE,KAAK,eACJ,OAAM,IAAI,cAAc,yBAAyB,0BAA0B;EAC5E,KAAK;AACJ,OAAI,MAAM,UAAU,SAAS,YAAY,MAAM,UAAU,UAAU,UAClE,QAAO,EAAE,SAAS,MAAM,WAAW;AAEpC,SAAM,IAAI,cAAc,0BAA0B,0CAA0C;;;AAI/F,SAAS,aAAa,OAAwB;AAC7C,QAAQ,kBAAwC,SAAS,MAAM;;;;;;;AAQhE,eAAsB,kBACrB,OACmC;CACnC,MAAM,OAAO,IAAI,4BAA4B,MAAM,GAAG;CACtD,MAAM,UAAU,MAAM,iBAAiB,MAAM,MAAM;AACnD,KAAI,aAAa,SAAS;EACzB,MAAM,OAAO,MAAM,eAAe,MAAM,SAAS,QAAQ,QAAQ;AACjE,SAAO;GACN,WAAW,QAAQ;GACnB,MAAM;GACN;GACA,YAAY,OAAO,MAAM,WAAW,KAAK,GAAG;GAC5C;;CAEF,MAAM,EAAE,WAAW,eAAe;AAElC,KAAI;AACH,MAAI,UAAU,sBAAsB,KACnC,QAAO;GACN,WAAW,MAAM,KAAK,gBAAgB,UAAU,IAAI,WAAW;GAC/D,MAAM;GACN,MAAM;GACN,YAAY;GACZ;EAGF,MAAM,QAAQA,WAAS,MAAM,SAAS,UAAU;EAChD,MAAM,SAAS,IAAI,oBAAoB,MAAM;EAC7C,MAAM,kBAAkB,MAAM,oBAAoB,OAAO,UAAU,OAAO;EAC1E,MAAM,aAAa,MAAM,kBACxB;GACC,IAAI,MAAM;GACV;GACA,aAAa,UAAU;GACvB,OAAO;GACP,QAAQ,MAAM;GACd,EACD,EACC,QAAQ;GACP,SAAS,cAAc,MAAM,GAAG;GAChC,cAAc,MAAM,cAAc;GAClC,EACD,CACD;EACD,MAAM,WAAW,MAAM,mBAAmB,OAAO;EACjD,MAAM,SAAS,UAAU,WAAW,MAAM;AAE1C,MAAI,CAAC,WAAW,QAAQ,CAAC,MAAM,OAAO,UAAU,EAAE;AACjD,SAAM,UAAU,MAAM,SAAS,MAAM,SAAS,OAAO,OAAO,EAAE,WAAW,MAAM;AAO/E,UAAO;IAAE,WANO,MAAM,KAAK,QAAQ,UAAU,IAAI,YAAY;KAC5D,OAAO;KACP,OAAO,OAAO;KACd;KACA,UAAU,YAAY,WAAW,OAAO,SAAS;KACjD,CAAC;IAC2B,MAAM;IAAO,MAAM;IAAM,YAAY;IAAM;;AAEzE,QAAM,OAAO,OAAO;EAEpB,MAAM,QAAQ,MAAM,kBAAkB,OAAO,OAAO,QAAQ,WAAW;AACvE,MAAI,CAAC,OAAO;GACX,MAAM,QAAQ,WAAW,SAAS;AAClC,UAAO;IACN,WAAW,MAAM,KAAK,KAAK,UAAU,IAAI,YAAY;KACpD,MAAM;KACN,QAAQ,QAAQ,EAAE,SAAS,MAAM,MAAM,GAAG;KAC1C,CAAC;IACF,MAAM;IACN,MAAM;IACN,YAAY;IACZ;;EAEF,MAAM,SAAS,MAAM,UAAU,OAAO,MAAM,MAAM,MAAM,QAAQ;EAChE,MAAM,WAAW,YAAY,WAAW,OAAO,SAAS;EACxD,MAAM,UAAU,MAAM,KAAK,uBAAuB,UAAU,IAAI,YAAY,WAAW;GACtF,OAAO;GACP,QAAQ;GACR,YAAY;GACZ,UAAU;IAAE,MAAM,SAAS;IAAO,OAAO,SAAS;IAAO;GACzD,CAAC;AACF,MAAI,QAAQ,UAAU,YACrB,QAAO;GAAE,WAAW;GAAS,MAAM;GAAM,MAAM;GAAM,YAAY;GAAM;AAExE,SAAO;GAAE,WAAW;GAAS,MAAM;GAAM,MAAM,MAAM;GAAM,YAAY;GAAQ;UACvE,OAAO;AACf,MAAI,EAAE,gBAAgB,MAAM,IAAI,MAAM,SAAS,uBAC9C,OAAM,KAAK,QAAQ,UAAU,IAAI,WAAW,CAAC,YAAY,OAAU;AAEpE,QAAM;;;;AAKR,eAAsB,eACrB,SACA,WACiC;CACjC,MAAM,OAAO,MAAMA,WAAS,SAAS,UAAU,CAAC,QAAQ,QAAQ,eAAe;AAC/E,KAAI,SAAS,KAAM,QAAO;AAC1B,QAAO,qBAAqB,MAAM,KAAK,MAAM,KAAK,CAAC;;;;;;;;;AAkBpD,eAAsB,aACrB,OAC8D;CAC9D,MAAM,SAAS,+BAA+B,UAAU,MAAM,UAAU;AACxE,KAAI,CAAC,OAAO,QACX,OAAM,IAAI,cAAc,8BAA8B,0BAA0B;CAGjF,MAAM,OAAO,IAAI,4BAA4B,MAAM,GAAG;CACtD,MAAM,QAAQ,MAAM,KAAK,MAAM,MAAM,aAAa,CAAC,UAAU,CAAC;AAC9D,KAAI,MAAM,YAAY,eACrB,OAAM,IAAI,cAAc,yBAAyB,0BAA0B;AAE5E,KAAI,MAAM,YAAY,mBAAmB,MAAM,UAAU,SAAS,UAAU;AAC3E,MAAI,MAAM,YAAY,UAAW,OAAM,KAAK,QAAQ,MAAM,UAAU,IAAI,MAAM,WAAW;AACzF,QAAM,IAAI,cAAc,0BAA0B,+BAA+B;;AAElF,KAAI,MAAM,UAAU,UAAU,WAAW;AACxC,QAAM,KAAK,QAAQ,MAAM,UAAU,IAAI,MAAM,WAAW;AACxD,QAAM,IAAI,cACT,0BACA,gEACA;;CAEF,MAAM,EAAE,WAAW,eAAe;AAElC,KAAI;EACH,MAAM,QAAQA,WAAS,MAAM,SAAS,UAAU;EAChD,MAAM,SAAS,MAAM,eAAe,MAAM,SAAS,UAAU;EAC7D,MAAM,aAAa,MAAM,SAAS,MAAM,SAAS,WAAW,MAAM,EAAE,gBAAgB;EACpF,MAAM,UAAU,sBAAsB,UAAU,WAAW;AAC3D,MAAI,CAAC,UAAU,CAAC,QAAQ,QACvB,OAAM,IAAI,cAAc,0BAA0B,4BAA4B;EAG/E,MAAM,QAAQ,IAAI,IAAI,OAAO,WAAW,KAAK,cAAc,UAAU,GAAG,CAAC;EACzE,MAAM,YAAY,OAAO,QAAQ,OAAO,KAAK,qBAAqB,EAAE,CAAC;EACrE,MAAM,UAAU,UAAU,QAAQ,CAAC,iBAAiB,CAAC,MAAM,IAAI,YAAY,CAAC;AAC5E,MAAI,QAAQ,SAAS,EACpB,OAAM,IAAI,cAAc,8BAA8B,qCAAqC,EAC1F,QAAQ,EAAE,YAAY,QAAQ,QAAQ,EACtC,CAAC;EAEH,MAAM,eAAe,MAAM,iBAC1B,MAAM,IACN,UAAU,SAAS,GAAG,YAAa,WAAW,OAAO,EAAE,GAAG,CAAC,OAAO,CAAE,CACpE;AACD,MAAI,aAAa,SAAS,EACzB,OAAM,IAAI,cAAc,8BAA8B,gCAAgC,EACrF,QAAQ,EAAE,OAAO,aAAa,QAAQ,EACtC,CAAC;EAIH,MAAM,OAAO,eAAe,QADV,eAAe,iBAAiB,OAAO,WAAW,EAAE,OAAO,KAAK,EACnC,qBAAqB,QAAQ,KAAK,CAAC;EAClF,MAAM,SAAS,MAAM,UAAU,OAAO,MAAM,QAAQ,KAAK;AACzD,QAAM,KAAK,QAAQ,UAAU,IAAI,YAAY,EAAE,YAAY,QAAQ,CAAC;AACpE,SAAO;GAAE;GAAM,YAAY;GAAQ;UAC3B,OAAO;AACf,MAAI,EAAE,gBAAgB,MAAM,IAAI,MAAM,SAAS,uBAC9C,OAAM,KAAK,QAAQ,UAAU,IAAI,WAAW,CAAC,YAAY,OAAU;AAEpE,QAAM;;;;;;;;;;;ACxgBR,eAAsB,oBACrB,IACA,OACgB;AAChB,KAAI;AACH,QAAM,IAAI,gBAAgB,GAAG,CAAC,IAAI;GAAE,QAAQ;GAAW,GAAG;GAAO,CAAC;UAC1D,OAAO;AACf,UAAQ,MAAM,kDAAkD,MAAM;;;;;;;;;;;;;;;;;ACNxE,IAAa,qBAAb,MAAgC;CAC/B,CAASC;CACT,CAASC;CACT,CAASC;CACT,aAAa;CACb,SAAS;CAET,KAAIC,cAAuB;AAC1B,SAAO,MAAKH,eAAgB,gBAAgB;;CAG7C,YAAY,UAA6B,EAAE,EAAE;AAC5C,QAAKA,eAAgB,QAAQ,gBAAgB,gBAAgB;AAC7D,QAAKC,YAAa,QAAQ,SAAS,gBAAgB;AACnD,QAAKC,UAAW,QAAQ,WAAW,mBAAmB,EAAE;;;;;;CAOzD,SAAS,OAA4B,EAAE,EAAW;EACjD,MAAM,UAAU,KAAK,WAAW,gBAAgB;EAChD,MAAM,QAAQ,KAAK,SAAS;AAC5B,MAAI,MAAKA,WAAY,MAAKA,QAAS,UAAU,UAAU,MAAKC,YAAc,QAAO;AACjF,MAAI,MAAKC,UAAW,EAAG,QAAO;AAC9B,SAAO,UAAU,KAAK,MAAKC,YAAa,SAAS,MAAKJ;;;CAIvD,MAAM,QAAQ,GAAS;AACtB,QAAKG;AACL,QAAKC,aAAc;;CAGpB,IAAI,QAAgB;AACnB,SAAO,MAAKD;;CAGb,IAAI,YAAoB;AACvB,SAAO,MAAKC;;;CAIb,YAAwB;AACvB,SAAO;GACN,SAAS,MAAKH,UACX,KAAK,IAAI,GAAG,MAAKC,cAAe,MAAKD,QAAS,QAAQ,GACtD,OAAO;GACV,OAAO,KAAK,IAAI,GAAG,MAAKD,YAAa,MAAKI,UAAW;GACrD;;;;;;;;;;AC7DH,IAAa,8BAAb,MAAyC;CACxC,YACC,AAAiB,IACjB,AAAiB,aAChB;EAFgB;EACA;;;CAIlB,MAAM,QAAQ,SAAmD;AAChE,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,QAAQ,EAAE,cAAc,EAAE,CAAC,CACzD,OAAM,KAAK,GACT,WAAW,+BAA+B,CAC1C,OACA,MAAM,KAAK,WAAW;GACrB,cAAc,KAAK;GACnB,UAAU,MAAM;GAChB,QAAQ,MAAM;GACd,OAAO,MAAM;GACb,EAAE,CACH,CACA,YAAY,aACZ,SAAS,QAAQ,CAAC,gBAAgB,WAAW,CAAC,CAAC,YAAY;GAC1D,SAAS,OAAO,GAAG,IAAI,kBAAkB;GACzC,QAAQ,OAAO,GAAG,IAAI,iBAAiB;GACvC,CAAC,CACF,CACA,SAAS;;CAIb,MAAM,QAAQ,UAAmE;EAChF,MAAM,yBAAS,IAAI,KAA6B;AAChD,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,SAAS,CAAC,EAAE,eAAe,EAAE;GACnE,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,+BAA+B,CAC1C,OAAO;IAAC;IAAY;IAAU;IAAQ,CAAC,CACvC,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,YAAY,MAAM,MAAM,CAC9B,SAAS;AACX,QAAK,MAAM,OAAO,KACjB,QAAO,IAAI,IAAI,UAAU;IACxB,SAAS,IAAI;IACb,QAAQ,IAAI;IACZ,OAAO,OAAO,IAAI,MAAM;IACxB,CAAC;;AAGJ,SAAO;;;CAIR,MAAM,KAAK,UAA8C,EAAE,EAA6B;EACvF,IAAI,QAAQ,KAAK,GACf,WAAW,+BAA+B,CAC1C,OAAO;GAAC;GAAY;GAAU;GAAQ,CAAC,CACvC,MAAM,gBAAgB,KAAK,KAAK,YAAY;EAC9C,MAAM,QAAQ,QAAQ;AACtB,MAAI,UAAU,OACb,SAAQ,MAAM,MAAM,GAAY,GAAG,SAAS,KAAK,IAAI,WAAW,CAAC,KAAK,QAAQ;AAM/E,UAJa,MAAM,MACjB,QAAQ,SAAS,KAAK,IAAI,WAAW,CAAC,CACtC,MAAM,KAAK,IAAI,KAAK,IAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,IAAK,CAAC,CACxD,SAAS,EACC,KAAK,SAAS;GACzB,SAAS,IAAI;GACb,QAAQ,IAAI;GACZ,OAAO,OAAO,IAAI,MAAM;GACxB,EAAE;;;CAIJ,MAAM,kBACL,UAA8C,EAAE,EACI;EACpD,IAAI,QAAQ,KAAK,GACf,WAAW,+BAA+B,CAC1C,OAAO,CAAC,WAAW,OAAO,GAAG,GAAG,IAAI,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAC1D,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,QAAQ,SAAS;EACnB,MAAM,QAAQ,QAAQ;AACtB,MAAI,UAAU,OACb,SAAQ,MAAM,MAAM,GAAY,GAAG,SAAS,KAAK,IAAI,SAAS,CAAC,KAAK,QAAQ;AAM7E,UAJa,MAAM,MACjB,QAAQ,SAAS,KAAK,IAAI,SAAS,CAAC,CACpC,MAAM,KAAK,IAAI,KAAK,IAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,IAAK,CAAC,CACxD,SAAS,EACC,KAAK,SAAS;GAAE,QAAQ,IAAI;GAAQ,OAAO,OAAO,IAAI,MAAM;GAAE,EAAE;;CAG7E,MAAM,SAA2E;EAChF,MAAM,MAAM,MAAM,KAAK,GACrB,WAAW,+BAA+B,CAC1C,QAAQ,OAAO,CACf,GAAG,GAAG,UAA2B,CAAC,GAAG,aAAa,EAClD,GAAG,GAAG,MAAuB,SAAS,CAAC,UAAU,CAAC,GAAG,QAAQ,CAC7D,CAAC,CACD,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,yBAAyB;EAC3B,MAAM,QAAQ,MAAM,KAAK,GACvB,WACA,KAAK,GACH,WAAW,+BAA+B,CAC1C,OAAO,CAAC,WAAW,OAAO,GAAG,GAAG,IAAI,QAAQ,CAAC,GAAG,QAAQ,CAAC,CAAC,CAC1D,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,QAAQ,SAAS,CACjB,GAAG,OAAO,CACZ,CACA,QAAQ,OAAO,GAAG,GAAG,IAA4B,aAAa,CAAC,GAAG,QAAQ,CAAC,CAC3E,yBAAyB;AAC3B,SAAO;GACN,WAAW,OAAO,IAAI,WAAW;GACjC,OAAO,OAAO,IAAI,MAAM;GACxB,WAAW,OAAO,MAAM,SAAS,EAAE;GACnC;;;;;;;;;;;;AC9GH,eAAe,aAAa,IAAgC;CAC3D,MAAM,SAAwB,gBAAgB,KAAK,UAAU;EAC5D,OAAO,KAAK;EACZ,SAAS,OAAO,OAAO,KAAK,SAAS,aAAa,GAC/C,eACA,OAAO,OAAO,KAAK,SAAS,aAAa,GACxC,eACA;EACJ,IAAI,OAAO,OAAO,KAAK,SAAS,KAAK,GAAG,OAAO;EAC/C,EAAE;AACH,QAAO,KAAK;EAAE,OAAO;EAAS,SAAS;EAAc,IAAI;EAAM,CAAC;CAChE,MAAM,cAAc,MAAM,GACxB,WAAW,sBAAsB,CACjC,OAAO,OAAO,CACd,QAAQ,OAAO,CACf,SAAS;AACX,MAAK,MAAM,EAAE,UAAU,aAAa;AACnC,qBAAmB,MAAM,kBAAkB;AAC3C,SAAO,KAAK;GAAE,OAAO,GAAG,uBAAuB;GAAQ,SAAS;GAAc,IAAI;GAAM,CAAC;;AAE1F,QAAO,OAAO,UAAU,GAAG,MAAO,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAG;;AAGvF,SAAS,aAAa,OAAoC;AACzD,KAAI,OAAO,UAAU,SAAU,QAAO;AACtC,KAAI,OAAO,UAAU,YAAY,OAAO,UAAU,SAAU,QAAO,OAAO,MAAM;AAChF,KAAI,iBAAiB,KAAM,QAAO,MAAM,aAAa;;AAItD,eAAsB,aAAa,IAAQ,YAA0C;CACpF,MAAM,SAAsB;EAAE;EAAY,QAAQ,EAAE;EAAE;AACtD,MAAK,MAAM,SAAS,MAAM,aAAa,GAAG,EAAE;EAM3C,MAAM,UAHM,MAAM,GAAkD;2BAFpD,MAAM,UAAU,GAAG,OAAO,IAAI,IAAI,MAAM,QAAQ,CAAC,KAAK,GAAG,OAGxC,eAFtB,MAAM,KAAK,GAAG,OAAO,IAAI,IAAI,MAAM,GAAG,CAAC,KAAK,GAAG,OAEP,cAAc,IAAI,IAAI,MAAM,MAAM,CAAC;IACpF,QAAQ,GAAG,EACM,KAAK;AACxB,SAAO,OAAO,KAAK;GAClB,OAAO,MAAM;GACb,OAAO,OAAO,QAAQ,KAAK,EAAE;GAC7B,YAAY,aAAa,QAAQ,QAAQ;GACzC,OAAO,aAAa,QAAQ,GAAG;GAC/B,CAAC;;AAEH,QAAO;;AAGR,SAAgB,YAAY,GAAgB,GAAyB;AACpE,KAAI,EAAE,eAAe,EAAE,cAAc,EAAE,OAAO,WAAW,EAAE,OAAO,OAAQ,QAAO;AACjF,QAAO,EAAE,OAAO,OAAO,OAAO,UAAU;EACvC,MAAM,QAAQ,EAAE,OAAO;AACvB,SACC,UAAU,UACV,MAAM,UAAU,MAAM,SACtB,MAAM,UAAU,MAAM,SACtB,MAAM,eAAe,MAAM,cAC3B,MAAM,UAAU,MAAM;GAEtB;;;;;;;;;;;;;AC3DH,MAAM,iBAAiB;;AAUvB,eAAsB,oBACrB,IACA,OACA,OAC4B;CAC5B,IAAI,QAAQ,GACV,WAAW,QAAQ,CACnB,OAAO;EAAC;EAAM;EAAe;EAAU;EAAO,CAAC,CAC/C,OAAO,OACP,GAAG,GAAG;EACL,GAAG,UAAU,KAAK,QAAQ;EAC1B,GACC,MACA,MACA,GACE,WAAW,kBAAkB,CAC7B,OAAO,kBAAkB,CACzB,MAAM,mBAAmB,UAAU,KAAK,CACxC,SAAiB,CACnB;EACD,GACC,MACA,MACA,GACE,WAAW,mBAAmB,CAC9B,OAAO,mBAAmB,CAC1B,MAAM,oBAAoB,UAAU,KAAK,CACzC,SAAiB,CACnB;EACD,CAAC,CACF;AACF,KAAI,UAAU,KAAM,SAAQ,MAAM,MAAM,GAAY,GAAG,SAAS,IAAI,KAAK,CAAC,KAAK,QAAQ;AAEvF,SADa,MAAM,MAAM,QAAQ,SAAS,IAAI,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,SAAS,EAC/D,KAAK,SAAS;EACzB,IAAI,IAAI;EACR,YAAY,IAAI;EAChB,QAAQ,IAAI;EACZ,MAAM,IAAI,SAAS,OAAO,OAAO,OAAO,IAAI,KAAK;EACjD,EAAE;;;;;;;AAQJ,eAAsB,iBACrB,SACA,KACA,UAAiC,EAAE,EAC+B;AAClE,KAAI,CAAE,MAAM,QAAQ,OAAO,IAAI,CAAG,QAAO;CACzC,MAAM,WAAW,MAAM,QAAQ,SAAS,IAAI;CAC5C,MAAM,SAAS,MAAM,cAAc;CACnC,MAAM,SAAS,SAAS,KAAK,WAAW;CACxC,IAAI,QAAQ;AACZ,KAAI;AACH,WAAS;GACR,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,OAAI,KAAM;AACV,YAAS,MAAM;AACf,OAAI,QAAQ,aAAa,UAAa,QAAQ,QAAQ,UAAU;AAC/D,UAAM,OAAO,QAAQ,CAAC,YAAY,OAAU;AAC5C,WAAO;;AAER,UAAO,OAAO,MAAM;;WAEZ;AACT,SAAO,aAAa;;AAErB,QAAO;EAAE,QAAQ,MAAM,OAAO,QAAQ;EAAE;EAAO;;;AAIhD,eAAsB,iBAAiB,IAA4D;CAClG,MAAM,OAAkD,EAAE;CAC1D,IAAI,QAAuB;AAC3B,UAAS;EACR,IAAI,QAAQ,GAAG,WAAW,QAAQ,CAAC,OAAO,CAAC,MAAM,cAAc,CAAC;AAChE,MAAI,UAAU,KAAM,SAAQ,MAAM,MAAM,GAAY,GAAG,SAAS,IAAI,KAAK,CAAC,KAAK,QAAQ;EACvF,MAAM,OAAO,MAAM,MAAM,QAAQ,SAAS,IAAI,KAAK,CAAC,CAAC,MAAM,eAAe,CAAC,SAAS;AACpF,OAAK,MAAM,OAAO,KAAM,MAAK,KAAK;GAAE,IAAI,IAAI;GAAI,YAAY,IAAI;GAAa,CAAC;EAC9E,MAAM,OAAO,KAAK,GAAG,GAAG;AACxB,MAAI,KAAK,SAAS,kBAAkB,CAAC,KAAM;AAC3C,UAAQ,KAAK;;AAEd,QAAO;;;AAIR,eAAsB,kBAAkB,IAAgC;AACvE,QAAO,mBAAmB,MAAM,iBAAiB,GAAG,CAAC;;AAGtD,MAAM,cAAc,IAAI,OAAO,GAAG,yBAAyB,yBAAyB,IAAI;AAExF,SAAS,YACR,OACA,MACA,SACU;AACV,KAAI,OAAO,UAAU,UAAU;AAC9B,MAAI,CAAC,MAAM,SAAS,yBAAyB,CAAE,QAAO;AACtD,SAAO,MAAM,QAAQ,cAAc,OAAO,YAAoB;AAC7D,OAAI,CAAC,KAAK,IAAI,QAAQ,CAAE,QAAO;AAC/B,WAAQ;AACR,UAAO;IACN;;AAEH,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,KAAK,SAAS,YAAY,MAAM,MAAM,QAAQ,CAAC;AACtF,KAAI,OAAO,UAAU,YAAY,UAAU,KAC1C,QAAO,OAAO,YACb,OAAO,QAAQ,MAAM,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,KAAK,YAAY,MAAM,MAAM,QAAQ,CAAC,CAAC,CACnF;AAEF,QAAO;;;;;;AAOR,SAAgB,wBACf,QACA,MAC+B;AAC/B,KAAI,KAAK,SAAS,EAAG,QAAO;EAAE;EAAQ,OAAO;EAAG;CAChD,MAAM,UAAU,EAAE,OAAO,GAAG;CAC5B,MAAM,OAAO,YAAY,QAAQ,MAAM,QAAQ;AAE/C,QAAO,QAAQ,UAAU,IAAI;EAAE;EAAQ,OAAO;EAAG,GAAG;EAAE,QAAQ;EAAW,OAAO,QAAQ;EAAO;;;;;;;;;;;;;;;;;;;;;;AC9DhG,SAAS,aAAa,IAAQ,MAA+C;AAC5E,QAAO,WAAW,GAAG,GAAG,GAAW,IAAI,KAAK,iBAAiB,GAAW,GAAG;;AAG5E,SAASC,QAAM,OAAwB;AACtC,QAAO,OAAO,SAAS,EAAE;;AAG1B,SAAS,cAAc,MAAkB,IAAY,OAAe,QAA+B;AAClG,QAAO,IAAI,cAAc,yBAAyB,2CAA2C,EAC5F,QAAQ;EAAE;EAAM;EAAI;EAAO;EAAQ,EACnC,CAAC;;AAGH,SAAS,SAA+B,MAAS,KAA2B;CAC3E,MAAM,SAAS,eAAe,MAAM,IAAI;AACxC,KAAI,CAAC,OAAO,SAAS;EACpB,MAAM,QAAQ,OAAO,OAAO;AAC5B,QAAM,cACL,MACA,OAAO,IAAI,OAAO,WAAW,IAAI,KAAK,IACtC,OAAO,QAAQ,IACf,OAAO,WAAW,UAClB;;AAEF,QAAO,OAAO;;AAGf,SAAS,SAAS,OAAoC;AACrD,QAAO,OAAO,UAAU,WAAW,QAAQ;;;AAI5C,eAAe,eACd,IACA,OACA,QACuB;CACvB,MAAM,wBAAQ,IAAI,KAAa;AAE/B,MAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,EAAE,KAAK,MAAM,iBAAiB,EAAE,CAAC,EAAE;EACjF,MAAM,SAAS,MAAM,GAAqD;uCACrC,IAAI,IAAI,MAAM,CAAC;iCACrB,IAAI,KAAK,MAAM,CAAC;+CACF,IAAI,KAAK,MAAM,CAAC;IAC3D,QAAQ,GAAG;AACb,OAAK,MAAM,OAAO,OAAO,KAAM,OAAM,IAAI,IAAI,qBAAqB,IAAI,GAAG;;AAE1E,QAAO;;AAGR,eAAe,gBAAgB,IAA2B;AAEzD,SADa,MAAM,GAAG,WAAW,sBAAsB,CAAC,OAAO,OAAO,CAAC,SAAS,EACpE,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU;;AAG9C,SAASC,eAAa,MAAsB;AAC3C,oBAAmB,MAAM,kBAAkB;AAC3C,QAAO,GAAG,uBAAuB;;;;;;;AAQlC,SAAS,YAAY,MAAmC;AACvD,oBAAmB,MAAM,kBAAkB;AAC3C,QAAO,IAAI,IAAI,KAAK;;AAUrB,MAAM,QAAQ,GAAY;AAE1B,SAAS,MAAM,OAAgE;AAC9E,QAAO,MAAM,WAAW,IAAI,QAAQ,GAAY,IAAI,IAAI,KAAK,OAAO,GAAG,OAAO,CAAC;;;AAIhF,SAAS,YACR,SACA,YACA,IACsB;AACtB,QAAO,MACN,QAAQ,MAAM,KACZ,SAAS,GAAY,IAAI,WAAW,KAAK,YAAY,KAAK,CAAC;oBAC3C,IAAI,IAAIA,eAAa,KAAK,CAAC,CAAC,iCAAiC,GAAG;OAEjF,CACD;;;AAIF,SAAS,YAAY,OAAe,OAAiD;AACpF,QAAO,GAAY;kBACF,IAAI,IAAI,MAAM,CAAC;wCACO,MAAM;gEACkB,MAAM;;;;AAKtE,SAAS,iBACR,SACA,YACA,OACsB;AACtB,QAAO,MACN,QAAQ,MAAM,KACZ,SACA,GAAY,IAAI,WAAW,KAAK,YAAY,KAAK,CAAC,OAAO,YAAYA,eAAa,KAAK,EAAE,MAAM,CAAC,GACjG,CACD;;AAGF,SAAS,IAAI,OAAe,QAAqC;AAChE,QAAO,GAAG,GAAG,IAAI,IAAI,GAAG,MAAM,GAAG,SAAS;;;;;;AAO3C,SAAS,QACR,OACA,cACA,OACsB;AACtB,QAAO,GAAG;;YAEC,IAAI,OAAO,KAAK,CAAC,QAAQ,IAAI,IAAI,MAAM,CAAC;WACzC,IAAI,OAAO,aAAa,CAAC,eAAe,MAAM;;YAE7C,IAAI,OAAO,KAAK,CAAC,QAAQ,IAAI,IAAI,MAAM,CAAC;0BAC1B,IAAI,OAAO,aAAa,CAAC;WACxC,MAAM;;;;;AAMjB,SAAS,aAAa,SAA6C;AAClE,QAAO,YACN,SACA,IAAI,oBAAoB,aAAa,EACrC,IAAI,oBAAoB,aAAa,CACrC;;AAGF,SAAS,cAAc,SAA6C;AACnE,QAAO,YAAY,SAAS,IAAI,aAAa,aAAa,EAAE,IAAI,aAAa,WAAW,CAAC;;;AAI1F,eAAe,iBACd,IACA,aACA,KACuB;CACvB,MAAM,wBAAQ,IAAI,KAAa;AAC/B,MAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,EAAE,eAAe,EAAE;EAC9D,MAAM,OAAO,MAAM,GACjB,WAAW,+BAA+B,CAC1C,OAAO,WAAW,CAClB,MAAM,gBAAgB,KAAK,YAAY,CACvC,MAAM,YAAY,MAAM,MAAM,CAC9B,SAAS;AACX,OAAK,MAAM,OAAO,KAAM,OAAM,IAAI,IAAI,SAAS;;AAEhD,QAAO;;;AAwBR,SAAS,QACR,MACA,WAIY;AACZ,SAAQ,SAAS,YAAY;EAC5B,MAAM,QAAQ,QAAQ,QAAQ,WAC7B,eAAe,QAAQ,KAAK,CAC5B;AACD,MAAI,MAAM,WAAW,QAAQ,OAAQ,OAAM,IAAI,MAAM,iBAAiB,KAAK,UAAU;AACrF,SAAO,UAAU,OAAO,QAAQ;;;AAuBlC,IAAM,cAAN,MAAoD;CACnD,AAAS;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,WAAW;CACX,SAA4B,EAAE;CAE9B,YAAY,IAAQ,QAA2B,SAAwB;EACtE,MAAM,OAAO,4BAA4B,OAAO,KAAK;AACrD,MAAI,CAAC,KAAM,OAAM,IAAI,MAAM,qBAAqB,OAAO,OAAO;AAC9D,OAAK,OAAO,OAAO;AACnB,QAAKH,KAAM;AACX,QAAKC,SAAU;AACf,QAAKC,UAAW;AAChB,QAAKC,UAAW,KAAK;;CAGtB,MAAc,iBAAgC;AAC7C,MAAI,MAAKC,QAAU;AACnB,QAAM,qBAAqB,MAAKJ,IAAK,MAAKC,OAAQ,MAAM;AACxD,QAAKI,QAAS,MAAM,gBAAgB,MAAKL,GAAI;AAC7C,QAAKI,UAAW;;CAGjB,AAAQ,UAA+B;AACtC,SAAO,MAAKH,OAAQ,MAAM,MAAKD,GAAI,IAAI,GAAG,GAAG,IAAI,IAAI,GAAG,MAAKC,OAAQ,MAAM,KAAK;;CAGjF,AAAQ,aAAkC;AACzC,SAAO,IAAI,KAAK,sBAAsB,MAAKD,IAAK,MAAKG,QAAS,CAAC;;CAGhE,AAAQ,UAAU,KAAe;EAChC,MAAM,aAAa,UAAU,MAAKH,IAAK,MAAKG,SAAU,IAAI;EAC1D,MAAM,MAAW;GAAE,MAAM,KAAK;GAAM,GAAG;GAAY;AACnD,MACC,KAAK,SAAS,kBACd,KAAK,SAAS,SACd,KAAK,SAAS,wBACd,KAAK,SAAS,2BAEd,KAAI,KAAK,YAAY,iBAAiB,KAAK,MAAM,IAAI,CAAC;AAEvD,SAAO;;CAGR,MAAc,OAAO,MAAgD;EACpE,MAAM,OAAO,KAAK,KAAK,QAAQ,KAAK,UAAU,IAAI,CAAC;AACnD,QAAM,MAAKF,OAAQ,UAAU,MAAM,MAAKC,QAAS;AACjD,SAAO,KAAK,KAAK,QAAQ,SAAS,KAAK,MAAM,IAAI,CAAC;;CAGnD,MAAc,OACb,SACA,QAC2B;AAC3B,MAAI,CAAC,MAAKD,OAAQ,UAAW,QAAO,EAAE,SAAS;AAC/C,SAAO,MAAKA,OAAQ,UAAU,SAAS;GAAE,IAAI,MAAKD;GAAK,SAAS,MAAKE;GAAU;GAAQ,CAAC;;CAGzF,MAAM,KAAK,OAA8B,OAA8C;AACtF,QAAM,KAAK,gBAAgB;EAC3B,MAAM,KAAK,MAAKF;EAChB,MAAM,QAAQ,IAAI,IAAI,MAAKC,OAAQ,MAAM;EACzC,MAAM,UAAyB;GAAE;GAAI,SAAS,MAAKC;GAAU,OAAO,MAAKG;GAAQ;EACjF,MAAM,SAAS,MAAKJ,OAAQ,SAAS,QAAQ,IAAI;EACjD,MAAM,aAAyC,EAAE;AACjD,MAAI,OAAQ,YAAW,KAAK,OAAO;EAEnC,IAAI;AACJ,MAAI,MAAKA,OAAQ,cAAc;GAC9B,MAAM,SAAS,IAAI,IAAI,GAAG,MAAKA,OAAQ,MAAM,GAAG,MAAKA,OAAQ,eAAe;GAC5E,MAAM,QAAQ,IAAI,IAAI,GAAG,MAAKA,OAAQ,MAAM,KAAK;GACjD,MAAM,QAAQ,MAAKA,OAAQ,YAAY,QAAQ,IAAI,GAAY;AAC/D,OAAI,OAAO;IACV,MAAM,QAAQ,MAAM,SAAS;AAC7B,eAAW,KACV,GAAG,qBAAqB,MAAM,wBAAwB,MAAM,OAAO,aAAa,IAAI,MAAM,CAAC,KAAK,MAAM,GAAG,IACzG;;GAEF,MAAM,QAAQ,WAAW,SAAS,IAAI,GAAG,SAAS,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG;AAC1F,YAAS,MAAM,GAAQ;;cAEZ,MAAM,WAAW,MAAM,SAAS,OAAO,eAAe,MAAM;;cAE5D,MAAM,4BAA4B,MAAM;4BAC1B,OAAO;aACtB,MAAM;;aAEN,KAAK,YAAY,CAAC;WACpB,MAAM,wCAAwC,MAAM;MACzD,MAAM;+BACmB,aAAa,IAAI,MAAM,CAAC;YAC3C,QAAQ,EAAE;KACjB,QAAQ,GAAG;SACP;GACN,MAAM,MAAM,KAAK,SAAS;AAC1B,OAAI,MAAO,YAAW,KAAK,GAAG,GAAG,aAAa,IAAI,IAAI,CAAC,KAAK,MAAM,KAAK;GACvE,MAAM,QAAQ,WAAW,SAAS,IAAI,GAAG,SAAS,IAAI,KAAK,YAAY,GAAG,QAAQ,KAAK,GAAG;AAC1F,YAAS,MAAM,GAAQ;aACb,KAAK,YAAY,CAAC;WACpB,MAAM;MACX,MAAM;eACG,aAAa,IAAI,IAAI,CAAC;YACzB,QAAQ,EAAE;KACjB,QAAQ,GAAG;;EAGd,MAAM,OAAO,OAAO,KAAK,UAAU;EACnC,MAAM,OAAO,OAAO,KAAK,MAAM,GAAG,MAAM;EACxC,MAAM,UAAU,MAAM,KAAK,OAAO,KAAK;EACvC,MAAM,OAAO,KAAK,KAAK,KAAK,UAAU;GACrC,MAAM,KAAK,QAAQ,QAAQ,MAAM;AACjC,UAAO,MAAKA,OAAQ,eAAe;IAAE;IAAI,OAAOH,QAAM,IAAI,QAAQ;IAAE,GAAG,EAAE,IAAI;IAC5E;EACF,MAAM,cAAc,MAAM,KAAK,OAAO,SAAS,KAAK;AACpD,SAAO;GACN,MAAM,KAAK,KAAK,KAAK,WAAW;IAC/B;IACA,QAAQ,YAAY,QAAQ,UAAU;IACtC,aAAa,YAAY,cAAc,UAAU,EAAE;IACnD,EAAE;GACH;GACA;;CAGF,MAAM,MAAM,KAAiE;AAC5E,QAAM,KAAK,gBAAgB;EAC3B,MAAM,KAAK,MAAKE;EAChB,MAAM,yBAAS,IAAI,KAAgC;AACnD,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,EAAE,eAAe,EAAE;GAC9D,MAAM,OAAO,MAAM,GAAQ;aACjB,KAAK,YAAY,CAAC;WACpB,IAAI,IAAI,MAAKC,OAAQ,MAAM,CAAC;YAC3B,KAAK,SAAS,CAAC,OAAO,IAAI,KAAK,MAAM,CAAC;KAC7C,QAAQ,GAAG;GACb,MAAM,UAAU,MAAM,KAAK,OAAO,KAAK,KAAK;GAC5C,MAAM,cAAc,MAAM,KAAK,OAAO,SAAS,MAAM;AACrD,QAAK,MAAM,UAAU,YAAY,QAChC,KAAI,OAAQ,QAAO,IAAI,OAAO,IAAI,OAAO;;AAG3C,SAAO;;CAGR,MAAM,YAA6B;EAClC,MAAM,SAAS,MAAKA,OAAQ,eAAe,IAAI;EAC/C,MAAM,QAAQ,SAAS,GAAG,SAAS,WAAW,GAAG;AAIjD,SAAOH,SAHQ,MAAM,GAAmB;+BACX,IAAI,IAAI,MAAKG,OAAQ,MAAM,CAAC,GAAG,MAAM;IAChE,QAAQ,MAAKD,GAAI,EACC,KAAK,IAAI,EAAE;;;AAIjC,SAAS,iBAAiB,MAAkB,KAA6C;CACxF,MAAM,QAAQ,SAAiB,SAAS,IAAI,MAAM,IAAI;AACtD,SAAQ,MAAR;EACC,KAAK,eACJ,QAAO;GACN;GACA,YAAY,KAAK,aAAa;GAC9B,YAAY,KAAK,aAAa;GAC9B,WAAW,KAAK,YAAY;GAC5B;EACF,KAAK,MACJ,QAAO;GAAE;GAAM,YAAY,KAAK,aAAa;GAAE,SAAS,KAAK,UAAU;GAAE;EAC1E,KAAK,qBACJ,QAAO;GAAE;GAAM,UAAU,KAAK,WAAW;GAAE,SAAS,KAAK,UAAU;GAAE;EACtE,QACC,QAAO;GACN,MAAM;GACN,aAAa,KAAK,cAAc;GAChC,SAAS,KAAK,UAAU;GACxB;;;AAIJ,SAAS,UAAU,GAAG,OAAkD;AACvE,cACC,IAAI,KACH,MAAM,SAAS,MAAM,UACpB,UAAU,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,EAAE,IAAI,IAAI,KAAK,CAAC,CAC7D,EACD,GAAG,OACH;;AAKH,eAAe,oBACd,SACA,SACA,UAC8B;CAC9B,MAAM,cAAc,QAAQ,QAAQ;AACpC,KAAI,CAAC,eAAe,CAAC,QAAQ,OAAQ,QAAO,EAAE,SAAS;CACvD,MAAM,MAAM,QAAQ,SAAS,WAAW;EACvC,MAAM,QAAiB,QAAQ,IAAI,QAAQ,SAAS;AACpD,SAAO,OAAO,UAAU,WAAW,CAAC,MAAM,GAAG,EAAE;GAC9C;AACF,KAAI,IAAI,WAAW,EAAG,QAAO,EAAE,SAAS;CACxC,MAAM,WAAW,MAAM,iBAAiB,QAAQ,IAAI,aAAa,IAAI;CACrE,MAAM,cAAuC,EAAE;AAY/C,QAAO;EAAE,SAXI,QAAQ,KAAK,WAAW;GACpC,MAAM,QAAiB,QAAQ,IAAI,QAAQ,SAAS;AACpD,OAAI,OAAO,UAAU,YAAY,SAAS,IAAI,MAAM,EAAE;AACrD,gBAAY,KAAK,EAAE,CAAC;AACpB,WAAO;;AAER,eAAY,KAAK,CAAC;IAAE,MAAM;IAAiB,OAAO;IAAG,CAAC,CAAC;GACvD,MAAM,OAAO,EAAE,GAAG,QAAQ;AAC1B,WAAQ,eAAe,MAAM,SAAS;AACtC,UAAO;IACN;EACsB;EAAa;;AAGtC,eAAe,mBACd,SACA,SACoC;AACpC,KAAI,CAAC,QAAQ,OAAQ,QAAO,EAAE,SAAS;CACvC,MAAM,MAAM,CAAC,GAAG,IAAI,IAAI,QAAQ,SAAS,MAAO,EAAE,aAAa,SAAY,EAAE,GAAG,CAAC,EAAE,SAAS,CAAE,CAAC,CAAC;AAChG,KAAI,IAAI,WAAW,EAAG,QAAO,EAAE,SAAS;CACxC,MAAM,wBAAQ,IAAI,KAAa;AAC/B,MAAK,MAAM,SAAS,OAAO,KAAK,eAAe,EAAE;EAChD,MAAM,OAAO,MAAM,QAAQ,GACzB,WAAW,gBAAgB,CAC3B,OAAO,KAAK,CACZ,MAAM,MAAM,MAAM,MAAM,CACxB,SAAS;AACX,OAAK,MAAM,OAAO,KAAM,OAAM,IAAI,IAAI,GAAG;;CAE1C,MAAM,cAAuC,EAAE;AAU/C,QAAO;EAAE,SATI,QAAQ,KAAK,WAAW;AACpC,OAAI,OAAO,aAAa,UAAa,MAAM,IAAI,OAAO,SAAS,EAAE;AAChE,gBAAY,KAAK,EAAE,CAAC;AACpB,WAAO;;AAER,eAAY,KAAK,CAAC;IAAE,MAAM;IAA2B,OAAO;IAAG,CAAC,CAAC;GACjE,MAAM,EAAE,UAAU,UAAU,GAAG,SAAS;AACxC,UAAO;IACN;EACsB;EAAa;;AAGtC,eAAe,0BACd,SACA,SAC2C;AAC3C,KAAI,CAAC,QAAQ,OAAQ,QAAO,EAAE,SAAS;CACvC,MAAM,QAAQ,IAAI,IAAI,MAAM,gBAAgB,QAAQ,GAAG,CAAC;CACxD,MAAM,cAAuC,EAAE;AAY/C,QAAO;EAAE,SAXI,QAAQ,KAAK,WAAW;GACpC,MAAM,OAAO,OAAO,aAAa,QAAQ,SAAS,MAAM,IAAI,KAAK,CAAC;AAClE,OAAI,CAAC,OAAO,eAAe,CAAC,QAAQ,KAAK,WAAW,OAAO,YAAY,QAAQ;AAC9E,gBAAY,KAAK,EAAE,CAAC;AACpB,WAAO;;AAER,eAAY,KAAK,CAChB;IAAE,MAAM;IAAuB,OAAO,OAAO,YAAY,SAAS,KAAK;IAAQ,CAC/E,CAAC;AACF,UAAO;IAAE,GAAG;IAAQ,aAAa;IAAM;IACtC;EACsB;EAAa;;AAGtC,eAAe,YAAY,MAAa,SAAuC;CAC9E,MAAM,MAAM,KAAK,SAAS,QAAS,OAAO,IAAI,OAAO,WAAW,CAAC,IAAI,GAAG,GAAG,EAAE,CAAE;AAC/E,KAAI,IAAI,WAAW,EAAG;CACtB,MAAM,QAAQ,MAAM,QAAQ,WAAW,IAAI;AAC3C,MAAK,MAAM,OAAO,MAAM;EACvB,MAAM,OAAO,OAAO,IAAI,OAAO,WAAW,MAAM,IAAI,IAAI,GAAG,GAAG;AAC9D,MAAI,SAAS,OAAW,KAAI,OAAO;;;AAMrC,MAAM,iCACL,GAAY,GAAG,IAAI,IAAI,eAAe,CAAC,OAAO,IAAI,KAAK,uBAAuB,KAAK,SAAS,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC;AAE7G,MAAM,wBAA6C,GAAY;;;;;;;;;;;;;AAc/D,MAAM,mBAAmB,GAAG;AAE5B,SAAS,YAAY,MAAqC;CACzD,MAAM,OAAO,4BAA4B,KAAK;AAC9C,KAAI,CAAC,KAAM,OAAM,IAAI,MAAM,qBAAqB,OAAO;AACvD,QAAO;EAAE;EAAM,OAAO,KAAK;EAAO;;AAGnC,SAAS,UAAU,MAAqC;AACvD,SAAQ,MAAR;EACC,KAAK,qBACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,cACC,GAAY;GACb;EACF,KAAK,QACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,cACC,GAAY;GACb;EACF,KAAK,eACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,WAAW,QAAQ,gBAAgB,0BAA0B;GAC7D;EACF,KAAK,WACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,cAAc,GAAY;8CACgB,iBAAiB;iDACd,iBAAiB;;GAE9D;EACF,KAAK,QACJ,QAAO;GACN,GAAG,YAAY,QAAQ;GACvB,SAAS,EAAE,cACV,QAAQ,sBAAsB,SAC3B,OACA,GAAY;;8BAEU,QAAQ,kBAAkB;;GAEpD,SAAS;GACT,WAAW,QAAQ,SAAS,mBAAmB;GAC/C;EACF,KAAK,OACJ,QAAO;GAAE,GAAG,YAAY,OAAO;GAAE,cAAc;GAAa;EAC7D,KAAK,UACJ,QAAO;GAAE,GAAG,YAAY,UAAU;GAAE,cAAc;GAAa,WAAW;GAAc;EACzF,KAAK,mBACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,SAAS,YACR,GAAY,2CAA2C,QACtD,oBACA,aACA,aAAa,QAAQ,CACrB;GACF;EACF,KAAK,YACJ,QAAO;GACN,GAAG,YAAY,YAAY;GAC3B,cAAc;GACd,YAAY,YAAY;IACvB,MAAM,YAAY,IAAI,sBAAsB,eAAe;AAC3D,WAAO,GAAY;;;SAGf,UAAU;YACP,YAAY,cAAc,UAAU,CAAC;YACrC,MAAM,QAAQ,MAAM,KAAK,SAAS,YAAYD,eAAa,KAAK,EAAE,UAAU,CAAC,CAAC,CAAC;;;;GAIvF;EACF,KAAK,SACJ,QAAO;GACN,GAAG,YAAY,SAAS;GACxB,WAAW,QAAQ,WAAW,SAAS,YACtC,oBAAoB,SAAS,SAAS,gBAAgB,CACtD;GACD;EACF,KAAK,UACJ,QAAO;GACN,GAAG,YAAY,UAAU;GACzB,WAAW,QAAQ,YAAY,SAAS,YACvC,oBAAoB,SAAS,SAAS,iBAAiB,CACvD;GACD;EACF,KAAK,qBACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,KAAK,UAAU,aAAa,WAAW;GACvC,cAAc,GAAY;;;;GAI1B;EACF,KAAK,2BACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,KAAK,UAAU,qBAAqB,WAAW;GAC/C,cAAc,GAAY;OACvB,YAAY,mBAAmB,IAAI,qCAAqC,oBAAoB,CAAC,CAAC;;;GAGjG;EACF,KAAK,WACJ,QAAO;GAAE,GAAG,YAAY,KAAK;GAAE,QAAQ;GAAe;EACvD,KAAK,eACJ,QAAO;GACN,GAAG,YAAY,eAAe;GAC9B,KAAK,UAAU,cAAc,YAAY,cAAc;GACvD,SAAS,YAAY,GAAY;OAC9B,iBAAiB,SAAS,IAAI,sBAAsB,aAAa,EAAE,IAAI,sBAAsB,WAAW,CAAC,CAAC;WACtG,YAAY,cAAc,IAAI,sBAAsB,cAAc,CAAC,CAAC;;GAE3E;EACF,KAAK,iBACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,SAAS,YAAY,GAAY;OAC9B,YAAY,SAAS,IAAI,2BAA2B,kBAAkB,EAAE,IAAI,2BAA2B,aAAa,CAAC,CAAC;WAClH,YAAY,mBAAmB,IAAI,2BAA2B,YAAY,CAAC,CAAC;;GAEnF;EACF,KAAK,oBACJ,QAAO;GACN,GAAG,YAAY,oBAAoB;GACnC,SAAS,YAAY;IACpB,MAAM,aAAa;AACnB,WAAO,GAAY;;;wCAGgB,IAAI,YAAY,iBAAiB,CAAC;sEACJ,IAAI,YAAY,iBAAiB,CAAC;;YAE5F,iBAAiB,SAAS,GAAG,gCAAgC,IAAI,YAAY,eAAe,CAAC,CAAC;YAC9F,iBAAiB,SAAS,GAAG,+BAA+B,IAAI,YAAY,cAAc,CAAC,CAAC;;;GAGpG;EACF,KAAK,MACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,KAAK,UAAU,cAAc,aAAa;GAC1C,SAAS,YACR,YAAY,SAAS,IAAI,eAAe,aAAa,EAAE,IAAI,eAAe,aAAa,CAAC;GACzF;EACF,KAAK,SACJ,QAAO;GACN,GAAG,YAAY,SAAS;GACxB,cAAc,GAAY;;;;;;;GAO1B;EACF,KAAK,WACJ,QAAO;GAAE,GAAG,YAAY,KAAK;GAAE,QAAQ;GAAiB;EACzD,KAAK,UACJ,QAAO;GACN,GAAG,YAAY,KAAK;GACpB,WAAW,GAAG,GAAG,IAAI,IAAI,eAAe;GACxC,QAAQ;GACR,aAAa;GACb;EACF,QACC,QAAO,YAAY,KAAK;;;AAc3B,IAAM,cAAN,MAAiD;CAChD,AAAS,OAAO;CAChB,CAASC;CACT,UAA6D;CAC7D,CAASM,8BAAe,IAAI,KAAyC;CAErE,YAAY,IAAQ;AACnB,QAAKN,KAAM;;;CAIZ,AAAQ,SAAqD;AAC5D,QAAKO,WAAY,MAAKP,GACpB,WAAW,sBAAsB,CACjC,SAAS,kBAAkB,gCAAgC,yBAAyB,CACpF,OAAO;GACP;GACA;GACA;GACA,CAAC,CACD,SAAS,CACT,MAAM,SAAS;GACf,MAAM,yBAAS,IAAI,KAA2D;AAC9E,QAAK,MAAM,OAAO,MAAM;IACvB,MAAM,OAAO,OAAO,IAAI,IAAI,WAAW,IAAI,EAAE;AAC7C,QAAI,IAAI,SAAS,QAAQ,IAAI,gBAAgB,KAC5C,MAAK,KAAK;KAAE,MAAM,IAAI;KAAM,aAAa,IAAI;KAAa,CAAC;AAE5D,WAAO,IAAI,IAAI,YAAY,KAAK;;AAEjC,UAAO;IACN;AACH,SAAO,MAAKO;;CAGb,MAAc,QAA2B;AACxC,SAAO,CAAC,IAAI,MAAM,KAAK,QAAQ,EAAE,MAAM,CAAC,CAAC,UAAU;;;CAIpD,AAAQ,WAAW,MAA0C;EAC5D,IAAI,UAAU,MAAKD,YAAa,IAAI,KAAK;AACzC,MAAI,CAAC,SAAS;AACb,cAAW,YAAY;IACtB,MAAM,QAAQP,eAAa,KAAK;IAChC,MAAM,UAAU,MAAM,KAAK,QAAQ,EAAE,IAAI,KAAK,IAAI,EAAE;IACpD,MAAM,eAAe,MAAM,iBAAiB,MAAKC,IAAK,MAAM;IAC5D,MAAM,UAAU,mBAAmB,QAAQ,aAAa;AACxD,+BAA2B,OAAO,SAAS,aAAa;AACxD,WAAO;KAAE;KAAM;KAAO;KAAS;OAC5B;AACJ,SAAKM,YAAa,IAAI,MAAM,QAAQ;;AAErC,SAAO;;CAGR,MAAc,cAA4C;EACzD,MAAM,SAAS,EAAE;AACjB,OAAK,MAAM,QAAQ,MAAM,KAAK,OAAO,CAAE,QAAO,KAAK,MAAM,KAAK,WAAW,KAAK,CAAC;AAC/E,SAAO;;CAGR,AAAQ,OAAO,YAA+B,KAAiC;EAC9E,MAAM,EAAE,YAAY,WAAW,iBAAiB,MAAKN,IAAK,WAAW,SAAS,IAAI;AAClF,SAAO,SAAS,SAAS;GACxB,MAAM;GACN,YAAY,WAAW;GACvB,GAAG;GACH;GACA,CAAC;;CAGH,AAAQ,WAAW,YAAoD;AACtE,SAAO,IAAI,KAAK,sBAAsB,MAAKA,IAAK,WAAW,QAAQ,CAAC;;CAGrE,MAAM,KAAK,OAA8B,OAA2C;EACnF,MAAM,KAAK,MAAKA;EAChB,MAAM,SAAuC,EAAE;AAC/C,OAAK,MAAM,cAAc,MAAM,KAAK,aAAa,EAAE;GAClD,MAAM,QAAQ,IAAI,IAAI,GAAG,WAAW,MAAM,KAAK;GAC/C,MAAM,QAAQ,QAAQ,GAAG,SAAS,aAAa,IAAI,MAAM,CAAC,KAAK,MAAM,OAAO,GAAG;GAC/E,MAAM,SAAS,MAAM,GAAQ;aACnB,KAAK,WAAW,WAAW,CAAC;WAC9B,IAAI,IAAI,WAAW,MAAM,CAAC;MAC/B,MAAM;eACG,aAAa,IAAI,MAAM,CAAC;YAC3B,QAAQ,EAAE;KACjB,QAAQ,GAAG;AACb,QAAK,MAAM,OAAO,OAAO,KAAM,QAAO,KAAK,KAAK,OAAO,YAAY,IAAI,CAAC;;AAEzE,SAAO,MAAM,GAAG,MAAM,mBAAmB,SAAS,GAAG,EAAE,CAAC;EACxD,MAAM,OAAO,OAAO,MAAM,GAAG,MAAM;AAEnC,SAAO;GACN,OAFc,MAAM,KAAK,sBAAsB,KAAK,EAEvC,KAAK,EAAE,QAAQ,mBAAmB;IAC9C,KAAK,EAAE,IAAI,OAAO,IAAI;IACtB;IACA;IACA,EAAE;GACH,MAAM,OAAO,UAAU;GACvB;;;;;;CAOF,MAAc,sBACb,SACmF;EACnF,MAAM,KAAK,MAAKA;EAChB,MAAM,cAAc,CACnB,GAAG,IAAI,IACN,QAAQ,SAAS,WAChB,CAAC,OAAO,gBAAgB,OAAO,gBAAgB,CAAC,QAC9C,OAAqB,OAAO,OAC7B,CACD,CACD,CACD;EACD,MAAM,4BAAY,IAAI,KAAa;EACnC,MAAM,UAAyB;GAC9B;GACA,SAAS,EAAE,YAAY,4BAAY,IAAI,KAAK,EAAE;GAC9C,OAAO,MAAM,KAAK,OAAO;GACzB;AACD,OAAK,MAAM,SAAS,OAAO,aAAa,eAAe,EAAE;GACxD,MAAM,OAAO,MAAM,GAAmB;;mBAEtB,IAAI,KAAK,MAAM,CAAC,QAAQ,cAAc,QAAQ,CAAC;KAC7D,QAAQ,GAAG;AACb,QAAK,MAAM,OAAO,KAAK,KAAM,WAAU,IAAI,IAAI,GAAG;;EAEnD,MAAM,eAAe,MAAM,eAC1B,IACA,mBACA,QAAQ,SAAS,WAChB,OAAO,uBAAuB,SAAY,EAAE,GAAG,CAAC,OAAO,mBAAmB,CAC1E,CACD;AACD,SAAO,QAAQ,KAAK,WAAW;GAC9B,MAAM,OAAgC,EAAE,GAAG,QAAQ;GACnD,IAAI,SAAS;AACb,QAAK,MAAM,YAAY,CAAC,kBAAkB,kBAAkB,EAAW;IACtE,MAAM,KAAK,OAAO;AAClB,QAAI,OAAO,UAAa,CAAC,UAAU,IAAI,GAAG,EAAE;AAC3C,YAAO,KAAK;AACZ;;;AAGF,OAAI,OAAO,uBAAuB,UAAa,CAAC,aAAa,IAAI,OAAO,mBAAmB,EAAE;AAC5F,WAAO,KAAK;AACZ;;AAED,OAAI,WAAW,EAAG,QAAO;IAAE;IAAQ,aAAa,EAAE;IAAE;AACpD,UAAO;IACN,QAAQ,SAAS,SAAS,KAAK;IAC/B,aAAa,CAAC;KAAE,MAAM;KAA2B,OAAO;KAAQ,CAAC;IACjE;IACA;;CAGH,MAAM,MACL,KACA,aAC8C;EAC9C,MAAM,QAAQ,IAAI,IAAI,MAAM,KAAK,OAAO,CAAC;EACzC,MAAM,yBAAS,IAAI,KAAuB;EAC1C,MAAM,WAAqB,EAAE;AAC7B,OAAK,MAAM,MAAM,IAAI,IAAI,IAAI,EAAE;GAC9B,MAAM,OAAO,aAAa,IAAI,GAAG;AACjC,OAAI,SAAS,OACZ,UAAS,KAAK,GAAG;YACP,MAAM,IAAI,KAAK,EAAE;IAC3B,MAAM,OAAO,OAAO,IAAI,KAAK,IAAI,EAAE;AACnC,SAAK,KAAK,GAAG;AACb,WAAO,IAAI,MAAM,KAAK;;;AAGxB,MAAI,SAAS,SAAS,EACrB,MAAK,MAAM,QAAQ,MAAO,QAAO,IAAI,MAAM,CAAC,GAAI,OAAO,IAAI,KAAK,IAAI,EAAE,EAAG,GAAG,SAAS,CAAC;EAGvF,MAAM,yBAAS,IAAI,KAAoC;AACvD,OAAK,MAAM,CAAC,MAAM,YAAY,QAAQ;GACrC,MAAM,aAAa,MAAM,KAAK,WAAW,KAAK;AAC9C,QAAK,MAAM,SAAS,OAAO,SAAS,eAAe,EAAE;IACpD,MAAM,OAAO,MAAM,GAAQ;cACjB,KAAK,WAAW,WAAW,CAAC;YAC9B,IAAI,IAAI,WAAW,MAAM,CAAC;aACzB,IAAI,IAAI,GAAG,WAAW,MAAM,KAAK,CAAC,OAAO,IAAI,KAAK,MAAM,CAAC;MAChE,QAAQ,MAAKA,GAAI;AACnB,SAAK,MAAM,OAAO,KAAK,MAAM;KAC5B,MAAM,SAAS,KAAK,OAAO,YAAY,IAAI;AAC3C,YAAO,IAAI,OAAO,IAAI,OAAO;;;;AAIhC,SAAO;;CAGR,MAAM,YAA6B;EAClC,IAAI,QAAQ;AACZ,OAAK,MAAM,cAAc,MAAM,KAAK,aAAa,EAAE;GAClD,MAAM,SAAS,MAAM,GAAmB;gCACX,IAAI,IAAI,WAAW,MAAM,CAAC;KACrD,QAAQ,MAAKA,GAAI;AACnB,YAASF,QAAM,OAAO,KAAK,IAAI,EAAE;;AAElC,SAAO;;;;;;;AAgBT,IAAM,kBAAN,MAAyD;CACxD,AAAS,OAAO;CAChB,CAASE;CACT,CAASE;CAET,YAAY,IAAQ,SAAwB;AAC3C,QAAKF,KAAM;AACX,QAAKE,UAAW;;CAGjB,MAAc,UAAsC;EACnD,MAAM,UAA6B,EAAE;EACrC,MAAM,QAAQ,MAAM,gBAAgB,MAAKF,GAAI;EAC7C,MAAM,UAAyB;GAAE,IAAI,MAAKA;GAAK,SAAS,MAAKE;GAAU;GAAO;AAC9E,OAAK,MAAM,QAAQ,MAClB,SAAQ,KAAK;GAAE,OAAOH,eAAa,KAAK;GAAE,QAAQ;GAAa,CAAC;AAEjE,UAAQ,KAAK;GAAE,OAAO;GAAa,QAAQ;GAAa,QAAQ,cAAc,QAAQ;GAAE,CAAC;EACzF,MAAM,cAAc,MAAKG,QAAS;AAClC,UAAQ,KAAK;GACZ,OAAO;GACP,QAAQ;GACR,QACC,gBAAgB,SACb,SACA,GAAY;+EAC4D,YAAY;;GAExF,CAAC;AACF,UAAQ,KAAK;GAAE,OAAO;GAAmB,QAAQ;GAAW,CAAC;AAC7D,MAAI,MAAKA,QAAS,YAAY,KAC7B,SAAQ,KAAK;GACZ,OAAO;GACP,QAAQ;GACR,QAAQ,GAAY,0BAA0B,QAC7C,oBACA,aACA,aAAa,QAAQ,CACrB;GACD,CAAC;AAEH,SAAO;;CAGR,MAAM,KAAK,OAA8B,OAA+C;EACvF,MAAM,KAAK,MAAKF;EAChB,MAAM,sBAAM,IAAI,KAAa;AAC7B,OAAK,MAAM,UAAU,MAAM,KAAK,SAAS,EAAE;GAC1C,MAAM,SAAS,IAAI,IAAI,GAAG,OAAO,MAAM,GAAG,OAAO,SAAS;GAC1D,MAAM,aAAyC,CAAC,GAAG,GAAG,OAAO,cAAc;AAC3E,OAAI,MAAO,YAAW,KAAK,GAAG,GAAG,aAAa,IAAI,OAAO,CAAC,KAAK,MAAM,KAAK;AAC1E,OAAI,OAAO,OAAQ,YAAW,KAAK,OAAO,OAAO;GACjD,MAAM,SAAS,MAAM,GAAmB;aAC9B,OAAO,cAAc,IAAI,IAAI,OAAO,MAAM,CAAC;YAC5C,IAAI,KAAK,YAAY,GAAG,QAAQ,CAAC;eAC9B,OAAO;eACP,aAAa,IAAI,OAAO,CAAC;YAC5B,QAAQ,EAAE;KACjB,QAAQ,GAAG;AACb,QAAK,MAAM,OAAO,OAAO,KAAM,KAAI,IAAI,IAAI,GAAG;;EAE/C,MAAM,SAAS,CAAC,GAAG,IAAI,CAAC,UAAU,GAAG,MACpC,mBAAmB,aAAa,EAAE,IAAI,GAAG,EAAE,EAAE,IAAI,GAAG,CAAC,CACrD;EACD,MAAM,UAAU,OAAO,MAAM,GAAG,MAAM;EACtC,MAAM,UAAU,MAAM,KAAK,MAAM,QAAQ;AACzC,SAAO;GACN,MAAM,QAAQ,KAAK,QAAQ;IAC1B,KAAK,EAAE,IAAI;IACX,QACC,QAAQ,IAAI,GAAG,IAAI,SAAS,aAAa;KAAE,MAAM;KAAa;KAAI,aAAa;KAAI,CAAC;IACrF,aAAa,EAAE;IACf,EAAE;GACH,MAAM,OAAO,UAAU;GACvB;;CAGF,MAAM,MAAM,KAAyE;EACpF,MAAM,yBAAS,IAAI,KAAwC;AAC3D,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,IAAI,CAAC,EAAE,eAAe,EAAE;GAC9D,MAAM,OAAO,MAAM,MAAKA,GACtB,WAAW,QAAQ,CACnB,OAAO;IAAC;IAAM;IAAQ;IAAQ,CAAC,CAC/B,MAAM,MAAM,MAAM,MAAM,CACxB,SAAS;AACX,QAAK,MAAM,OAAO,KACjB,QAAO,IACN,IAAI,IACJ,SAAS,aAAa;IACrB,MAAM;IACN,IAAI,IAAI;IACR,aAAa,IAAI,QAAQ,IAAI;IAC7B,OAAO,IAAI;IACX,CAAC,CACF;;AAGH,SAAO;;CAGR,MAAM,YAA2B;AAChC,SAAO;;;AAMT,SAAgB,aACf,IACA,MACA,SACyB;AACzB,KAAI,SAAS,QAAS,QAAO,IAAI,YAAY,GAAG;AAChD,KAAI,SAAS,YAAa,QAAO,IAAI,gBAAgB,IAAI,QAAQ;AACjE,QAAO,IAAI,YAAY,IAAI,UAAU,KAAK,EAAE,QAAQ;;;;;AC5jCrD,MAAM,UAAU,IAAI,aAAa;AACjC,MAAM,YAAY;AAClB,MAAM,4BAA4B;;AAElC,MAAM,kBAAkB;AAIxB,MAAa,sBAAsB,EAAE,aAAa,EACjD,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,CAAC;AAWF,SAAS,iBAAiB,SAA2B;AACpD,QAAO,oBAAoB,MAAM,WAAW,EAAE,CAAC,CAAC,YAAY;;;;;;;AAQ7D,eAAsB,aACrB,OAC8D;CAC9D,MAAM,UAAU,oBAAoB,MAAM,MAAM,WAAW,EAAE,CAAC;CAC9D,MAAM,SAAS,MAAM,IAAI,4BAA4B,MAAM,GAAG,CAAC,OAAO;EACrE,MAAM;EACN,WAAW,MAAM;EACjB,gBAAgB,MAAM;EACtB;EACA,CAAC;AACF,KAAI,CAAC,OAAO,WAAW,iBAAiB,OAAO,UAAU,QAAQ,KAAK,iBAAiB,QAAQ,CAC9F,OAAM,IAAI,cACT,iCACA,wEACA;AAEF,QAAO;;AA6BR,MAAM,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;AAE5C,MAAM,sBAAsB,EAAE,aAAa;CAE1C,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,MAAM,MAAM,CAAC;CAC5C,SAAS,EAAE,MAAM,EAAE,QAAQ,CAAC;CAC5B,OAAO,EAAE,SAAS;CAElB,aAAa,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM;CACxC,eAAe,EAAE,SAAS;CAC1B,OAAO,EAAE,MAAM,oBAAoB;CACnC,OAAO,EAAE,aAAa;EAAE;EAAO,OAAO;EAAO,CAAC;CAC9C,CAAC;AAIF,SAAS,eAA8B;AACtC,QAAO;EACN,QAAQ,EAAE;EACV,SAAS,EAAE;EACX,OAAO;EACP,aAAa,EAAE;EACf,eAAe;EACf,OAAO,EAAE;EACT,OAAO;GAAE,OAAO;GAAG,OAAO;GAAG;EAC7B;;AAGF,SAAS,YAAY,OAA+B;AACnD,QAAO,UAAU,SAAY,cAAc,GAAG,oBAAoB,MAAM,MAAM;;AAG/E,SAAS,eAAe,SAAgC;CACvD,IAAI,QAAQ;AACZ,MAAK,MAAM,UAAU,OAAO,OAAO,QAAQ,OAAO,CACjD,MAAK,MAAM,WAAW,OAAQ,UAAS;AAExC,QAAO;;AAGR,MAAM,mBAAmB,EAAE,aAAa;CACvC,OAAO,EAAE,QAAQ,YAAY;CAC7B,OAAO,EAAE,MAAM,CAAC,UAAU;CAC1B,CAAC;AAEF,SAAS,cACR,SACA,MACA,MACA,QACO;AACP,KAAI,UAAU,EAAG;CACjB,MAAM,MAAM,GAAG,KAAK,GAAG;AACvB,SAAQ,YAAY,QAAQ,QAAQ,YAAY,QAAQ,KAAK;;;AAI9D,MAAM,aAAoE;CACzE,OAAO;CACP,UAAU;CACV,MAAM;CACN,oBAAoB;CACpB,0BAA0B;CAC1B,UAAU;CACV,gBAAgB;CAChB,KAAK;CACL,SAAS;CACT,kBAAkB;CAClB,WAAW;CACX,cAAc;CACd,mBAAmB;CACnB,QAAQ;CACR,UAAU;CACV,OAAO;CACP;;AA8BD,MAAM,kBAAkD,IAAI,IAAI,CAC/D,0BACA,sBACA,CAAC;;;;;;;AAcF,eAAsB,cAAc,OAAyD;CAC5F,MAAM,aAAa,IAAI,4BAA4B,MAAM,GAAG;CAC5D,IAAI;CACJ,IAAI,aAAa,MAAM;AACvB,KAAI,eAAe,QAAW;EAC7B,MAAM,QAAQ,MAAM,WAAW,MAAM,MAAM,aAAa,CAAC,WAAW,UAAU,CAAC;AAC/E,MAAI,MAAM,YAAY,eAAgB,QAAO;GAAE,WAAW,MAAM;GAAW,SAAS;GAAQ;AAC5F,MAAI,MAAM,YAAY,gBACrB,QAAO;GAAE,WAAW,MAAM;GAAW,SAAS;GAAY;AAE3D,cAAY,MAAM;AAClB,eAAa,MAAM;QACb;AACN,cAAY,MAAM,WAAW,QAAQ,MAAM,YAAY;AACvD,MAAI,UAAU,SAAS,YAAY,UAAU,eAAe,WAC3D,OAAM,IAAI,cAAc,uBAAuB,oCAAoC;;AAGrF,KAAI,UAAU,SAAS,UAAU;AAChC,QAAM,WAAW,QAAQ,UAAU,IAAI,WAAW;AAClD,QAAM,IAAI,cAAc,0BAA0B,6BAA6B;;CAGhF,MAAM,OAAO,IAAI,WAAW,OAAO,WAAW,WAAW;AACzD,KAAI;AAEH,SADe,MAAM,KAAK,KAAK;UAEvB,OAAO;AACf,MAAI,gBAAgB,MAAM,IAAI,CAAC,gBAAgB,IAAI,MAAM,KAAK,CAK7D,QAAO;GAAE,WAJM,MAAM,WAAW,KAAK,UAAU,IAAI,YAAY;IAC9D,MAAM,MAAM;IACZ,QAAQ,MAAM;IACd,CAAC;GAC0B,SAAS;GAAU;AAEhD,MAAI,EAAE,gBAAgB,MAAM,IAAI,MAAM,SAAS,uBAC9C,OAAM,WAAW,QAAQ,UAAU,IAAI,WAAW,CAAC,YAAY,OAAU;AAE1E,QAAM;;;AAIR,IAAM,aAAN,MAAiB;CAChB,CAASQ;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT;CACA,QAA8B;CAC9B,aAAiC;CACjC,2BAAW,IAAI,KAAyC;CACxD,iBAA6C;CAC7C,CAASC,gCAAiB,IAAI,KAAsB;CAEpD,YAAY,OAA2B,WAA8B,YAAoB;AACxF,QAAKV,QAAS;AACd,QAAKC,KAAM,MAAM;AACjB,QAAKU,YAAa;AAClB,QAAKF,aAAc;AACnB,QAAKP,aAAc,IAAI,4BAA4B,MAAM,GAAG;AAC5D,QAAKC,cAAe,IAAI,6BAA6B,MAAM,GAAG;AAC9D,QAAKC,QAAS,IAAI,4BAA4B,MAAM,IAAI,UAAU,GAAG;AACrE,QAAKC,SAAU,MAAM,UAAU,IAAI,oBAAoB;AACvD,QAAKC,QAAS,IAAI,cACjB,MAAM,SACN,cAAc,UAAU,UAAU,IAAI,UAAU,cAAc,CAC9D;AACD,QAAKC,SAAU,IAAI,oBAAoB,MAAKD,MAAO;AACnD,QAAKE,UAAW,oBAAoB,MAAM,UAAU,WAAW,EAAE,CAAC;;CAGnE,KAAII,WAAqB;AACxB,SAAO,MAAKJ,QAAS,YAAY;;CAGlC,MAAM,MAAoC;EACzC,IAAI,SAAS,KAAK,eAAe;AACjC,MAAI,WAAW,MAAM;AACpB,YAAS,MAAM,KAAK,MAAM,EAAE;AAC5B,SAAM,KAAK,QAAQ,QAAQ,UAAU;;AAEtC,WAAS;GACR,MAAM,SAAS,MAAM,KAAK,KAAK,OAAO;AACtC,WAAQ,OAAO,MAAf;IACC,KAAK,QAEJ,QAAO;KAAE,WADQ,MAAM,MAAKN,WAAY,QAAQ,MAAKS,UAAW,IAAI,MAAKF,WAAY;KACvD,SAAS;KAAY;IAEpD,KAAK,YAAY;KAChB,MAAM,QAAQ,KAAK,eAAe;KAClC,MAAM,OAAO,MAAKE,UAAW;AAU7B,YAAO;MAAE,WATS,MAAM,MAAKT,WAAY,SAAS,MAAKS,UAAW,IAAI,MAAKF,YAAa;OACvF,YAAY,gBAAgB;OAC5B,UAAU;QACT,GAAG;QACH,MAAM;QACN;QACA,GAAI,MAAM,cAAc,SAAY,EAAE,GAAG,EAAE,YAAY,KAAK,WAAW;QACvE;OACD,CAAC;MAC6B,SAAS;MAAY;;IAErD,KAAK,OAKJ,QAAO;KAAE,WAJM,MAAM,MAAKP,WAAY,KAAK,MAAKS,UAAW,IAAI,MAAKF,YAAa;MAChF,MAAM,OAAO;MACb,QAAQ,OAAO;MACf,CAAC;KAC0B,SAAS;KAAU;IAEhD,KAAK;AACJ,cAAS,OAAO;AAChB,SAAI,OAAO,QAMV,QAAO;MAAE,WALQ,MAAM,MAAKP,WAAY,QAAQ,MAAKS,UAAW,IAAI,MAAKF,YAAa;OACrF;OACA,OAAO,OAAO;OACd,UAAU,KAAK,YAAY,OAAO;OAClC,CAAC;MAC4B,SAAS;MAAY;AAEpD,WAAM,KAAK,QAAQ,OAAO;AAC1B;;;;CAKJ,AAAQ,gBAAqC;EAC5C,MAAM,SAAgC,MAAKE,UAAW;AACtD,MAAI,WAAW,KAAM,QAAO;AAC5B,UAAQ,OAAO,OAAf;GACC,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,kBACJ,QAAO;GACR,QACC,OAAM,IAAI,cAAc,0BAA0B,uCAAuC;;;CAI5F,MAAc,QAAQ,QAAsB,OAAkC;AAC7E,QAAKA,YAAa,MAAM,MAAKT,WAAY,QAAQ,MAAKS,UAAW,IAAI,MAAKF,YAAa;GACtF;GACA,OAAO,OAAO;GACd,UAAU,KAAK,YAAY,OAAO;GAClC,GAAI,QAAQ,EAAE,OAAO,GAAG,EAAE;GAC1B,CAAC;;;CAIH,AAAQ,gBAAwB;AAC/B,SAAO,KAAK,eAAe,CAAC,SAAS;;CAGtC,AAAQ,YAAY,QAAwC;EAC3D,MAAM,QAAQ,KAAK,eAAe;EAClC,MAAM,QAAQ,KAAK,eAAe;AAClC,UAAQ,OAAO,OAAf;GACC,KAAK,eACJ,QAAO;IAAE,MAAM;IAAG;IAAO,SAAS;IAAG;GACtC,KAAK,iBACJ,QAAO;IACN,MAAM,IAAI,MAAM,QAAQ,OAAO,KAAK;IACpC;IACA,SAAS,eAAe,YAAY,OAAO,QAAQ,CAAC;IACpD;GACF,KAAK,mBAAmB;IACvB,MAAM,UAAU,YAAY,OAAO,QAAQ;AAC3C,WAAO;KACN,MAAM,IAAI,MAAM;KAChB;KACA,SAAS,eAAe,QAAQ;KAChC,WAAW,QAAQ,MAAM;KACzB;;GAEF,KAAK,kBACJ,QAAO;IAAE,GAAG,MAAKE,UAAW;IAAU,MAAM,IAAI,MAAM;IAAQ;IAAO;;;;CAKxE,MAAc,MAAM,SAAwC;AAE3D,SAAO;GACN,OAAO;GACP;GACA,OAJ0B,MAAM,aAAa,MAAKV,IAAK,MAAKU,UAAW,WAAW;GAKlF,cAAc;GACd,SAAS,cAAc;GACvB;;CAGF,MAAc,KAAK,QAA2C;AAC7D,UAAQ,OAAO,OAAf;GACC,KAAK,eACJ,QAAO,KAAK,qBAAqB,OAAO,eAAe,KAAK,UAAU,OAAO,CAAC;GAC/E,KAAK,iBACJ,QAAO,KAAK,qBAAqB,OAAO,eAAe,KAAK,YAAY,OAAO,CAAC;GACjF,KAAK,kBACJ,QAAO,KAAK,aAAa,OAAO;GACjC,KAAK,kBACJ,QAAO,KAAK,aAAa,OAAO;;;;;;;;CASnC,MAAc,qBACb,SACA,KACsB;AACtB,MAAI;AACH,UAAO,MAAM,KAAK;WACV,OAAO;AACf,OAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS,gCAC5C,QAAO,KAAK,QAAQ,QAAQ;AAE7B,SAAM;;;CAMR,MAAc,UACb,QACsB;AACtB,MAAI,CAAC,MAAKN,OAAQ,UAAU,CAAE,QAAO,EAAE,MAAM,SAAS;AACtD,QAAKA,OAAQ,OAAO;EACpB,MAAM,aAAa,MAAM,oBACxB,MAAKJ,IACL,OAAO,cACP,0BACA;AACD,MAAI,WAAW,WAAW,EACzB,QAAO;GACN,MAAM;GACN,QAAQ;IACP,OAAO;IACP,SAAS,OAAO;IAChB,OAAO,OAAO;IACd,MAAM,aAAa;IACnB,OAAO;IACP,SAAS;IACT,SAAS,OAAO;IAChB;GACD;EAEF,IAAI,QAAQ,OAAO;AACnB,OAAK,MAAM,aAAa,YAAY;GAEnC,MAAM,QAAQ,MAAKI,OAAQ,cAAc;AACzC,OAAI,CAAC,SAAS,CAAC,MAAKA,OAAQ,SAAS;IAAE,SAAS;IAAG,OAAO;IAAG,CAAC,CAAE;GAChE,MAAM,SAAS,MAAM,iBAAiB,MAAKL,MAAO,SAAS,UAAU,YAAY,EAChF,UAAU,QAAQ,SAAY,MAAKK,OAAQ,WAAW,CAAC,OACvD,CAAC;AACF,OAAI,WAAW,YAAa;AAC5B,SAAKA,OAAQ,MAAM,QAAQ,SAAS,EAAE;AACtC,OAAI,WAAW,MACd;QAAI,UAAU,WAAW,QACxB,OAAM,IAAI,cACT,+BACA,sCACA,EAAE,QAAQ,EAAE,SAAS,UAAU,IAAI,EAAE,CACrC;UAEI;AACN,UAAM,MAAKD,MAAO,QAAQ,CACzB;KAAE,SAAS,UAAU;KAAI,QAAQ,OAAO;KAAQ,OAAO,OAAO;KAAO,CACrE,CAAC;AACF,UAAM,MAAKD,YAAa,YACvB,MAAKQ,UAAW,IAChB,CAAC;KAAE,MAAM,cAAc,OAAO,OAAO;KAAE,OAAO,OAAO;KAAO,QAAQ,OAAO;KAAQ,CAAC,EACpF,WACA;;AAEF,WAAQ,UAAU;;AAEnB,MAAI,UAAU,OAAO,aAAc,QAAO,EAAE,MAAM,SAAS;AAC3D,SAAO;GAAE,MAAM;GAAU,QAAQ;IAAE,GAAG;IAAQ,cAAc;IAAO;GAAE;;CAKtE,AAAQ,OAAO,MAA0C;EACxD,IAAI,SAAS,MAAKE,QAAS,IAAI,KAAK;AACpC,MAAI,CAAC,QAAQ;GACZ,MAAM,UAAyB;IAC9B,mBAAmB,MAAKF,UAAW;IACnC,UAAU,MAAKC;IACf,YAAY,OAAO,QAAQ;KAC1B,MAAM,UAAU,MAAM,MAAKR,MAAO,QAAQ,IAAI;AAC9C,YAAO,IAAI,IAAI,MAAM,KAAK,UAAU,CAAC,IAAI,WAAW,CAAC,IAAI,MAAM,OAAO,CAAC,CAAC;;IAEzE;AACD,YAAS,aAAa,MAAKH,IAAK,MAAM,QAAQ;AAC9C,SAAKY,QAAS,IAAI,MAAM,OAAO;;AAEhC,SAAO;;;CAIR,MAAc,gBAAgB,KAA8C;EAC3E,MAAM,UAAU,IAAI,QAAQ,OAAO,CAAC,MAAKH,cAAe,IAAI,GAAG,CAAC;AAChE,MAAI,QAAQ,SAAS,GAAG;GACvB,MAAM,WAAW,MAAM,MAAKN,MAAO,QAAQ,QAAQ;AACnD,QAAK,MAAM,MAAM,QAAS,OAAKM,cAAe,IAAI,IAAI,SAAS,IAAI,GAAG,CAAC;;AAExE,SAAO,IAAI,IAAI,IAAI,QAAQ,OAAO,MAAKA,cAAe,IAAI,GAAG,KAAK,MAAM,CAAC;;CAG1E,MAAc,WAAqE;AAClF,MAAI,CAAC,MAAKI,QAAS,CAAC,MAAKC,WAAY;AACpC,SAAKD,OAAQ,MAAM,kBAAkB,MAAKb,GAAI;AAC9C,SAAKc,YAAa,cAAc,MAAKD,KAAM;;AAE5C,SAAO;GAAE,MAAM,MAAKA;GAAO,WAAW,MAAKC;GAAY;;CAGxD,AAAQ,gBAA8B;AACrC,SAAO,aAAa,QAClB,SAAS,MAAKH,YAAc,SAAS,aAAa,SAAS,mBAC5D;;CAGF,AAAQ,SAAS,MAAqC;EACrD,MAAM,QAAQ,KAAK,eAAe;AAClC,SAAO,MAAM,MAAM,QAAQ,KAAK,GAAG,MAAM;;CAG1C,MAAc,YACb,QACsB;AACtB,MAAI,CAAC,MAAKP,OAAQ,SAAS,EAAE,OAAO,GAAG,CAAC,CAAE,QAAO,EAAE,MAAM,SAAS;EAClE,MAAM,UAAU,YAAY,OAAO,QAAQ;EAC3C,MAAM,EAAE,MAAM,cAAc,MAAM,KAAK,UAAU;EACjD,MAAM,SAAS,KAAK,OAAO,OAAO,KAAK;EAEvC,MAAM,UAA+B,EAAE;EACvC,MAAM,QAAkB,EAAE;EAC1B,MAAM,UAAU,IAAI,IAAI,QAAQ,QAAQ;EACxC,IAAI,QAAQ;EACZ,IAAI,QAAQ,OAAO;EACnB,IAAI,WAAW;AACf,OAAM,QAAO,QAAQ,SAAS,gBAAgB,cAAc;GAC3D,MAAM,OAAO,MAAM,OAAO,KACzB,OACA,KAAK,IAAI,WAAW,gBAAgB,eAAe,QAAQ,OAAO,CAClE;AACD,QAAK,MAAM,OAAO,KAAK,MAAM;AAC5B,QAAI,IAAI,WAAW,MAAM;AACxB,aAAQ,IAAI;AACZ;;IAED,MAAM,YAAY,iBAAiB,IAAI,QAAQ;KAC9C,MAAM;KACN;KACA,YAAY;KACZ,CAAC;IACF,MAAM,QAAQ,UAAU,OAAO;AAC/B,QAAI,MACH,OAAM,IAAI,cACT,8BACA,0DACA,EACC,QAAQ;KACP,MAAM,OAAO;KACb,IAAI,IAAI,OAAO;KACf,QAAQ,MAAM;KACd,MAAM,MAAM;KACZ,EACD,CACD;IAEF,MAAM,WAAW,wBAChB,UAAU,OACV,MAAM,KAAK,gBAAgB,UAAU,SAAS,CAC9C;IACD,MAAM,SAAS,SAAS;IACxB,MAAM,OAAO,iBAAiB,OAAO;AACrC,QAAI,YAAY,MAAM,UAAU,CAAC,SAAS,EACzC,OAAM,IAAI,cACT,8BACA,4CACA,EAAE,QAAQ;KAAE,MAAM,OAAO;KAAM,IAAI,OAAO;KAAI,EAAE,CAChD;IAEF,MAAM,YAAY,QAAQ,OAAO,KAAK,CAAC,aAAa;AACpD,QAAI,QAAQ,SAAS,KAAK,QAAQ,YAAY,gBAAgB,WAAY,OAAM;AAChF,YAAQ,KAAK,OAAO;AACpB,UAAM,KAAK,KAAK;AAChB,aAAS;AACT,YAAQ,IAAI;AACZ,SAAK,MAAM,cAAc,IAAI,YAC5B,eAAc,SAAS,WAAW,MAAM,OAAO,MAAM,WAAW,MAAM;AAEvE,kBAAc,SAAS,yBAAyB,OAAO,MAAM,UAAU,YAAY;AACnF,kBAAc,SAAS,sBAAsB,OAAO,MAAM,SAAS,MAAM;AACzE,QAAI,UAAU,SAAS,MAAM,YAAY,QAAQ,SAAS,sBAAsB,CAC/E,eAAc,SAAS,uBAAuB,OAAO,MAAM,EAAE;AAE9D,QAAI,YAAY,UAAU,OAAO,OAAO,WAAW,SAAU,SAAQ,IAAI,OAAO,OAAO;AACvF,QAAI,OAAO,SAAS,WAAW,OAAO,cAAc,OAAW,SAAQ,QAAQ;;AAEhF,OAAI,KAAK,MAAM;AACd,eAAW;AACX;;;AAGF,MAAI,QAAQ,SAAS,GAAG;GACvB,MAAM,QAAQ,MAAM,MAAKE,OAAQ,iBAAiB,OAAO,MAAM,OAAO,SAAS,QAAQ;AACvF,SAAM,MAAKJ,YAAa,YACvB,MAAKQ,UAAW,IAChB,CAAC;IAAE,MAAM,MAAM;IAAM,OAAO,MAAM;IAAO,QAAQ,MAAM;IAAQ,CAAC,EAChE,WACA;AACD,SAAKN,OAAQ,MAAM,MAAM,MAAM;AAC/B,WAAQ,OAAO,OAAO,QAAQ,CAAC,GAAI,QAAQ,OAAO,OAAO,SAAS,EAAE,EAAG,QAAQ,OAAO;QAEtF,OAAKA,OAAQ,MAAM,EAAE;AAEtB,UAAQ,UAAU,CAAC,GAAG,QAAQ,CAAC,SAAS,aAAa;EAErD,MAAM,UAAU,QAAQ,SAAS,IAAI,OAAO,UAAU,IAAI,OAAO;AACjE,MAAI,CAAC,SACJ,QAAO;GAAE,MAAM;GAAU,QAAQ;IAAE,GAAG;IAAQ;IAAO;IAAS;IAAS;GAAE;EAE1E,MAAM,OAAO,KAAK,SAAS,OAAO,KAAK;AACvC,MAAI,SAAS,KACZ,QAAO;GACN,MAAM;GACN,QAAQ;IACP,OAAO;IACP,SAAS,OAAO;IAChB,OAAO,OAAO;IACd,cAAc;IACd,WAAW;IACX;IACA;GACD;AAEF,SAAO;GACN,MAAM;GACN,QAAQ;IAAE,GAAG;IAAQ,MAAM;IAAM,OAAO;IAAM,SAAS;IAAG;IAAS;GACnE;;CAKF,MAAc,aACb,QACsB;AACtB,MAAI,CAAC,MAAKA,OAAQ,UAAU,CAAE,QAAO,EAAE,MAAM,SAAS;AACtD,QAAKA,OAAQ,OAAO;EACpB,MAAM,UAAU,YAAY,OAAO,QAAQ;AAE3C,MAAI,CAAC,QAAQ,eAAe;GAC3B,MAAM,UAAU,MAAM,MAAKH,WAAY,QAAQ,MAAKS,UAAW,GAAG;GAClE,MAAM,QAAQ,MAAM,aAAa,MAAKV,IAAK,QAAQ,WAAW;AAC9D,OAAI,CAAC,YAAY,OAAO,OAAO,MAAM,CAAE,QAAO,KAAK,QAAQ,OAAO,QAAQ;AAC1E,SAAM,KAAK,aAAa,QAAQ;AAChC,WAAQ,gBAAgB;AACxB,UAAO;IAAE,MAAM;IAAU,QAAQ;KAAE,GAAG;KAAQ;KAAS;IAAE;;EAG1D,MAAM,QAAQ,MAAM,MAAKE,YAAa,KAAK,MAAKQ,UAAW,IAAI;GAC9D,OAAO;GACP,OAAO,OAAO,aAAa;GAC3B,OAAO,gBAAgB;GACvB,CAAC;EACF,MAAM,UAA8B,EAAE;EACtC,IAAI,QAAQ;AACZ,OAAK,MAAM,QAAQ,OAAO;GACzB,MAAM,SAAS,iBAAiB,KAAK,KAAK;AAC1C,OAAI,CAAC,UAAW,OAAO,SAAS,aAAa,OAAO,SAAS,QAAU;GACvE,MAAM,QAA0B;IAAE,MAAM,KAAK;IAAM,OAAO,KAAK;IAAO,QAAQ,KAAK;IAAQ;AAC3F,OAAI,OAAO,SAAS,WAAW;IAC9B,MAAM,UAAU,QAAQ,OAAO,OAAO,QAAQ,OAAO;AACrD,QAAI,YAAY,OACf,OAAM,IAAI,cACT,yBACA,0CACA,EACC,QAAQ,EAAE,MAAM,KAAK,MAAM,EAC3B,CACD;AAEF,UAAM,UAAU;;GAEjB,MAAM,OAAO,QAAQ,OAAO,KAAK,UAAU,MAAM,CAAC,CAAC,aAAa;AAChE,OAAI,QAAQ,SAAS,KAAK,QAAQ,OAAO,gBAAgB,WAAY;AACrE,WAAQ,KAAK,MAAM;AACnB,YAAS;;EAGV,MAAM,YAAY,QAAQ,GAAG,GAAG;AAChC,MAAI,WAAW;GACd,MAAM,MAAqB,MAAM,MAAKJ,OAAQ,gBAAgB,OAAO,cAAc,QAAQ;AAC3F,SAAM,MAAKJ,YAAa,YACvB,MAAKQ,UAAW,IAChB,CAAC;IAAE,MAAM,IAAI;IAAM,OAAO,IAAI;IAAO,QAAQ,IAAI;IAAQ,CAAC,EAC1D,WACA;AACD,WAAQ,QAAQ,CAAC,GAAG,QAAQ,OAAO,IAAI;AACvC,WAAQ,QAAQ;IACf,OAAO,QAAQ,MAAM,QAAQ,QAAQ;IACrC,OAAO,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,KAAK,UAAU,MAAM,MAAM,OAAO,EAAE;IACjF;AACD,UAAO;IACN,MAAM;IACN,QAAQ;KACP,GAAG;KACH,cAAc,OAAO,eAAe;KACpC,WAAW,UAAU;KACrB;KACA;IACD;;EAGF,MAAM,WAAW,MAAM,KAAK,cAAc,SAAS,OAAO,QAAQ;EAClE,MAAM,SAAS,MAAM,MAAKJ,OAAQ,cAAc,SAAS;AACzD,QAAKI,YAAa,MAAM,MAAKT,WAAY,QAAQ,MAAKS,UAAW,IAAI,MAAKF,YAAa,EACtF,eAAe,QACf,CAAC;AACF,SAAO;GAAE,MAAM;GAAU,QAAQ;IAAE,OAAO;IAAmB,UAAU;IAAM;GAAE;;CAGhF,MAAc,aAAa,SAAuC;AACjE,OAAK,MAAM,QAAQ,KAAK,eAAe,EAAE;GACxC,MAAM,OAAO,MAAM,KAAK,OAAO,KAAK,CAAC,WAAW;AAChD,OAAI,SAAS,KAAM;GACnB,MAAM,YAAY,QAAQ,OAAO,SAAS,EAAE,EAAE,QAAQ,KAAK,MAAM,MAAM,GAAG,EAAE;GAC5E,MAAM,UAAU,OAAO;AACvB,OAAI,YAAY,EAAG;GACnB,MAAM,OAAO,WAAW;AACxB,OAAI,CAAC,QAAQ,UAAU,EACtB,OAAM,IAAI,cAAc,yBAAyB,8BAA8B,EAC9E,QAAQ;IAAE;IAAM;IAAM;IAAU,EAChC,CAAC;AAEH,iBAAc,SAAS,MAAM,MAAM,QAAQ;;;CAI7C,MAAc,QAAQ,SAAsC;AAC3D,MAAI,WAAW,gBAAgB,oBAC9B,QAAO;GACN,MAAM;GACN,MAAM;GACN,QAAQ,EAAE,UAAU,SAAS;GAC7B;EAEF,IAAI;AACJ;AACC,aAAU,MAAM,MAAKN,YAAa,mBAAmB,MAAKQ,UAAW,GAAG;SAChE,UAAU;AACnB,QAAM,MAAKV,GACT,WAAW,+BAA+B,CAC1C,MAAM,gBAAgB,KAAK,MAAKU,UAAW,GAAG,CAC9C,SAAS;AACX,QAAKA,YAAa,MAAM,MAAKT,WAAY,QAAQ,MAAKS,UAAW,GAAG;AACpE,SAAO;GAAE,MAAM;GAAU,QAAQ,MAAM,KAAK,MAAM,UAAU,EAAE;GAAE;;CAGjE,MAAc,cACb,SACA,UAC+B;EAC/B,MAAM,SAAS,MAAM,MAAKP,MAAO,QAAQ;EACzC,MAAM,2BAAW,IAAI,KAAyB;EAC9C,MAAM,UAA0C,EAAE;AAClD,OAAK,MAAM,QAAQ,cAAc;GAChC,MAAM,SAAS,QAAQ,OAAO;AAC9B,OAAI,CAAC,UAAU,OAAO,WAAW,EAAG;AACpC,WAAQ,QAAQ;IAAE,OAAO,OAAO,QAAQ,KAAK,MAAM,MAAM,GAAG,EAAE;IAAE,QAAQ,OAAO;IAAQ;AACvF,YAAS,IAAI,aAAa,MAAM;;AAEjC,MAAI,MAAKQ,SAAW,UAAS,IAAI,WAAW;AAC5C,MAAI,OAAO,QAAQ,EAAG,UAAS,IAAI,QAAQ;EAC3C,MAAM,gBACL,MAAKZ,MAAO,iBAAiB,eAAe,EAAE,iBAAiB,QAAQ,QAAQ,MAAM;EACtF,MAAM,UAAU,IAAI,IAAI,CAAC,GAAG,QAAQ,SAAS,cAAc,CAAC;AAC5D,MAAI,QAAQ,OAAO,EAAG,UAAS,IAAI,OAAO;AAC1C,MAAI,QAAQ,MAAO,UAAS,IAAI,QAAQ;EACxC,MAAM,cAAc,CAAC,GAAG,SAAS,CAAC,SAAS,aAAa;EAExD,MAAM,kBAA0C,EAAE;AAClD,OAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,QAAQ,YAAY,EAAE;GAChE,MAAM,CAAC,MAAM,QAAQ,IAAI,MAAM,IAAI;GACnC,MAAM,QAAQ,4BAA4B,MAAM,cAAc,cAAc,KAAK;GACjF,MAAM,aAAa,aAAa,MAAM,cAAc,cAAc,KAAK;AACvE,OAAI,CAAC,SAAS,CAAC,cAAc,WAAW,EAAG;AAC3C,mBAAgB,KAAK;IAAE,MAAM;IAAO,MAAM;IAAY,OAAO;IAAQ,CAAC;;AAEvE,kBAAgB,MAAM,GAAG,MAAM,aAAa,EAAE,MAAM,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,EAAE,KAAK,CAAC;AAE5F,SAAO;GACN,QAAQ;GACR,eAAe;GACf,WAAW,MAAM;GACjB,cAAc,MAAM,kBAAkB,MAAKC,GAAI;GAC/C,4BAAW,IAAI,MAAM,EAAC,aAAa;GACnC,wBAAwB,MAAKD,MAAO,iBAAiB;GACrD,SAAS;GACT,UAAU;GACV,kBAAkB,oBAAoB,YAAY;GAClD,SAAS;IAAE,SAAS;IAAe,MAAM,CAAC,GAAG,QAAQ,CAAC,SAAS,aAAa;IAAE;GAC9E;GACA,OAAO;IAAE,OAAO,OAAO;IAAO,YAAY,OAAO;IAAW;GAC5D,OAAO;IAAE,OAAO,QAAQ,MAAM;IAAO,YAAY,QAAQ,MAAM;IAAO;GACtE,OAAO,QAAQ;GACf;GACA,OAAO,EAAE,UAAU;GACnB;;CAKF,AAAQ,gBAAqC;AAC5C,QAAKgB,kBAAmB,IAAI,oBAC3B,MAAKV,OACL,MAAKL,IACL,MAAKD,MAAO,SACZ,MAAKW,UAAW,GAChB;AACD,SAAO,MAAKK;;CAGb,MAAc,aACb,QACsB;EACtB,MAAM,SAAS,KAAK,eAAe;AACnC,MAAI,OAAO,eAAe,QAAW;GACpC,MAAM,WAAW,MAAM,OAAO,UAAU;GACxC,MAAM,WAAW,OAAO,YAAY,WAAW,SAAS;AACxD,OAAI,aAAa,KAChB,QAAO;IACN,MAAM;IACN,QAAQ;KAAE,GAAG;KAAQ,UAAU;KAAM,YAAY;MAAE,OAAO;MAAa,OAAO;MAAM;KAAE;IACtF;GAEF,MAAM,OAAO,gBAAgB,SAAS,MAAM,SAAS,IAAI;GACzD,MAAM,SAAS,MAAM,MAAKb,YAAa,IAAI,MAAKQ,UAAW,IAAI,KAAK;AACpE,OAAI,CAAC,OACJ,OAAM,IAAI,cAAc,yBAAyB,+BAA+B,EAC/E,QAAQ,EAAE,MAAM,EAChB,CAAC;AAEH,OAAI,CAAC,MAAKN,OAAQ,SAAS,EAAE,OAAO,OAAO,OAAO,CAAC,CAAE,QAAO,EAAE,MAAM,SAAS;AAC7E,SAAKA,OAAQ,MAAM,OAAO,MAAM;GAChC,MAAM,EAAE,cAAc,MAAM,KAAK,UAAU;GAC3C,MAAM,QAAQ,MAAM,OAAO,UAAU,SAAS,MAAM,SAAS,KAAK,OAAO;AACzE,QAAK,MAAM,UAAU,MACpB,KAAI,YAAY,OAAO,MAAM,UAAU,CAAC,SAAS,EAChD,OAAM,IAAI,cACT,8BACA,uCACA,EAAE,QAAQ;IAAE,MAAM,SAAS;IAAM,IAAI,OAAO,OAAO;IAAI,EAAE,CACzD;GAGH,MAAM,OAAO,UAAU,UAAU,SAAS;AAC1C,UAAO;IACN,MAAM;IACN,QACC,SAAS,OACN;KAAE,GAAG;KAAQ,UAAU;KAAM,YAAY;MAAE,OAAO;MAAa,OAAO;MAAM;KAAE,GAC9E;KAAE,GAAG;KAAQ,UAAU;KAAM;IACjC;;EAGF,MAAM,aAAa,iBAAiB,MAAM,OAAO,WAAW;EAC5D,MAAM,WAAW,MAAKL,MAAO;AAC7B,MAAI,CAAC,SAAU,QAAO,EAAE,MAAM,YAAY;AAE1C,MAAI,MAAKK,OAAQ,QAAQ,KAAK,CAAC,MAAKA,OAAQ,UAAU,CAAE,QAAO,EAAE,MAAM,SAAS;EAChF,MAAM,SAAS,MAAM,SAAS;GAC7B,IAAI,MAAKJ;GACT;GACA,aAAa,MAAKU,UAAW;GAC7B,OAAO,WAAW;GAClB,QAAQ,MAAKN;GACb,CAAC;EACF,MAAM,UAAU,OAAO,SAAS;AAChC,MAAI,QACH,QAAO;GACN,MAAM;GACN,MAAM;GACN,QAAQ;IACP,QAAQ;IACR,SAAS,QAAQ;IACjB,MAAM,QAAQ,QAAQ;IACtB,IAAI,QAAQ,MAAM;IAClB;GACD;AAEF,MAAI,OAAO,KAAM,QAAO,EAAE,MAAM,YAAY;AAC5C,SAAO;GACN,MAAM;GACN,QAAQ;IACP,GAAG;IACH,YAAY;KAAE,OAAO;KAAa,OAAO,EAAE,MAAM,CAAC,MAAM,OAAO,SAAS,KAAK;KAAE;IAC/E;GACD,SAAS;GACT;;;AAIH,SAAS,WACR,UACyD;AACzD,MAAK,MAAM,QAAQ,aAClB,MAAK,SAAS,QAAQ,OAAO,UAAU,KAAK,EAAG,QAAO;EAAE;EAAM,KAAK;EAAG,MAAM;EAAG;AAEhF,QAAO;;AAGR,SAAS,UACR,UACA,UACyD;AACzD,KAAI,SAAS,MAAM,KAAK,SAAS,QAAQ,SAAS,OAAO,UAAU,GAClE,QAAO;EAAE,MAAM,SAAS;EAAM,KAAK,SAAS,MAAM;EAAG,MAAM;EAAG;AAE/D,MAAK,MAAM,QAAQ,aAAa,MAAM,aAAa,QAAQ,SAAS,KAAK,GAAG,EAAE,CAC7E,MAAK,SAAS,QAAQ,OAAO,UAAU,KAAK,EAAG,QAAO;EAAE;EAAM,KAAK;EAAG,MAAM;EAAG;AAEhF,QAAO;;;;;;;AAUR,IAAa,sBAAb,cAAyC,oBAAoB;CAC5D,CAASJ;CACT,CAASgB;CACT,CAASC;CAET,YAAY,OAAsB,IAAQ,SAAkB,aAAqB;AAChF,QAAM,MAAM;AACZ,QAAKjB,KAAM;AACX,QAAKgB,UAAW;AAChB,QAAKC,cAAe;;CAGrB,MAAe,KAAK,QAAqD;EACxE,MAAM,MAAM,MAAM,MAAKjB,GACrB,WAAW,+BAA+B,CAC1C,UAAU,SAAS,YAAY,wCAAwC,CACvE,OAAO,CAAC,mCAAmC,CAAC,CAC5C,MAAM,6CAA6C,KAAK,MAAKiB,YAAa,CAC1E,MAAM,uCAAuC,KAAK,OAAO,CACzD,QAAQ,wCAAwC,CAChD,kBAAkB;AACpB,MAAI,CAAC,IACJ,OAAM,IAAI,cAAc,yBAAyB,mCAAmC,EACnF,QAAQ,EAAE,MAAM,cAAc,OAAO,EAAE,EACvC,CAAC;AAEH,MAAI;AACH,WAAQ,MAAM,MAAKD,QAAS,SAAS,IAAI,YAAY,EAAE;WAC/C,OAAO;AACf,SAAM,IAAI,cAAc,+BAA+B,sCAAsC;IAC5F,QAAQ,EAAE,MAAM,cAAc,OAAO,EAAE;IACvC,OAAO;IACP,CAAC;;;;;AAML,SAAgB,kBAAkB,OAIV;AAKvB,QAAO,IAAI,oBAJG,IAAI,cACjB,MAAM,SACN,cAAc,UAAU,MAAM,UAAU,IAAI,MAAM,UAAU,cAAc,CAC1E,EACqC,MAAM,IAAI,MAAM,SAAS,MAAM,UAAU,GAAG;;;;;;;;;;;;;;;;ACrhCnF,MAAa,2BAA2B;AAOxC,IAAa,gCAAb,MAA2C;CAC1C,YACC,AAAiB,IACjB,AAAiB,cACjB,AAAiB,aAChB;EAHgB;EACA;EACA;;;;;;;CAQlB,MAAM,QAAQ,YAAoB,UAAqD;AACtF,MAAI,SAAS,WAAW,EAAG;AAC3B,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,SAAS,EAAE,cAAc,EAAE,CAAC,CAC1D,OAAM,KAAK,GACT,WAAW,gCAAgC,CAC3C,OACA,MAAM,KAAK,aAAa;GACvB,gBAAgB,KAAK;GACrB,aAAa;GACb,aAAa,QAAQ;GACrB,WAAW,QAAQ;GACnB,cAAc,KAAK;GACnB,EAAE,CACH,CACA,YAAY,aACZ,SAAS,QAAQ;GAAC;GAAgB;GAAe;GAAc,CAAC,CAAC,WAAW,CAC5E,CACA,SAAS;EAEZ,MAAM,SAAS,MAAM,KAAK,QACzB,YACA,SAAS,KAAK,YAAY,QAAQ,WAAW,CAC7C;AACD,OAAK,MAAM,WAAW,SACrB,KAAI,OAAO,IAAI,QAAQ,WAAW,KAAK,QAAQ,SAC9C,OAAM,IAAI,cAAc,8BAA8B,gCAAgC,EACrF,QAAQ;GAAE,MAAM;GAAY,IAAI,QAAQ;GAAY,EACpD,CAAC;;CAKL,MAAM,IAAI,YAAoB,SAAyC;AACtE,QAAM,KAAK,QAAQ,YAAY,CAAC,QAAQ,CAAC;;CAG1C,MAAM,IAAI,YAAoB,YAA4C;AAQzE,UAPY,MAAM,KAAK,GACrB,WAAW,gCAAgC,CAC3C,OAAO,YAAY,CACnB,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,eAAe,KAAK,WAAW,CACrC,MAAM,eAAe,KAAK,WAAW,CACrC,kBAAkB,GACR,aAAa;;;CAI1B,MAAM,QAAQ,YAAoB,aAA8D;EAC/F,MAAM,yBAAS,IAAI,KAAqB;AACxC,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,YAAY,CAAC,EAAE,eAAe,EAAE;GACtE,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,gCAAgC,CAC3C,OAAO,CAAC,eAAe,YAAY,CAAC,CACpC,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,eAAe,KAAK,WAAW,CACrC,MAAM,eAAe,MAAM,MAAM,CACjC,SAAS;AACX,QAAK,MAAM,OAAO,KAAM,QAAO,IAAI,IAAI,aAAa,IAAI,UAAU;;AAEnE,SAAO;;;CAIR,MAAM,eACL,YACA,WAC+B;EAC/B,MAAM,yBAAS,IAAI,KAAqB;AACxC,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC,EAAE,eAAe,EAAE;GACpE,MAAM,OAAO,MAAM,KAAK,GACtB,WAAW,gCAAgC,CAC3C,OAAO,CAAC,eAAe,YAAY,CAAC,CACpC,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,eAAe,KAAK,WAAW,CACrC,MAAM,aAAa,MAAM,MAAM,CAC/B,SAAS;AACX,QAAK,MAAM,OAAO,KAAM,QAAO,IAAI,IAAI,WAAW,IAAI,YAAY;;AAEnE,SAAO;;;CAIR,MAAM,KACL,YACA,UAA8C,EAAE,EACnB;EAC7B,IAAI,QAAQ,KAAK,GACf,WAAW,gCAAgC,CAC3C,OAAO,CAAC,eAAe,YAAY,CAAC,CACpC,MAAM,gBAAgB,KAAK,KAAK,YAAY,CAC5C,MAAM,eAAe,KAAK,WAAW;EACvC,MAAM,QAAQ,QAAQ;AACtB,MAAI,UAAU,OACb,SAAQ,MAAM,MAAM,GAAY,GAAG,SAAS,KAAK,IAAI,cAAc,CAAC,KAAK,QAAQ;AAMlF,UAJa,MAAM,MACjB,QAAQ,SAAS,KAAK,IAAI,cAAc,CAAC,CACzC,MAAM,KAAK,IAAI,KAAK,IAAI,QAAQ,SAAS,KAAK,EAAE,EAAE,IAAK,CAAC,CACxD,SAAS,EACC,KAAK,SAAS;GAAE,YAAY,IAAI;GAAa,UAAU,IAAI;GAAW,EAAE;;;;;;AC7GtF,MAAM,oBAAyC,IAAI,IAAI,aAAa;;AAGpE,MAAa,qBAAqB;AAOlC,IAAa,gBAAb,MAA2B;CAC1B,AAAS;CACT,AAAS;CACT,CAASE,yBAAU,IAAI,KAAuD;CAC9E,CAASC,yBAAU,IAAI,KAAwC;CAC/D;;CAEA,eAAe;CAEf,YACC,AAAS,IACT,AAAS,SACT,AAAS,KACT,AAAO,WACP,AAAS,YACT,AAAS,MACT,AAAS,UACT,AAAS,QACT,AAAS,QACR;EATQ;EACA;EACA;EACF;EACE;EACA;EACA;EACA;EACA;AAET,OAAK,SAAS,WAAW,GAAG;AAC5B,OAAK,WAAW,IAAI,8BAA8B,IAAI,SAAS,cAAc,UAAU,GAAG;;CAG3F,IAAI,cAAsB;AACzB,SAAO,KAAK,UAAU;;CAGvB,WAAW,MAA0B;AACpC,SAAO,KAAK,SAAS,QAAQ,OAAO,UAAU;;;CAI/C,MAAM,MAA4B,MAAS,KAA8C;EACxF,MAAM,MAAM,GAAG,KAAK,GAAG;EACvB,IAAI,UAAU,MAAKD,OAAQ,IAAI,IAAI;AACnC,MAAI,CAAC,SAAS;AACb,aAAU,KAAK,OAAO,UAAU,MAAM,IAAI;AAC1C,SAAKA,OAAQ,IAAI,KAAK,QAAQ;;AAE/B,SAAO;;;CAIR,MAAM,WAAiC,MAA0C;EAChF,MAAM,UAAkC,EAAE;AAC1C,OAAK,IAAI,MAAM,GAAG,MAAM,KAAK,WAAW,KAAK,EAAE,MAC9C,MAAK,MAAM,UAAU,MAAM,KAAK,MAAM,MAAM,IAAI,CAAE,SAAQ,KAAK,OAAO,OAAO;AAE9E,SAAO;;;CAIR,MAAM,aAAa,YAAmE;AACrF,UAAQ,MAAM,KAAK,OAAO,WAAW,EAAE;;;CAIxC,MAAM,eAAe,YAAkD;AACtE,UAAQ,MAAM,KAAK,OAAO,WAAW,EAAE;;CAGxC,AAAQ,OAAO,YAA+C;EAC7D,IAAI,UAAU,MAAKC,OAAQ,IAAI,WAAW;AAC1C,MAAI,CAAC,SAAS;AACb,aAAU,KAAK,GACb,WAAW,iBAAiB,CAC5B,UAAU,uBAAuB,0BAA0B,+BAA+B,CAC1F,OAAO;IACP;IACA;IACA;IACA,CAAC,CACD,MAAM,4BAA4B,KAAK,WAAW,CAClD,SAAS,CACT,MAAM,UAAU;IAChB,SAAS,IAAI,IACZ,KAAK,KAAK,QAAQ,CAAC,IAAI,MAAM,kBAAkB,IAAI,YAAY,CAAC,CAAU,CAC1E;IACD,UAAU,IAAI,IACb,KAAK,QAAQ,QAAQ,OAAO,IAAI,SAAS,KAAK,EAAE,CAAC,KAAK,QAAQ,IAAI,KAAK,CACvE;IACD,EAAE;AACJ,SAAKA,OAAQ,IAAI,YAAY,QAAQ;;AAEtC,SAAO;;;;;;;CAQR,MAAM,UAAU,OAAe,UAAyC;EACvE,MAAM,SAAS,MAAM,KAAK,GACxB,WAAW,gCAAgC,CAC3C,OAAO;GACP,gBAAgB,KAAK,SAAS;GAC9B,cAAc,KAAK,UAAU;GAC7B,aAAa;GACb,aAAa,GAAG,MAAM,GAAG,SAAS,KAAK,GAAG,SAAS,IAAI,GAAG,SAAS;GACnE,WAAW;GACX,CAAC,CACD,YAAY,aACZ,SAAS,QAAQ;GAAC;GAAgB;GAAe;GAAc,CAAC,CAAC,WAAW,CAC5E,CACA,kBAAkB;AACpB,OAAK,eAAe,OAAO,OAAO,4BAA4B,GAAG,GAAG;;CAGrE,gBAAgB,WAA8C;AAC7D,MAAI,cAAc,OAAW,QAAO;EACpC,MAAM,WAAW,KAAK,KAAK,UAAU;AACrC,SAAO,OAAO,OAAO,UAAU,UAAU,GAAI,SAAS,cAAc,OAAQ;;;;;;;;CAS7E,MAAM,iBACL,SACA,OACe;EACf,MAAM,2BAAW,IAAI,KAAa;EAClC,IAAI,SAAS;AACb,OAAK,MAAM,QAAQ,OAAO;AACzB,OAAI,CAAC,KAAK,SAAS,yBAAyB,CAAE;AAC9C,YAAS;AACT,QAAK,MAAM,SAAS,KAAK,SAAS,kBAAkB,CACnD,KAAI,MAAM,OAAO,OAAW,UAAS,IAAI,MAAM,GAAG;;AAGpD,MAAI,CAAC,OAAQ,QAAO,CAAC,GAAG,QAAQ;EAChC,MAAM,eAAe,MAAM,KAAK,SAAS,QAAQ,0BAA0B,CAAC,GAAG,SAAS,CAAC;AACzF,SAAO,QAAQ,KAAK,WAAW;GAC9B,MAAM,SAAS,iBAAiB,QAAQ;IAAE,MAAM;IAAU;IAAc,CAAC;GACzE,MAAM,QAAQ,OAAO,OAAO;AAC5B,OAAI,MACH,OAAM,IAAI,cAAc,8BAA8B,8BAA8B,EACnF,QAAQ;IAAE,MAAM,OAAO;IAAM,IAAI,OAAO;IAAI,MAAM,MAAM;IAAM,EAC9D,CAAC;AAEH,UAAO,OAAO;IACb;;;CAIH,iBAAuC;AACtC,QAAKC,mBAAoB,KAAK,GAC5B,WAAW,gCAAgC,CAC3C,OAAO,cAAc,CACrB,UAAU,CACV,MAAM,gBAAgB,KAAK,KAAK,UAAU,GAAG,CAC7C,SAAS,CACT,MAAM,SAAS,IAAI,IAAI,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,OAAO,iBAAiB,CAAC,CAAC;AACtF,SAAO,MAAKA;;CAGb,YAAY,MAAwB;AAEnC,QAAKA,kBADW,MAAKA,kBACc,QAAQ,wBAAQ,IAAI,KAAa,CAAC,EAAE,MAAM,UAC5E,MAAM,IAAI,KAAK,CACf;;;;;;CAOF,MAAM,aACL,MACA,SAC+B;EAC/B,MAAM,YAAY,MAAM,KAAK,gBAAgB;EAC7C,MAAM,yBAAS,IAAI,KAAqB;AACxC,MAAI,UAAU,SAAS,EAAG,QAAO;EACjC,MAAM,yBAAS,IAAI,KAA0B;EAC7C,MAAM,QAAQ,YAAwB,OAAgB;AACrD,OAAI,OAAO,OAAO,YAAY,CAAC,UAAU,IAAI,WAAW,CAAE;GAC1D,IAAI,MAAM,OAAO,IAAI,WAAW;AAChC,OAAI,CAAC,IAAK,QAAO,IAAI,YAAa,sBAAM,IAAI,KAAK,CAAE;AACnD,OAAI,IAAI,GAAG;;AAEZ,OAAK,MAAM,UAAU,SAAS;AAC7B,QAAK,MAAM,OAAO,GAAG;AACrB,QAAK,MAAM,aAAa,gBAAgB,OAAO;AAC9C,QAAI,UAAU,OAAO,KAAM;AAC3B,SAAK,MAAM,UAAU,UAAU,QAAS,MAAK,QAAQ,OAAO,UAAU,UAAU;;;AAGlF,OAAK,MAAM,CAAC,YAAY,QAAQ,OAC/B,MAAK,MAAM,CAAC,YAAY,aAAa,MAAM,KAAK,SAAS,QAAQ,YAAY,CAAC,GAAG,IAAI,CAAC,CACrF,QAAO,IAAI,GAAG,WAAW,QAAQ,cAAc,SAAS;AAG1D,SAAO;;;AAIT,SAAS,iBAAiB,OAAwB;AACjD,QAAO,kBAAkB,IAAI,MAAM;;AAGpC,SAAS,kBAAkB,OAAgC;AAC1D,SAAQ,OAAR;EACC,KAAK;EACL,KAAK;EACL,KAAK,OACJ,QAAO;EACR,QACC,QAAO;;;;AAKV,SAAgB,kBACf,QACA,WACI;AACJ,KAAI,UAAU,SAAS,EAAG,QAAO;CACjC,MAAM,OAAgC,EAAE,GAAG,QAAQ;CACnD,MAAM,MAAM,UAAU,IAAI,GAAG,OAAO,KAAK,QAAQ,OAAO,KAAK;AAC7D,KAAI,QAAQ,OAAW,MAAK,KAAK;AACjC,MAAK,MAAM,aAAa,gBAAgB,OAAO,OAAO;AACrD,MAAI,UAAU,OAAO,KAAM;EAC3B,MAAM,QAAQ,KAAK,UAAU;AAC7B,MAAI,OAAO,UAAU,SAAU;AAC/B,OAAK,MAAM,UAAU,UAAU,SAAS;GACvC,MAAM,SAAS,UAAU,IAAI,GAAG,OAAO,QAAQ,QAAQ;AACvD,OAAI,WAAW,QAAW;AACzB,SAAK,UAAU,YAAY;AAC3B;;;;AAKH,QAAO;;;;;;;;;AChRR,MAAM,YAAY;;;;;;AAOlB,eAAsB,aAAa,GAAG,OAAkC;CACvE,MAAM,MAAM,MAAM,UAAU,MAAM,KAAK,KAAS,CAAC;CACjD,IAAI,OAAO,OAAO,KAAK,IAAI,MAAM,GAAG,GAAG,GAAG;CAC1C,IAAI,KAAK;AACT,MAAK,IAAI,QAAQ,GAAG,QAAQ,IAAI,SAAS;AACxC,OAAK,UAAU,OAAO,OAAO,IAAI,IAAI;AACrC,WAAS;;AAEV,QAAO;;;AAIR,eAAsB,QAAQ,QAAgB,SAAkC;CAC/E,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,MAAM,MAAM,OAAO,OAAO,UAC/B,OACA,QAAQ,OAAO,OAAO,EACtB;EAAE,MAAM;EAAQ,MAAM;EAAW,EACjC,OACA,CAAC,OAAO,CACR;CACD,MAAM,YAAY,MAAM,OAAO,OAAO,KAAK,QAAQ,KAAK,QAAQ,OAAO,QAAQ,CAAC;AAChF,QAAO,MAAM,KAAK,IAAI,WAAW,UAAU,GAAG,SAAS,KAAK,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAAC,KAC1F,GACA;;;;;;;;;;;;;;;;;;;ACKF,MAAM,SAAS,CAAC,KAAK;AAErB,eAAe,4BAA4B,QAAyC;AACnF,KAAI,OAAO,SAAS,qBAAsB,OAAM,IAAI,MAAM,gCAAgC;CAE1F,MAAM,SAAS,OAAO;AACtB,QAAO,EAAE,aAAa,MAAM,uBAAuB,OAAO,EAAE;;AAG7D,MAAM,aAAyD;CAC9D,YAAY,EAAE,KAAK,QAAQ;CAC3B,oBAAoB;EACnB,KAAK;EACL,UAAU,UAAU,WAAW,4BAA4B,OAAO;EAClE;CACD,cAAc,EAAE,KAAK,QAAQ;CAC7B,UAAU,EAAE,KAAK,QAAQ;CACzB,cAAc,EAAE,KAAK,QAAQ;CAC7B,cAAc,EAAE,KAAK,QAAQ;CAC7B,OAAO,EAAE,KAAK,QAAQ;CACtB,MAAM,EAAE,KAAK,QAAQ;CACrB,QAAQ,EAAE,KAAK,QAAQ;CACvB,oBAAoB,EAAE,KAAK,CAAC,aAAa,WAAW,EAAE;CACtD,0BAA0B,EAAE,KAAK,CAAC,qBAAqB,WAAW,EAAE;CACpE,UAAU,EAAE,KAAK,QAAQ;CACzB,cAAc,EAAE,KAAK;EAAC;EAAc;EAAY;EAAc,EAAE;CAChE,gBAAgB,EAAE,KAAK,QAAQ;CAC/B,mBAAmB,EAAE,KAAK,QAAQ;CAClC,KAAK,EAAE,KAAK,CAAC,cAAc,aAAa,EAAE;CAC1C,MAAM,EAAE,KAAK,QAAQ;CACrB,WAAW,EAAE,KAAK,QAAQ;CAC1B,aAAa,EAAE,KAAK,QAAQ;CAC5B,QAAQ,EAAE,KAAK,QAAQ;CACvB,SAAS,EAAE,KAAK,QAAQ;CACxB,UAAU;EACT,KAAK;EACL,gBAAgB;GAAE,iBAAiB,MAAM;GAAE,cAAc;GAAG,kBAAkB;GAAG;EACjF;CACD,SAAS,EAAE,KAAK,QAAQ;CACxB,kBAAkB;EACjB,KAAK;EACL,SAAS,OAAO,SAAS,YAAY,EACpC,YAAY,MAAM,QAAQ,QAAQ,UAAU,eAAe,oBAAoB,OAAO,KAAK,EAC3F;EACD;CACD,SAAS;EACR,KAAK,CAAC,OAAO;EACb,UAAU;GAAE,MAAM;GAAU,QAAQ,CAAC,OAAO;GAAE,QAAQ,CAAC,SAAS,WAAW;GAAE;EAC7E,gBAAgB,EAAE,UAAU,MAAM,EAAE;EACpC;CACD;AAED,MAAM,mCAAmB,IAAI,KAAK;;;;;;AAOlC,MAAa,uBAAuB;;AAGpC,MAAM,sBAAsB,cAAc,EAAE;AAE5C,SAAgB,WAAW,MAAoC;AAC9D,QAAO,OAAO,OAAO,YAAY,KAAK;;AAGvC,SAAS,QAAQ,MAAgB;CAChC,MAAM,OAAO,4BAA4B,KAAK;AAC9C,KAAI,CAAC,KAAM,OAAM,IAAI,MAAM,qBAAqB,OAAO;AACvD,QAAO;;;AAIR,SAAgB,cAAc,MAAgB,OAAuB;CACpE,MAAM,OAAO,QAAQ,KAAK;CAC1B,MAAM,cAAc,SACnB,mBAAmB,MAAM,OAAO,KAAK,KAAK,QAAQ,CAAC,QAAQ,WAAW,MAAM,IAAI,OAAO,GAAG;AAC3F,KAAI,SAAS,WAAY,QAAO,WAAW,MAAM;AAEjD,QADgB,KAAK,KAAK,QAAQ,oBAAoB,IACpC,IAAI,WAAW,oBAAoB;;;AAetD,eAAsB,aACrB,SACA,MACA,QACA,UAAwB,EAAE,EACQ;CAClC,MAAM,UAAU,gBAAgB,QAAQ;CACxC,MAAM,WAAW,OAAO,QAAQ,UAAU,SAAS,aAAa,CAAC,QAAQ,IAAI,MAAM,OAAO,GAAG,CAAC;AAC9F,KAAI,SAAS,WAAW,EAAG,QAAO,EAAE;CACpC,MAAM,cAAc,SAAS,KAAK,UACjC,qBAAqB,MAAM,QAAQ,QAAQ,MAAM,EAAE,kBAAkB,kBAAkB,CAAC,CACxF;CACD,MAAM,WAAW,MAAM,QAAQ,iBAC9B,aACA,SAAS,KAAK,UAAU,MAAM,KAAK,CACnC;AACD,KAAI,SAAS,YAAY;AACxB,QAAM,cAAc,SAAS,MAAM,UAAU,SAAS,MAAM;AAC5D,SAAO;;CAER,MAAM,UAAkC,EAAE;AAC1C,MAAK,IAAI,QAAQ,GAAG,QAAQ,SAAS,QAAQ,SAAS,qBAAqB;EAK1E,MAAM,UAFY,MAAM,mBAAmB,SAF7B,SAAS,MAAM,OAAO,QAAQ,oBAAoB,CAE6B;AAG7F,QAAM,cAAc,SAAS,MAAM,SAAS,SAAS,MAAM;AAC3D,UAAQ,KAAK,GAAG,QAAQ;;AAEzB,QAAO;;;;;;;;;;;;AAaR,eAAe,mBACd,SACA,SAC2C;CAC3C,MAAM,aAAa,QAAQ,QAAQ,WAAW,OAAO,WAAW,OAAO,gBAAgB,GAAG;AAC1F,KAAI,WAAW,WAAW,EAAG,QAAO,CAAC,GAAG,QAAQ;CAChD,MAAM,QAAQ,MAAM,iBAAiB,SAAS,WAAW;CAEzD,MAAM,0BAAU,IAAI,KAAa;AACjC,YAAW,SAAS,QAAQ,UAAU;EACrC,MAAM,UAAU,WAAW,MAAM,GAAG,MAAM,CAAC,QAAQ,UAAU,CAAC,QAAQ,IAAI,MAAM,GAAG,CAAC;EACpF,MAAM,QAAQ,CAAC;GAAE,MAAM,OAAO;GAAa,OAAO;GAAO,CAAC;EAC1D,MAAM,wBAAQ,IAAI,KAAa;AAC/B,SAAO,MAAM,SAAS,GAAG;GACxB,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO;AACrC,QAAK,MAAM,UAAU,MAAM,IAAI,KAAK,IAAI,EAAE,EAAE;AAE3C,QAAI,WAAW,OAAO,WAAW,SAAS,WAAW,OAAO;AAC3D,aAAQ,IAAI,OAAO,GAAG;AACtB;;AAED,SAAK,MAAM,SAAS,SAAS;AAC5B,SAAI,MAAM,WAAW,UAAU,MAAM,IAAI,MAAM,GAAG,CAAE;AACpD,WAAM,IAAI,MAAM,GAAG;AACnB,WAAM,KAAK;MAAE,MAAM,MAAM;MAAa,OAAO;MAAM,CAAC;;;;GAItD;AACF,KAAI,QAAQ,SAAS,EAAG,QAAO,CAAC,GAAG,QAAQ;AAC3C,OAAM,QAAQ,SAAS,QACtB,sBACA,MAAM,KAAK,UAAU,QAAQ;EAAE,YAAY;EAAI,UAAU;EAAI,EAAE,CAC/D;AACD,QAAO,QAAQ,KAAK,WAAY,QAAQ,IAAI,OAAO,GAAG,GAAG;EAAE,GAAG;EAAQ,SAAS;EAAO,GAAG,OAAQ;;;;;;;;;AAUlG,eAAe,iBACd,SACA,YACoC;CACpC,MAAM,SAAS,CAAC,GAAG,IAAI,IAAI,WAAW,KAAK,WAAW,OAAO,YAAY,CAAC,CAAC;CAC3E,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,WAAW,KAAK,WAAW,OAAO,OAAO,CAAC,CAAC;CACvE,MAAM,SAAS,MAAM,GAAoC;2CACf,IAAI,KAAK,OAAO,KAAK,SAAS,GAAG,IAAI,KAAK,GAAG,CAAC,CAAC;;;;;;;8BAO5D,IAAI,KAAK,WAAW,KAAK,WAAW,OAAO,GAAG,CAAC,CAAC;;iDAE7B,IAAI,KAAK,QAAQ,CAAC;GAChE,QAAQ,QAAQ,GAAG;CACrB,MAAM,wBAAQ,IAAI,KAA0B;AAC5C,MAAK,MAAM,OAAO,OAAO,MAAM;EAC9B,MAAM,UAAU,MAAM,IAAI,IAAI,MAAM,oBAAI,IAAI,KAAa;AACzD,UAAQ,IAAI,IAAI,KAAK;AACrB,QAAM,IAAI,IAAI,OAAO,QAAQ;;AAE9B,QAAO;;AAGR,SAAS,gBAAgB,SAA6C;CACrE,MAAM,EAAE,cAAc,QAAQ;AAC9B,QAAO,IAAI,IAAY,CACtB,GAAI,UAAU,cAAc,WAAW,sBAAsB,QAAQ,EAAE,EACvE,GAAI,UAAU,gBAAgB,WAAW,sBAAsB,UAAU,EAAE,CAC3E,CAAC;;AAGH,SAAS,UAAU,KAAwB,KAAkB;AAC5D,QAAO,IAAI,KAAK,WAAW,OAAO,IAAI,QAAQ,CAAC,CAAC,KAAK,KAAS;;AAG/D,SAAgB,eAAe,MAAkB,IAA2B;AAC3E,QAAO,IAAI,cACV,yBACA,4DACA,EAAE,QAAQ;EAAE;EAAM;EAAI,QAAQ;EAAmB,EAAE,CACnD;;;;;;;;;;;AAYF,SAAgB,iBACf,SACA,KACO;CACP,MAAM,SAAS;EAAE,MAAM,IAAI;EAAM,IAAI,IAAI;EAAI,QAAQ,IAAI;EAAQ;AACjE,KAAI,CAAC,QAAQ,aACZ,OAAM,IAAI,cACT,yBACA,4DACA,EAAE,QAAQ;EAAE,GAAG;EAAQ,QAAQ;EAAuB,EAAE,CACxD;AAEF,KAAI,CAAC,IAAI,WAAW,IAAI,UACvB,OAAM,IAAI,cACT,yBACA,+CACA,EACC,QAAQ;EAAE,GAAG;EAAQ,QAAQ;EAAa,EAC1C,CACD;;AAIH,eAAe,cACd,SACA,MACA,SACA,SACA,OACgB;CAChB,MAAM,OAAO,QAAQ,KAAK;CAC1B,MAAM,SAAS,WAAW;CAC1B,MAAM,YAAY,MAAM,QAAQ,aAAa,MAAM,QAAQ;CAC3D,MAAM,SAAsC,EAAE,GAAG,aAAa,KAAK,QAAQ,EAAE;CAC7E,MAAM,OAAc,EAAE;AACtB,MAAK,MAAM,UAAU,SAAS;EAC7B,MAAM,SAAS,kBAAkB,QAAQ,UAAU;EACnD,MAAM,MAAM;GACX,GAAG,aAAa,QAAQ,IAAI,KAAK,SAAS,QAAQ;IAAE;IAAM,IAAI,OAAO;IAAI,CAAC;GAC1E,GAAI,OAAO,UAAU,MAAM,OAAO,QAAQ,SAAS,OAAO,GAAG,EAAE;GAC/D;EACD,MAAM,QAAQ,QAAQ,QAAQ,OAAO;AACrC,MAAI,OAAO;AACV,UAAO,OAAO,KAAK,MAAM,IAAI;AAC7B,UAAO,OAAO,QAAQ,MAAM,OAAO;;AAEpC,OAAK,KAAK,IAAI;;CAEf,MAAM,UAAU,OAAO,KAAK,KAAK,MAAM,EAAE,CAAC;CAC1C,MAAM,aAAa,MAAM,gBAAgB,QAAQ,IAAI,OAAO,QAAQ;AACnE,QAAM,WAAW,KAAK,KAAK,OAAO,SAAS,MAAM,OAAO,SAAS;EACjE,MAAM,SAAS,IAAI,KACjB,MAAM,aAAa,KAAK,KAAK,OAAO,OAAO,KAAK,KAAK,EAAE,KAAK,QAAQ,CACpE,UAAU,OAAO,KAAK,IAAI,EAC1B,IACA,CAAC,CACF;EACD,MAAM,QAAgC,EAAE;AACxC,OAAK,SAAS,KAAK,UAAU;GAC5B,MAAM,SAAS,QAAQ;AACvB,OAAI,CAAC,OAAQ;GACb,MAAM,WAAW,OAAO,IAAI,UAAU,OAAO,KAAK,IAAI,CAAC;AACvD,OAAI,CAAC,SAAU,OAAM,eAAe,MAAM,OAAO,GAAG;GACpD,MAAM,SAAS,gBAAgB,QAAQ,IAAI,QAAQ,KAAK,UAAU,EAAE,QAAQ,QAAQ,QAAQ,CAAC;AAC7F,OAAI,WAAW,KAAM;AACrB,oBAAiB,SAAS;IACzB;IACA,IAAI,OAAO;IACX;IACA,SAAS,OAAO,QAAQ;IACxB,WAAW,SAAS,UAAU,IAAI,GAAG,KAAK,QAAQ,OAAO,KAAK;IAC9D,CAAC;AACF,SAAM,KAAK,OAAO;IACjB;AACF,SAAO;GACN;AACF,KAAI,WAAW,WAAW,EAAG;CAE7B,MAAM,WAAW,MAAM,QAAQ,IAC9B,WAAW,IAAI,OAAO,YAAY;EACjC,YAAY,OAAO;EACnB,UAAU,MAAM,aAAa,QAAQ,aAAa,MAAM,OAAO,GAAG;EAClE,EAAE,CACH;AACD,OAAM,QAAQ,SAAS,QAAQ,MAAM,SAAS;AAC9C,SAAQ,YAAY,KAAK;AACzB,OAAM,cAAc,SAAS,MAAM,YAAY,SAAS,KAAK;;;;;ACjV9D,MAAM,kBAAkB,aAAa,sBAAsB;AAC3D,MAAM,mBAAmB,OAAO,KAAK,gBAAgB;AAErD,SAAgB,aAAa,YAA4B;AACxD,oBAAmB,YAAY,kBAAkB;AACjD,QAAO,GAAG,uBAAuB;;;AAIlC,SAAgB,mBAAmB,OAAe,YAA4B;CAC7E,MAAM,UAAU,iBAAiB,SAAS;AAC1C,KAAI,cAAc,QAAQ,KAAK,EAC9B,QAAO,SAAS,IAAI,KAAK,KAAK,aAAa,GAAG,IAAI,KAAK,KAAK,QAAQ,IAAI,GAAG;AAE5E,QAAO,mBAAmB,OAAO,QAAQ,GAAG;;AAG7C,eAAsB,aACrB,SACA,QACgB;CAChB,MAAM,+BAAe,IAAI,KAAyC;AAClE,MAAK,MAAM,SAAS,QAAQ;EAC3B,MAAM,OAAO,aAAa,IAAI,MAAM,OAAO,WAAW,IAAI,EAAE;AAC5D,OAAK,KAAK,MAAM;AAChB,eAAa,IAAI,MAAM,OAAO,YAAY,KAAK;;AAEhD,MAAK,MAAM,CAAC,YAAY,UAAU,cAAc;EAC/C,MAAM,eAAe,MAAM,QAAQ,aAAa,WAAW;EAC3D,MAAM,mBAAmB,IAAI,IAAI,CAAC,CAAC,YAAY,aAAa,CAAC,CAAC;EAC9D,MAAM,cAAc,MAAM,KAAK,UAC9B,qBAAqB,MAAM,QAAQ,QAAQ,MAAM,EAAE,kBAAkB,CAAC,CACtE;AAKD,QAAM,uBAAuB,SAAS,YAAY,cAJjC,MAAM,QAAQ,iBAC9B,aACA,MAAM,KAAK,UAAU,MAAM,KAAK,CAChC,EACyE,MAAM;;;AAIlF,SAAS,YACR,cAC8B;CAC9B,MAAM,SAAsC,EAAE;AAC9C,MAAK,MAAM,CAAC,MAAM,eAAe,aAAc,QAAO,QAAQ,mBAAmB,WAAW;AAC5F,QAAO;;AAGR,SAAS,SACR,IACA,QACA,QACA,UACM;CACN,MAAM,MAAM,aAAa,IAAI,uBAAuB,QAAQ;EAAE,MAAM;EAAS,IAAI,OAAO;EAAI,CAAC;AAC7F,MAAK,MAAM,QAAQ,OAAO,KAAK,OAAO,OAAO,CAC5C,KAAI,CAAC,OAAO,OAAO,QAAQ,KAAK,CAC/B,OAAM,IAAI,cAAc,2BAA2B,0CAA0C,EAC5F,QAAQ;EAAE,MAAM;EAAS,IAAI,OAAO;EAAI,OAAO;EAAM,EACrD,CAAC;AAGJ,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,OAAO,CACjD,KAAI,QAAQ,YACX,IACA,OACA,OAAO,OAAO,OACd;EAAE,MAAM;EAAS,IAAI,OAAO;EAAI,QAAQ;EAAM,EAC9C,EAAE,SAAS,SAAS,IAAI,KAAK,EAAE,CAC/B;AAEF,QAAO;;AAGR,eAAe,uBACd,SACA,YACA,cACA,SACA,OACgB;CAChB,MAAM,QAAQ,aAAa,WAAW;CACtC,MAAM,SAAS,YAAY,aAAa;CACxC,MAAM,WAAW,MAAM,QAAQ,eAAe,WAAW;CACzD,MAAM,SAAS;EAAE,GAAG;EAAiB,GAAG;EAAQ;CAChD,MAAM,YAAY,MAAM,QAAQ,aAAa,SAAS,QAAQ;CAC9D,MAAM,OAAO,QAAQ,KAAK,WACzB,SAAS,QAAQ,IAAI,kBAAkB,QAAQ,UAAU,EAAE,QAAQ,SAAS,CAC5E;CACD,MAAM,UAAU,OAAO,KAAK,OAAO;CACnC,MAAM,OAAO,cAAc,QAAQ,OAAO,KAAK;CAE/C,MAAM,aAAa,MAAM,gBAAgB,QAAQ,IAAI,OAAO,QAAQ;AACnE,QAAM,WAAW,KAAK,OAAO,OAAO,mBAAmB,SAAS,KAAK;EACrE,IAAI,SAAS,MAAM,WAAW,KAAK,OAAO,KAAK;AAC/C,MAAI,MAAM;GACT,MAAM,aAAa,OAAO,KAAK,OAAO;AACtC,QAAK,MAAM,OAAO,MAAM;IACvB,MAAM,WAAW,OAAO,IAAI,OAAO,IAAI,GAAG,CAAC;AAC3C,QACC,CAAC,YACD,gBAAgB,QAAQ,IAAI,iBAAiB,KAAK,UAAU,EAC3D,QAAQ,QAAQ,QAChB,CAAC,KAAK,KAEP;AAED,UAAM,cAAc,KAAK,OAAO,MAAM,OAAO,IAAI,GAAG,EAAE,KAAK,WAAW;;AAEvE,YAAS,MAAM,WAAW,KAAK,OAAO,KAAK;;EAG5C,MAAM,QAAuB,EAAE;AAC/B,OAAK,SAAS,KAAK,UAAU;GAC5B,MAAM,SAAS,QAAQ;AACvB,OAAI,CAAC,OAAQ;GACb,MAAM,WAAW,OAAO,IAAI,OAAO,IAAI,GAAG,CAAC;AAC3C,OAAI,CAAC,SAAU,OAAM,eAAe,SAAS,OAAO,GAAG;GACvD,MAAM,SAAS,gBAAgB,QAAQ,IAAI,QAAQ,KAAK,UAAU,EACjE,QAAQ,QAAQ,QAChB,CAAC;AACF,OAAI,WAAW,KAAM;AACrB,oBAAiB,SAAS;IACzB,MAAM;IACN,IAAI,OAAO;IACX;IACA,SAAS;IACT,WAAW,SAAS,UAAU,IAAI,cAAc,OAAO,KAAK;IAC5D,CAAC;AACF,SAAM,KAAK,OAAO;IACjB;AACF,SAAO;GACN;AACF,KAAI,WAAW,WAAW,EAAG;CAE7B,MAAM,WAAW,MAAM,QAAQ,IAC9B,WAAW,IAAI,OAAO,YAAY;EACjC,YAAY,OAAO;EACnB,UAAU,MAAM,aAAa,QAAQ,aAAa,SAAS,OAAO,GAAG;EACrE,EAAE,CACH;AACD,OAAM,QAAQ,SAAS,QAAQ,SAAS,SAAS;AACjD,SAAQ,YAAY,QAAQ;AAC5B,OAAM,uBAAuB,SAAS,YAAY,cAAc,YAAY,KAAK;;AAGlF,eAAe,WACd,IACA,OACA,MAC4B;CAC5B,MAAM,SAAS,MAAM,aAAa,IAAI,OAAO,CAAC,KAAK,EAAE,KAAK;AAC1D,QAAO,IAAI,IAAI,OAAO,KAAK,QAAQ,CAAC,OAAO,IAAI,GAAG,EAAE,IAAI,CAAC,CAAC;;;;;;;;;;;;;;;;AC9J3D,MAAM,YAAY;AAClB,MAAM,iBAAiB;AAEvB,SAAgB,eAAe,QAA4D;CAC1F,MAAM,WAAW,UAAU,KAAK,OAAO,SAAS,GAAG;AACnD,KAAI,SAAU,QAAO,SAAS,aAAa;CAC3C,MAAM,WAAW,KAAK,aAAa,OAAO,SAAS;AACnD,QAAO,YAAY,eAAe,KAAK,SAAS,GAAG,IAAI,aAAa;;AAGrE,eAAsB,gBACrB,SACA,QACkB;AAClB,QAAO,GAAG,MAAM,aAAa,QAAQ,aAAa,SAAS,OAAO,GAAG,GAAG,eAAe,OAAO;;;AAI/F,eAAsB,UAAU,SAAwB,QAAsC;CAC7F,MAAM,SAAS,MAAM,IAAI,6BAA6B,QAAQ,GAAG,CAAC,IACjE,QAAQ,aACR,cAAc,OAAO,KAAK,CAC1B;AACD,KAAI,CAAC,UAAU,OAAO,UAAU,WAC/B,OAAM,IAAI,cAAc,+BAA+B,4BAA4B,EAClF,QAAQ;EAAE,MAAM;EAAS,IAAI,OAAO;EAAI,EACxC,CAAC;AAEH,QAAO,OAAO;;;AAIf,MAAa,uBAAuB;AAEpC,eAAsB,WACrB,SACA,OACA,OACgB;CAChB,MAAM,SAAS,MAAM;CACrB,MAAM,aAAa,MAAM,gBAAgB,SAAS,OAAO;AACzD,OAAM,QAAQ,SAAS,IAAI,0BAA0B;EACpD,YAAY,OAAO;EACnB,UAAU;EACV,CAAC;CAGF,MAAM,YADY,MAAM,QAAQ,aAAa,SAAS,CAAC,OAAO,CAAC,EACpC,IAAI,cAAc,OAAO,KAAK,IAAI,OAAO;CACpE,MAAM,WAAW,MAAM,QAAQ,GAC7B,WAAW,QAAQ,CACnB,OAAO,CAAC,eAAe,SAAS,CAAC,CACjC,MAAM,MAAM,KAAK,SAAS,CAC1B,kBAAkB;CAEpB,IAAI,cAA6B;CACjC,MAAM,OAAO,UAAU,gBAAgB;AACvC,KAAI,KAMH,gBALe,MAAM,QAAQ,GAC3B,WAAW,QAAQ,CACnB,OAAO,eAAe,CACtB,MAAM,MAAM,KAAK,SAAS,CAC1B,yBAAyB,EACN;MACf;EACN,MAAM,QAAQ,IAAI,gBAAgB,QAAQ,GAAG;AAC7C,MAAI,CAAE,MAAM,MAAM,iBAAiB,WAAW,CAC7C,OAAM,MAAM,oBAAoB,UAAU,WAAW;AAEtD,gBAAc,MAAM,SAAS,SAAS,QAAQ,YAAY,MAAM;;AAGjE,OAAM,aAAa,SAAS,SAAS,CAAC,MAAM,EAAE,EAC7C,cAAc;EACb,KAAK;GAAE,aAAa;GAAY,cAAc;GAAa,QAAQ;GAAS;EAC5E,QAAQ;GAAE,aAAa;GAAQ,QAAQ;GAAQ;EAC/C,GACD,CAAC;AACF,KAAI,CAAC,KAAM,OAAM,IAAI,gBAAgB,QAAQ,GAAG,CAAC,oBAAoB,WAAW;;AAGjF,eAAe,SACd,SACA,QACA,YACA,OACyB;CACzB,MAAM,WAAyB,EAAE;CACjC,IAAI,gBAAgB;CACpB,MAAM,cAAc,QAAQ,KAAK,SAAS;CAC1C,MAAM,MAAM,IAAI,gBAAwC,EACvD,UAAU,OAAO,YAAY;AAC5B,MAAI,eAAe,gBAAgB,MAAM,cAAc,wBAAwB;AAC9E,YAAS,KAAK,MAAM,OAAO,CAAC;AAC5B,oBAAiB,MAAM;;AAExB,aAAW,QAAQ,MAAM;IAE1B,CAAC;CACF,MAAM,QAAQ,MAAM,QAAQ,OAAO,KAAK,OAAO,KAAK,EAAE,YAAY,IAAI;AACtE,OAAM,YACL,QAAQ,SACR,YACA,MACA;EAAE;EAAO,QAAQ,OAAO;EAAM,EAC9B,EAAE,aAAa,OAAO,UAAU,CAChC;AACD,KAAI,CAAC,eAAe,kBAAkB,MAAO,QAAO;CACpD,MAAM,MAAM,IAAI,WAAW,cAAc;CACzC,IAAI,SAAS;AACb,MAAK,MAAM,QAAQ,UAAU;AAC5B,MAAI,IAAI,MAAM,OAAO;AACrB,YAAU,KAAK;;AAEhB,QAAO,mBAAmB,IAAI;;;;;;;;;;;AC/G/B,MAAa,0BAA0B;;;;;;;AAQvC,MAAa,yBAAyB;;;;;;AAOtC,MAAa,gBAA4E;CACxF,GAAG;CACH,QAAQ,mBAAmB,OAAO,QAAQ,SAAS,SAAS,QAAQ;CACpE,WAAW,mBAAmB,UAAU,SAAS,SAChD,SAAS,mBAAmB,CAAC,MAAM,QAAQ,GAAG,CAAC,KAAK,CACpD;CACD;AAED,MAAM,gBAAgB;AACtB,MAAM,cAAc;AACpB,MAAM,wBAAwB;;AAG9B,IAAa,wBAAb,cAA2C,MAAM;AAIjD,SAAgB,cAAc,OAA0C;CACvE,MAAM,OAAO,cAAc,OAAO;AAClC,KAAI,CAAC,KAAM,OAAM,IAAI,MAAM,SAAS,MAAM,iBAAiB;AAC3D,QAAO;EAAE;EAAM,KAAK;EAAG,MAAM;EAAG;;;;;;AAOjC,eAAsB,eACrB,SACA,OACA,OACA,YACiC;CACjC,MAAM,UAAU,cAAc;CAC9B,IAAI,WAAkC;AACtC,QAAO,UAAU;EAChB,MAAM,YAAY,QAAQ,QAAQ,SAAS,KAAK;AAChD,MAAI,cAAc,GACjB,OAAM,IAAI,cAAc,0BAA0B,wCAAwC;AAE3F,MAAI,SAAS,OAAO,QAAQ,WAAW,SAAS,KAAK,EAAE;GACtD,MAAM,OAAO,QAAQ,YAAY;AACjC,cAAW,OAAO;IAAE,MAAM;IAAM,KAAK;IAAG,MAAM;IAAG,GAAG;AACpD;;EAED,MAAM,QAAQ,MAAM,QAAQ,MAAM,SAAS,MAAM,SAAS,IAAI;AAC9D,MAAI,SAAS,QAAQ,MAAM,QAAQ;AAClC,cAAW;IAAE,MAAM,SAAS;IAAM,KAAK,SAAS,MAAM;IAAG,MAAM;IAAG;AAClE;;EAED,MAAM,OAAO,MAAM,SAAS,SAAS,OAAO,UAAU,MAAM;AAC5D,MAAI,CAAC,QAAQ,OAAO,SAAS;GAAE,SAAS,KAAK,UAAU;GAAG,OAAO,KAAK;GAAO,CAAC,CAC7E,QAAO;AAER,UAAQ,OAAO,MAAM,KAAK,MAAM;AAChC,QAAM,QAAQ,UAAU,OAAO,SAAS;AACxC,QAAM,KAAK,KAAK;EAChB,MAAM,OAAO,SAAS,OAAO,KAAK;AAClC,aACC,QAAQ,MAAM,SACX;GAAE,MAAM,SAAS;GAAM,KAAK,SAAS,MAAM;GAAG,MAAM;GAAG,GACvD;GAAE,MAAM,SAAS;GAAM,KAAK,SAAS;GAAK;GAAM;AACpD,QAAM,WAAW,SAAS;;AAE3B,QAAO;;AAUR,eAAe,SACd,SACA,OACA,UACA,OACgB;CAChB,MAAM,OAAO,SAAS;CACtB,MAAM,OAAO,MAAM,MAAM,SAAS,KAAK;AAEvC,KAAI,SAAS,cAAc;EAC1B,MAAM,CAAC,UAAU;AACjB,MAAI,CAAC,UAAU,OAAO,OAAO,SAAS,aAAc,OAAM,IAAI,MAAM,wBAAwB;EAC5F,MAAM,SAAS,OAAO;AACtB,SAAO;GACN,OAAO;GACP,SAAS;GACT,OAAO;GACP,WAAW,iBAAiB,SAAS,OAAO;GAC5C;;AAGF,KAAI,SAAS,SAAS;EACrB,MAAM,CAAC,UAAU;AACjB,MAAI,CAAC,UAAU,OAAO,OAAO,SAAS,QAAS,OAAM,IAAI,MAAM,0BAA0B;EACzF,MAAM,QAAQ;GAAE,QAAQ,OAAO;GAAQ,MAAM,OAAO;GAAM;EAC1D,MAAM,QAAQ,MAAM,UAAU,SAAS,OAAO,OAAO;AACrD,SAAO;GACN,OAAO;GACP,SAAS;GACT;GACA,WAAW,WAAW,SAAS,OAAO,MAAM;GAC5C;;AAGF,KAAI,SAAS,SAAS;EACrB,MAAM,QAAQ,SAAS,SAAS,KAAK,MAAM,GAAG,YAAY,CAAC;AAC3D,MAAI,UAAU,YACb,QAAO;GACN,OAAO,MAAM;GACb,SACC,IACA,KAAK,KAAK,MAAM,SAAS,eAAe,GAAG,IAC3C,cAAc,kBAAkB,MAAM,OAAO;GAC9C,OAAO;GACP,WAAW,2BAA2B,SAAS,MAAM;GACrD;EAEF,IAAI,UAAU;EACd,MAAM,gCAAgB,IAAI,KAAqB;AAC/C,OAAK,MAAM,SAAS,MACnB,eAAc,IACb,MAAM,OAAO,aACZ,cAAc,IAAI,MAAM,OAAO,WAAW,IAAI,KAAK,EACpD;AAEF,OAAK,MAAM,CAAC,YAAY,UAAU,eAAe;GAChD,MAAM,SAAS,MAAM,QAAQ,aAAa,WAAW;AACrD,cAAW,mBAAmB,OAAO,OAAO,KAAK;;AAElD,SAAO;GAAE,OAAO,MAAM;GAAQ;GAAS,OAAO;GAAG,WAAW,aAAa,SAAS,MAAM;GAAE;;AAG3F,KAAI,CAAC,WAAW,KAAK,CACpB,OAAM,IAAI,cAAc,0BAA0B,wCAAwC;CAE3F,MAAM,QAAQ,KAAK,MAAM,GAAG,cAAc;AAC1C,QAAO;EACN,OAAO,MAAM;EACb,SAAS,cAAc,MAAM,MAAM,OAAO;EAC1C,OAAO;EACP,KAAK,YAAY;AAGhB,SAAM,aAAa,SAAS,MAFb,MAAM,KAAK,YAAY;IAAE,QAAQ,OAAO;IAAQ,MAAM,OAAO;IAAM,EAAE,CAET;AAC3E,OAAI,SAAS,SACZ,OAAM,sBAAsB,SAAS,SAAS,UAAU,MAAM,CAAC;;EAGjE;;AAGF,SAAS,SACR,MACA,QACuB;AACvB,QAAO,OAAO,KAAK,SAAS;AAC3B,MAAI,KAAK,OAAO,SAAS,KAAM,OAAM,IAAI,MAAM,YAAY,KAAK,UAAU;AAE1E,SAAO;GAAE,QAAQ,KAAK;GAA2B,MAAM,KAAK;GAAM;GACjE;;AAGH,eAAe,iBACd,SACA,QACgB;CAChB,MAAM,UAAU,MAAM,QAAQ,WAAW,QAAQ,EAAE,QACjD,UAAU,MAAM,iBAAiB,OAAO,GACzC;AACD,KAAI;AACH,QAAM,IAAI,eAAe,QAAQ,GAAG,CAAC,iBAAiB,QAAQ,QAAQ,EAAE,QAAQ,MAAM,CAAC;UAC/E,OAAO;AACf,MAAI,iBAAiB,YACpB,OAAM,IAAI,cAAc,yBAAyB,oCAAoC;GACpF,QAAQ;IAAE,MAAM;IAAc,IAAI,OAAO;IAAI,QAAQ,MAAM;IAAM;GACjE,OAAO;GACP,CAAC;AAEH,QAAM;;;;;;;AAQR,eAAe,sBACd,SACA,QACgB;CAChB,MAAM,WAAW,OAAO,SAAS,EAAE,aAClC,OAAO,kBAAkB,UAAa,QAAQ,gBAAgB,OAAO,cAAc,KAAK,OACrF,CACA;EACC,YAAY,GAAG,OAAO,OAAO,GAAG,OAAO;EACvC,UAAU,OAAO,oBAAoB,OAAO;EAC5C,CACD,GACA,EAAE,CACL;AACD,OAAM,QAAQ,SAAS,QAAQ,yBAAyB,SAAS;;;;;;;;AASlE,eAAe,2BACd,SACA,QACgB;CAChB,MAAM,aAAa,OACjB,KAAK,UAAU,MAAM,OAAO,CAC5B,QACC,WACA,OAAO,oBAAoB,UAC3B,OAAO,uBAAuB,UAC9B,QAAQ,gBAAgB,OAAO,gBAAgB,KAAK,KACrD;AACF,KAAI,WAAW,WAAW,EAAG;CAC7B,MAAM,SAAS,MAAM,QAAQ,SAAS,QACrC,yBACA,WAAW,KAAK,WAAW,GAAG,OAAO,OAAO,GAAG,OAAO,kBAAkB,CACxE;CACD,MAAM,WAAW,WAAW,QAAQ,WACnC,OAAO,IAAI,GAAG,OAAO,OAAO,GAAG,OAAO,kBAAkB,CACxD;AACD,KAAI,SAAS,WAAW,EAAG;CAE3B,MAAM,YAAY,MAAM,QAAQ,aAAa,SAAS,SAAS;CAC/D,MAAM,YAAY,SAAS,KAAK,WAAW,kBAAkB,QAAQ,UAAU,CAAC,GAAG;CACnF,MAAM,2BAAW,IAAI,KAAa;AAClC,MAAK,MAAM,SAAS,OAAO,WAAW,eAAe,EAAE;EACtD,MAAM,OAAO,MAAM,QAAQ,GACzB,WAAW,0BAA0B,CACrC,OAAO,CAAC,mBAAmB,aAAa,CAAC,CACzC,MAAM,cAAc,MAAM,MAAM,CAChC,OAAO,EAAE,QAAQ,KAAK,iBACtB,IACC,OACC,WAAW,gCAAgC,CACzC,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,CACxB,MAAM,8CAA8C,KAAK,QAAQ,YAAY,CAC7E,MAAM,6CAA6C,KAAK,uBAAuB,CAC/E,SACA,6CACA,KACA,6BACA,CACF,CACD,CACD,CACA,SAAS;AACX,OAAK,MAAM,OAAO,KAAM,UAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,IAAI,aAAa;;CAGtF,MAAM,UAA+C,EAAE;AACvD,UAAS,SAAS,QAAQ,UAAU;AACnC,MAAI,SAAS,IAAI,GAAG,OAAO,WAAW,QAAQ,UAAU,SAAS,CAAE;EACnE,MAAM,cAAc,OAAO,IAAI,GAAG,OAAO,OAAO,GAAG,OAAO,kBAAkB;AAC5E,MAAI,gBAAgB,OAAW;EAC/B,MAAM,SAA8B;GACnC,MAAM;GACN,IAAI,iBAAiB,OAAO,YAAY,OAAO,GAAG;GAClD,YAAY,OAAO;GACnB,SAAS,OAAO;GAChB;GACA,WAAW;GACX,GAAI,OAAO,cAAc,SAAY,EAAE,GAAG,EAAE,WAAW,OAAO,WAAW;GACzE;AACD,UAAQ,KAAK;GAAE,QAAQ;GAAQ,MAAM;GAAI,CAAC;GACzC;AACF,KAAI,QAAQ,WAAW,EAAG;AAE1B,OAAM,QAAQ,SAAS,QACtB,wBACA,QAAQ,KAAK,EAAE,cAAc;EAAE,YAAY,OAAO;EAAI,UAAU,OAAO;EAAa,EAAE,CACtF;AACD,OAAM,aAAa,SAAS,kBAAkB,QAAQ;;;;;AClOvD,MAAM,mBAAmB,EAAE,KAAK,aAAa;AAC7C,MAAM,cAAc,EAAE,QAAQ,CAAC,KAAK,CAAC,aAAa;AAElD,MAAM,qBAAqB,EAAE,aAAa;CACzC,OAAO,EAAE,KAAK;EAAC;EAAW;EAAW;EAAU;EAAS;EAAS,CAAC;CAClE,MAAM;CACN,KAAK;CACL,MAAM;CACN,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY;CAEzC,SAAS,EAAE,aAAa;EAAE,SAAS;EAAa,OAAO,EAAE,QAAQ,CAAC,UAAU;EAAE,CAAC;CAC/E,YAAY,EACV,MAAM,EAAE,aAAa;EAAE,MAAM,EAAE,QAAQ;EAAE,IAAI,EAAE,QAAQ;EAAE,QAAQ,EAAE,QAAQ;EAAE,CAAC,CAAC,CAC/E,IAAI,gBAAgB,uBAAuB;CAC7C,CAAC;;AAKF,MAAM,iBAAwC,aAAa,QAAQ,SAAS,SAAS,YAAY;;AAGjG,MAAM,gBAAuC,eAAe,QAAQ,SAAS,SAAS,UAAU;AAEhG,MAAM,mBAAmB;;;;;;AAOzB,eAAsB,iBACrB,OACkC;AAClC,QAAO,IAAI,WAAW,MAAM,CAAC,KAAK;;AAGnC,SAAS,gBAA8B;AACtC,QAAO;EACN,OAAO;EACP,MAAM,eAAe,MAAM;EAC3B,KAAK;EACL,MAAM;EACN,QAAQ,EAAE;EACV,SAAS;GAAE,SAAS;GAAG,OAAO;GAAM;EACpC,YAAY,EAAE;EACd;;AAGF,IAAM,aAAN,MAAiB;CAChB,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC;CACT,CAASC,0BAAW,IAAI,KAAyC;CACjE;CACA,YAA4B;CAC5B,QAA8B;CAC9B,WAAyC;CACzC,gCAAgB,IAAI,KAAqB;CAEzC,YAAY,OAA8B;AACzC,QAAKJ,QAAS;AACd,QAAKC,KAAM,MAAM;AACjB,QAAKE,SAAU,IAAI,oBAClB,MAAM,OAAO,OACb,IAAI,6BAA6B,MAAM,GAAG,CAAC,gBAAgB,MAAM,YAAY,CAC7E;AACD,QAAKD,WAAY,IAAI,8BACpB,MAAM,IACN,MAAM,KAAK,OAAO,QAClB,MAAM,YACN;AACD,QAAKG,SACJ,MAAM,WAAW,QAAQ,MAAM,WAAW,SACvC,eAAe,GACf,mBAAmB,MAAM,MAAM,OAAO;;CAG3C,MAAM,MAAuC;AAC5C,MAAK,MAAM,MAAKF,OAAQ,QAAQ,KAAM,MAAKH,MAAO,KAAK,cACtD,OAAM,IAAI,cAAc,oCAAoC,gCAAgC;AAE7F,WAAS;GACR,MAAM,aAAa,MAAM,KAAK,MAAM;AACpC,OAAI,eAAe,OAAQ,QAAO,KAAK,QAAQ;AAC/C,OAAI,eAAe,QAAS,QAAO;IAAE,MAAM;IAAO,QAAQ,MAAKK;IAAS;;;CAI1E,AAAQ,SAAS,MAAc,IAAY,QAAsB;AAChE,MAAI,MAAKA,OAAQ,WAAW,SAAS,gBAAgB,uBACpD,OAAKA,OAAQ,WAAW,KAAK;GAAE;GAAM;GAAI;GAAQ,CAAC;;CAIpD,MAAc,OAA+C;EAC5D,MAAM,SAAS,MAAKL,MAAO;AAC3B,MAAI,CAAC,OAAO,SAAS,EAAE,OAAO,GAAG,CAAC,CAAE,QAAO;AAC3C,UAAQ,MAAKK,OAAQ,OAArB;GACC,KAAK;AACJ,WAAO,MAAM,EAAE;AACf,UAAM,KAAK,aAAa;AACxB,WAAO;GACR,KAAK;AACJ,WAAO,MAAM,EAAE;AACf,UAAM,KAAK,aAAa;AACxB,WAAO;GACR,KAAK;AACJ,WAAO,MAAM,EAAE;AACf,UAAM,KAAK,YAAY;AACvB,WAAO;GACR,KAAK,QACJ,QAAO,KAAK,WAAW;GACxB,KAAK,SACJ,QAAO;;;CAMV,AAAQ,OAAO,MAA0C;EACxD,IAAI,SAAS,MAAKD,QAAS,IAAI,KAAK;AACpC,MAAI,CAAC,QAAQ;AAYZ,YAAS,aAAa,MAAKH,IAAK,MAXD,EAC9B,YAAY,OAAO,QAAQ;IAC1B,MAAM,WAAW,MAAM,KAAK,YAAY,SAAS,IAAI;IACrD,MAAM,wBAAQ,IAAI,KAAqB;AACvC,SAAK,MAAM,MAAM,KAAK;KACrB,MAAM,OAAO,MAAKK,aAAc,IAAI,SAAS,IAAI,GAAG,IAAI,GAAG;AAC3D,SAAI,SAAS,OAAW,OAAM,IAAI,IAAI,KAAK;;AAE5C,WAAO;MAER,CAC6C;AAC9C,SAAKF,QAAS,IAAI,MAAM,OAAO;;AAEhC,SAAO;;;CAIR,MAAc,cAAgC;AAC7C,MAAI,MAAKG,aAAc,KAQtB,OAAKA,WAPO,MAAM,MAAKN,GACrB,WAAW,gCAAgC,CAC3C,OAAO,cAAc,CACrB,MAAM,gBAAgB,KAAK,MAAKD,MAAO,YAAY,CACnD,MAAM,eAAe,MAAM,CAAC,GAAG,aAAa,CAAC,CAC7C,MAAM,EAAE,CACR,kBAAkB,KACK;AAE1B,SAAO,MAAKO;;CAGb,MAAc,UAAU,MAAkB,KAAsD;AAC/F,MAAI,CAAE,MAAM,KAAK,aAAa,IAAK,IAAI,WAAW,EAAG,wBAAO,IAAI,KAAK;AACrE,SAAO,MAAKL,SAAU,QAAQ,MAAM,IAAI;;CAGzC,MAAc,YACb,MACA,KAC+B;AAC/B,MAAI,CAAE,MAAM,KAAK,aAAa,IAAK,IAAI,WAAW,EAAG,wBAAO,IAAI,KAAK;AACrE,SAAO,MAAKA,SAAU,eAAe,MAAM,IAAI;;;CAIhD,MAAc,OACb,SACA,QAC+B;AAC/B,MAAI,CAAE,MAAM,KAAK,aAAa,IAAK,QAAQ,WAAW,EAAG,QAAO;EAChE,MAAM,OAAO,QAAQ,IAAI;AACzB,MAAI,CAAC,KAAM,QAAO;EAClB,MAAM,aAA8D,EAAE;AACtE,MAAI,CAAC,gBAAgB,KAAK,IAAI,SAAS,UACtC,YAAW,KAAK;GAAE,UAAU;GAAM,QAAQ;GAAM,CAAC;AAClD,OAAK,MAAM,aAAa,gBAAgB,OAAO;GAC9C,MAAM,SAAS,UAAU,QAAQ;AACjC,OAAI,UAAU,OAAO,QAAQ,CAAC,UAAU,WAAW,YAAa;AAChE,cAAW,KAAK;IAAE,UAAU,UAAU;IAAU;IAAQ,CAAC;;EAE1D,MAAM,uBAAO,IAAI,KAAkC;AACnD,OAAK,MAAM,EAAE,UAAU,YAAY,YAAY;GAC9C,MAAM,SAAS,QAAQ,SAAS,WAAW;IAC1C,MAAM,QAAiB,QAAQ,IAAI,QAAQ,SAAS;AACpD,WAAO,OAAO,UAAU,WAAW,CAAC,MAAM,GAAG,EAAE;KAC9C;AACF,QAAK,IAAI,UAAU,MAAM,OAAO,QAAQ,OAAO,CAAC;;AAEjD,SAAO,QAAQ,KAAK,WAAW;GAC9B,MAAM,OAAgC,EAAE,GAAG,QAAQ;AACnD,QAAK,MAAM,EAAE,cAAc,YAAY;IACtC,MAAM,QAAQ,KAAK;IACnB,MAAM,SAAS,OAAO,UAAU,WAAW,KAAK,IAAI,SAAS,EAAE,IAAI,MAAM,GAAG;AAC5E,QAAI,WAAW,OAAW,MAAK,YAAY;;AAE5C,OAAI,kBAAkB,KAAK,CAAE,MAAK,KAAK,YAAY,KAAK;AAExD,UAAO;IACN;;CAGH,MAAc,WAAmC;AAChD,MAAI,CAAC,MAAKM,MAAO;GAChB,MAAM,OAAO,MAAM,iBAAiB,MAAKP,GAAI;GAC7C,MAAM,WAAW,MAAM,KAAK,YAC3B,SACA,KAAK,KAAK,QAAQ,IAAI,GAAG,CACzB;AACD,SAAKO,OAAQ,mBACZ,KAAK,KAAK,SAAS;IAAE,IAAI,SAAS,IAAI,IAAI,GAAG,IAAI,IAAI;IAAI,YAAY,IAAI;IAAY,EAAE,CACvF;;AAEF,SAAO,MAAKA;;CAGb,MAAc,wBAAwD;AACrE,MAAI,MAAKC,QAAU,QAAO,MAAKA;EAC/B,MAAM,SAAS,MAAKN;EACpB,MAAM,8BAAc,IAAI,KAAqB;AAC7C,aAAW,MAAM,EAAE,YAAY,OAAO,QAAQ,aAAa,CAC1D,aAAY,IAAI,OAAO,IAAI,OAAO,KAAK;EAExC,MAAM,wBAAQ,IAAI,KAA2C;AAC7D,aAAW,MAAM,EAAE,YAAY,OAAO,QAAQ,QAAQ,EAAE;GACvD,MAAM,OAAO,YAAY,IAAI,OAAO,aAAa;AACjD,OAAI,SAAS,OAAW;GACxB,MAAM,SAAS,MAAM,IAAI,KAAK,oBAAI,IAAI,KAA8B;AACpE,UAAO,IAAI,OAAO,MAAM,OAAO,WAAW;AAC1C,SAAM,IAAI,MAAM,OAAO;;AAExB,QAAKM,UAAW,EAAE,kBAAkB,OAAO;AAC3C,SAAO,MAAKA;;CAGb,AAAQ,mBAAwC;EAC/C,MAAM,2BAAW,IAAI,KAAa;EAClC,MAAM,EAAE,cAAc,MAAKT,MAAO;AAClC,MAAI,UAAU,cAAc,SAC3B,MAAK,MAAM,QAAQ,sBAAsB,MAAO,UAAS,IAAI,KAAK;AAEnE,MAAI,UAAU,gBAAgB,SAC7B,MAAK,MAAM,QAAQ,sBAAsB,QAAS,UAAS,IAAI,KAAK;AAErE,SAAO;;CAGR,AAAQ,WACP,MACA,UACC;AACD,SAAO,SAAS,QAAQ,OAAO,UAAU;;CAK1C,MAAc,cAA6B;EAC1C,MAAM,WAAW,MAAM,MAAKG,OAAQ,UAAU;EAC9C,MAAM,EAAE,MAAM,QAAQ,MAAKE;AAC3B,MAAI,OAAO,KAAK,WAAW,MAAM,SAAS,EAAE;AAC3C,QAAK,aAAa;AAClB;;EAGD,MAAM,QAAQ,MAAM,MAAKF,OAAQ,UAAU,MAAM,IAAI;EACrD,MAAM,UAAU,MAAM,KAAK,uBAAuB;EAClD,MAAM,WAAW,SAAS,YAAY,KAAK,kBAAkB,mBAAG,IAAI,KAAa;EACjF,MAAM,iBAAiB,MACrB,KAAK,WAAW,OAAO,OAAO,CAC9B,QAAQ,WAAW,CAAC,SAAS,IAAI,OAAO,GAAG,CAAC;AAC9C,MAAI,SAAS,SACZ;QAAK,MAAM,UAAU,eACpB,KAAI,OAAO,SAAS,QAAS,OAAKG,aAAc,IAAI,OAAO,IAAI,OAAO,KAAK;;EAG7E,MAAM,YAAY,MAAM,KAAK,oBAC5B,eAAe,KAAK,WACnB,yBAAyB,qBAAqB,QAAQ,MAAKN,MAAO,MAAM,QAAQ,CAAC,CACjF,CACD;EAED,MAAM,UAAU,MAAM,KAAK,OAAO,YAAY,QAAQ,QAAQ,KAAK,UAAU,QAAQ,IAAI,CAAC;EAC1F,MAAM,SAAS,QAAQ,KAAK,WAAW,OAAO,GAAG;EACjD,MAAM,cAAc,IAAI,IACvB,QAAQ,SAAS,WAChB,OAAO,SAAS,UAAU,CAAC,CAAC,OAAO,IAAI,OAAO,WAAW,CAAU,GAAG,EAAE,CACxE,CACD;EACD,MAAM,QAAQ,MAAM,KAAK,YAAY,MAAM,QAAQ,YAAY;EAC/D,MAAM,UAAU,MAAM,KAAK,OAC1B,OAAO,SAAS,OAAO;GACtB,MAAM,SAAS,MAAM,IAAI,GAAG;AAC5B,UAAO,SAAS,CAAC,OAAO,GAAG,EAAE;IAC5B,GACD,QAAQ,QAAQ,KAAK,YAAY,QAAQ,IAAI,CAC9C;EACD,MAAM,eAAe,IAAI,IAAI,QAAQ,KAAK,WAAW,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC;EAC1E,MAAM,OAAO,MAAM,KAAK,UAAU;EAElC,MAAM,SAAkC,EAAE;EAC1C,IAAI,WAAW;AACf,OAAK,MAAM,YAAY,WAAW;GACjC,MAAM,SAAS,aAAa,IAAI,SAAS,GAAG;AAC5C,OAAI,CAAC,QAAQ;AACZ,SAAK,SAAS,MAAM,SAAS,IAAI,UAAU;AAC3C;;GAED,MAAM,YAAY,iBAAiB,QAAQ;IAAE,MAAM;IAAU;IAAM,YAAY;IAAM,CAAC;AACtF,OAAI,UAAU,OAAO,SAAS,EAC7B,MAAK,SAAS,MAAM,SAAS,IAAI,aAAa,UAAU,OAAO,IAAI,QAAQ,YAAY;GAExF,MAAM,SACL,UAAU,MAAM,SAAS,WAAW,SAAS,SAAS,UACnD;IAAE,GAAG,UAAU;IAAO,MAAM,SAAS;IAAM,GAC3C,UAAU;AACd,UAAO,KAAK,CAAC,SAAS,IAAI,MAAM,aAAa,OAAO,CAAC,CAAC;AACtD,OAAI,cAAc,OAAO,KAAK,cAAc,SAAS,CAAE;OAClD,MAAK,SAAS,MAAM,SAAS,IAAI,YAAY;;AAGnD,QAAM,IAAI,6BAA6B,MAAKC,GAAI,CAAC,iBAChD,MAAKD,MAAO,aACZ,gBAAgB,MAAM,IAAI,EAC1B,MAAM,mBAAmB,OAAO,CAChC;AACD,QAAKK,OAAQ,OAAO,SAAS,MAAKA,OAAQ,OAAO,SAAS,KAAK;AAC/D,QAAKA,OAAQ,MAAM,MAAM;;;CAI1B,MAAc,oBAAoB,SAA4D;EAC7F,MAAM,YAAY,QAAQ,SAAS,WAAY,OAAO,SAAS,aAAa,CAAC,OAAO,GAAG,GAAG,EAAE,CAAE;AAC9F,MAAI,UAAU,WAAW,EAAG,QAAO;EACnC,MAAM,UAAU,MAAM,MAAKH,SAAU,QAAQ,sBAAsB,UAAU;AAC7E,MAAI,QAAQ,SAAS,EAAG,QAAO;AAC/B,SAAO,QAAQ,KAAK,WACnB,OAAO,SAAS,cAAc,QAAQ,IAAI,OAAO,GAAG,GAAG;GAAE,GAAG;GAAQ,SAAS;GAAO,GAAG,OACvF;;CAGF,MAAc,YACb,MACA,KACA,aACC;AACD,MAAI;AACH,UAAO,MAAM,KAAK,OAAO,KAAK,CAAC,MAAM,KAAK,YAAY;WAC9C,OAAO;AACf,OAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS,wBAC5C,OAAM,IAAI,cACT,gCACA,oCACA;IACC,QAAQ;KAAE,GAAG,MAAM;KAAQ;KAAM;IACjC,OAAO;IACP,CACD;AAEF,SAAM;;;CAIR,AAAQ,cAAoB;EAC3B,MAAM,OAAO,eAAe,eAAe,QAAQ,MAAKG,OAAQ,KAAK,GAAG;AACxE,MAAI,MAAM;AACT,SAAKA,OAAQ,OAAO;AACpB,SAAKA,OAAQ,MAAM;AACnB;;AAED,QAAKA,OAAQ,QAAQ;AACrB,QAAKA,OAAQ,MAAM;;CAKpB,MAAc,cAA6B;EAC1C,MAAM,WAAW,MAAM,MAAKH,SAAU,KAAK,wBAAwB;GAClE,OAAO,MAAKG,OAAQ,QAAQ,SAAS;GACrC,OAAO;GACP,CAAC;EACF,MAAM,uBAAO,IAAI,KAGd;AACH,OAAK,MAAM,SAAS,OACnB,SAAS,KAAK,YAAY,QAAQ,WAAW,EAC7C,eACA,EAAE;GACF,MAAM,QAAQ,MAAM,MAAKJ,GACvB,WAAW,0BAA0B,CACrC,OAAO;IAAC;IAAM;IAAa;IAAc;IAAa,CAAC,CACvD,MAAM,MAAM,MAAM,MAAM,CACxB,SAAS;AACX,QAAK,MAAM,OAAO,MAAO,MAAK,IAAI,IAAI,IAAI,IAAI;;AAE/C,OAAK,MAAM,WAAW,UAAU;GAC/B,MAAM,MAAM,KAAK,IAAI,QAAQ,WAAW;AACxC,OAAI,CAAC,IAAK,MAAK,SAAS,kBAAkB,QAAQ,YAAY,0BAA0B;YAEvF,IAAI,cAAc,QAAQ,YAC1B,OAAO,IAAI,WAAW,KAAK,KAC3B,IAAI,eAAe,KAEnB,MAAK,SAAS,kBAAkB,QAAQ,YAAY,4BAA4B;;AAGlF,QAAKI,OAAQ,QAAQ,WAAW,SAAS;EACzC,MAAM,OAAO,SAAS,GAAG,GAAG;AAC5B,MAAI,QAAQ,SAAS,WAAW,kBAAkB;AACjD,SAAKA,OAAQ,QAAQ,QAAQ,KAAK;AAClC;;AAED,QAAKA,OAAQ,QAAQ;AACrB,QAAKA,OAAQ,OAAO,cAAc,MAAM;;CAKzC,MAAc,aAA4B;EACzC,MAAM,WAAW,MAAM,MAAKF,OAAQ,UAAU;EAC9C,MAAM,OAAO,MAAKE,OAAQ;EAC1B,MAAM,OAAO,MAAM,KAAK,OAAO,KAAK,CAAC,WAAW;EAChD,IAAI,WAAW,SAAS,QAAQ,OAAO,SAAS;AAChD,MAAI,SAAS,iBAAkB,aAAY,MAAKA,OAAQ,QAAQ;AAChE,MAAI,SAAS,QAAQ,SAAS,SAC7B,MAAK,SAAS,MAAM,KAAK,sBAAsB,SAAS,UAAU,OAAO;EAG1E,MAAM,OAAO,cAAc,cAAc,QAAQ,KAAK,GAAG;AACzD,MAAI,MAAM;AACT,SAAKA,OAAQ,OAAO;AACpB;;AAED,QAAKA,OAAQ,QAAQ;AACrB,QAAKA,OAAQ,OAAO;AACpB,QAAKA,OAAQ,MAAM;AACnB,QAAKA,OAAQ,OAAO;;CAKrB,cACC;CAED,MAAc,YAAoD;EACjE,MAAM,WAAW,MAAM,MAAKF,OAAQ,UAAU;EAC9C,MAAM,EAAE,KAAK,SAAS,MAAKE;AAC3B,MAAI,OAAO,KAAK,WAAW,SAAS,SAAS,EAAE;AAC9C,SAAKA,OAAQ,QAAQ;AACrB,UAAO;;AAER,MAAI,MAAKK,YAAa,QAAQ,KAAK;GAClC,MAAM,WAAW,MAAM,MAAKP,OAAQ,UAAU,SAAS,IAAI,EAAE,KAAK,MAAM,EAAE,OAAO;GACjF,MAAM,YAAY,MAAM,KAAK,UAC5B,SACA,QAAQ,KAAK,WAAW,OAAO,GAAG,CAClC;GACD,MAAM,MAAM,QAAQ,KAAK,WAAW,UAAU,IAAI,OAAO,GAAG,IAAI,OAAO,GAAG;GAC1E,MAAM,uBAAO,IAAI,KAAqB;AACtC,QAAK,MAAM,OAAO,MAAM,KAAK,gBAAgB,IAAI,CAAE,MAAK,IAAI,IAAI,IAAI,IAAI,WAAW;GACnF,MAAM,yBAAS,IAAI,KAAqB;AACxC,WAAQ,SAAS,QAAQ,UAAU;IAClC,MAAM,MAAM,KAAK,IAAI,IAAI,UAAU,OAAO,GAAG;AAC7C,QAAI,QAAQ,OAAW,QAAO,IAAI,OAAO,IAAI,IAAI;KAChD;AACF,SAAKO,aAAc;IAAE;IAAK;IAAS,MAAM;IAAQ;;EAGlD,MAAM,SAAS,MAAKA,WAAY,QAAQ;AACxC,MAAI,CAAC,UAAU,OAAO,SAAS,SAAS;AACvC,SAAKL,OAAQ,MAAM,MAAM;AACzB,SAAKA,OAAQ,OAAO;AACpB,UAAO;;EAER,MAAM,SAAS,MAAKL,MAAO;EAE3B,MAAM,QAAQ,OAAO,cAAc;AACnC,MAAI,CAAC,SAAS,CAAC,OAAO,SAAS,EAAE,OAAO,GAAG,CAAC,CAAE,QAAO;EAErD,MAAM,MAAM,MAAKU,WAAY,KAAK,IAAI,OAAO,GAAG;AAChD,MAAI,QAAQ,QAAW;AACtB,UAAO,MAAM,EAAE;AACf,QAAK,SAAS,SAAS,OAAO,IAAI,UAAU;SACtC;GACN,MAAM,SAAS,MAAM,iBAAiB,MAAKV,MAAO,SAAS,KAAK,EAC/D,UAAU,QAAQ,SAAY,OAAO,WAAW,CAAC,OACjD,CAAC;AACF,OAAI,WAAW,YAAa,QAAO;AACnC,UAAO,MAAM,KAAK,IAAI,QAAQ,SAAS,GAAG,EAAE,CAAC;AAC7C,OAAI,WAAW,KAAM,MAAK,SAAS,SAAS,OAAO,IAAI,eAAe;YAC7D,OAAO,WAAW,OAAO,KAAM,MAAK,SAAS,SAAS,OAAO,IAAI,gBAAgB;;AAE3F,QAAKK,OAAQ,OAAO,OAAO;AAC3B,SAAO;;CAGR,MAAc,gBAAgB,KAAwB;EACrD,MAAM,OAAkD,EAAE;AAC1D,OAAK,MAAM,SAAS,OAAO,CAAC,GAAG,IAAI,EAAE,eAAe,EAAE;GACrD,MAAM,QAAQ,MAAM,MAAKJ,GACvB,WAAW,QAAQ,CACnB,OAAO,CAAC,MAAM,cAAc,CAAC,CAC7B,MAAM,MAAM,MAAM,MAAM,CACxB,SAAS;AACX,QAAK,MAAM,OAAO,MAAO,MAAK,KAAK;IAAE,IAAI,IAAI;IAAI,YAAY,IAAI;IAAa,CAAC;;AAEhF,SAAO;;CAKR,MAAc,SAA0C;EACvD,MAAM,WAAW,MAAM,MAAKE,OAAQ,UAAU;EAC9C,MAAM,SAAS,IAAI,6BAA6B,MAAKF,GAAI;EACzD,MAAM,eAAwC,EAAE;AAChD,OAAK,MAAM,QAAQ,eAClB,MAAK,IAAI,MAAM,GAAG,MAAM,KAAK,WAAW,MAAM,SAAS,EAAE,MACxD,cAAa,KAAK,CAAC,MAAM,IAAI,CAAC;EAGhC,MAAM,QAAQ,MAAM,OAAO,QAC1B,MAAKD,MAAO,aACZ,aAAa,KAAK,CAAC,MAAM,SAAS,gBAAgB,OAAO,KAAK,EAAE,IAAI,CAAC,CACrE;EACD,MAAM,SAA0C,EAAE;AAClD,OAAK,MAAM,CAAC,MAAM,QAAQ,cAAc;GACvC,MAAM,OAAO,MAAM,IAAI,gBAAgB,OAAO,KAAK,EAAE,IAAI,CAAC,EAAE;AAC5D,OAAI,CAAC,KACJ,OAAM,IAAI,cAAc,yBAAyB,0BAA0B,EAC1E,QAAQ;IAAE;IAAM;IAAK,EACrB,CAAC;AAEH,UAAO,KAAK;IAAC;IAAM;IAAK;IAAK,CAAC;;AAE/B,SAAO;GACN,MAAM;GACN,eAAe,MAAM,cAAc,OAAO;GAC1C,QAAQ,EAAE,GAAG,MAAKK,OAAQ,QAAQ;GAClC,YAAY,CAAC,GAAG,MAAKA,OAAQ,WAAW;GACxC;;;;;;;AAQH,SAAS,yBAAyB,QAA8C;CAC/E,MAAM,OAAO,cAAc,OAAO;CAClC,MAAM,WAAW,0BAA0B,KAAK;AAChD,KAAI,aAAa,KAAM,QAAO;AAE9B,QAAO,KAAK,MAAM,SAAS;;AAG5B,SAAS,OAAO,MAA0B;CACzC,MAAM,QAAQ,aAAa,MAAM,cAAc,cAAc,KAAK;AAClE,KAAI,CAAC,MAAO,OAAM,IAAI,MAAM,uBAAuB,OAAO;AAC1D,QAAO;;AAGR,MAAM,YAAiC,IAAI,IAAI,mBAAmB;AAElE,SAAS,gBAAgB,MAA2B;AACnD,QAAO,UAAU,IAAI,KAAK;;AAG3B,SAAS,kBACR,QACwE;AACxE,QAAO,OAAO,OAAO,SAAS,YAAY,UAAU,IAAI,OAAO,KAAK;;;;;;;;;;;;;;;;;;;AC5nBrE,MAAM,oBAAoB;AAC1B,MAAM,uBAAuB;AAC7B,MAAM,0BAA0B;AAChC,MAAM,mBAAmB;AACzB,MAAM,oBAAoB;AAC1B,MAAM,sBAAsB;;AAE5B,MAAM,mBAAmB;;AAUzB,eAAsB,WACrB,SACA,OACA,YACkC;CAClC,IAAI,WAAmC;AACvC,QAAO,UAAU;EAChB,MAAM,OAA0C,MAAM,QAAQ,SAAS,SAAS;AAChF,MAAI,SAAS,SAAU,QAAO;AAC9B,MAAI,KAAM,OAAM,WAAW,KAAK;AAChC,aAAW;;AAEZ,QAAO;;AAGR,SAAS,SAAS,MAA2C;CAC5D,MAAM,YAAY,cAAc,cAAc,QAAQ,KAAK,GAAG;AAC9D,QAAO,YAAY;EAAE,MAAM;EAAW,OAAO;EAAM,GAAG;;AAGvD,eAAe,YAAY,SAAqD;AAC/E,SAAQ,MAAM,QAAQ,WAAW,aAAa,EAAE,UAAU,GAAG,MAAM,WAAW,EAAE,MAAM,EAAE,KAAK,CAAC;;AAG/F,eAAe,QACd,SACA,UAC6C;AAC7C,SAAQ,SAAS,MAAjB;EACC,KAAK,SACJ,QAAO,WAAW,SAAS,SAAS,MAAM;EAC3C,KAAK,eAAe;GACnB,MAAM,cAAc,MAAM,YAAY,QAAQ,EAAE,MAC9C,cAAc,SAAS,UAAU,QAAQ,WAAW,UAAU,MAAM,SAAS,MAAM,GAAG,EACvF;AACD,OAAI,CAAC,WAAY,QAAO,SAAS,cAAc;AAC/C,OAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,kBAAkB,CAAC,CAAE,QAAO;AACpE,WAAQ,OAAO,OAAO;AACtB,SAAM,qCACL,QAAQ,IACR,WAAW,MACX,sBACA;AACD,UAAO;IAAE,MAAM;IAAe,OAAO,WAAW;IAAM;;EAEvD,KAAK;AACJ,OAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,mBAAmB,CAAC,CAAE,QAAO;AACrE,WAAQ,OAAO,OAAO;AACtB,QAAK,MAAM,QAAQ,0BAA0B,YAC5C,OAAM,GAAG;;eAEE,KAAK;;;;;;MAMd,QAAQ,QAAQ,GAAG;AAEtB,SAAM,QAAQ,GACZ,WAAW,UAAU,CACrB,MAAM,QAAQ,MAAM,CAAC,GAAG,0BAA0B,OAAO,CAAC,CAC1D,SAAS;AACX,UAAO,SAAS,UAAU;EAE3B,KAAK,aACJ,QAAO,aAAa,SAAS,SAAS,MAAM;EAC7C,KAAK;AACJ,OAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,kBAAkB,CAAC,CAAE,QAAO;AACpE,WAAQ,OAAO,OAAO;AACtB,SAAM,iBAAiB,QAAQ;AAC/B,UAAO,SAAS,SAAS;;;AAI5B,SAAS,YAAY,OAA0C;AAC9D,QAAO,kBAAkB,MAAM,cAAc,cAAc,MAAM;;AAQlE,eAAe,cAAc,SAAiD;CAC7E,MAAM,UAA0B,EAAE;AAClC,MAAK,MAAM,UAAU,MAAM,YAAY,QAAQ,EAAE;EAEhD,MAAM,SADQ,qBAAqB,QAAQ,QAAQ,MAAM,EAAE,kCAAkB,IAAI,KAAK,EAAE,CAAC,CACpE;AACrB,MAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,OAAO,CAAE;AAC5E,MAAI,OAAO,YAAY,KAAM;AAC7B,MAAI,CAAC,SAAS,QAAQ,GAAG,CACxB,OAAM,IAAI,cACT,yBACA,oDACA,EAAE,QAAQ;GAAE,MAAM;GAAc,IAAI,OAAO;GAAI,EAAE,CACjD;AAEF,UAAQ,KAAK;GAAE;GAAQ;GAAQ,CAAC;;AAEjC,QAAO;;;AAIR,eAAe,WACd,SACA,OAC6C;CAC7C,MAAM,CAAC,UAAU,aAAa,OAAO,MAAM,IAAI,IAAI,EAAE;CACrD,MAAM,aAAa,cAAc,SAAY,OAAO,OAAO,UAAU;CACrE,MAAM,UAAU,MAAM,cAAc,QAAQ,EAAE,MAAM,cACnD,eAAe,OACZ,aAAa,UAAa,WAAW,UAAU,OAAO,MAAM,SAAS,GAAG,IACxE,UAAU,OAAO,SAAS,SAC7B;AACD,KAAI,CAAC,OAAQ,QAAO,SAAS,SAAS;CACtC,MAAM,OAAO,OAAO,OAAO;CAC3B,MAAM,MAAM,IAAI,WAAW,QAAQ,GAAG;AAEtC,KAAI,eAAe,MAAM;AACxB,MAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,sBAAsB,CAAC,CAAE,QAAO;AACxE,UAAQ,OAAO,OAAO;EACtB,MAAM,SAAS,MAAM,IAAI,oBAAoB,KAAK;AAClD,MAAI,OAAO,SAAS,GAAG;GACtB,MAAM,UAAU,OAAO,OAAO;AAC9B,SAAM,IAAI,aAAa,KAAK;AAC5B,SAAM,IAAI,eACT,MACA,QACA,OAAO,YAAY,YAAY,YAAY,OACxC,OAAO,YACP,OAAO,QAAQ,QAAQ,CAAC,QACtB,UAAqC,OAAO,MAAM,OAAO,SAC1D,CACD,GACA,QACH,YAAY,OAAO,OAAO,SAAS,GAAG,OAAO,OAAO,WAAW,OAC/D;;AAEF,SAAO;GAAE,MAAM;GAAU,OAAO,GAAG,KAAK;GAAK;;AAG9C,KAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,yBAAyB,CAAC,CAAE,QAAO;AAC3E,SAAQ,OAAO,OAAO;CACtB,MAAM,SAAS,MAAM,IAAI,oBAAoB,KAAK;CAClD,MAAM,OACL,OAAO,SAAS,IAAI,MAAM,IAAI,cAAc,MAAM,QAAQ,YAAY,kBAAkB,GAAG;AAC5F,KAAI,SAAS,KAAM,QAAO;EAAE,MAAM;EAAU,OAAO,GAAG,KAAK,GAAG;EAAQ;AACtE,OAAM,QAAQ,GACZ,YAAY,sBAAsB,CAClC,IAAI,EAAE,eAAe,KAAK,UAAU,OAAO,OAAO,EAAE,CAAC,CACrD,MAAM,MAAM,KAAK,OAAO,OAAO,GAAG,CAClC,SAAS;AACX,QAAO;EAAE,MAAM;EAAU,OAAO;EAAM;;;;;;;;;;AAWvC,eAAe,aACd,SACA,OAC6C;AAC7C,KAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,qBAAqB,CAAC,CAAE,QAAO;AACvE,SAAQ,OAAO,OAAO;CACtB,MAAM,KAAK,QAAQ;CACnB,IAAI,WAAW,GACb,WAAW,wBAAwB,CACnC,QAAQ,OAAO,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,OAAO,CAAC;AAC9C,KAAI,UAAU,KAAM,YAAW,SAAS,MAAM,QAAQ,KAAK,MAAM;CACjE,MAAM,OAAO,MAAM,GACjB,WAAW,wBAAwB,CACnC,OAAO;EAAC;EAAM;EAAQ;EAAgB;EAAe;EAAoB,CAAC,CAC1E,MAAM,QAAQ,KAAK,SAAS,CAC5B,QAAQ,KAAK,CACb,SAAS;CACX,MAAM,OAAO,KAAK,IAAI;AACtB,KAAI,SAAS,QAAW;AACvB,QAAM,GACJ,WAAW,8BAA8B,CACzC,OAAO,OACP,GAAG,IACF,GAAG,OACF,GACE,WAAW,wBAAwB,CACnC,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,CACxB,SAAS,8BAA8B,KAAK,mCAAmC,CACjF,CACD,CACD,CACA,SAAS;AACX,SAAO,SAAS,aAAa;;CAG9B,MAAM,UAAU,KACd,KAAK,QAAQ,IAAI,qBAAqB,IAAI,GAAG,CAC7C,QAAQ,QAAQ,cAAe,YAAY,SAAS,YAAY,OAAQ;CAC1E,MAAM,kBAAkB,CACvB,GAAG,IAAI,IAAI,KAAK,SAAS,QAAQ,yBAAyB,IAAI,YAAY,CAAC,CAAC,CAC5E;CACD,MAAM,eAAe,KAAK,MAAM,QAAQ,IAAI,iBAAiB,EAAE,GAAG,IAAI;CAOtE,MAAM,KANQ,MAAM,GAClB,WAAW,8BAA8B,CACzC,OAAO,KAAK,CACZ,MAAM,MAAM,KAAK,QAAQ,CACzB,MAAM,QAAQ,MAAM,KAAK,CACzB,kBAAkB,GACD,MAAM,aAAa,QAAQ,aAAa,kBAAkB,KAAK,GAAG;AACrF,OAAM,GACJ,WAAW,8BAA8B,CACzC,OAAO;EAAE;EAAI;EAAM;EAAc,aAAa,KAAK,UAAU,gBAAgB;EAAE,CAAC,CAChF,YAAY,OACZ,GACE,OAAO,OAAO,CACd,YAAY;EAAE;EAAI;EAAc,aAAa,KAAK,UAAU,gBAAgB;EAAE,CAAC,CACjF,CACA,SAAS;AACX,QAAO;EAAE,MAAM;EAAc,OAAO;EAAM;;AAG3C,eAAe,iBAAiB,SAAuC;AACtE,MAAK,MAAM,aAAa,OAAO,OAAO,eAAe,CAAE,uBAAsB,UAAU;AACvF,MAAK,MAAM,cAAc,MAAM,YAAY,QAAQ,EAAE;AACpD,4BAA0B,WAAW,KAAK;AAC1C,wBAAsB,WAAW,KAAK;;AAEvC,8BAA6B;AAC7B,kCAAiC;CACjC,MAAM,EAAE,qBAAqB,gCAC5B,MAAM,OAAO;CACd,MAAM,EAAE,0BAA0B,MAAM,OAAO;CAC/C,MAAM,EAAE,4BAA4B,MAAM,OAAO;CACjD,MAAM,EAAE,8BAA8B,MAAM,OAAO;AACnD,sBAAqB;AACrB,8BAA6B;AAC7B,wBAAuB;AACvB,0BAAyB;AACzB,4BAA2B;;;;;;;;;;;ACtR5B,MAAM,kBAAkB;AAExB,SAAgB,iBAAiB,SAAoD;AACpF,QAAO,QAAQ,KAAK,gBAAgB,SAAS,mBAC5C,eAAe,SAAS,4BAA4B,eAAe,QAAQ,EAAE,CAC7E;;;;;;;;AAcF,eAAsB,cACrB,SACA,MACA,YAC4B;CAC5B,MAAM,QAAQ,iBAAiB,QAAQ;CACvC,IAAI,OAAO;AACX,QAAO,OAAO,MAAM,QAAQ;EAC3B,MAAM,OAAO,MAAM;AACnB,MAAI,CAAC,KAAM;AACX,MAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,iBAAiB,CAAC,CACzD,QAAO;GAAE,OAAO;GAAY,MAAM;GAAM;AAEzC,UAAQ,OAAO,OAAO;AACtB,QAAM,WAAW,SAAS,KAAK;AAC/B;AACA,QAAM,WAAW,KAAK;;CAGvB,MAAM,gBAAgB,MAAM,SAAS,SAAU,KAAK,SAAS,eAAe,CAAC,KAAK,GAAG,GAAG,EAAE,CAAE;AAC5F,QAAO,cAAc,SAAS,GAAG;AAChC,MAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,iBAAiB,CAAC,CACzD,QAAO;GAAE,OAAO;GAAY,MAAM;GAAM;AAEzC,UAAQ,OAAO,OAAO;AAMtB,OALgB,MAAM,QAAQ,GAC5B,WAAW,2CAA2C,CACtD,OAAO,gBAAgB,CACvB,MAAM,iBAAiB,MAAM,cAAc,CAC3C,SAAS,EACC,WAAW,EAAG;EAC1B,MAAM,OAAO,MAAM,wCAAwC,QAAQ,GAAG;AACtE,MAAI,KAAK,YAAY,UAAU,KAAK,YAAY,gBAAgB,KAAK,YAAY,QAChF,QAAO;GAAE,OAAO;GAAQ,MAAM;GAAM;AAErC,MAAI,KAAK,YAAY,SACpB,OAAM,IAAI,cACT,yBACA,kDACA;;AAGH,QAAO,EAAE,OAAO,QAAQ;;AAGzB,eAAe,WAAW,SAAwB,MAAsC;CACvF,MAAM,KAAK,QAAQ;AACnB,SAAQ,KAAK,MAAb;EACC,KAAK,cAAc;GAClB,MAAM,MACJ,MAAM,GACL,WAAW,sBAAsB,CACjC,OAAO,OAAO,CACd,MAAM,MAAM,KAAK,KAAK,GAAG,CACzB,kBAAkB,IACnB,MAAM,GACL,WAAW,2CAA2C,CACtD,OAAO,0BAA0B,CACjC,MAAM,iBAAiB,KAAK,KAAK,GAAG,CACpC,kBAAkB;AACrB,OAAI,CAAC,IAAK;AACV,OAAI;AACH,UAAM,IAAI,eAAe,GAAG,CAAC,iBAAiB,IAAI,KAAK;YAC/C,OAAO;AACf,QAAI,iBAAiB,eAAe,MAAM,SAAS,uBAAwB;AAC3E,QAAI,iBAAiB,YACpB,OAAM,IAAI,cAAc,6BAA6B,iCAAiC;KACrF,QAAQ;MAAE,MAAM,KAAK;MAAM,IAAI,KAAK;MAAI,QAAQ,MAAM;MAAM;KAC5D,OAAO;KACP,CAAC;AAEH,UAAM;;AAEP;;EAED,KAAK;AACJ,SAAM,GACJ,WAAW,aAAa,CACxB,MAAM,MAAM,KAAK,KAAK,GAAG,CACzB,OAAO,OACP,GAAG,IACF,GAAG,OACF,GACE,WAAW,qBAAqB,CAChC,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,CACxB,MACA,kCACA,KACA,GAAG,GAAG,SAAS,gCAAgC,gBAAgB,CAC/D,CACF,CACD,CACD,CACA,SAAS;AACX;EACD,KAAK;AACJ,SAAM,GAAG,WAAW,qBAAqB,CAAC,MAAM,MAAM,KAAK,KAAK,GAAG,CAAC,SAAS;AAC7E;EACD,KAAK;AACJ,SAAM,GAAG,WAAW,kBAAkB,CAAC,MAAM,MAAM,KAAK,KAAK,GAAG,CAAC,SAAS;AAC1E;EACD,KAAK;AACJ,SAAM,GACJ,WAAW,wBAAwB,CACnC,MAAM,MAAM,KAAK,KAAK,GAAG,CACzB,OAAO,OACP,GAAG,IACF,GAAG,OACF,GACE,WAAW,aAAa,CACxB,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,CACxB,SAAS,mBAAmB,KAAK,6BAA6B,CAChE,CACD,CACD,CACA,SAAS;AACX;EACD,KAAK;AACJ,SAAM,GACJ,WAAW,gBAAgB,CAC3B,MAAM,MAAM,KAAK,KAAK,GAAG,CACzB,OAAO,OACP,GAAG,IACF,GAAG,OACF,GACE,WAAW,qBAAqB,CAChC,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,CACxB,SAAS,8BAA8B,KAAK,mBAAmB,CACjE,CACD,CACD,CACA,SAAS;AACX;EACD,KAAK;AACJ,SAAM,GACJ,WAAW,uBAAuB,CAClC,MAAM,MAAM,KAAK,KAAK,GAAG,CACzB,OAAO,OACP,GAAG,IACF,GAAG,OACF,GACE,WAAW,kBAAkB,CAC7B,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,CACxB,SAAS,2BAA2B,KAAK,0BAA0B,CACrE,CACD,CACD,CACA,SAAS;AACX;EACD,KAAK;AACJ,SAAM,GACJ,WAAW,mBAAmB,CAC9B,MAAM,MAAM,KAAK,KAAK,GAAG,CACzB,MAAM,UAAU,KAAK,QAAQ,CAC7B,SAAS;AACX;EACD,KAAK;AACJ,SAAM,GACJ,WAAW,8BAA8B,CACzC,MAAM,iBAAiB,KAAK,KAAK,GAAG,CACpC,OAAO,OACP,GAAG,OACF,GACE,WAAW,sBAAsB,CACjC,OAAO,GAAG,IAAI,GAAG,MAAM,CAAC,CACxB,MAAM,0BAA0B,KAAK,KAAK,GAAG,CAC7C,MAAM,8BAA8B,KAAK,OAAO,CAClD,CACD,CACA,SAAS;AACX,SAAM,GACJ,WAAW,sBAAsB,CACjC,MAAM,MAAM,KAAK,KAAK,GAAG,CACzB,MAAM,UAAU,KAAK,OAAO,CAC5B,SAAS;AACX;EACD,QACC,OAAM,IAAI,cAAc,yBAAyB,8BAA8B,EAC9E,QAAQ;GAAE,MAAM,KAAK;GAAM,IAAI,KAAK;GAAI,EACxC,CAAC;;;;;;;ACxKL,MAAa,kBAAkB;;AA6C/B,MAAM,cAA8C,IAAI,IAAI,CAC3D,uBACA,wBACA,CAAC;;;;;;;;AASF,MAAM,eAAqE;CAC1E,uBAAuB;CACvB,wBAAwB;CACxB,uBAAuB;CACvB;AAED,MAAM,qBAAqB;;AAG3B,SAAgB,iBAAiB,UAA0B;AAC1D,QAAO,KAAK,IAAI,kBAAkB,KAAK,KAAK,IAAI,GAAG,WAAW,EAAE,EAAE,mBAAmB;;AAGtF,MAAM,oBAAoB;CAAC;CAAW;CAAW;CAAY;AAE7D,SAAS,OAAO,WAA8B,iBAAqC;AAClF,QAAO;EACN;EACA,iBAAiB,gBAAgB,UAAU,MAAM,UAAU,MAAM,GAAG,OAAO;EAC3E;;;;;;;;AASF,eAAsB,uBAAuB,OAKqB;CACjE,MAAM,MAAM,IAAI,4BAA4B,MAAM,GAAG;CACrD,MAAM,YAAY,MAAM,IAAI,QAAQ,MAAM,YAAY;AACtD,KAAI,UAAU,SAAS,SACtB,OAAM,IAAI,cAAc,0BAA0B,6BAA6B;AAEhF,KAAI,UAAU,kBAAkB,MAAM,cACrC,OAAM,IAAI,cAAc,oCAAoC,gCAAgC;AAE7F,KAAI,UAAU,eAAe,QAAQ,UAAU,eAAe,MAAM,WACnE,OAAM,IAAI,cAAc,iCAAiC,6BAA6B;AAEvF,KAAI,UAAU,UAAU,aAAa,UAAU,UAAU,WAAW;EACnE,MAAM,UACJ,wBAA8C,SAAS,UAAU,MAAM,IACxE,UAAU,sBAAsB;AACjC,MAAI,UAAU,UAAU,aAAa,QAAS,QAAO;GAAE;GAAW,WAAW;GAAO;AACpF,QAAM,IAAI,cAAc,0BAA0B,yCAAyC;;CAE5F,MAAM,QAAQ,MAAM,IAAI,MAAM,UAAU,IAAI,CAAC,UAAU,CAAC;AACxD,KAAI,MAAM,YAAY,eACrB,OAAM,IAAI,cAAc,yBAAyB,4BAA4B;AAE9E,KAAI,MAAM,YAAY,gBACrB,OAAM,IAAI,cAAc,0BAA0B,yCAAyC;AAM5F,QAAO;EAAE,WAJS,MAAM,IAAI,QAAQ,UAAU,IAAI,MAAM,YAAY;GACnE,OAAO;GACP,QAAQ,EAAE,OAAO,WAAW;GAC5B,CAAC;EAC6B,WAAW;EAAM;;AAGjD,eAAsB,cAAc,SAA6D;CAChG,MAAM,MAAM,IAAI,4BAA4B,QAAQ,GAAG;CACvD,MAAM,QAAQ,MAAM,IAAI,MAAM,QAAQ,aAAa,kBAAkB;AACrE,KAAI,MAAM,YAAY,WAAW;AAChC,MAAI,MAAM,UAAU,SAAS,SAC5B,OAAM,IAAI,cAAc,0BAA0B,6BAA6B;AAEhF,SAAO;GAAE,GAAG,OAAO,MAAM,WAAW,gBAAgB;GAAE,OAAO;GAAO;;CAGrE,MAAM,OAAO,MAAM,eAAe,SAAS,KAAK,MAAM,WAAW,MAAM,WAAW;AAClF,QAAO;EAAE,GAAG;EAAM,OAAO,gBAAgB,KAAK,UAAU,MAAM,KAAK,UAAU,MAAM;EAAE;;AAGtF,eAAe,eACd,SACA,KACA,WACA,YACsB;AACtB,KACC,UAAU,SAAS,YAClB,UAAU,UAAU,aAAa,UAAU,UAAU,WACrD;AACD,QAAM,IAAI,QAAQ,UAAU,IAAI,WAAW;AAC3C,QAAM,IAAI,cACT,0BACA,8CACA;;AAGF,KAAI;AACH,MAAI,MAAM,qBAAqB,QAAQ,GAAG,CACzC,QAAO,OAAO,MAAM,IAAI,QAAQ,UAAU,IAAI,WAAW,EAAE,gBAAgB;AAG5E,SAAO,MAAM,QADG,MAAM,YAAY,SAAS,KAAK,WAAW,WAAW,EACxC,QAAQ,OAAO;UACrC,OAAO;AACf,MAAI,iBAAiB,sBACpB,QAAO,OAAO,MAAM,IAAI,gBAAgB,UAAU,IAAI,WAAW,EAAE,EAAE;AAEtE,MAAI,gBAAgB,MAAM,IAAI,YAAY,IAAI,MAAM,KAAK,CAAE,OAAM;EACjE,MAAM,OAA0B,gBAAgB,MAAM,GAAG,MAAM,OAAO;EACtE,MAAM,SAAS,gBAAgB,MAAM,GAAG,MAAM,SAAS;EACvD,MAAM,QAAQ,aAAa;AAC3B,MAAI,UAAU,UAAc,gBAAgB,MAAM,IAAI,SAAS,wBAC9D,QAAO,OAAO,MAAM,IAAI,KAAK,UAAU,IAAI,YAAY;GAAE;GAAM;GAAQ,CAAC,EAAE,EAAE;AAE7E,MAAI,CAAC,gBAAgB,MAAM,CAAE,SAAQ,MAAM,kCAAkC,MAAM;EAEnF,MAAM,WAAW,cADF,MAAM,IAAI,QAAQ,UAAU,GAAG,CACR,GAAG;EACzC,MAAM,cAAc;GAAE,GAAG;GAAQ;GAAU;AAC3C,MAAI,YAAY,MACf,QAAO,OAAO,MAAM,IAAI,KAAK,UAAU,IAAI,YAAY;GAAE;GAAM,QAAQ;GAAa,CAAC,EAAE,EAAE;AAK1F,SAAO,OAHU,MAAM,IAAI,QAAQ,UAAU,IAAI,YAAY,EAC5D,YAAY;GAAE;GAAM,QAAQ;GAAa,EACzC,CAAC,EACsB,iBAAiB,SAAS,CAAC;;;;AAKrD,SAAS,cAAc,WAAsC;AAC5D,KAAI,UAAU,cAAc,QAAQ,gBAAgB,UAAU,MAAM,UAAU,MAAM,CAAE,QAAO;CAC7F,MAAM,WAAW,UAAU,aAAa;AACxC,QAAO,OAAO,aAAa,WAAW,WAAW;;AAGlD,eAAe,qBAAqB,IAAwC;AAC3E,KAAI;AAMH,UALY,MAAM,GAChB,WAAW,iCAAiC,CAC5C,OAAO,QAAQ,CACf,MAAM,YAAY,KAAK,sBAAsB,CAC7C,kBAAkB,GACR,UAAU;UACd,OAAO;AACf,MAAI,oBAAoB,MAAM,CAAE,QAAO;AACvC,QAAM;;;AAIR,eAAe,YACd,SACA,KACA,WACA,YACyB;CACzB,MAAM,QAAQ,IAAI,cACjB,QAAQ,SACR,cAAc,UAAU,UAAU,IAAI,UAAU,cAAc,CAC9D;CACD,MAAM,SAAS,IAAI,oBAClB,OACA,IAAI,6BAA6B,QAAQ,GAAG,CAAC,gBAAgB,UAAU,GAAG,CAC1E;CACD,MAAM,WAAW,MAAM,OAAO,UAAU;CACxC,MAAM,gBAAgB,MAAM,OAAO,QAAQ;AAC3C,KAAI,UAAU,kBAAkB,cAC/B,OAAM,IAAI,cAAc,oCAAoC,gCAAgC;CAE7F,MAAM,WAAW,MAAM,MAAM,QAAQ,QAAQ,gBAAgB,cAAc;AAC3E,KAAI,aAAa,KAChB,OAAM,IAAI,cAAc,iCAAiC,yBAAyB;CAEnF,MAAM,SAAS,qBAAqB,UAAU,KAAK,MAAM,SAAS,CAAC;AACnE,KAAI,CAAC,OAAO,WAAY,MAAM,WAAW,OAAO,KAAK,KAAM,UAAU,WACpE,OAAM,IAAI,cAAc,iCAAiC,6BAA6B;CAEvF,MAAM,OAAO,OAAO;AACpB,KAAI,KAAK,kBAAkB,cAC1B,OAAM,IAAI,cAAc,iCAAiC,8BAA8B;AAExF,KAAI,CAAC,iBAAiB,KAAK,CAC1B,OAAM,IAAI,cAAc,yBAAyB,2BAA2B;AAE7E,QAAO,IAAI,cACV,QAAQ,IACR,QAAQ,SACR,KACA,WACA,YACA,MACA,UACA,QACA,QAAQ,UAAU,IAAI,oBAAoB,CAC1C;;AAGF,SAAS,cAAc,OAAoB;AAC1C,QAAO;EAAE,MAAM,cAAc,QAAQ,MAAM;EAAE,OAAO,cAAc;EAAQ;;AAG3E,eAAe,WACd,SACA,QACA,QAAyE,EAAE,EAC3D;CAChB,MAAM,YAAY,MAAM,QAAQ,IAAI,QAAQ,QAAQ,aAAa,QAAQ,YAAY;EACpF,GAAG;EACH,GAAI,QAAQ,UAAU,cAAc,OAAO,EAAE,GAAG,EAAE,YAAY,MAAM;EACpE,OAAO,OAAO;EACd;EACA,UAAU,cAAc,OAAO,MAAM;EACrC,CAAC;AACF,SAAQ,YAAY;AACpB,KAAI,UAAU,sBAAsB,KAAM,OAAM,IAAI,uBAAuB;;AAG5E,SAAS,cAAc,WAA4C;CAClE,MAAM,SAAS,UAAU;AACzB,KAAI,WAAW,KAAM,QAAO,EAAE,OAAO,WAAW;AAChD,KAAI,CAAE,cAAoC,SAAS,OAAO,MAAM,CAC/D,OAAM,IAAI,cAAc,0BAA0B,2CAA2C;AAG9F,QAAO;;AAGR,SAAS,sBAAsB,OAAkC;CAChE,MAAM,OAAO,cAAc,cAAc,QAAQ,MAAM,GAAG;AAC1D,KAAI,SAAS,UAAW,QAAO;EAAE,OAAO;EAAW,MAAM;EAAU,OAAO;EAAM;CAChF,MAAM,cAAc,qBAAqB,MAAM,cAAsB,cAAc,KAAK;AACxF,KAAI,CAAC,YAAa,OAAM,IAAI,MAAM,2BAA2B,QAAQ;AACrE,QAAO;EAAE,OAAO;EAAa,UAAU,cAAc,YAAY;EAAE;;;AAIpE,MAAM,wBAAwB;AAE9B,eAAe,UAAU,SAAwB,iBAA8C;AAC9F,QAAO,OACN,MAAM,QAAQ,IAAI,QAAQ,QAAQ,aAAa,QAAQ,WAAW,EAClE,gBACA;;AAGF,eAAe,QAAQ,SAAwB,QAA+C;AAC7F,UAAS;EACR,MAAM,SAAS,cAAc,QAAQ,UAAU;AAC/C,UAAQ,OAAO,OAAf;GACC,KAAK;AACJ,UAAM,QAAQ,QAAQ;AACtB;GACD,KAAK,kBAAkB;IACtB,MAAM,WAAW,MAAM,cAAc,SAAS,OAAO,OAAO,SAC3D,WAAW,SAAS;KAAE,OAAO;KAAkB;KAAM,CAAC,CACtD;AACD,QAAI,SAAS,UAAU,WAAY,QAAO,UAAU,SAAS,EAAE;AAC/D,QAAI,SAAS,UAAU,OAAQ,QAAO,UAAU,SAAS,gBAAgB;AACzE,QAAI,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,uBAAuB,CAAC,CAC/D,QAAO,UAAU,SAAS,EAAE;AAE7B,UAAM,WAAW,SAAS;KAAE,OAAO;KAAU,UAAU,cAAc,SAAS;KAAE,CAAC;AACjF;;GAED,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK;GACL,KAAK,gBAAgB;IACpB,MAAM,QAAQ,OAAO;AAIrB,QAHkB,MAAM,eAAe,SAAS,OAAO,OAAO,WAAW,aACxE,WAAW,SAAS;KAAE;KAAO;KAAU,CAAC,CACxC,IACgB,CAAC,QAAQ,OAAO,SAAS,EAAE,SAAS,uBAAuB,CAAC,CAC5E,QAAO,UAAU,SAAS,EAAE;AAE7B,UAAM,WAAW,SAAS,sBAAsB,MAAM,CAAC;AACvD;;GAED,KAAK;AAMJ,QALkB,MAAM,WACvB,SACA;KAAE,MAAM,OAAO;KAAM,OAAO,OAAO;KAAO,GACzC,aAAa,WAAW,SAAS;KAAE,OAAO;KAAW,GAAG;KAAU,CAAC,CACpE,CACc,QAAO,UAAU,SAAS,EAAE;AAC3C,UAAM,WACL,SACA;KAAE,OAAO;KAAU,UAAU;KAAM,YAAY;KAAM,YAAY;KAAG,EACpE,EAAE,OAAO,aAAa,CACtB;AACD;GAED,KAAK,SACJ,QAAO,UAAU,SAAS,QAAQ,OAAO,YAAY,KAAK;;;;AAK9D,eAAe,QAAQ,SAAuC;AAI7D,OAAM,WAAW,SAAS,EAAE,OAAO,WAAW,EAAE,EAAE,OAAO,WAAW,CAAC;CACrE,MAAM,SAAS,MAAM,kBAAkB,QAAQ,GAAG;CAClD,MAAM,UAAU,WAAW,QAAQ,GAAG,GAAG,aAAa;AACtD,KAAI,WAAW,QAAQ,KAAK,OAAO,UAAU,YAAY,QAAQ,KAAK,OAAO,QAC5E,OAAM,IAAI,cAAc,iCAAiC,mCAAmC;AAE7F,OAAM,uBAAuB,QAAQ;CACrC,MAAM,SAAS,MAAM,sBAAsB,QAAQ,GAAG;CACtD,MAAM,WAAW,IAAI,IAAI,iBAAiB,QAAQ,CAAC,KAAK,SAAS,GAAG,KAAK,KAAK,GAAG,KAAK,KAAK,CAAC;CAC5F,MAAM,aAAa,OAAO,eAAe,QACvC,SAAS,CAAC,SAAS,IAAI,GAAG,KAAK,KAAK,GAAG,KAAK,KAAK,CAClD;AACD,KAAI,CAAC,OAAO,SAAS,WAAW,SAAS,EACxC,OAAM,IAAI,cAAc,6BAA6B,gCAAgC,EACpF,QAAQ;EAAE,UAAU,OAAO,SAAS;EAAQ,oBAAoB,WAAW;EAAQ,EACnF,CAAC;AAEH,OAAM,WAAW,SAAS;EAAE,OAAO;EAAkB,MAAM;EAAG,EAAE,EAAE,qBAAqB,MAAM,CAAC;;AAG/F,eAAe,uBAAuB,SAAuC;CAC5E,MAAM,WAAW,OAAO,QAAQ,QAAQ,KAAK,UAAU,kBAAkB;CACzE,MAAM,UAAU,CAAC,GAAG,IAAI,IAAI,SAAS,SAAS,GAAG,YAAa,WAAW,OAAO,EAAE,GAAG,CAAC,OAAO,CAAE,CAAC,CAAC;CACjG,MAAM,wBAAQ,IAAI,KAAa;AAC/B,MAAK,MAAM,SAAS,OAAO,SAAS,eAAe,EAAE;EACpD,MAAM,OAAO,MAAM,QAAQ,GACzB,WAAW,QAAQ,CACnB,OAAO,KAAK,CACZ,MAAM,MAAM,MAAM,MAAM,CACxB,SAAS;AACX,OAAK,MAAM,OAAO,KAAM,OAAM,IAAI,IAAI,GAAG;;CAE1C,MAAM,UAAU,SAAS,MAAM,GAAG,YAAY,WAAW,QAAQ,CAAC,MAAM,IAAI,OAAO,CAAC;AACpF,KAAI,QACH,OAAM,IAAI,cAAc,8BAA8B,yCAAyC,EAC9F,QAAQ,EAAE,WAAW,QAAQ,IAAI,EACjC,CAAC;;AAIJ,eAAe,UACd,SACA,QACA,OACsB;CACtB,MAAM,OAAO,MAAM,OAAO;EACzB,IAAI,QAAQ;EACZ,SAAS,QAAQ;EACjB,aAAa,QAAQ;EACrB,QAAQ,QAAQ;EAChB,MAAM,QAAQ;EACd,QAAQ;EACR,QAAQ,QAAQ;EAChB,CAAC;AAEF,KAAI,CAAC,KAAK,MAAM;AACf,QAAM,WAAW,SAAS;GACzB,OAAO;GACP,UAAU;GACV,YAAY;GACZ,YAAY;GACZ,UAAU,OAAO,KAAK,OAAO;GAC7B,CAAC;AACF,SAAO,UAAU,SAAS,EAAE;;AAE7B,KAAI,KAAK,WAAW,SAAS,GAAG;EAC/B,MAAM,SAA0C,EAAE,YAAY,KAAK,WAAW,QAAQ;AACtF,OAAK,WAAW,MAAM,GAAG,gBAAgB,uBAAuB,CAAC,SAAS,UAAU,UAAU;AAC7F,UAAO,YAAY,WAAW,GAAG,SAAS,KAAK,GAAG,SAAS,GAAG,GAAG,SAAS,SAAS,MAClF,GACA,IACA;IACA;AACF,QAAM,IAAI,cACT,gCACA,4CACA,EACC,QACA,CACD;;CAEF,MAAM,YAAY,QAAQ;AAC1B,KAAI,UAAU,kBAAkB,QAAQ,UAAU,eAAe,KAChE,OAAM,IAAI,cAAc,0BAA0B,6BAA6B;CAEhF,MAAM,UAAU,MAAM,YAAY;EACjC,aAAa,UAAU;EACvB,eAAe,UAAU;EACzB,YAAY,UAAU;EACtB,cAAc,QAAQ,KAAK,OAAO;EAClC,cAAc,QAAQ,SAAS;EAC/B,eAAe;EACf,uBAAuB;EACvB,8BAAa,IAAI,MAAM,EAAC,aAAa;EACrC,eAAe,KAAK;EACpB,QAAQ,KAAK;EACb,UAAU,QAAQ,KAAK,SACrB,MAAM,GAAG,IAAI,CACb,KAAK,aAAa;GAAE,MAAM,QAAQ;GAAM,SAAS,QAAQ;GAAS,EAAE;EACtE,cAAc;EACd,CAAC;AAKF,QAAO,OAJW,MAAM,QAAQ,IAAI,SAAS,UAAU,IAAI,QAAQ,YAAY;EAC9E;EACA,UAAU;GAAE,MAAM,cAAc;GAAQ,OAAO,cAAc;GAAQ;EACrE,CAAC,EACuB,EAAE;;AAG5B,SAAS,OAAO,OAAoD;AAEnE,QAAO;;;;;;ACtbR,MAAM,iBAAiB;AAEvB,SAAS,aAAa,OAAyB;AAC9C,QACC,gBAAgB,MAAM,KACrB,MAAM,SAAS,yBAAyB,MAAM,SAAS;;AAI1D,MAAM,qBAAqB;AAC3B,MAAM,iBAAiB;AAIvB,SAAS,QAAQ,MAAc,SAAiB,SAAgD;AAC/F,QAAO;EACN,SAAS;EACT,OAAO,YAAY,SAAY;GAAE;GAAM;GAAS,GAAG;GAAE;GAAM;GAAS;GAAS;EAC7E;;AAGF,SAAS,YAAY,OAAgB,cAAsB,iBAAsC;AAChG,KAAI,gBAAgB,MAAM,CACzB,QAAO,QAAQ,MAAM,MAAM,MAAM,SAAS,MAAM,SAAS,EAAE,GAAG,MAAM,QAAQ,GAAG,OAAU;AAE1F,KAAI,iBAAiB,mBACpB,QAAO,QAAQ,kBAAkB,4BAA4B;AAE9D,SAAQ,MAAM,cAAc,gBAAgB,IAAI,MAAM;AACtD,QAAO,QAAQ,cAAc,gBAAgB;;AAG9C,SAAS,UAAU,OAAmC;AACrD,QAAO,KAAK,IAAI,KAAK,IAAI,KAAK,MAAM,SAAS,mBAAmB,EAAE,EAAE,EAAE,eAAe;;AAGtF,SAAS,iBACR,QACgD;AAChD,KAAI,WAAW,OAAW,QAAO;CACjC,MAAM,EAAE,YAAY,OAAO,aAAa,OAAO;AAC/C,QAAO;EAAE,WAAW;EAAY;EAAI;;AAGrC,SAAS,SAAS,SAAkB,WAA6C;AAChF,QAAO,IAAI,cACV,SACA,cAAc,UAAU,MAAM,UAAU,IAAI,UAAU,cAAc,CACpE;;AAGF,eAAe,cACd,YACA,aAC6B;CAC7B,MAAM,YAAY,MAAM,WAAW,IAAI,YAAY;AACnD,KAAI,CAAC,aAAa,UAAU,SAAS,SACpC,OAAM,IAAI,cAAc,gCAAgC,+BAA+B;AAExF,QAAO;;AA2BR,eAAsB,2BACrB,IACA,QAC2C;AAC3C,KAAI;EACH,MAAM,SAAS,MAAM,sBAAsB,GAAG;AAC9C,SAAO;GACN,SAAS;GACT,MAAM;IACL,gBAAgB,CAAC,GAAG,0BAA0B;IAC9C,UAAU,CAAC,GAAG,sBAAsB;IACpC,kBAAkB,CAAC,GAAG,kBAAkB,CAAC,UAAU;IACnD,QAAQ;KACP,eAAe,gBAAgB;KAC/B,iBAAiB,gBAAgB;KACjC,YAAY,gBAAgB;KAC5B,cAAc,gBAAgB;KAC9B,cAAc,gBAAgB;KAC9B,YAAY,gBAAgB;KAC5B,aAAa,gBAAgB;KAC7B,WAAW,gBAAgB;KAC3B,cAAc,OAAO;KACrB;IACD,gBAAgB;KACf,OAAO,OAAO;KACd,UAAU,OAAO,SAAS,KAAK,aAAa,EAAE,GAAG,SAAS,EAAE;KAC5D,gBAAgB,OAAO,eAAe,KAAK,UAAU,EAAE,GAAG,MAAM,EAAE;KAClE;IACD;GACD;UACO,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,uCAAuC;;;AAW7F,eAAe,YACd,IACA,aACA,SACgC;CAChC,MAAM,QAAQ,UAAU,QAAQ,MAAM;CACtC,MAAM,QAAQ,QAAQ,WAAW,SAAY,SAAY,aAAa,QAAQ,OAAO,CAAC;CACtF,MAAM,QAAQ,MAAM,IAAI,6BAA6B,GAAG,CAAC,KAAK,aAAa;EAC1E,OAAO;EACP;EACA,OAAO,QAAQ;EACf,CAAC;CACF,MAAM,QAAQ,MACZ,MAAM,GAAG,MAAM,CACf,KAAK,UAAU;EAAE,MAAM,KAAK;EAAM,OAAO,KAAK;EAAO,QAAQ,KAAK;EAAQ,EAAE;CAC9E,MAAM,OAAO,MAAM,GAAG,GAAG;AACzB,QAAO,MAAM,SAAS,SAAS,OAC5B;EAAE;EAAO,YAAY,aAAa,KAAK,MAAM,KAAK,KAAK;EAAE,GACzD,EAAE,OAAO;;AAGb,eAAe,cACd,IACA,SACA,WACA,UACA,OACgB;CAChB,MAAM,SAAS,IAAI,6BAA6B,GAAG;AAEnD,MADiB,MAAM,OAAO,IAAI,UAAU,IAAI,cAAc,GAChD,UAAU,YAAY;EACnC,MAAM,SAAS,MAAM,UAAU,MAAM;AACrC,QAAM,SAAS,SAAS,UAAU,CAAC,YAAY,eAAe,OAAO,MAAM,YAAY,QAAQ;GAC9F,aAAa;GACb,6BAA6B,OAAO,WAAW,UAAU,IAAI,cAAc;GAC3E,CAAC;AACF,QAAM,OAAO,YACZ,UAAU,IACV,CAAC;GAAE,MAAM;GAAe,OAAO,MAAM;GAAY;GAAQ,CAAC,EAC1D,WACA;;AAEF,OAAM,OAAO,YACZ,UAAU,IACV,SAAS,MAAM,KAAK,SAAS;EAAE,MAAM,IAAI;EAAM,OAAO,IAAI;EAAO,QAAQ,IAAI;EAAQ,EAAE,CACvF;;;;;;;;AAgBF,eAAsB,mBACrB,IACA,SACA,OAGC;AACD,KAAI;EACH,MAAM,WAAW,cAAc,MAAM,SAAS;EAC9C,MAAM,SAAS,MAAM,cAAc,SAAS;EAC5C,MAAM,SAAS,MAAM,sBAAsB,GAAG;AAC9C,MAAI,CAAC,OAAO,MACX,OAAM,IAAI,cACT,6BACA,6DACA,EAAE,QAAQ,EAAE,UAAU,OAAO,SAAS,QAAQ,EAAE,CAChD;EAGF,MAAM,EAAE,WAAW,YAAY,MADZ,IAAI,4BAA4B,GAAG,CACN,OAAO;GACtD,MAAM;GACN,WAAW,MAAM;GACjB,gBAAgB,MAAM;GACtB,eAAe;GACf,cAAc,SAAS;GACvB,CAAC;AACF,MAAI,UAAU,SAAS,SACtB,OAAM,IAAI,cAAc,0BAA0B,6BAA6B;AAEhF,MAAI,QACH,OAAM,oBAAoB,IAAI;GAC7B,SAAS,MAAM;GACf,QAAQ;GACR,cAAc;GACd,YAAY,UAAU;GACtB,SAAS,EAAE,eAAe,QAAQ;GAClC,CAAC;AAEH,MAAI,UAAU,UAAU,YACvB,OAAM,cAAc,IAAI,SAAS,WAAW,UAAU,MAAM,SAAS;AAEtE,SAAO;GACN,SAAS;GACT,MAAM;IACL,WAAW,kBAAkB,UAAU;IACvC;IACA,SAAS,MAAM,YAAY,IAAI,UAAU,IAAI,EAAE,CAAC;IAChD;GACD;UACO,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,0BAA0B;;;AAI/E,eAAsB,oBACrB,IACA,aACA,SAC2C;AAC3C,KAAI;AACH,QAAM,cAAc,IAAI,4BAA4B,GAAG,EAAE,YAAY;AACrE,SAAO;GAAE,SAAS;GAAM,MAAM,MAAM,YAAY,IAAI,aAAa,QAAQ;GAAE;UACnE,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,+BAA+B;;;AAuBpF,SAAS,UAAU,MAAkD,cAA8B;AAClG,SAAQ,MAAR;EACC,KAAK,WACJ,QAAO,gBAAgB;EACxB,KAAK,QACJ,QAAO;EACR,KAAK;EACL,KAAK,UACJ,QAAO,gBAAgB;;;AAI1B,eAAe,aAAa,MAAyC,OAAe;CACnF,MAAM,SAAS,MAAM,cAAc;CACnC,MAAM,UAAU,oBAAoB,QAAQ;EAC3C,UAAU;EACV,uBACC,IAAI,cAAc,+BAA+B,+BAA+B;EACjF,CAAC;AACF,KAAI,KAAM,OAAM,KAAK,YAAY,QAAQ,OAAO,CAAC,OAAO,IAAI,gBAAgB,CAAC;AAC7E,QAAO;EAAE,QAAQ,MAAM,OAAO,QAAQ;EAAE,OAAO,QAAQ,OAAO;EAAE;;;;;;;AAQjE,eAAe,iBACd,OACA,MACA,MACmB;AACnB,KAAI,CAAE,MAAM,MAAM,OAAO,KAAK,CAAG,QAAO;CACxC,IAAI;AACJ,KAAI;AACH,aAAW,MAAM,MAAM,QAAQ,SAAS,MAAM,OAAO,KAAK,CAAC;UACnD,OAAO;AACf,QAAM,IAAI,cAAc,0BAA0B,gCAAgC,EACjF,OAAO,OACP,CAAC;;AAEH,KAAI;EACH,MAAM,SAAS,MAAM,aAAa,SAAS,MAAM,KAAK,MAAM;AAC5D,SAAO,OAAO,UAAU,KAAK,SAAS,OAAO,WAAW,KAAK;UACrD,OAAO;AACf,MAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS,8BAA+B,QAAO;AACnF,QAAM;;;;;;;;;;;AAYR,eAAsB,uBACrB,IACA,SACA,OAC6C;AAC7C,KAAI;EACH,MAAM,aAAa,IAAI,4BAA4B,GAAG;EACtD,MAAM,YAAY,MAAM,cAAc,YAAY,MAAM,YAAY;AACpE,MAAI,UAAU,UAAU,YACvB,OAAM,IAAI,cACT,0BACA,6CACA;EAEF,MAAM,SAAS,iBAAiB,MAAM,KAAK;AAC3C,MAAI,CAAC,OACJ,OAAM,IAAI,cAAc,yBAAyB,uBAAuB;EAEzE,MAAM,SAAS,IAAI,6BAA6B,GAAG;EACnD,MAAM,OAAO,MAAM,OAAO,IAAI,UAAU,IAAI,OAAO,KAAK;AACxD,MAAI,CAAC,KACJ,OAAM,IAAI,cAAc,8BAA8B,uCAAuC,EAC5F,QAAQ,EAAE,MAAM,OAAO,MAAM,EAC7B,CAAC;EAEH,MAAM,QAAQ,UAAU,OAAO,MAAM,MAAM,aAAa;AACxD,MAAI,KAAK,QAAQ,MAChB,OAAM,IAAI,cAAc,2BAA2B,yCAAyC,EAC3F,QAAQ;GAAE,MAAM,OAAO;GAAM,OAAO,KAAK;GAAO;GAAO,EACvD,CAAC;AAEH,MAAI,MAAM,kBAAkB,KAAK,MAChC,OAAM,IAAI,cACT,+BACA,mDACA,EAAE,QAAQ;GAAE,MAAM,OAAO;GAAM,UAAU,KAAK;GAAO,EAAE,CACvD;EAGF,MAAM,QAAQ,SAAS,SAAS,UAAU;AAC1C,MAAI,KAAK,UAAU,cAAe,MAAM,iBAAiB,OAAO,OAAO,MAAM,KAAK,EAAG;GACpF,MAAM,WAAW,MAAM,aAAa,MAAM,MAAM,KAAK,MAAM;AAC3D,OAAI,SAAS,UAAU,KAAK,MAC3B,OAAM,IAAI,cAAc,+BAA+B,4BAA4B,EAClF,QAAQ;IAAE,MAAM,OAAO;IAAM,UAAU,KAAK;IAAO,EACnD,CAAC;AAEH,OAAI,SAAS,WAAW,KAAK,OAC5B,OAAM,IAAI,cAAc,iCAAiC,8BAA8B,EACtF,QAAQ,EAAE,MAAM,OAAO,MAAM,EAC7B,CAAC;AAEH,UAAO;IACN,SAAS;IACT,MAAM;KACL,MAAM,OAAO;KACb,OAAO,KAAK;KACZ,iBAAiB;KACjB,YAAY,MAAM,OAAO,aAAa,UAAU,GAAG,EAAE;KACrD;IACD;;AAGF,QAAM,MAAM,YAAY,OAAO,MAAM,MAAM,QAAQ,IAAI,WAAW,EAAE,EAAE,KAAK,OAAO,KAAK,QAAQ,EAC9F,6BAA6B,OAAO,WAAW,UAAU,IAAI,OAAO,KAAK,EACzE,CAAC;AACF,OAAK,MAAM,WAAW,QAAQ,UAAU,GAAG,EAAE,UAAU,YACtD,OAAM,IAAI,cACT,0BACA,6CACA;AAEF,MAAI,OAAO,SAAS,SAAS;GAC5B,MAAM,UAAU,MAAM,IAAI,oBAAoB,MAAM,CAAC,WAAW,OAAO,IAAI;AAC3E,SAAM,OAAO,YACZ,UAAU,IACV,QAAQ,KAAK,WAAW;IAAE,MAAM,MAAM;IAAM,OAAO,MAAM;IAAO,QAAQ,MAAM;IAAQ,EAAE,CACxF;;AAEF,QAAM,OAAO,aAAa,UAAU,IAAI,KAAK;AAC7C,SAAO;GACN,SAAS;GACT,MAAM;IACL,MAAM,OAAO;IACb,OAAO,KAAK;IACZ,iBAAiB;IACjB,YAAY,MAAM,OAAO,aAAa,UAAU,GAAG,EAAE;IACrD;GACD;UACO,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,oCAAoC;;;;;;;;AA0B1F,eAAsB,oBACrB,IACA,SACA,OAC0C;AAC1C,KAAI;EACH,MAAM,aAAa,IAAI,4BAA4B,GAAG;EACtD,IAAI,YAAY,MAAM,cAAc,YAAY,MAAM,YAAY;EAClE,IAAI,OAA8B;EAClC,IAAI,SAA8B;AAElC,MAAI,UAAU,UAAU,aAAa;GACpC,MAAM,EAAE,aAAa,MAAM,IAAI,6BAA6B,GAAG,CAAC,aAAa,UAAU,GAAG;AAC1F,OAAI,WAAW,EACd,OAAM,IAAI,cAAc,yBAAyB,uCAAuC,EACvF,QAAQ,EAAE,SAAS,UAAU,EAC7B,CAAC;;AAIJ,MAAI,UAAU,UAAU,eAAe,UAAU,UAAU,aAAa;GACvE,MAAM,OAAO,MAAM,kBAAkB;IACpC;IACA;IACA,aAAa,UAAU;IACvB,QAAQ,MAAM,UAAU,IAAI,oBAAoB;IAChD,eAAe,MAAM;IACrB,CAAC,CAAC,OAAO,UAAmB;AAC5B,QAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS,wBAAyB,QAAO;AAC7E,UAAM;KACL;AACF,OAAI,CAAC,KACJ,QAAO;IACN,SAAS;IACT,MAAM;KACL,WAAW,kBAAkB,MAAM,WAAW,QAAQ,UAAU,GAAG,CAAC;KACpE,iBAAiB;KACjB;IACD;AAEF,eAAY,KAAK;AACjB,OAAI,CAAC,KAAK,KACT,QAAO;IACN,SAAS;IACT,MAAM;KAAE,WAAW,kBAAkB,UAAU;KAAE,iBAAiB;KAAG;IACrE;AAEF,UAAO,KAAK;AACZ,YAAS,KAAK;aACJ,UAAU,UAAU,WAAW;AACzC,UAAO,MAAM,eAAe,SAAS,UAAU;AAC/C,YAAS,UAAU;QAEnB,OAAM,IAAI,cAAc,0BAA0B,0BAA0B;AAG7E,MAAI,UAAU,UAAU,aAAa,MAAM,cAAc,QAAW;GACnE,MAAM,YAAY,MAAM,aAAa;IACpC;IACA;IACA,aAAa,UAAU;IACvB,WAAW,MAAM;IACjB,CAAC;AACF,UAAO,UAAU;AACjB,YAAS,UAAU;AACnB,eAAY,MAAM,WAAW,QAAQ,UAAU,GAAG;;AAGnD,SAAO;GACN,SAAS;GACT,MAAM;IACL,WAAW,kBAAkB,UAAU;IACvC,GAAI,OAAO,EAAE,MAAM,GAAG,EAAE;IACxB,GAAI,QAAQ,SAAS,EAAE,YAAY,QAAQ,GAAG,EAAE;IAChD,iBAAiB;IACjB;GACD;UACO,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,2BAA2B;;;AAIjF,eAAsB,iBACrB,IACA,SACA,aACyE;AACzE,KAAI;EACH,MAAM,YAAY,MAAM,cAAc,IAAI,4BAA4B,GAAG,EAAE,YAAY;EACvF,MAAM,OAAO,UAAU,aAAa,MAAM,eAAe,SAAS,UAAU,GAAG;AAC/E,MAAI,CAAC,QAAQ,CAAC,UAAU,WACvB,OAAM,IAAI,cAAc,0BAA0B,+BAA+B;AAElF,SAAO;GAAE,SAAS;GAAM,MAAM;IAAE;IAAM,YAAY,UAAU;IAAY;GAAE;UAClE,OAAO;AACf,SAAO,YAAY,OAAO,0BAA0B,6BAA6B;;;AAMnF,eAAsB,gBACrB,IACA,aAMC;AACD,KAAI;EACH,MAAM,YAAY,MAAM,cAAc,IAAI,4BAA4B,GAAG,EAAE,YAAY;EACvF,MAAM,QAAQ,MAAM,IAAI,6BAA6B,GAAG,CAAC,aAAa,UAAU,GAAG;AACnF,SAAO;GAAE,SAAS;GAAM,MAAM;IAAE,WAAW,kBAAkB,UAAU;IAAE;IAAO;GAAE;UAC1E,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,wBAAwB;;;AAI7E,eAAsB,iBACrB,IACA,SACgF;AAChF,KAAI;EACH,MAAM,OAAO,MAAM,IAAI,4BAA4B,GAAG,CAAC,KAAK;GAC3D,MAAM;GACN,OAAO,UAAU,QAAQ,MAAM;GAC/B,QAAQ,iBAAiB,QAAQ,OAAO;GACxC,CAAC;AACF,SAAO;GACN,SAAS;GACT,MAAM,KAAK,OACR;IAAE,OAAO,KAAK;IAAO,YAAY,aAAa,KAAK,KAAK,WAAW,KAAK,KAAK,GAAG;IAAE,GAClF,EAAE,OAAO,KAAK,OAAO;GACxB;UACO,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,yBAAyB;;;;AAK9E,eAAsB,mBACrB,IACA,aACA,QAC6D;AAC7D,KAAI;EACH,MAAM,aAAa,IAAI,4BAA4B,GAAG;AACtD,QAAM,cAAc,YAAY,YAAY;EAC5C,MAAM,YAAY,MAAM,WAAW,cAAc,YAAY;AAC7D,QAAM,oBAAoB,IAAI;GAC7B,SAAS;GACT,QAAQ;GACR,cAAc;GACd,YAAY;GACZ,CAAC;AACF,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,WAAW,kBAAkB,UAAU,EAAE;GAAE;UACnE,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,0BAA0B;;;;;;;AAQ/E,eAAsB,oBACrB,IACA,aACA,QAC6D;AAC7D,KAAI;EACH,MAAM,aAAa,IAAI,4BAA4B,GAAG;AACtD,QAAM,cAAc,YAAY,YAAY;EAC5C,MAAM,YAAY,MAAM,WAAW,QAAQ,YAAY;AACvD,QAAM,oBAAoB,IAAI;GAC7B,SAAS;GACT,QAAQ;GACR,cAAc;GACd,YAAY;GACZ,CAAC;AACF,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,WAAW,kBAAkB,UAAU,EAAE;GAAE;UACnE,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,2BAA2B;;;AAMhF,eAAe,cACd,YACA,aAC6B;CAC7B,MAAM,YAAY,MAAM,WAAW,IAAI,YAAY;AACnD,KAAI,CAAC,aAAa,UAAU,SAAS,SACpC,OAAM,IAAI,cAAc,gCAAgC,+BAA+B;AAExF,QAAO;;AAGR,eAAe,sBACd,IACA,aAC6B;CAC7B,MAAM,YAAY,MAAM,cAAc,IAAI,4BAA4B,GAAG,EAAE,YAAY;AACvF,KAAI,UAAU,UAAU,WACvB,OAAM,IAAI,cAAc,0BAA0B,yBAAyB;AAE5E,KAAI,UAAU,uBAAuB,KACpC,OAAM,IAAI,cAAc,oBAAoB,uCAAuC;AAEpF,QAAO;;;;;;AAOR,eAAe,2BACd,WACA,UACA,OACa;AACb,KAAI;AACH,SAAO,MAAM,OAAO;UACZ,OAAO;AACf,MAAI,SACH,OAAM,UAAU,QAAQ,SAAS,GAAG,CAAC,OAAO,iBAA0B;AACrE,WAAQ,MAAM,mDAAmD,aAAa;IAC7E;AAEH,QAAM;;;;AAKR,eAAsB,mBAAmB,SAA+C;AACvF,QAAO,gBAAgB,oBAAoB,MAAM,QAAQ,CAAC;;;;;;;AA0B3D,eAAsB,mBACrB,IACA,OAC+E;AAC/E,KAAI;EACH,MAAM,YAAY,IAAI,2BAA2B,GAAG;AACpD,MAAI,MAAM,SACT,OAAM,UAAU,QAAQ,MAAM,SAAS,IAAI;GAC1C,QAAQ,MAAM;GACd,QAAQ;GACR,cAAc,MAAM,mBAAmB,MAAM,QAAQ;GACrD,SAAS,MAAM,SAAS;GACxB,CAAC;EAEH,MAAM,EAAE,WAAW,YAAY,MAAM,2BAA2B,WAAW,MAAM,gBAChF,aAAa;GACZ;GACA,WAAW,MAAM;GACjB,SAAS,MAAM;GACf,gBAAgB,MAAM;GACtB,CAAC,CACF;AACD,MAAI,MAAM,SAAU,OAAM,UAAU,cAAc,MAAM,SAAS,IAAI,UAAU,GAAG;AAClF,MAAI,QACH,OAAM,oBAAoB,IAAI;GAC7B,SAAS,MAAM;GACf,QAAQ;GACR,cAAc;GACd,YAAY,UAAU;GACtB,CAAC;AAEH,SAAO;GAAE,SAAS;GAAM,MAAM;IAAE,WAAW,kBAAkB,UAAU;IAAE;IAAS;GAAE;UAC5E,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,0BAA0B;;;AAU/E,MAAM,mBAA2C,UAAU,0BAA0B,MAAM;;AAG3F,eAAsB,oBACrB,IACA,SACA,OAC6F;AAC7F,KAAI;EACH,MAAM,aAAa,IAAI,4BAA4B,GAAG;AACtD,QAAM,cAAc,YAAY,MAAM,YAAY;EAClD,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,cAAc;IAC1B;IACA;IACA,aAAa,MAAM;IACnB,QAAQ,MAAM;IACd,eAAe,MAAM;IACrB;IACA,CAAC;WACM,OAAO;AACf,OAAI,gBAAgB,MAAM,IAAI,MAAM,SAAS,sBAC5C,QAAO;IACN,SAAS;IACT,MAAM;KACL,WAAW,kBAAkB,MAAM,WAAW,QAAQ,MAAM,YAAY,CAAC;KACzE,iBAAiB;KACjB;IACD;AAEF,SAAM;;EAEP,MAAM,kBACL,KAAK,YAAY,aAAa,IAAI,KAAK,YAAY,SAAS,iBAAiB;AAC9E,SAAO;GACN,SAAS;GACT,MAAM;IAAE,WAAW,kBAAkB,KAAK,UAAU;IAAE;IAAiB;GACvE;UACO,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,2BAA2B;;;AAIhF,eAAsB,gBACrB,IACA,aAC6D;AAC7D,KAAI;AAEH,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,WAAW,kBADzB,MAAM,cAAc,IAAI,4BAA4B,GAAG,EAAE,YAAY,CAChB,EAAE;GAAE;UACnE,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,wBAAwB;;;AAI7E,eAAsB,iBACrB,IACA,SACgF;AAChF,KAAI;EACH,MAAM,OAAO,MAAM,IAAI,4BAA4B,GAAG,CAAC,KAAK;GAC3D,MAAM;GACN,OAAO,UAAU,QAAQ,MAAM;GAC/B,QAAQ,iBAAiB,QAAQ,OAAO;GACxC,CAAC;AACF,SAAO;GACN,SAAS;GACT,MAAM,KAAK,OACR;IAAE,OAAO,KAAK;IAAO,YAAY,aAAa,KAAK,KAAK,WAAW,KAAK,KAAK,GAAG;IAAE,GAClF,EAAE,OAAO,KAAK,OAAO;GACxB;UACO,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,yBAAyB;;;AAY9E,SAAS,qBAAoC;AAC5C,QAAO,IAAI,cACV,iCACA,2CACA;;;;;;;AAQF,SAAS,gBACR,MACA,UAC6B;CAC7B,IAAI;CACJ,IAAI,QAAQ;AACZ,QAAO,KAAK,YACX,IAAI,gBAAwC;EAC3C,MAAM,QAAQ;AACb,YAAS,MAAM,cAAc;;EAE9B,UAAU,OAAO,YAAY;AAC5B,YAAS,MAAM;AACf,OAAI,QAAQ,SAAS,MAAO,OAAM,oBAAoB;AACtD,WAAQ,OAAO,MAAM;AACrB,cAAW,QAAQ,MAAM;;EAE1B,MAAM,QAAQ;AACb,OAAI,UAAU,SAAS,SAAU,MAAM,QAAQ,QAAQ,KAAM,SAAS,OACrE,OAAM,oBAAoB;;EAG5B,CAAC,CACF;;AAGF,eAAe,eACd,IACA,SACA,WACA,MAC4B;CAC5B,MAAM,SAAS,iBAAiB,KAAK;AACrC,KAAI,CAAC,OAAQ,OAAM,IAAI,cAAc,yBAAyB,uBAAuB;CACrF,MAAM,SAAS,kBAAkB;EAAE;EAAI;EAAS;EAAW,CAAC;AAC5D,KAAI,OAAO,SAAS,YAAY;EAC/B,MAAM,QAAQ,MAAM,OAAO,MAAM,UAAU,eAAe,gBAAgB,cAAc;AACxF,SAAO;GACN,MAAM;GACN,OAAO,MAAM;GACb,QAAQ,MAAM,UAAU,MAAM;GAC9B,MAAM,IAAI,eAA2B,EACpC,MAAM,YAAY;AACjB,eAAW,QAAQ,MAAM;AACzB,eAAW,OAAO;MAEnB,CAAC;GACF;;CAEF,MAAM,OAAO,MAAM,IAAI,6BAA6B,GAAG,CAAC,IAAI,UAAU,IAAI,OAAO,KAAK;AACtF,KAAI,CAAC,QAAQ,KAAK,UAAU,WAC3B,OAAM,IAAI,cAAc,8BAA8B,mCAAmC,EACxF,QAAQ,EAAE,MAAM,OAAO,MAAM,EAC7B,CAAC;CAEH,MAAM,SACL,OAAO,SAAS,UACb,MAAM,OAAO,KAAK,OAAO,OAAO,IAC/B,MAAM,OAAO,MAAM,KAAK,OAAO,KAAK,EAAE;AAC3C,QAAO;EACN,MAAM,KAAK;EACX,OAAO,KAAK;EACZ,QAAQ,KAAK;EACb,MAAM,gBAAgB,QAAQ,KAAK;EACnC;;;;;;;AAQF,eAAsB,iBACrB,IACA,SACA,aACA,MACuC;AACvC,KAAI;AAEH,SAAO;GAAE,SAAS;GAAM,MAAM,MAAM,eAAe,IAAI,SADrC,MAAM,sBAAsB,IAAI,YAAY,EACa,KAAK;GAAE;UAC1E,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,6BAA6B;;;AAIlF,gBAAgB,mBACf,IACA,SACA,WACoC;CACpC,MAAM,WAAW,MAAM,eAAe,IAAI,SAAS,WAAW,cAAc;AAC5E,OAAM;EAAE,MAAM,SAAS;EAAM,OAAO,SAAS;EAAO,YAAY,SAAS;EAAM;CAC/E,MAAM,SAAS,IAAI,6BAA6B,GAAG;CACnD,IAAI;AACJ,UAAS;EACR,MAAM,OAAO,MAAM,OAAO,KAAK,UAAU,IAAI;GAAE,OAAO;GAAY;GAAO,OAAO;GAAK,CAAC;AACtF,OAAK,MAAM,QAAQ,MAAM;AACxB,OAAI,KAAK,SAAS,cAAe;AACjC,SAAM;IACL,MAAM,KAAK;IACX,OAAO,KAAK;IACZ,MAAM,aAAa,MAAM,eAAe,IAAI,SAAS,WAAW,KAAK,KAAK,EAAE;IAC5E;;EAEF,MAAM,OAAO,KAAK,GAAG,GAAG;AACxB,MAAI,CAAC,QAAQ,KAAK,SAAS,IAAK;AAChC,UAAQ,KAAK;;;;;;;;;;;AAYf,eAAsB,oBACrB,IACA,SACA,aAC2D;AAC3D,KAAI;AAEH,SAAO;GACN,SAAS;GACT,MAAM,EAAE,MAAM,gBAAgB,mBAAmB,IAAI,SAHpC,MAAM,sBAAsB,IAAI,YAAY,CAGW,CAAC,EAAE;GAC3E;UACO,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,gCAAgC;;;;;;;;;AAyBrF,eAAsB,oBACrB,IACA,SACA,OAC6D;AAC7D,KAAI;EACH,MAAM,YAAY,MAAM,cAAc,IAAI,4BAA4B,GAAG,EAAE,MAAM,YAAY;AAC7F,MAAI,UAAU,kBAAkB,MAAM,cACrC,OAAM,IAAI,cAAc,oCAAoC,gCAAgC;AAE7F,MAAI,UAAU,eAAe,QAAQ,UAAU,eAAe,MAAM,WACnE,OAAM,IAAI,cAAc,iCAAiC,6BAA6B;AAEvF,MAAI,UAAU,UAAU,WAAW;GAClC,MAAM,OAAO,MAAM,eAAe,SAAS,UAAU;AACrD,OAAI,CAAC,QAAQ,CAAC,iBAAiB,KAAK,CACnC,OAAM,IAAI,cAAc,yBAAyB,gCAAgC,EAChF,QAAQ,EAAE,UAAU,MAAM,SAAS,UAAU,GAAG,EAChD,CAAC;;EAGJ,MAAM,YAAY,IAAI,2BAA2B,GAAG;AACpD,MAAI,MAAM,SACT,OAAM,UAAU,QAAQ,MAAM,SAAS,IAAI;GAC1C,QAAQ,MAAM;GACd,QAAQ;GACR,aAAa,UAAU;GACvB,eAAe,MAAM;GACrB,YAAY,MAAM;GAClB,SAAS,MAAM,SAAS;GACxB,CAAC;EAEH,MAAM,EAAE,WAAW,WAAW,WAAW,mBAAmB,MAAM,2BACjE,WACA,MAAM,gBAEL,uBAAuB;GACtB;GACA,aAAa,UAAU;GACvB,eAAe,MAAM;GACrB,YAAY,MAAM;GAClB,CAAC,CACH;AACD,MAAI,eACH,OAAM,oBAAoB,IAAI;GAC7B,SAAS,MAAM;GACf,QAAQ;GACR,cAAc;GACd,YAAY,UAAU;GACtB,SAAS;IAAE,eAAe,MAAM;IAAe,YAAY,MAAM;IAAY;GAC7E,CAAC;AAEH,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,WAAW,kBAAkB,UAAU,EAAE;GAAE;UACnE,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,2BAA2B;;;;;;;;;;AAWhF,eAAsB,oBACrB,IACA,SACA,OAC6F;AAC7F,KAAI;EACH,MAAM,aAAa,IAAI,4BAA4B,GAAG;AACtD,QAAM,cAAc,YAAY,MAAM,YAAY;EAClD,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,cAAc;IAC1B;IACA;IACA,aAAa,MAAM;IACnB,QAAQ;IACR,QAAQ,MAAM;IACd,CAAC;WACM,OAAO;AACf,OAAI,aAAa,MAAM,CACtB,QAAO;IACN,SAAS;IACT,MAAM;KACL,WAAW,kBAAkB,MAAM,WAAW,QAAQ,MAAM,YAAY,CAAC;KACzE,iBAAiB;KACjB;IACD;AAEF,SAAM;;AAEP,MAAI,KAAK,MAAO,OAAM,eAAe,IAAI,KAAK,WAAW,MAAM,OAAO;AACtE,SAAO;GACN,SAAS;GACT,MAAM;IAAE,WAAW,kBAAkB,KAAK,UAAU;IAAE,iBAAiB,KAAK;IAAiB;GAC7F;UACO,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,2BAA2B;;;AAIhF,eAAe,eACd,IACA,WACA,QACgB;AAChB,KAAI,UAAU,UAAU,YAAY;EACnC,MAAM,SAAS,UAAU,SAAS,UAAU,EAAE;AAC9C,QAAM,oBAAoB,IAAI;GAC7B,SAAS;GACT,QAAQ;GACR,cAAc;GACd,YAAY,UAAU;GACtB,SAAS;IACR,eAAe,UAAU;IACzB,YAAY,UAAU;IACtB,SAAS,OAAO,OAAO,OAAO,CAAC,QAAQ,KAAK,UAAU,MAAM,OAAO,EAAE;IACrE;GACD,CAAC;YACQ,UAAU,UAAU,SAC9B,OAAM,oBAAoB,IAAI;EAC7B,SAAS;EACT,QAAQ;EACR,cAAc;EACd,YAAY,UAAU;EACtB,SAAS,EAAE,WAAW,UAAU,WAAW;EAC3C,QAAQ;EACR,CAAC;;AAIJ,eAAsB,oBACrB,IACA,aACqD;AACrD,KAAI;EACH,MAAM,YAAY,MAAM,cAAc,IAAI,4BAA4B,GAAG,EAAE,YAAY;AACvF,MAAI,UAAU,UAAU,cAAc,CAAC,UAAU,QAChD,OAAM,IAAI,cAAc,0BAA0B,wBAAwB;AAE3E,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,SAAS,UAAU,SAAS;GAAE;UACtD,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,gCAAgC;;;AAMrF,MAAM,sBAA4E;CACjF,QAAQ;CACR,QAAQ;CACR;AAED,eAAsB,mBACrB,IACA,SACyE;AACzE,KAAI;EACH,MAAM,OAAO,MAAM,IAAI,2BAA2B,GAAG,CAAC,KAAK;GAC1D,QAAQ,QAAQ;GAChB,OAAO,UAAU,QAAQ,MAAM;GAC/B,QAAQ,iBAAiB,QAAQ,OAAO;GACxC,CAAC;AACF,SAAO;GACN,SAAS;GACT,MAAM,KAAK,OACR;IAAE,OAAO,KAAK;IAAO,YAAY,aAAa,KAAK,KAAK,WAAW,KAAK,KAAK,GAAG;IAAE,GAClF,EAAE,OAAO,KAAK,OAAO;GACxB;UACO,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,2BAA2B;;;;;;;;AAShF,eAAsB,qBACrB,IACA,OAKqD;AACrD,KAAI;EACH,MAAM,YAAY,IAAI,2BAA2B,GAAG;EACpD,MAAM,WAAW,MAAM,UAAU,IAAI,MAAM,WAAW;AACtD,MAAI,CAAC,SACJ,OAAM,IAAI,cAAc,6BAA6B,qBAAqB;AAE3E,MAAI,CAAC,cAAc,MAAM,MAAM,oBAAoB,SAAS,QAAQ,CACnE,QAAO,QAAQ,aAAa,2BAA2B;EAExD,MAAM,UACL,MAAM,aAAa,YAChB,MAAM,UAAU,QAAQ,SAAS,IAAI,MAAM,KAAK,GAAG,GACnD,MAAM,UAAU,KAAK,SAAS,IAAI,MAAM,KAAK,GAAG;AACpD,QAAM,oBAAoB,IAAI;GAC7B,SAAS,MAAM,KAAK;GACpB,QAAQ,MAAM,aAAa,YAAY,8BAA8B;GACrE,cAAc;GACd,YAAY,SAAS;GACrB,SAAS;IACR,QAAQ,SAAS;IACjB,QAAQ,SAAS;IACjB,GAAI,SAAS,gBAAgB,OAAO,EAAE,GAAG,EAAE,aAAa,SAAS,aAAa;IAC9E;GACD,CAAC;AACF,SAAO;GAAE,SAAS;GAAM,MAAM,EAAE,UAAU,SAAS;GAAE;UAC7C,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,4BAA4B;;;;;;;;;;AAuBjF,eAAsB,wBACrB,IACA,OACuB;AACvB,KAAI;EACH,MAAM,YAAY,IAAI,2BAA2B,GAAG;EACpD,MAAM,WACJ,MAAM,UAAU,YAAY;GAAE,GAAG;GAAO,SAAS,MAAM;GAAoB,CAAC,IAC5E,MAAM,UAAU,cAAc,MAAM;AACtC,SAAO,QAAQ,8BAA8B,uCAAuC;GACnF,YAAY,SAAS;GACrB,WAAW,SAAS;GACpB,CAAC;UACM,OAAO;AACf,SAAO,YAAY,OAAO,yBAAyB,6BAA6B"}
1
+ {"version":3,"file":"transfer-DgeCvHnj.mjs","names":["encoder","decodeRecordLine","encoder","#manifest","decodeRecordLine","encoder","isPlainObject","parseEmbeddedJson","count","runUnit","stageFor","#queryCeiling","#byteLimit","#metrics","#unitCeiling","#units","#bytesUsed","count","contentTable","#db","#config","#options","#columns","#covered","#slugs","#collections","#fields","#input","#db","#operations","#stagedFiles","#blobs","#budget","#stage","#writer","#options","#leaseToken","#mediaExported","#operation","#comments","#readers","#keys","#scannable","#packageReader","#storage","#operationId","#chunks","#fields","#rewrittenKinds","#input","#db","#identity","#reader","#readers","#cursor","#packageBlobs","#rewrites","#keys","#context","#mediaChunk"],"sources":["../src/transfer/ops/collation.ts","../src/transfer/ops/staged-files.ts","../src/transfer/site-id.ts","../src/transfer/format/records.ts","../src/transfer/staging/package.ts","../src/transfer/domain.ts","../src/transfer/analyze/read.ts","../src/transfer/analyze/write-rules.ts","../src/transfer/analyze/target.ts","../src/transfer/analyze/plan.ts","../src/transfer/ops/package-index.ts","../src/transfer/analyze/issues.ts","../src/transfer/analyze/unique-keys.ts","../src/transfer/format/media-refs.ts","../src/transfer/analyze/values.ts","../src/transfer/analyze/validate.ts","../src/transfer/analyze/step.ts","../src/transfer/audit.ts","../src/transfer/ops/budget.ts","../src/transfer/ops/media-blobs.ts","../src/transfer/export/fence.ts","../src/transfer/export/media.ts","../src/transfer/export/readers.ts","../src/transfer/export/exporter.ts","../src/transfer/ops/identity-map.ts","../src/transfer/import/context.ts","../src/transfer/import/ids.ts","../src/transfer/import/writers.ts","../src/transfer/import/entries.ts","../src/transfer/import/media.ts","../src/transfer/import/stages.ts","../src/transfer/export/verify.ts","../src/transfer/import/rebuild.ts","../src/transfer/import/scaffold.ts","../src/transfer/import/advance.ts","../src/api/handlers/transfer.ts"],"sourcesContent":["import { sql, type Kysely, type RawBuilder } from \"kysely\";\n\nimport { isPostgres } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\n\n/**\n * A text column compared bytewise. Package ordering is by UTF-16 code unit\n * and portable ids and paths are ASCII, so bytewise order is package order.\n * SQLite compares TEXT with BINARY by default; Postgres needs `COLLATE \"C\"`\n * because database collations are usually linguistic.\n */\nexport function bytewise(db: Kysely<Database>, column: string): RawBuilder<string> {\n\treturn isPostgres(db)\n\t\t? sql<string>`${sql.ref(column)} COLLATE \"C\"`\n\t\t: sql<string>`${sql.ref(column)}`;\n}\n\n/** `LIKE` pattern matching values that start with `prefix` (use with `ESCAPE '\\'`). */\nexport function likePrefix(prefix: string): string {\n\treturn `${prefix.replaceAll(\"\\\\\", \"\\\\\\\\\").replaceAll(\"%\", \"\\\\%\").replaceAll(\"_\", \"\\\\_\")}%`;\n}\n","/**\n * Files belonging to an operation's staged package.\n *\n * For an import, every file the manifest's index declares is `declared` with\n * its expected size and digest, then becomes `verified` once `putVerified`\n * stored exactly those bytes. For an export, each file the exporter writes is\n * recorded `verified` as it is written; finalization streams them in path\n * order into the index chunks. Verification stores each record chunk's\n * logical hash in `logical_sha256`.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport type { ExpectedFile } from \"../staging/stage.js\";\nimport { bytewise, likePrefix } from \"./collation.js\";\nimport { timestampNow } from \"./time.js\";\n\nexport type StagedFileState = \"declared\" | \"verified\";\n\nexport interface StagedFile {\n\tpath: string;\n\tbytes: number;\n\tsha256: string;\n\tstate: StagedFileState;\n\tverifiedAt: string | null;\n\tlogicalSha256: string | null;\n}\n\nexport interface DeclaredFile {\n\tpath: string;\n\tbytes: number;\n\tsha256: string;\n}\n\nfunction toStagedFile(row: {\n\tpath: string;\n\tbytes: number | string;\n\tsha256: string;\n\tstate: string;\n\tverified_at: string | null;\n\tlogical_sha256: string | null;\n}): StagedFile {\n\treturn {\n\t\tpath: row.path,\n\t\tbytes: Number(row.bytes),\n\t\tsha256: row.sha256,\n\t\tstate: row.state === \"verified\" ? \"verified\" : \"declared\",\n\t\tverifiedAt: row.verified_at,\n\t\tlogicalSha256: row.logical_sha256,\n\t};\n}\n\n/** Bound values per inserted row: six columns plus the timestamp offset in `verified_at`. */\nconst STAGED_FILE_BINDS = 7;\n\nexport class TransferStagedFileRepository {\n\tconstructor(private readonly db: Kysely<Database>) {}\n\n\t/**\n\t * Declare expected files. Re-declaring an identical file is a no-op; a\n\t * different size or digest for an existing path throws\n\t * `TRANSFER_FILE_DIGEST_MISMATCH`.\n\t */\n\tasync declareMany(\n\t\toperationId: string,\n\t\tfiles: readonly DeclaredFile[],\n\t\tstate: StagedFileState = \"declared\",\n\t): Promise<void> {\n\t\tfor (const batch of chunks([...files], rowsPerInsert(STAGED_FILE_BINDS))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_staged_files\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((file) => ({\n\t\t\t\t\t\toperation_id: operationId,\n\t\t\t\t\t\tpath: file.path,\n\t\t\t\t\t\tbytes: file.bytes,\n\t\t\t\t\t\tsha256: file.sha256,\n\t\t\t\t\t\tstate,\n\t\t\t\t\t\tverified_at: state === \"verified\" ? timestampNow(this.db) : null,\n\t\t\t\t\t\tlogical_sha256: null,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) => conflict.columns([\"operation_id\", \"path\"]).doNothing())\n\t\t\t\t.execute();\n\t\t}\n\t\tfor (const batch of chunks([...files], SQL_BATCH_SIZE)) {\n\t\t\tconst stored = await this.getMany(\n\t\t\t\toperationId,\n\t\t\t\tbatch.map((file) => file.path),\n\t\t\t);\n\t\t\tfor (const file of batch) {\n\t\t\t\tconst existing = stored.get(file.path);\n\t\t\t\tif (!existing || existing.bytes !== file.bytes || existing.sha256 !== file.sha256) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_FILE_DIGEST_MISMATCH\",\n\t\t\t\t\t\t\"File was already declared with a different size or digest\",\n\t\t\t\t\t\t{ detail: { path: file.path } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/** Record that the declared bytes were stored and verified. Returns false if the declaration differs. */\n\tasync markVerified(operationId: string, file: DeclaredFile): Promise<boolean> {\n\t\tconst result = await this.db\n\t\t\t.updateTable(\"_emdash_transfer_staged_files\")\n\t\t\t.set({ state: \"verified\", verified_at: timestampNow(this.db) })\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"path\", \"=\", file.path)\n\t\t\t.where(\"bytes\", \"=\", file.bytes)\n\t\t\t.where(\"sha256\", \"=\", file.sha256)\n\t\t\t.executeTakeFirst();\n\t\treturn Number(result.numUpdatedRows ?? 0n) > 0;\n\t}\n\n\t/**\n\t * The size and digest each staged file of an operation was verified with,\n\t * or null for a file that is not verified. Readers check what they read\n\t * against these, since a later upload can replace a verified object.\n\t */\n\tverifiedDigests(operationId: string): (path: string) => Promise<ExpectedFile | null> {\n\t\treturn async (path) => {\n\t\t\tconst file = await this.get(operationId, path);\n\t\t\treturn file?.state === \"verified\" ? { bytes: file.bytes, sha256: file.sha256 } : null;\n\t\t};\n\t}\n\n\tasync isVerified(operationId: string, path: string): Promise<boolean> {\n\t\treturn (await this.get(operationId, path))?.state === \"verified\";\n\t}\n\n\tasync setLogicalSha256(operationId: string, path: string, logicalSha256: string): Promise<void> {\n\t\tawait this.db\n\t\t\t.updateTable(\"_emdash_transfer_staged_files\")\n\t\t\t.set({ logical_sha256: logicalSha256 })\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"path\", \"=\", path)\n\t\t\t.execute();\n\t}\n\n\tasync get(operationId: string, path: string): Promise<StagedFile | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select([\"path\", \"bytes\", \"sha256\", \"state\", \"verified_at\", \"logical_sha256\"])\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"path\", \"=\", path)\n\t\t\t.executeTakeFirst();\n\t\treturn row ? toStagedFile(row) : null;\n\t}\n\n\tasync getMany(operationId: string, paths: readonly string[]): Promise<Map<string, StagedFile>> {\n\t\tconst result = new Map<string, StagedFile>();\n\t\tfor (const batch of chunks([...new Set(paths)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t\t.select([\"path\", \"bytes\", \"sha256\", \"state\", \"verified_at\", \"logical_sha256\"])\n\t\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t\t.where(\"path\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.path, toStagedFile(row));\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Files in path order, optionally filtered by state or path prefix. */\n\tasync list(\n\t\toperationId: string,\n\t\toptions: { state?: StagedFileState; prefix?: string; after?: string; limit?: number } = {},\n\t): Promise<StagedFile[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select([\"path\", \"bytes\", \"sha256\", \"state\", \"verified_at\", \"logical_sha256\"])\n\t\t\t.where(\"operation_id\", \"=\", operationId);\n\t\tif (options.state) query = query.where(\"state\", \"=\", options.state);\n\t\tif (options.prefix !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`path LIKE ${likePrefix(options.prefix)} ESCAPE '\\\\'`);\n\t\t}\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"path\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"path\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map(toStagedFile);\n\t}\n\n\tasync countByState(operationId: string): Promise<Record<StagedFileState, number>> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select((eb) => [\"state\", eb.fn.countAll<number | string>().as(\"count\")])\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.groupBy(\"state\")\n\t\t\t.execute();\n\t\tconst counts: Record<StagedFileState, number> = { declared: 0, verified: 0 };\n\t\tfor (const row of rows) {\n\t\t\tif (row.state === \"declared\" || row.state === \"verified\")\n\t\t\t\tcounts[row.state] = Number(row.count);\n\t\t}\n\t\treturn counts;\n\t}\n\n\t/** Delete up to `limit` rows for an operation; returns how many were deleted. */\n\tasync deleteForOperation(operationId: string, limit = 500): Promise<number> {\n\t\tconst paths = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t\t.select(\"path\")\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.limit(limit)\n\t\t\t.execute();\n\t\tlet deleted = 0;\n\t\tfor (const batch of chunks(\n\t\t\tpaths.map((row) => row.path),\n\t\t\tSQL_BATCH_SIZE,\n\t\t)) {\n\t\t\tconst result = await this.db\n\t\t\t\t.deleteFrom(\"_emdash_transfer_staged_files\")\n\t\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t\t.where(\"path\", \"in\", batch)\n\t\t\t\t.executeTakeFirst();\n\t\t\tdeleted += Number(result.numDeletedRows ?? 0n);\n\t\t}\n\t\treturn deleted;\n\t}\n}\n","import type { Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { OptionsRepository } from \"../database/repositories/options.js\";\nimport type { Database } from \"../database/types.js\";\n\n/**\n * Option holding this installation's site id. Target-local: never exported\n * and never overwritten by an import.\n */\nexport const SITE_ID_OPTION = \"emdash:site_id\";\n\n/**\n * This installation's site id, created on first use. Concurrent first callers\n * converge on one value: creation is an insert-if-absent, and a caller that\n * loses the race reads the winner's value.\n */\nexport async function getOrCreateSiteId(db: Kysely<Database>): Promise<string> {\n\tconst options = new OptionsRepository(db);\n\tconst existing = await options.get(SITE_ID_OPTION);\n\tif (typeof existing === \"string\" && existing.length > 0) return existing;\n\n\tconst candidate = ulid();\n\tconst result = await options.compareAndSet(SITE_ID_OPTION, null, candidate);\n\tif (result.applied) return candidate;\n\n\tconst winner = await options.get(SITE_ID_OPTION);\n\tif (typeof winner === \"string\" && winner.length > 0) return winner;\n\tthrow new Error(\"Site id option exists but is not a non-empty string\");\n}\n","/**\n * NDJSON encoding of record and index chunks.\n *\n * A chunk is a sequence of lines, each the canonical JSON of one record (or\n * index entry) followed by `\\n`, with no blank lines. A chunk holds at most\n * {@link TRANSFER_LIMITS.chunkRecords} lines and\n * {@link TRANSFER_LIMITS.chunkBytes} bytes; a record line is at most\n * {@link TRANSFER_LIMITS.recordLineBytes} bytes.\n */\n\nimport { TransferError } from \"../errors.js\";\nimport { canonicalJson, CanonicalJsonError, parseCanonicalJson } from \"./canonical.js\";\nimport { type RecordKind, type RecordOfKind, validateRecord } from \"./kinds.js\";\nimport { TRANSFER_LIMITS } from \"./limits.js\";\nimport { decodeUtf8 } from \"./manifest.js\";\n\nconst encoder = new TextEncoder();\n\n/** Canonical line (without newline) for a record; enforces the line limit. */\nexport function encodeRecordLine(record: { kind: RecordKind; id: string }): string {\n\tconst line = canonicalJson(record);\n\tconst bytes = encoder.encode(line).byteLength;\n\tif (bytes > TRANSFER_LIMITS.recordLineBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Record exceeds the line size limit\", {\n\t\t\tdetail: { kind: record.kind, id: record.id, bytes, limit: TRANSFER_LIMITS.recordLineBytes },\n\t\t});\n\t}\n\treturn line;\n}\n\nexport interface DecodedRecord<K extends RecordKind> {\n\trecord: RecordOfKind<K>;\n\t/** The canonical line without its newline; its SHA-256 is the record hash. */\n\tline: string;\n}\n\n/**\n * Validate one line as a record of `kind`. Throws `TRANSFER_RECORD_INVALID`\n * (with a location but never record content) or `TRANSFER_LIMIT_EXCEEDED`.\n */\nexport function decodeRecordLine<K extends RecordKind>(\n\tkind: K,\n\tline: string,\n\tlocation: { path: string; line: number },\n): DecodedRecord<K> {\n\tif (encoder.encode(line).byteLength > TRANSFER_LIMITS.recordLineBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Record exceeds the line size limit\", {\n\t\t\tdetail: { path: location.path, line: location.line },\n\t\t});\n\t}\n\tlet raw: unknown;\n\ttry {\n\t\traw = parseCanonicalJson(line);\n\t} catch (error) {\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Record is not canonical JSON\", {\n\t\t\tdetail: {\n\t\t\t\tpath: location.path,\n\t\t\t\tline: location.line,\n\t\t\t\treason: error instanceof CanonicalJsonError ? error.message : \"invalid\",\n\t\t\t},\n\t\t});\n\t}\n\tconst result = validateRecord(kind, raw);\n\tif (!result.success) {\n\t\tconst first = result.issues[0];\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Record failed validation\", {\n\t\t\tdetail: {\n\t\t\t\tpath: location.path,\n\t\t\t\tline: location.line,\n\t\t\t\tfield: first?.path ?? \"\",\n\t\t\t\treason: first?.message ?? \"invalid\",\n\t\t\t},\n\t\t});\n\t}\n\treturn { record: result.record, line };\n}\n\n/**\n * Split chunk text into lines, enforcing chunk limits and the trailing\n * newline. Returns the lines without their newlines.\n */\nexport function splitChunkLines(bytes: Uint8Array, path: string): string[] {\n\tif (bytes.byteLength > TRANSFER_LIMITS.chunkBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk exceeds the size limit\", {\n\t\t\tdetail: { path, limit: TRANSFER_LIMITS.chunkBytes },\n\t\t});\n\t}\n\tconst text = decodeUtf8(bytes, \"TRANSFER_RECORD_INVALID\");\n\tif (text.length === 0) {\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Chunk is empty\", { detail: { path } });\n\t}\n\tif (!text.endsWith(\"\\n\")) {\n\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Chunk must end with a newline\", {\n\t\t\tdetail: { path },\n\t\t});\n\t}\n\tconst lines = text.slice(0, -1).split(\"\\n\");\n\tif (lines.length > TRANSFER_LIMITS.chunkRecords) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk has too many lines\", {\n\t\t\tdetail: { path, limit: TRANSFER_LIMITS.chunkRecords },\n\t\t});\n\t}\n\tlines.forEach((line, index) => {\n\t\tif (line.length === 0) {\n\t\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Chunk contains a blank line\", {\n\t\t\t\tdetail: { path, line: index + 1 },\n\t\t\t});\n\t\t}\n\t});\n\treturn lines;\n}\n\n/** Join canonical lines into chunk bytes, enforcing chunk limits. */\nexport function encodeChunk(lines: readonly string[], path: string): Uint8Array {\n\tif (lines.length === 0 || lines.length > TRANSFER_LIMITS.chunkRecords) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk line count out of range\", {\n\t\t\tdetail: { path, lines: lines.length },\n\t\t});\n\t}\n\tconst bytes = encoder.encode(`${lines.join(\"\\n\")}\\n`);\n\tif (bytes.byteLength > TRANSFER_LIMITS.chunkBytes) {\n\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"Chunk exceeds the size limit\", {\n\t\t\tdetail: { path, bytes: bytes.byteLength },\n\t\t});\n\t}\n\treturn bytes;\n}\n","/**\n * Staged package reader and writer.\n *\n * The writer stores package files under a {@link TransferStage}, returning\n * the index entry (size and digest) for each. The reader parses and validates\n * what is staged: the manifest, index chunks (checked against the digests the\n * manifest pins), record chunks (every line strictly validated), and blobs.\n */\n\nimport { TransferError } from \"../errors.js\";\nimport { canonicalJson } from \"../format/canonical.js\";\nimport { packageDigest, sha256Hex, type Sha256Digest } from \"../format/digest.js\";\nimport type { RecordKind, RecordOfKind } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tparseIndexLine,\n\tparseManifest,\n\tserializeManifest,\n\ttype IndexChunkRef,\n\ttype PackageFileEntry,\n\ttype SitePackageManifest,\n} from \"../format/manifest.js\";\nimport { indexChunkPath, MANIFEST_PATH, mediaBlobPath, recordChunkPath } from \"../format/paths.js\";\nimport {\n\tdecodeRecordLine,\n\tencodeChunk,\n\tencodeRecordLine,\n\tsplitChunkLines,\n} from \"../format/records.js\";\nimport { readStreamBytes, TransferStage, type ExpectedFile } from \"./stage.js\";\n\nconst encoder = new TextEncoder();\n\nexport class StagedPackageWriter {\n\tconstructor(readonly stage: TransferStage) {}\n\n\t/** Store bytes at a package path; returns its index entry (without `records`). */\n\tasync writeFile(path: string, bytes: Uint8Array): Promise<PackageFileEntry> {\n\t\tconst sha256 = await sha256Hex(bytes);\n\t\tawait this.stage.putVerified(path, bytes, bytes.byteLength, sha256);\n\t\treturn { path, bytes: bytes.byteLength, sha256 };\n\t}\n\n\t/** Encode and store one record chunk. Records must already be in stream order. */\n\tasync writeRecordChunk<K extends RecordKind>(\n\t\tkind: K,\n\t\tseq: number,\n\t\trecords: readonly RecordOfKind<K>[],\n\t): Promise<PackageFileEntry> {\n\t\tconst path = recordChunkPath(kind, seq);\n\t\tfor (const record of records) {\n\t\t\tif (record.kind !== kind) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Record kind does not match its chunk\", {\n\t\t\t\t\tdetail: { path, id: record.id },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tconst lines = records.map((record) => encodeRecordLine(record));\n\t\tconst entry = await this.writeFile(path, encodeChunk(lines, path));\n\t\treturn { ...entry, records: records.length };\n\t}\n\n\t/** Encode and store one index chunk. */\n\tasync writeIndexChunk(seq: number, entries: readonly PackageFileEntry[]): Promise<IndexChunkRef> {\n\t\tconst path = indexChunkPath(seq);\n\t\tconst lines = entries.map((entry) => canonicalJson(entry));\n\t\tconst file = await this.writeFile(path, encodeChunk(lines, path));\n\t\treturn { path, bytes: file.bytes, sha256: file.sha256, entries: entries.length };\n\t}\n\n\t/** Store a media blob, verifying the declared size and digest as it streams. */\n\tasync writeBlob(\n\t\tsha256: string,\n\t\tbody: ReadableStream<Uint8Array> | Uint8Array,\n\t\tbytes: number,\n\t): Promise<PackageFileEntry> {\n\t\tconst path = mediaBlobPath(sha256);\n\t\tawait this.stage.putVerified(path, body, bytes, sha256);\n\t\treturn { path, bytes, sha256 };\n\t}\n\n\t/** Store the manifest; returns its package digest. */\n\tasync writeManifest(manifest: SitePackageManifest): Promise<Sha256Digest> {\n\t\tconst text = serializeManifest(parseManifest(serializeManifest(manifest)));\n\t\tconst bytes = encoder.encode(text);\n\t\tawait this.stage.putVerified(MANIFEST_PATH, bytes, bytes.byteLength, await sha256Hex(bytes));\n\t\treturn packageDigest(manifest);\n\t}\n}\n\nexport interface StagedRecord<K extends RecordKind> {\n\trecord: RecordOfKind<K>;\n\t/** Canonical line without newline; its SHA-256 is the record hash. */\n\tline: string;\n\tseq: number;\n\t/** Zero-based line number within the chunk. */\n\tindex: number;\n}\n\n/** Size and digest a staged file must have when read, or null when it is not verified. */\nexport type StagedFileDigests = (path: string) => Promise<ExpectedFile | null>;\n\nexport class StagedPackageReader {\n\t#manifest: SitePackageManifest | undefined;\n\n\t/**\n\t * With `digests`, every record chunk read is checked against the size and\n\t * digest it was verified with, and a chunk that is not verified is missing.\n\t */\n\tconstructor(\n\t\treadonly stage: TransferStage,\n\t\tprivate readonly digests?: StagedFileDigests,\n\t) {}\n\n\t/** The parsed, validated manifest (read once). */\n\tasync manifest(): Promise<SitePackageManifest> {\n\t\tif (!this.#manifest) {\n\t\t\tconst bytes = await this.stage.readBytes(MANIFEST_PATH, TRANSFER_LIMITS.manifestBytes);\n\t\t\tthis.#manifest = parseManifest(bytes);\n\t\t}\n\t\treturn this.#manifest;\n\t}\n\n\tasync digest(): Promise<Sha256Digest> {\n\t\treturn packageDigest(await this.manifest());\n\t}\n\n\t/** Entries of one index chunk, verified against the digest the manifest pins. */\n\tasync indexChunk(seq: number): Promise<PackageFileEntry[]> {\n\t\tconst manifest = await this.manifest();\n\t\tconst ref = manifest.index[seq];\n\t\tif (!ref) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Index chunk is not declared\", {\n\t\t\t\tdetail: { seq },\n\t\t\t});\n\t\t}\n\t\tconst bytes = await this.readVerified(ref.path, ref);\n\t\tconst entries = splitChunkLines(bytes, ref.path).map((line) => parseIndexLine(line));\n\t\tif (entries.length !== ref.entries) {\n\t\t\tthrow new TransferError(\"TRANSFER_MANIFEST_INVALID\", \"Index chunk entry count mismatch\", {\n\t\t\t\tdetail: { path: ref.path },\n\t\t\t});\n\t\t}\n\t\treturn entries;\n\t}\n\n\t/** Every index entry in path order, starting at index chunk `fromSeq`. */\n\tasync *index(fromSeq = 0): AsyncGenerator<{ seq: number; entry: PackageFileEntry }> {\n\t\tconst manifest = await this.manifest();\n\t\tfor (let seq = fromSeq; seq < manifest.index.length; seq++) {\n\t\t\tfor (const entry of await this.indexChunk(seq)) yield { seq, entry };\n\t\t}\n\t}\n\n\t/**\n\t * Records of one chunk, each strictly validated. Pass `expected` (from the\n\t * index) to also verify the chunk's size and digest; otherwise the reader's\n\t * `digests`, when it has them, supply it.\n\t */\n\tasync readChunk<K extends RecordKind>(\n\t\tkind: K,\n\t\tseq: number,\n\t\texpected?: ExpectedFile,\n\t): Promise<Array<StagedRecord<K>>> {\n\t\tconst path = recordChunkPath(kind, seq);\n\t\tconst file = expected ?? (await this.expectedFile(path));\n\t\tconst bytes = file\n\t\t\t? await this.readVerified(path, file)\n\t\t\t: await this.stage.readBytes(path, TRANSFER_LIMITS.chunkBytes);\n\t\treturn splitChunkLines(bytes, path).map((line, index) => {\n\t\t\tconst decoded = decodeRecordLine(kind, line, { path, line: index + 1 });\n\t\t\treturn { record: decoded.record, line: decoded.line, seq, index };\n\t\t});\n\t}\n\n\t/** Records of `kind` in stream order, starting at chunk `fromSeq`. */\n\tasync *records<K extends RecordKind>(kind: K, fromSeq = 0): AsyncGenerator<StagedRecord<K>> {\n\t\tconst manifest = await this.manifest();\n\t\tconst chunks = manifest.records[kind]?.chunks ?? 0;\n\t\tfor (let seq = fromSeq; seq < chunks; seq++) {\n\t\t\tyield* await this.readChunk(kind, seq);\n\t\t}\n\t}\n\n\tasync blob(sha256: string): Promise<ReadableStream<Uint8Array>> {\n\t\treturn (await this.stage.open(mediaBlobPath(sha256))).body;\n\t}\n\n\tprivate async expectedFile(path: string): Promise<ExpectedFile | undefined> {\n\t\tif (!this.digests) return undefined;\n\t\tconst expected = await this.digests(path);\n\t\tif (!expected) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Staged file is not verified\", {\n\t\t\t\tdetail: { path },\n\t\t\t});\n\t\t}\n\t\treturn expected;\n\t}\n\n\tprivate async readVerified(path: string, expected: ExpectedFile): Promise<Uint8Array> {\n\t\tconst file = await this.stage.open(path);\n\t\tlet bytes: Uint8Array;\n\t\ttry {\n\t\t\tbytes = await readStreamBytes(file.body, Math.max(expected.bytes, 0));\n\t\t} catch (error) {\n\t\t\tif (error instanceof TransferError && error.code === \"TRANSFER_LIMIT_EXCEEDED\") {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\", {\n\t\t\t\t\tdetail: { path },\n\t\t\t\t});\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tif (bytes.byteLength !== expected.bytes) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\", {\n\t\t\t\tdetail: { path },\n\t\t\t});\n\t\t}\n\t\tif ((await sha256Hex(bytes)) !== expected.sha256) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_FILE_DIGEST_MISMATCH\",\n\t\t\t\t\"Staged file digest does not match\",\n\t\t\t\t{\n\t\t\t\t\tdetail: { path },\n\t\t\t\t},\n\t\t\t);\n\t\t}\n\t\treturn bytes;\n\t}\n}\n","/**\n * Is the target's portable domain empty enough to import into?\n *\n * Setup always applies a seed (the project's seed file or the built-in\n * default), so a brand-new site is never row-empty. The domain counts as\n * empty when it holds no content and no user-made schema: no term\n * assignments, relations, content references, bylines or byline fields,\n * media or media folders, revisions, SEO rows, comments or reactions,\n * redirects, or user sections, and only seeded collections and block types,\n * no collection with a row in its content table (trash included). Everything\n * else a seed leaves is scaffold:\n * - the seeded collections;\n * - the seeded block types (`source = 'seed'`) and their versions;\n * - taxonomy definitions attached only to those collections or to\n * collections that do not exist, and their unassigned terms;\n * - menus and their items, widget areas and their widgets;\n * - sections with `source = 'theme'` (seeded theme sections).\n *\n * The importer's `clear_scaffold` stage deletes exactly the reported\n * `seededScaffold` items, in order: terms before their definitions, menu\n * items before menus, widgets before widget areas, and block types after the\n * collections whose fields name them.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../database/types.js\";\nimport { validateIdentifier } from \"../database/validate.js\";\n\nexport type ScaffoldItem =\n\t| { type: \"collection\"; id: string; slug: string }\n\t| { type: \"term\"; id: string; name: string; slug: string; locale: string }\n\t| { type: \"taxonomy_def\"; id: string; name: string; locale: string }\n\t| { type: \"menu_item\"; id: string; menuId: string; label: string }\n\t| { type: \"menu\"; id: string; name: string; locale: string }\n\t| { type: \"widget\"; id: string; areaId: string; widgetType: string }\n\t| { type: \"widget_area\"; id: string; name: string }\n\t| { type: \"section\"; id: string; slug: string }\n\t| { type: \"block_type\"; id: string; slug: string };\n\nexport type DomainBlocker =\n\t| { code: \"table_not_empty\"; table: string }\n\t| { code: \"collection_not_seeded\"; id: string; slug: string }\n\t| { code: \"block_type_not_seeded\"; id: string; slug: string }\n\t| { code: \"collection_has_entries\"; id: string; slug: string }\n\t| { code: \"taxonomy_def_not_scaffold\"; id: string; name: string };\n\nexport interface PortableDomainInspection {\n\tempty: boolean;\n\tseededScaffold: ScaffoldItem[];\n\tblockers: DomainBlocker[];\n}\n\n/** Tables that must hold no rows at all (sections are checked separately). */\nconst MUST_BE_EMPTY = [\n\t\"content_taxonomies\",\n\t\"_emdash_relations\",\n\t\"_emdash_content_references\",\n\t\"_emdash_bylines\",\n\t\"_emdash_byline_fields\",\n\t\"_emdash_byline_field_values\",\n\t\"_emdash_byline_field_group_values\",\n\t\"_emdash_content_bylines\",\n\t\"media\",\n\t\"media_folders\",\n\t\"revisions\",\n\t\"_emdash_seo\",\n\t\"_emdash_comments\",\n\t\"_emdash_comment_reactions\",\n\t\"_emdash_redirects\",\n] as const;\n\nfunction isSeededSource(source: string | null): boolean {\n\treturn source === \"seed\" || (source?.startsWith(\"template:\") ?? false);\n}\n\nfunction parseCollections(value: string | null): string[] | null {\n\tif (value === null) return [];\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(value);\n\t\tif (!Array.isArray(parsed)) return null;\n\t\treturn parsed.every((item): item is string => typeof item === \"string\") ? parsed : null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport async function inspectPortableDomain(\n\tdb: Kysely<Database>,\n): Promise<PortableDomainInspection> {\n\tconst blockers: DomainBlocker[] = [];\n\tconst seededScaffold: ScaffoldItem[] = [];\n\n\tconst probes = MUST_BE_EMPTY.map(\n\t\t(table, index) => sql`(SELECT 1 FROM ${sql.ref(table)} LIMIT 1) AS ${sql.ref(`t${index}`)}`,\n\t);\n\tprobes.push(\n\t\tsql`(SELECT 1 FROM _emdash_sections WHERE source <> 'theme' LIMIT 1) AS ${sql.ref(\"user_sections\")}`,\n\t);\n\tconst occupied = await sql<Record<string, unknown>>`SELECT ${sql.join(probes)}`.execute(db);\n\tconst flags = occupied.rows[0] ?? {};\n\tMUST_BE_EMPTY.forEach((table, index) => {\n\t\tif (flags[`t${index}`] != null) blockers.push({ code: \"table_not_empty\", table });\n\t});\n\tif (flags.user_sections != null)\n\t\tblockers.push({ code: \"table_not_empty\", table: \"_emdash_sections\" });\n\n\tconst collections = await db\n\t\t.selectFrom(\"_emdash_collections\")\n\t\t.select([\"id\", \"slug\", \"source\"])\n\t\t.orderBy(\"slug\")\n\t\t.execute();\n\tconst seeded = collections.filter((collection) => isSeededSource(collection.source));\n\tfor (const collection of collections) {\n\t\tif (!isSeededSource(collection.source)) {\n\t\t\tblockers.push({ code: \"collection_not_seeded\", id: collection.id, slug: collection.slug });\n\t\t}\n\t}\n\n\tif (seeded.length > 0) {\n\t\tconst contentProbes = seeded.map((collection, index) => {\n\t\t\tvalidateIdentifier(collection.slug, \"collection slug\");\n\t\t\treturn sql`(SELECT 1 FROM ${sql.ref(`ec_${collection.slug}`)} LIMIT 1) AS ${sql.ref(`c${index}`)}`;\n\t\t});\n\t\tconst content = await sql<Record<string, unknown>>`SELECT ${sql.join(contentProbes)}`.execute(\n\t\t\tdb,\n\t\t);\n\t\tconst contentFlags = content.rows[0] ?? {};\n\t\tseeded.forEach((collection, index) => {\n\t\t\tif (contentFlags[`c${index}`] != null) {\n\t\t\t\tblockers.push({ code: \"collection_has_entries\", id: collection.id, slug: collection.slug });\n\t\t\t} else {\n\t\t\t\tseededScaffold.push({ type: \"collection\", id: collection.id, slug: collection.slug });\n\t\t\t}\n\t\t});\n\t}\n\n\tconst scaffoldSlugs = new Set(\n\t\tseededScaffold.flatMap((item) => (item.type === \"collection\" ? [item.slug] : [])),\n\t);\n\tconst existingSlugs = new Set(collections.map((collection) => collection.slug));\n\tconst taxonomyDefs = await db\n\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t.select([\"id\", \"name\", \"locale\", \"collections\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tconst scaffoldDefs: ScaffoldItem[] = [];\n\tfor (const def of taxonomyDefs) {\n\t\tconst attached = parseCollections(def.collections);\n\t\tif (attached?.every((slug) => scaffoldSlugs.has(slug) || !existingSlugs.has(slug))) {\n\t\t\tscaffoldDefs.push({ type: \"taxonomy_def\", id: def.id, name: def.name, locale: def.locale });\n\t\t} else {\n\t\t\tblockers.push({ code: \"taxonomy_def_not_scaffold\", id: def.id, name: def.name });\n\t\t}\n\t}\n\n\tconst blockTypes = await db\n\t\t.selectFrom(\"_emdash_block_types\")\n\t\t.select([\"id\", \"slug\", \"source\"])\n\t\t.orderBy(\"slug\")\n\t\t.execute();\n\tfor (const blockType of blockTypes) {\n\t\tif (blockType.source !== \"seed\") {\n\t\t\tblockers.push({ code: \"block_type_not_seeded\", id: blockType.id, slug: blockType.slug });\n\t\t}\n\t}\n\n\t// Terms, menu items, and widgets are only scaffold on a site without content;\n\t// on any other site the blockers already say it is not empty.\n\tif (blockers.length > 0) return { empty: false, seededScaffold, blockers };\n\n\tconst terms = await db\n\t\t.selectFrom(\"taxonomies\")\n\t\t.select([\"id\", \"name\", \"slug\", \"locale\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const term of terms) {\n\t\tseededScaffold.push({\n\t\t\ttype: \"term\",\n\t\t\tid: term.id,\n\t\t\tname: term.name,\n\t\t\tslug: term.slug,\n\t\t\tlocale: term.locale,\n\t\t});\n\t}\n\tseededScaffold.push(...scaffoldDefs);\n\n\tconst menuItems = await db\n\t\t.selectFrom(\"_emdash_menu_items\")\n\t\t.select([\"id\", \"menu_id\", \"label\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const item of menuItems) {\n\t\tseededScaffold.push({\n\t\t\ttype: \"menu_item\",\n\t\t\tid: item.id,\n\t\t\tmenuId: item.menu_id,\n\t\t\tlabel: item.label,\n\t\t});\n\t}\n\n\tconst menus = await db\n\t\t.selectFrom(\"_emdash_menus\")\n\t\t.select([\"id\", \"name\", \"locale\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const menu of menus) {\n\t\tseededScaffold.push({ type: \"menu\", id: menu.id, name: menu.name, locale: menu.locale });\n\t}\n\n\tconst widgets = await db\n\t\t.selectFrom(\"_emdash_widgets\")\n\t\t.select([\"id\", \"area_id\", \"type\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const widget of widgets) {\n\t\tseededScaffold.push({\n\t\t\ttype: \"widget\",\n\t\t\tid: widget.id,\n\t\t\tareaId: widget.area_id,\n\t\t\twidgetType: widget.type,\n\t\t});\n\t}\n\n\tconst areas = await db\n\t\t.selectFrom(\"_emdash_widget_areas\")\n\t\t.select([\"id\", \"name\"])\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const area of areas)\n\t\tseededScaffold.push({ type: \"widget_area\", id: area.id, name: area.name });\n\n\tconst sections = await db\n\t\t.selectFrom(\"_emdash_sections\")\n\t\t.select([\"id\", \"slug\"])\n\t\t.where(\"source\", \"=\", \"theme\")\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tfor (const section of sections) {\n\t\tseededScaffold.push({ type: \"section\", id: section.id, slug: section.slug });\n\t}\n\n\tfor (const blockType of blockTypes) {\n\t\tseededScaffold.push({ type: \"block_type\", id: blockType.id, slug: blockType.slug });\n\t}\n\n\treturn { empty: true, seededScaffold, blockers };\n}\n","/**\n * Reading staged record chunks for analysis, turning every failure into a\n * blocker whose message and detail never include package content: only the\n * error code of a read failure is used, with a fixed message.\n */\n\nimport { TransferError, type TransferErrorCode } from \"../errors.js\";\nimport { parseCanonicalJson } from \"../format/canonical.js\";\nimport { sha256Hex } from \"../format/digest.js\";\nimport { validateRecord, type RecordKind, type RecordOfKind } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { PlanBlocker, PlanBlockerCode } from \"../format/plan.js\";\nimport { splitChunkLines } from \"../format/records.js\";\nimport { readStreamBytes, type ExpectedFile, type TransferStage } from \"../staging/stage.js\";\n\nconst encoder = new TextEncoder();\n\nconst ERROR_BLOCKERS: Partial<\n\tRecord<TransferErrorCode, { code: PlanBlockerCode; message: string }>\n> = {\n\tTRANSFER_LIMIT_EXCEEDED: { code: \"limit_exceeded\", message: \"Package file exceeds a limit\" },\n\tTRANSFER_FILE_MISSING: { code: \"file_missing\", message: \"Package file is missing\" },\n\tTRANSFER_FILE_SIZE_MISMATCH: {\n\t\tcode: \"file_mismatch\",\n\t\tmessage: \"Package file size does not match its declaration\",\n\t},\n\tTRANSFER_FILE_DIGEST_MISMATCH: {\n\t\tcode: \"file_mismatch\",\n\t\tmessage: \"Package file digest does not match its declaration\",\n\t},\n\tTRANSFER_UNSUPPORTED_FORMAT: {\n\t\tcode: \"unsupported_format\",\n\t\tmessage: \"Unsupported package format or version\",\n\t},\n\tTRANSFER_UNSUPPORTED_FEATURE: {\n\t\tcode: \"unsupported_feature\",\n\t\tmessage: \"Package requires features this site does not support\",\n\t},\n\tTRANSFER_RECORD_INVALID: { code: \"record_invalid\", message: \"Package file is malformed\" },\n\tTRANSFER_PATH_INVALID: { code: \"package_invalid\", message: \"Package path is invalid\" },\n};\n\n/**\n * A blocker for a {@link TransferError} raised while reading package files.\n * Only the error code is used; the location comes from the caller.\n */\nexport function blockerForError(\n\terror: TransferError,\n\tlocation: { path?: string; line?: number } = {},\n): PlanBlocker {\n\tconst mapped = ERROR_BLOCKERS[error.code] ?? {\n\t\tcode: \"package_invalid\",\n\t\tmessage: \"Package file failed validation\",\n\t};\n\tconst detail: Record<string, string | number> = {};\n\tif (location.path !== undefined) detail.path = location.path;\n\tif (location.line !== undefined) detail.line = location.line;\n\treturn { code: mapped.code, message: mapped.message, detail };\n}\n\n/** Read one staged chunk, verifying size and digest, and split it into lines. */\nexport async function readVerifiedChunk(\n\tstage: TransferStage,\n\tpath: string,\n\texpected: ExpectedFile,\n): Promise<string[]> {\n\tconst file = await stage.open(path);\n\tlet bytes: Uint8Array;\n\ttry {\n\t\tbytes = await readStreamBytes(file.body, expected.bytes);\n\t} catch (error) {\n\t\tif (error instanceof TransferError && error.code === \"TRANSFER_LIMIT_EXCEEDED\") {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\");\n\t\t}\n\t\tthrow error;\n\t}\n\tif (bytes.byteLength !== expected.bytes) {\n\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"Staged file size does not match\");\n\t}\n\tif ((await sha256Hex(bytes)) !== expected.sha256) {\n\t\tthrow new TransferError(\"TRANSFER_FILE_DIGEST_MISMATCH\", \"Staged file digest does not match\");\n\t}\n\treturn splitChunkLines(bytes, path);\n}\n\nexport type DecodedLine<K extends RecordKind> =\n\t| { ok: true; record: RecordOfKind<K> }\n\t| { ok: false; blocker: PlanBlocker };\n\n/**\n * Decode and strictly validate one record line. A failure names the chunk,\n * the one-based line, and at most a known top-level property of the kind.\n */\nexport function decodeRecordLine<K extends RecordKind>(\n\tkind: K,\n\tline: string,\n\tlocation: { path: string; line: number },\n): DecodedLine<K> {\n\tconst detail = { path: location.path, line: location.line };\n\tif (encoder.encode(line).byteLength > TRANSFER_LIMITS.recordLineBytes) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tblocker: {\n\t\t\t\tcode: \"limit_exceeded\",\n\t\t\t\tmessage: \"Record exceeds the line size limit\",\n\t\t\t\tkind,\n\t\t\t\tdetail,\n\t\t\t},\n\t\t};\n\t}\n\tlet raw: unknown;\n\ttry {\n\t\traw = parseCanonicalJson(line);\n\t} catch {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tblocker: { code: \"record_invalid\", message: \"Record is not canonical JSON\", kind, detail },\n\t\t};\n\t}\n\tconst result = validateRecord(kind, raw);\n\tif (!result.success) {\n\t\tconst field = result.issues[0]?.path || undefined;\n\t\treturn {\n\t\t\tok: false,\n\t\t\tblocker: {\n\t\t\t\tcode: \"record_invalid\",\n\t\t\t\tmessage: \"Record failed schema validation\",\n\t\t\t\tkind,\n\t\t\t\tdetail: field === undefined ? detail : { ...detail, field },\n\t\t\t},\n\t\t};\n\t}\n\treturn { ok: true, record: result.record };\n}\n","/**\n * Values the site's own write paths refuse. The importer writes rows\n * directly, so analysis applies the same validators the admin API does and\n * blocks a package holding a value that API would reject.\n */\n\nimport { httpUrl } from \"../../api/schemas/common.js\";\nimport { safeHref } from \"../../api/schemas/menus.js\";\nimport { createRedirectBody } from \"../../api/schemas/redirects.js\";\nimport { coerceFieldValue } from \"../../database/repositories/byline.js\";\nimport { EmDashValidationError } from \"../../database/repositories/types.js\";\nimport { isPattern, validateDestinationParams, validatePattern } from \"../../redirects/patterns.js\";\nimport { isTerminalStatus } from \"../../redirects/status.js\";\nimport { validateBlockFields } from \"../../schema/block-type-contract.js\";\nimport type { BlockFieldDefinition } from \"../../schema/block-types.js\";\nimport { SchemaError } from \"../../schema/registry.js\";\nimport { RESERVED_FIELD_SLUGS, type BylineFieldType } from \"../../schema/types.js\";\nimport { compileUrlPattern } from \"../../schema/url-pattern.js\";\nimport type {\n\tBlockTypeRecord,\n\tBlockTypeVersionRecord,\n\tRedirectRecord,\n\tSitePackageRecord,\n} from \"../format/kinds.js\";\nimport type { ValueIssue } from \"./values.js\";\n\n/** What the byline field write path checks a value against. */\nexport interface BylineFieldFacts {\n\ttype: BylineFieldType;\n\t/** Choices of a `select` field. */\n\toptions?: string[];\n}\n\n/** Facts from earlier records that some rules need. */\nexport interface WriteRuleFacts {\n\t/** Byline fields by id. */\n\tbylineFields: ReadonlyMap<string, BylineFieldFacts>;\n}\n\nfunction rejected(property: string, message: string): ValueIssue {\n\treturn { code: \"value_constraint_violation\", message, property };\n}\n\nconst REDIRECT_BODY_MESSAGES: Record<string, string> = {\n\tsource: \"Redirect source is not a path on this site\",\n\tdestination: \"Redirect destination is not a path on this site\",\n\ttype: \"Redirect type is not supported\",\n};\n\nfunction redirectIssues(record: RedirectRecord): ValueIssue[] {\n\tconst issues: ValueIssue[] = [];\n\tconst body = createRedirectBody.safeParse({\n\t\tsource: record.source,\n\t\tdestination: record.destination,\n\t\ttype: record.type,\n\t});\n\tif (!body.success) {\n\t\tconst properties = new Set(body.error.issues.map((issue) => String(issue.path[0])));\n\t\tfor (const [property, message] of Object.entries(REDIRECT_BODY_MESSAGES)) {\n\t\t\tif (properties.has(property)) issues.push(rejected(property, message));\n\t\t}\n\t}\n\tconst pattern = isPattern(record.source);\n\tif (record.isPattern !== pattern) {\n\t\tissues.push(rejected(\"isPattern\", \"Redirect pattern flag does not match its source\"));\n\t}\n\tif (pattern) {\n\t\tif (validatePattern(record.source) !== null) {\n\t\t\tissues.push(rejected(\"source\", \"Redirect source is not a valid pattern\"));\n\t\t} else if (\n\t\t\t!isTerminalStatus(record.type) &&\n\t\t\tvalidateDestinationParams(record.source, record.destination) !== null\n\t\t) {\n\t\t\tissues.push(\n\t\t\t\trejected(\n\t\t\t\t\t\"destination\",\n\t\t\t\t\t\"Redirect destination uses a parameter its source does not capture\",\n\t\t\t\t),\n\t\t\t);\n\t\t}\n\t}\n\treturn issues;\n}\n\n/** Whether the redirect API would accept this redirect; only these may be compiled. */\nexport function isImportableRedirect(record: RedirectRecord): boolean {\n\treturn redirectIssues(record).length === 0;\n}\n\nconst BYLINE_FIELD_VALUE_MESSAGES: Record<BylineFieldType, string> = {\n\tstring: \"Byline field value is not a string\",\n\ttext: \"Byline field value is not a string\",\n\turl: \"Byline field value is not an http or https URL\",\n\tboolean: \"Byline field value is not a boolean\",\n\tselect: \"Byline field value is not one of the field's choices\",\n};\n\nfunction bylineFieldValueIssues(field: BylineFieldFacts | undefined, value: unknown): ValueIssue[] {\n\tif (!field) return [];\n\ttry {\n\t\tcoerceFieldValue(\n\t\t\t{ slug: \"\", type: field.type, validation: { options: field.options } },\n\t\t\tvalue ?? null,\n\t\t);\n\t\treturn [];\n\t} catch (error) {\n\t\tif (error instanceof EmDashValidationError) {\n\t\t\treturn [rejected(\"value\", BYLINE_FIELD_VALUE_MESSAGES[field.type])];\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nfunction acceptsUrlPattern(pattern: string): boolean {\n\ttry {\n\t\tcompileUrlPattern(pattern);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nconst URL_SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*:/;\n\n/**\n * The SEO API takes only http(s) canonical URLs, but stored canonicals may\n * also be site paths, which the renderer resolves against the site URL.\n */\nfunction acceptsCanonical(canonical: string): boolean {\n\tif (URL_SCHEME.test(canonical) || canonical.startsWith(\"//\")) {\n\t\treturn httpUrl.safeParse(canonical).success;\n\t}\n\treturn true;\n}\n\nconst RESERVED_BLOCK_TYPE_SLUGS: ReadonlySet<string> = new Set(RESERVED_FIELD_SLUGS);\nconst MAX_BLOCK_TYPE_LABEL = 200;\n\nfunction blockTypeIssues(record: BlockTypeRecord): ValueIssue[] {\n\tconst issues: ValueIssue[] = [];\n\tif (RESERVED_BLOCK_TYPE_SLUGS.has(record.slug)) {\n\t\tissues.push(rejected(\"slug\", \"Block type slug is reserved\"));\n\t}\n\tif (record.label.trim().length === 0 || record.label.length > MAX_BLOCK_TYPE_LABEL) {\n\t\tissues.push(rejected(\"label\", \"Block type label is empty or too long\"));\n\t}\n\tif (record.source !== \"user\" && record.source !== \"seed\") {\n\t\tissues.push(rejected(\"source\", \"Block type source is not supported\"));\n\t}\n\treturn issues;\n}\n\nfunction blockTypeVersionIssues(record: BlockTypeVersionRecord): ValueIssue[] {\n\tconst issues: ValueIssue[] = [];\n\tif (record.version < 1) issues.push(rejected(\"version\", \"Block type version is not positive\"));\n\ttry {\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- validateBlockFields checks every entry's shape\n\t\tvalidateBlockFields(record.fields as unknown as BlockFieldDefinition[]);\n\t} catch (error) {\n\t\tif (!(error instanceof SchemaError)) throw error;\n\t\tissues.push(rejected(\"fields\", \"Block type fields are not valid on this site\"));\n\t}\n\treturn issues;\n}\n\nexport function writeRuleIssues(record: SitePackageRecord, facts: WriteRuleFacts): ValueIssue[] {\n\tswitch (record.kind) {\n\t\tcase \"block_type\":\n\t\t\treturn blockTypeIssues(record);\n\t\tcase \"block_type_version\":\n\t\t\treturn blockTypeVersionIssues(record);\n\t\tcase \"redirect\":\n\t\t\treturn redirectIssues(record);\n\t\tcase \"collection\":\n\t\t\treturn record.urlPattern !== undefined && !acceptsUrlPattern(record.urlPattern)\n\t\t\t\t? [rejected(\"urlPattern\", \"Collection URL pattern is invalid\")]\n\t\t\t\t: [];\n\t\tcase \"byline\":\n\t\t\treturn record.websiteUrl !== undefined && !httpUrl.safeParse(record.websiteUrl).success\n\t\t\t\t? [rejected(\"websiteUrl\", \"Byline website is not an http or https URL\")]\n\t\t\t\t: [];\n\t\tcase \"byline_field_value\":\n\t\tcase \"byline_field_group_value\":\n\t\t\treturn bylineFieldValueIssues(facts.bylineFields.get(record.fieldId), record.value);\n\t\tcase \"seo\":\n\t\t\treturn record.seoCanonical !== undefined && !acceptsCanonical(record.seoCanonical)\n\t\t\t\t? [rejected(\"seoCanonical\", \"Canonical URL is not an http or https URL or a site path\")]\n\t\t\t\t: [];\n\t\tcase \"menu_item\":\n\t\t\treturn record.customUrl !== undefined && !safeHref.safeParse(record.customUrl).success\n\t\t\t\t? [rejected(\"customUrl\", \"Menu item URL uses a scheme menus do not allow\")]\n\t\t\t\t: [];\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n","/**\n * Inspection of the import target: whether its portable domain is empty,\n * whether it is configured for the package's locales, which redirects would\n * loop, and which target users match package principals.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { isValidLocaleCode, type I18nConfig } from \"../../i18n/config.js\";\nimport { detectLoops, type RedirectEdge } from \"../../redirects/loops.js\";\nimport { SchemaRegistry } from \"../../schema/registry.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { VERSION } from \"../../version.js\";\nimport { inspectPortableDomain, type DomainBlocker, type ScaffoldItem } from \"../domain.js\";\nimport { isTransferError } from \"../errors.js\";\nimport { compareIds } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport { recordChunkPath } from \"../format/paths.js\";\nimport type { PlanBlocker } from \"../format/plan.js\";\nimport type { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport type { TransferStage } from \"../staging/stage.js\";\nimport { decodeRecordLine, readVerifiedChunk } from \"./read.js\";\nimport { isImportableRedirect } from \"./write-rules.js\";\n\n/** What analysis needs to know about the target site besides its database. */\nexport interface AnalysisTargetContext {\n\t/** Locales the site is configured for (Astro `i18n.locales`). */\n\tlocales: readonly string[];\n\t/** Largest media upload the site accepts, in bytes (`maxUploadSize`). */\n\tmaxUploadSize: number;\n\t/** EmDash version of the target, recorded in the plan. */\n\temdashVersion: string;\n}\n\n/**\n * Target context from the site's configuration. A site without i18n config\n * serves only the default locale `en`.\n */\nexport function analysisTargetContext(config: {\n\ti18n: I18nConfig | null;\n\tmaxUploadSize?: number;\n\temdashVersion?: string;\n}): AnalysisTargetContext {\n\treturn {\n\t\tlocales: config.i18n ? [...config.i18n.locales] : [\"en\"],\n\t\tmaxUploadSize: config.maxUploadSize ?? TRANSFER_LIMITS.defaultMaxBlobBytes,\n\t\temdashVersion: config.emdashVersion ?? VERSION,\n\t};\n}\n\nconst DOMAIN_BLOCKER_MESSAGES: Record<DomainBlocker[\"code\"], string> = {\n\ttable_not_empty: \"The site already has content of this kind\",\n\tcollection_not_seeded: \"The site has a collection that was not created by setup\",\n\tcollection_has_entries: \"A collection on the site already has entries\",\n\ttaxonomy_def_not_scaffold: \"The site has a taxonomy that was not created by setup\",\n\tblock_type_not_seeded: \"The site has a block type that was not created by setup\",\n};\n\nfunction domainBlocker(blocker: DomainBlocker): PlanBlocker {\n\tconst detail: Record<string, string> = { reason: blocker.code };\n\tif (blocker.code === \"table_not_empty\") detail.table = blocker.table;\n\telse if (blocker.code === \"taxonomy_def_not_scaffold\") detail.taxonomy = blocker.name;\n\telse if (blocker.code === \"block_type_not_seeded\") detail.blockType = blocker.slug;\n\telse detail.collection = blocker.slug;\n\treturn {\n\t\tcode: \"target_not_empty\",\n\t\tmessage: DOMAIN_BLOCKER_MESSAGES[blocker.code],\n\t\tdetail,\n\t};\n}\n\nexport interface DomainFindings {\n\tblockers: PlanBlocker[];\n\tscaffold: ScaffoldItem[];\n}\n\n/**\n * Domain blockers and scaffold, plus a blocker for each `ec_*` table named\n * for a package collection that has no collection row: the importer would\n * reuse it as the collection's table.\n */\nexport async function inspectTargetDomain(\n\tdb: Kysely<Database>,\n\tcollectionSlugs: readonly string[],\n): Promise<DomainFindings> {\n\tconst inspection = await inspectPortableDomain(db);\n\tconst blockers = inspection.blockers.map(domainBlocker);\n\tconst packaged = new Set(collectionSlugs);\n\tif (packaged.size > 0) {\n\t\tfor (const orphan of await new SchemaRegistry(db).discoverOrphanedTables()) {\n\t\t\tif (!packaged.has(orphan.slug)) continue;\n\t\t\tblockers.push({\n\t\t\t\tcode: \"target_not_empty\",\n\t\t\t\tmessage: \"The site has a leftover content table for a collection in the package\",\n\t\t\t\tdetail: { reason: \"orphaned_table\", table: orphan.tableName },\n\t\t\t});\n\t\t}\n\t}\n\treturn { blockers, scaffold: inspection.seededScaffold };\n}\n\n/** The target's spelling of `locale`: an exact match, else a case-insensitive one. */\nfunction configuredLocale(locale: string, target: AnalysisTargetContext): string | undefined {\n\tif (target.locales.includes(locale)) return locale;\n\tconst folded = locale.toLowerCase();\n\treturn target.locales.find((candidate) => candidate.toLowerCase() === folded);\n}\n\n/**\n * A blocker for each package locale the target is not configured for\n * (case-insensitive), and for each that shares the target's spelling with\n * another package locale, since their rows would collide once recased.\n */\nexport function checkLocales(\n\tmanifest: SitePackageManifest,\n\ttarget: AnalysisTargetContext,\n): PlanBlocker[] {\n\tconst blockers: PlanBlocker[] = [];\n\tconst claimed = new Set(\n\t\tmanifest.locales.used.filter((locale) => target.locales.includes(locale)),\n\t);\n\tfor (const locale of manifest.locales.used) {\n\t\tif (target.locales.includes(locale)) continue;\n\t\tconst configured = configuredLocale(locale, target);\n\t\tif (configured !== undefined && !claimed.has(configured)) {\n\t\t\tclaimed.add(configured);\n\t\t\tcontinue;\n\t\t}\n\t\tblockers.push({\n\t\t\tcode: \"locale_not_configured\",\n\t\t\tmessage:\n\t\t\t\tconfigured === undefined\n\t\t\t\t\t? \"The package uses a locale this site is not configured for\"\n\t\t\t\t\t: \"The package uses locales that differ only in case\",\n\t\t\t...(isValidLocaleCode(locale) ? { detail: { locale } } : {}),\n\t\t});\n\t}\n\treturn blockers;\n}\n\n/** Package locales the target configures with different casing, and the target's spelling. */\nexport function localeRecasing(\n\tmanifest: SitePackageManifest,\n\ttarget: AnalysisTargetContext,\n): Array<{ from: string; to: string }> {\n\treturn manifest.locales.used.flatMap((locale) => {\n\t\tconst configured = configuredLocale(locale, target);\n\t\treturn configured === undefined || configured === locale\n\t\t\t? []\n\t\t\t: [{ from: locale, to: configured }];\n\t});\n}\n\n/** Redirect packages above this size are not checked for loops. */\nexport const MAX_LOOP_CHECKED_REDIRECTS = 10_000;\n\n/**\n * Ids of package redirects that take part in a loop, using the same detection\n * the redirect admin uses. Reads every redirect chunk; unreadable chunks and\n * redirects the redirect API would refuse were already reported by\n * validation and are skipped, so no unvalidated pattern is compiled.\n */\nexport async function findRedirectLoops(\n\tmanifest: SitePackageManifest,\n\tstage: TransferStage,\n\tstagedFiles: TransferStagedFileRepository,\n\toperationId: string,\n): Promise<string[]> {\n\tconst summary = manifest.records.redirect;\n\tif (!summary || summary.count > MAX_LOOP_CHECKED_REDIRECTS) return [];\n\tconst edges: RedirectEdge[] = [];\n\tfor (let seq = 0; seq < summary.chunks; seq++) {\n\t\tconst path = recordChunkPath(\"redirect\", seq);\n\t\tconst file = await stagedFiles.get(operationId, path);\n\t\tif (!file || file.state !== \"verified\") continue;\n\t\tlet lines: string[];\n\t\ttry {\n\t\t\tlines = await readVerifiedChunk(stage, path, file);\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error)) continue;\n\t\t\tthrow error;\n\t\t}\n\t\tlines.forEach((line, index) => {\n\t\t\tconst decoded = decodeRecordLine(\"redirect\", line, { path, line: index + 1 });\n\t\t\tif (!decoded.ok || !isImportableRedirect(decoded.record)) return;\n\t\t\tconst { record } = decoded;\n\t\t\tedges.push({\n\t\t\t\tid: record.id,\n\t\t\t\tsource: record.source,\n\t\t\t\tdestination: record.destination,\n\t\t\t\tenabled: record.enabled,\n\t\t\t\tisPattern: record.isPattern,\n\t\t\t});\n\t\t});\n\t}\n\treturn detectLoops(edges).toSorted(compareIds);\n}\n\n/** Target users read per query while matching principal emails. */\nconst USER_PAGE_SIZE = 500;\n\n/**\n * Email case folding for principal matching. SQL `lower()` folds only ASCII\n * on SQLite, so folding happens here, identically on every dialect.\n */\nexport function foldEmail(email: string): string {\n\treturn email.normalize(\"NFC\").toLowerCase();\n}\n\n/**\n * Target users whose email matches a principal's, case-insensitively. A\n * principal gets a suggestion only when exactly one user matches. Reads the\n * users table in id-ordered pages of {@link USER_PAGE_SIZE}.\n */\nexport async function suggestPrincipalUsers(\n\tdb: Kysely<Database>,\n\tprincipals: ReadonlyArray<{ id: string; email?: string }>,\n): Promise<Map<string, string>> {\n\tconst wanted = new Set(\n\t\tprincipals.flatMap((principal) => (principal.email ? [foldEmail(principal.email)] : [])),\n\t);\n\tconst usersByEmail = new Map<string, string[]>();\n\tif (wanted.size > 0) {\n\t\tlet after: string | null = null;\n\t\tfor (;;) {\n\t\t\tlet query = db\n\t\t\t\t.selectFrom(\"users\")\n\t\t\t\t.select([\"id\", \"email\"])\n\t\t\t\t.orderBy(\"id\")\n\t\t\t\t.limit(USER_PAGE_SIZE);\n\t\t\tif (after !== null) query = query.where(\"id\", \">\", after);\n\t\t\tconst rows = await query.execute();\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst folded = foldEmail(row.email);\n\t\t\t\tif (!wanted.has(folded)) continue;\n\t\t\t\tconst list = usersByEmail.get(folded) ?? [];\n\t\t\t\tlist.push(row.id);\n\t\t\t\tusersByEmail.set(folded, list);\n\t\t\t}\n\t\t\tconst last = rows.at(-1);\n\t\t\tif (rows.length < USER_PAGE_SIZE || !last) break;\n\t\t\tafter = last.id;\n\t\t}\n\t}\n\tconst suggestions = new Map<string, string>();\n\tfor (const principal of principals) {\n\t\tif (!principal.email) continue;\n\t\tconst matches = usersByEmail.get(foldEmail(principal.email)) ?? [];\n\t\tconst [only] = matches;\n\t\tif (matches.length === 1 && only !== undefined) suggestions.set(principal.id, only);\n\t}\n\treturn suggestions;\n}\n\n/** Ids among `userIds` that are not target users. */\nexport async function findMissingUsers(\n\tdb: Kysely<Database>,\n\tuserIds: readonly string[],\n): Promise<string[]> {\n\tconst unique = [...new Set(userIds)];\n\tconst found = new Set<string>();\n\tfor (const batch of chunks(unique, SQL_BATCH_SIZE)) {\n\t\tconst rows = await db.selectFrom(\"users\").select(\"id\").where(\"id\", \"in\", batch).execute();\n\t\tfor (const row of rows) found.add(row.id);\n\t}\n\treturn unique.filter((id) => !found.has(id)).toSorted(compareIds);\n}\n","/**\n * Import plan assembly and decisions.\n *\n * A plan has decision-independent parts (counts, validation and target\n * findings, the package's export transformations, transformations the\n * target forces) and parts that follow from the decisions (principal mapping\n * transformations, principal conflict blockers). {@link applyDecisions} recomputes\n * only the latter, so resubmitting decisions never needs the package again.\n */\n\nimport type { ScaffoldItem } from \"../domain.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport {\n\tsiteImportPlanSchema,\n\ttype PlanBlocker,\n\ttype PlanPrincipal,\n\ttype PlanWarning,\n\ttype SiteImportDecisions,\n\ttype SiteImportPlan,\n} from \"../format/plan.js\";\nimport {\n\tEXPORT_TRANSFORMATION_CODES,\n\tIMPORT_TRANSFORMATION_CODES,\n\ttype ImportTransformationCode,\n\ttype PlanTransformation,\n} from \"../format/transformations.js\";\nimport { SITE_PACKAGE_FORMAT_VERSION } from \"../format/version.js\";\nimport { MAX_LOOP_CHECKED_REDIRECTS } from \"./target.js\";\nimport type { ValidationSummary } from \"./validate.js\";\nimport type { TargetDialect } from \"./values.js\";\n\nconst MAX_LISTED_IDS = 10_000;\nconst MAX_PROVIDER_WARNINGS = 100;\n\n/** Stages an import always runs besides its record chunks and media steps. */\nconst FIXED_IMPORT_STEPS = 10;\n\nconst DECISION_BLOCKER_CODES: ReadonlySet<string> = new Set([\"principal_conflict\"]);\nconst DECISION_TRANSFORMATION_CODES: ReadonlySet<string> = new Set<ImportTransformationCode>([\n\t\"principal_mapped\",\n\t\"principal_unmapped\",\n]);\n\nexport interface PlanOrigin {\n\tsiteId: string;\n\tpackageId: string;\n\tcreatedAt: string;\n\tcreatedByEmDashVersion: string;\n}\n\nexport interface PlanTarget {\n\tsiteId: string;\n\tdialect: TargetDialect;\n\temdashVersion: string;\n}\n\n/** Byline facts the principal-conflict check needs, by principal id. */\nexport interface PrincipalBylines {\n\t/** Locales in which each principal has a byline. */\n\tlocales: ReadonlyMap<string, ReadonlySet<string>>;\n\t/** Principals with more than one byline in some locale. */\n\tsharedLocale: ReadonlySet<string>;\n}\n\nexport interface PlanInputs {\n\tpackageDigest: `sha256:${string}`;\n\tmanifest: SitePackageManifest;\n\ttarget: PlanTarget;\n\tsummary: ValidationSummary;\n\tvalidationBlockers: readonly PlanBlocker[];\n\tvalidationWarnings: readonly PlanWarning[];\n\ttargetBlockers: readonly PlanBlocker[];\n\tscaffold: readonly ScaffoldItem[];\n\tredirectLoops: readonly string[];\n\tlocaleRecasing: ReadonlyArray<{ from: string; to: string }>;\n\tsuggestions: ReadonlyMap<string, string>;\n\ttargetSettings: { title?: string; tagline?: string };\n}\n\nconst TRANSFORMATION_ORDER: readonly string[] = [\n\t...EXPORT_TRANSFORMATION_CODES,\n\t...IMPORT_TRANSFORMATION_CODES,\n];\n\n/** Export transformations first, then import transformations; each in vocabulary order. */\nfunction sortTransformations(transformations: PlanTransformation[]): PlanTransformation[] {\n\treturn transformations.toSorted(\n\t\t(a, b) => TRANSFORMATION_ORDER.indexOf(a.code) - TRANSFORMATION_ORDER.indexOf(b.code),\n\t);\n}\n\nfunction externalProviderWarnings(summary: ValidationSummary): PlanWarning[] {\n\treturn [...summary.externalProviders].slice(0, MAX_PROVIDER_WARNINGS).map(([provider, uses]) => ({\n\t\tcode: \"media_provider_external\",\n\t\tmessage: \"Content uses media from an external provider, which is not copied\",\n\t\tcount: uses,\n\t\tdetail: { provider },\n\t}));\n}\n\nfunction uncheckedRedirectWarnings(manifest: SitePackageManifest): PlanWarning[] {\n\tconst count = manifest.records.redirect?.count ?? 0;\n\tif (count <= MAX_LOOP_CHECKED_REDIRECTS) return [];\n\treturn [\n\t\t{\n\t\t\tcode: \"redirect_loops_unchecked\",\n\t\t\tmessage:\n\t\t\t\t\"The package has too many redirects to check for loops before importing; a redirect that would close a loop is imported disabled\",\n\t\t\tkind: \"redirect\",\n\t\t\tcount,\n\t\t},\n\t];\n}\n\nfunction estimateSteps(manifest: SitePackageManifest): number {\n\tlet chunks = 0;\n\tfor (const summary of Object.values(manifest.records)) chunks += summary?.chunks ?? 0;\n\treturn (\n\t\tFIXED_IMPORT_STEPS + chunks + Math.ceil(manifest.media.totalBytes / TRANSFER_LIMITS.stepBytes)\n\t);\n}\n\nexport function defaultDecisions(\n\tprincipals: readonly Pick<PlanPrincipal, \"id\" | \"suggestedUserId\">[],\n): SiteImportDecisions {\n\treturn {\n\t\tprincipalMappings: Object.fromEntries(\n\t\t\tprincipals.map((principal) => [principal.id, principal.suggestedUserId ?? null]),\n\t\t),\n\t\tsiteTitle: \"package\",\n\t\tsiteTagline: \"package\",\n\t};\n}\n\nfunction settingSummary(packageValue?: string, targetValue?: string) {\n\treturn {\n\t\t...(packageValue === undefined ? {} : { package: packageValue }),\n\t\t...(targetValue === undefined ? {} : { target: targetValue.slice(0, 4096) }),\n\t};\n}\n\n/** Build the plan with default decisions applied. */\nexport function buildPlan(inputs: PlanInputs, bylines: PrincipalBylines): SiteImportPlan {\n\tconst { manifest, summary } = inputs;\n\n\tconst principals: PlanPrincipal[] = summary.principals.map((principal) => {\n\t\tconst suggestedUserId = inputs.suggestions.get(principal.id);\n\t\treturn {\n\t\t\tid: principal.id,\n\t\t\tdisplayName: principal.displayName,\n\t\t\t...(principal.email === undefined ? {} : { email: principal.email }),\n\t\t\treferences: summary.principalReferences.get(principal.id) ?? 0,\n\t\t\t...(suggestedUserId === undefined ? {} : { suggestedUserId }),\n\t\t};\n\t});\n\n\tconst transformations: PlanTransformation[] = [...manifest.transformations];\n\tif (inputs.scaffold.length > 0) {\n\t\ttransformations.push({\n\t\t\tcode: \"seeded_scaffold_removed\",\n\t\t\tcount: inputs.scaffold.length,\n\t\t\titems: inputs.scaffold\n\t\t\t\t.slice(0, MAX_LISTED_IDS)\n\t\t\t\t.map((item) => ({ type: item.type, id: item.id })),\n\t\t});\n\t}\n\tif (inputs.redirectLoops.length > 0) {\n\t\ttransformations.push({\n\t\t\tcode: \"redirect_loop_disabled\",\n\t\t\tkind: \"redirect\",\n\t\t\tids: inputs.redirectLoops.slice(0, MAX_LISTED_IDS),\n\t\t});\n\t}\n\tif (inputs.localeRecasing.length > 0) {\n\t\ttransformations.push({ code: \"locale_recased\", locales: [...inputs.localeRecasing] });\n\t}\n\tif (inputs.target.dialect === \"postgres\") {\n\t\tif (summary.searchEnabledCollections.length > 0) {\n\t\t\ttransformations.push({\n\t\t\t\tcode: \"search_unsupported\",\n\t\t\t\tkind: \"collection\",\n\t\t\t\tids: summary.searchEnabledCollections.slice(0, MAX_LISTED_IDS),\n\t\t\t});\n\t\t}\n\t\tif (summary.float4Rounded > 0) {\n\t\t\ttransformations.push({ code: \"float4_rounded\", count: summary.float4Rounded });\n\t\t}\n\t}\n\n\tconst plan: SiteImportPlan = {\n\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\tpackageDigest: inputs.packageDigest,\n\t\torigin: {\n\t\t\tsiteId: manifest.originSiteId,\n\t\t\tpackageId: manifest.packageId,\n\t\t\tcreatedAt: manifest.createdAt,\n\t\t\tcreatedByEmDashVersion: manifest.createdByEmDashVersion,\n\t\t},\n\t\ttarget: inputs.target,\n\t\tcounts: Object.fromEntries(\n\t\t\tObject.entries(manifest.records).map(([kind, record]) => [kind, record.count]),\n\t\t),\n\t\tbytes: { records: summary.recordBytes, media: manifest.media.totalBytes },\n\t\tprincipals,\n\t\tsettings: {\n\t\t\ttitle: settingSummary(summary.settings.title, inputs.targetSettings.title),\n\t\t\ttagline: settingSummary(summary.settings.tagline, inputs.targetSettings.tagline),\n\t\t},\n\t\tdecisions: defaultDecisions(principals),\n\t\ttransformations,\n\t\twarnings: [\n\t\t\t...inputs.validationWarnings,\n\t\t\t...externalProviderWarnings(summary),\n\t\t\t...uncheckedRedirectWarnings(manifest),\n\t\t],\n\t\tblockers: [...inputs.validationBlockers, ...inputs.targetBlockers],\n\t\testimatedSteps: estimateSteps(manifest),\n\t};\n\treturn applyDecisions(plan, plan.decisions, bylines);\n}\n\n/**\n * A plan for a package whose manifest could not be read: identity and\n * blockers only.\n */\nexport function buildBlockedPlan(input: {\n\tpackageDigest: `sha256:${string}`;\n\torigin: PlanOrigin;\n\ttarget: PlanTarget;\n\tblockers: readonly PlanBlocker[];\n\twarnings: readonly PlanWarning[];\n}): SiteImportPlan {\n\treturn siteImportPlanSchema.parse({\n\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\tpackageDigest: input.packageDigest,\n\t\torigin: input.origin,\n\t\ttarget: input.target,\n\t\tcounts: {},\n\t\tbytes: { records: 0, media: 0 },\n\t\tprincipals: [],\n\t\tsettings: { title: {}, tagline: {} },\n\t\tdecisions: defaultDecisions([]),\n\t\ttransformations: [],\n\t\twarnings: [...input.warnings],\n\t\tblockers: [...input.blockers],\n\t\testimatedSteps: 0,\n\t});\n}\n\n/**\n * The plan with `decisions` in place and every decision-dependent\n * transformation and blocker recomputed.\n */\nexport function applyDecisions(\n\tplan: SiteImportPlan,\n\tdecisions: SiteImportDecisions,\n\tbylines: PrincipalBylines,\n): SiteImportPlan {\n\tlet mappedReferences = 0;\n\tlet unmappedReferences = 0;\n\tconst principalsByUser = new Map<string, string[]>();\n\tconst conflicts: PlanBlocker[] = [];\n\tfor (const principal of plan.principals) {\n\t\tconst userId = Object.hasOwn(decisions.principalMappings, principal.id)\n\t\t\t? decisions.principalMappings[principal.id]\n\t\t\t: null;\n\t\tif (userId === null || userId === undefined) {\n\t\t\tunmappedReferences += principal.references;\n\t\t\tcontinue;\n\t\t}\n\t\tmappedReferences += principal.references;\n\t\tif (bylines.sharedLocale.has(principal.id)) {\n\t\t\tconflicts.push({\n\t\t\t\tcode: \"principal_conflict\",\n\t\t\t\tmessage: \"A principal with several bylines in one locale is mapped to a user\",\n\t\t\t\tkind: \"principal\",\n\t\t\t\tid: principal.id,\n\t\t\t\tdetail: { user: userId },\n\t\t\t});\n\t\t}\n\t\tconst list = principalsByUser.get(userId) ?? [];\n\t\tlist.push(principal.id);\n\t\tprincipalsByUser.set(userId, list);\n\t}\n\n\tfor (const [userId, principalIds] of principalsByUser) {\n\t\tfor (let i = 0; i < principalIds.length; i++) {\n\t\t\tfor (let j = i + 1; j < principalIds.length; j++) {\n\t\t\t\tconst first = principalIds[i];\n\t\t\t\tconst second = principalIds[j];\n\t\t\t\tif (first === undefined || second === undefined) continue;\n\t\t\t\tconst firstLocales = bylines.locales.get(first);\n\t\t\t\tconst secondLocales = bylines.locales.get(second);\n\t\t\t\tif (!firstLocales || !secondLocales) continue;\n\t\t\t\tif (![...firstLocales].some((locale) => secondLocales.has(locale))) continue;\n\t\t\t\tconflicts.push({\n\t\t\t\t\tcode: \"principal_conflict\",\n\t\t\t\t\tmessage: \"Two principals with bylines in the same locale are mapped to one user\",\n\t\t\t\t\tkind: \"principal\",\n\t\t\t\t\tid: second,\n\t\t\t\t\tdetail: { principal: first, user: userId },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tconst transformations = plan.transformations.filter(\n\t\t(transformation) => !DECISION_TRANSFORMATION_CODES.has(transformation.code),\n\t);\n\tif (mappedReferences > 0) {\n\t\ttransformations.push({ code: \"principal_mapped\", count: mappedReferences });\n\t}\n\tif (unmappedReferences > 0) {\n\t\ttransformations.push({ code: \"principal_unmapped\", count: unmappedReferences });\n\t}\n\n\treturn siteImportPlanSchema.parse({\n\t\t...plan,\n\t\tdecisions,\n\t\ttransformations: sortTransformations(transformations),\n\t\tblockers: [\n\t\t\t...plan.blockers.filter((blocker) => !DECISION_BLOCKER_CODES.has(blocker.code)),\n\t\t\t...conflicts,\n\t\t],\n\t});\n}\n","/**\n * Per-operation index of package records, filled while analysis parses the\n * record streams, so cross-reference checks run as bounded SQL lookups\n * instead of holding the package in memory.\n *\n * Conventions for what analysis stores:\n * - `group_id`: the record's `translationGroup`, or its `id` when it has none\n * (what `by: \"group\"` references resolve against);\n * - `name_key`: the collection or block type `slug`, the menu `name`, or the\n * block type version's `blockTypeVersionKey` (what `by: \"slug\"` and\n * `by: \"name\"` references resolve against);\n * - `parent_id` and `depth` for topological kinds.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { compareIds, isRecordKind, type RecordKind, type ReferenceKey } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\n\nexport interface PackageIndexEntry {\n\tkind: RecordKind;\n\tid: string;\n\tgroupId?: string | null;\n\tparentId?: string | null;\n\tnameKey?: string | null;\n\tdepth?: number;\n}\n\nconst KEY_COLUMN = {\n\tid: \"id\",\n\tgroup: \"group_id\",\n\tslug: \"name_key\",\n\tname: \"name_key\",\n} as const satisfies Record<ReferenceKey, string>;\n\nexport class TransferPackageIndexRepository {\n\tconstructor(\n\t\tprivate readonly db: Kysely<Database>,\n\t\tprivate readonly operationId: string,\n\t) {}\n\n\t/** Insert entries; an entry already present (a retried batch) is left as is. */\n\tasync insertMany(entries: readonly PackageIndexEntry[]): Promise<void> {\n\t\tfor (const batch of chunks([...entries], rowsPerInsert(7))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_package_index\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((entry) => ({\n\t\t\t\t\t\toperation_id: this.operationId,\n\t\t\t\t\t\tkind: entry.kind,\n\t\t\t\t\t\tid: entry.id,\n\t\t\t\t\t\tgroup_id: entry.groupId ?? null,\n\t\t\t\t\t\tparent_id: entry.parentId ?? null,\n\t\t\t\t\t\tname_key: entry.nameKey ?? null,\n\t\t\t\t\t\tdepth: entry.depth ?? 0,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) => conflict.columns([\"operation_id\", \"kind\", \"id\"]).doNothing())\n\t\t\t\t.execute();\n\t\t}\n\t}\n\n\tasync get(kind: RecordKind, id: string): Promise<PackageIndexEntry | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.selectAll()\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.where(\"kind\", \"=\", kind)\n\t\t\t.where(\"id\", \"=\", id)\n\t\t\t.executeTakeFirst();\n\t\tif (!row || !isRecordKind(row.kind)) return null;\n\t\treturn {\n\t\t\tkind: row.kind,\n\t\t\tid: row.id,\n\t\t\tgroupId: row.group_id,\n\t\t\tparentId: row.parent_id,\n\t\t\tnameKey: row.name_key,\n\t\t\tdepth: Number(row.depth),\n\t\t};\n\t}\n\n\t/**\n\t * Values from `values` that no indexed record of any of `kinds` matches on\n\t * `key` (sorted, unique).\n\t */\n\tasync findMissing(\n\t\tkinds: readonly RecordKind[],\n\t\tkey: ReferenceKey,\n\t\tvalues: readonly string[],\n\t): Promise<string[]> {\n\t\tconst column = KEY_COLUMN[key];\n\t\tconst unique = [...new Set(values)];\n\t\tconst found = new Set<string>();\n\t\tfor (const batch of chunks(unique, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t\t.select(sql<string>`${sql.ref(column)}`.as(\"value\"))\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"kind\", \"in\", [...kinds])\n\t\t\t\t.where(sql.ref(column), \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) found.add(row.value);\n\t\t}\n\t\treturn unique.filter((value) => !found.has(value)).toSorted(compareIds);\n\t}\n\n\t/** Depth of each indexed record of `kind` among `ids`. */\n\tasync depths(kind: RecordKind, ids: readonly string[]): Promise<Map<string, number>> {\n\t\tconst result = new Map<string, number>();\n\t\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t\t.select([\"id\", \"depth\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"kind\", \"=\", kind)\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.id, Number(row.depth));\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync count(kind?: RecordKind): Promise<number> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.select((eb) => eb.fn.countAll<number | string>().as(\"count\"))\n\t\t\t.where(\"operation_id\", \"=\", this.operationId);\n\t\tif (kind) query = query.where(\"kind\", \"=\", kind);\n\t\tconst row = await query.executeTakeFirstOrThrow();\n\t\treturn Number(row.count);\n\t}\n\n\t/** Delete up to `limit` entries; returns how many were deleted. */\n\tasync deleteSome(limit = 500): Promise<number> {\n\t\tconst rows = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.select([\"kind\", \"id\"])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.limit(limit)\n\t\t\t.execute();\n\t\tlet deleted = 0;\n\t\tconst byKind = new Map<string, string[]>();\n\t\tfor (const row of rows) byKind.set(row.kind, [...(byKind.get(row.kind) ?? []), row.id]);\n\t\tfor (const [kind, ids] of byKind) {\n\t\t\tfor (const batch of chunks(ids, SQL_BATCH_SIZE)) {\n\t\t\t\tconst result = await this.db\n\t\t\t\t\t.deleteFrom(\"_emdash_transfer_package_index\")\n\t\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t\t.where(\"kind\", \"=\", kind)\n\t\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t\t.executeTakeFirst();\n\t\t\t\tdeleted += Number(result.numDeletedRows ?? 0n);\n\t\t\t}\n\t\t}\n\t\treturn deleted;\n\t}\n}\n","/**\n * Bounded blocker and warning lists for analysis.\n *\n * Issue messages are fixed strings and details carry only locations (package\n * paths, line numbers, property names, record kinds and ids) — never record\n * values. Package content is untrusted and plans, errors, and logs are shown\n * to people who did not necessarily write the package.\n */\n\nimport { z } from \"zod\";\n\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tplanBlockerSchema,\n\tplanWarningSchema,\n\ttype PlanBlocker,\n\ttype PlanWarning,\n} from \"../format/plan.js\";\n\nexport const issueStateSchema = z.strictObject({\n\tblockers: z.array(planBlockerSchema),\n\twarnings: z.array(planWarningSchema),\n\tdroppedBlockers: z.number().int().nonnegative(),\n\tdroppedWarnings: z.number().int().nonnegative(),\n});\n\nexport type IssueState = z.infer<typeof issueStateSchema>;\n\nexport function emptyIssues(): IssueState {\n\treturn { blockers: [], warnings: [], droppedBlockers: 0, droppedWarnings: 0 };\n}\n\nexport function addBlocker(issues: IssueState, blocker: PlanBlocker): void {\n\tif (issues.blockers.length < TRANSFER_LIMITS.planIssues) issues.blockers.push(blocker);\n\telse issues.droppedBlockers++;\n}\n\nexport function addWarning(issues: IssueState, warning: PlanWarning): void {\n\tif (issues.warnings.length < TRANSFER_LIMITS.planIssues) issues.warnings.push(warning);\n\telse issues.droppedWarnings++;\n}\n\n/** The warnings plus an `issues_truncated` warning when either list overflowed. */\nexport function finalWarnings(issues: IssueState): PlanWarning[] {\n\tif (issues.droppedBlockers === 0 && issues.droppedWarnings === 0) return [...issues.warnings];\n\treturn [\n\t\t...issues.warnings,\n\t\t{\n\t\t\tcode: \"issues_truncated\",\n\t\t\tmessage: \"More issues were found than the plan lists\",\n\t\t\tcount: issues.droppedBlockers + issues.droppedWarnings,\n\t\t\tdetail: { blockers: issues.droppedBlockers, warnings: issues.droppedWarnings },\n\t\t},\n\t];\n}\n","/**\n * Package-internal violations of the target's unique constraints.\n *\n * Each record contributes a key per unique constraint it would occupy on the\n * target. Keys are stored as extra rows of the package index under the kind\n * `unique:<constraint>`, with the key's digest as `id` and the owning record\n * id as `group_id`. Inserting is insert-if-absent, so the first owner of a\n * key wins; any other record whose key row names a different owner collides\n * with it. Retrying a chunk re-inserts the same rows and finds the same\n * owners, so the check is idempotent and needs no memory between chunks.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { canonicalJson } from \"../format/canonical.js\";\nimport { sha256Hex } from \"../format/digest.js\";\nimport type { SitePackageRecord } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\n\nexport const UNIQUE_CONSTRAINTS = [\n\t\"block_type_slug\",\n\t\"block_type_version\",\n\t\"entry_slug_locale\",\n\t\"entry_active_group_locale\",\n\t\"term_name_slug_locale\",\n\t\"term_group_locale\",\n\t\"taxonomy_def_name_locale\",\n\t\"byline_slug_locale\",\n\t\"byline_group_locale\",\n\t\"byline_principal_locale\",\n\t\"byline_field_slug\",\n\t\"menu_name_locale\",\n\t\"relation_name_locale\",\n\t\"relation_group_locale\",\n\t\"widget_area_name\",\n\t\"section_slug\",\n\t\"content_reference_groups\",\n\t\"content_byline_entry_byline\",\n\t\"media_folder_name_key\",\n] as const;\n\nexport type UniqueConstraint = (typeof UNIQUE_CONSTRAINTS)[number];\n\n/** Key-row kind prefix; never a record kind, so record lookups ignore these rows. */\nconst KEY_KIND_PREFIX = \"unique:\";\n\nexport interface UniqueKey {\n\tconstraint: UniqueConstraint;\n\tparts: readonly string[];\n}\n\nfunction key(constraint: UniqueConstraint, ...parts: string[]): UniqueKey {\n\treturn { constraint, parts };\n}\n\n/**\n * Postgres `lower()` folds the way JavaScript does for the locales EmDash\n * accepts; SQLite's ASCII-only `lower()` agrees on ASCII locale codes.\n */\nfunction lowerLocale(locale: string): string {\n\treturn locale.toLowerCase();\n}\n\n/** Keys a record occupies in the target's unique constraints. */\nexport function uniqueKeysOf(record: SitePackageRecord): UniqueKey[] {\n\tswitch (record.kind) {\n\t\tcase \"block_type\":\n\t\t\treturn [key(\"block_type_slug\", record.slug)];\n\t\tcase \"block_type_version\":\n\t\t\treturn [key(\"block_type_version\", record.blockTypeId, String(record.version))];\n\t\tcase \"entry\": {\n\t\t\tconst keys: UniqueKey[] = [];\n\t\t\tif (record.slug !== undefined) {\n\t\t\t\tkeys.push(key(\"entry_slug_locale\", record.collection, record.slug, record.locale));\n\t\t\t}\n\t\t\tif (record.deletedAt === undefined && record.translationGroup !== undefined) {\n\t\t\t\tkeys.push(\n\t\t\t\t\tkey(\n\t\t\t\t\t\t\"entry_active_group_locale\",\n\t\t\t\t\t\trecord.collection,\n\t\t\t\t\t\trecord.translationGroup,\n\t\t\t\t\t\tlowerLocale(record.locale),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn keys;\n\t\t}\n\t\tcase \"term\": {\n\t\t\tconst keys = [key(\"term_name_slug_locale\", record.name, record.slug, record.locale)];\n\t\t\tif (record.translationGroup !== undefined) {\n\t\t\t\tkeys.push(key(\"term_group_locale\", record.translationGroup, record.locale));\n\t\t\t}\n\t\t\treturn keys;\n\t\t}\n\t\tcase \"taxonomy_def\":\n\t\t\treturn [key(\"taxonomy_def_name_locale\", record.name, record.locale)];\n\t\tcase \"byline\": {\n\t\t\tconst keys = [key(\"byline_slug_locale\", record.slug, record.locale)];\n\t\t\tif (record.translationGroup !== undefined) {\n\t\t\t\tkeys.push(key(\"byline_group_locale\", record.translationGroup, record.locale));\n\t\t\t}\n\t\t\tif (record.userPrincipal !== undefined) {\n\t\t\t\tkeys.push(key(\"byline_principal_locale\", record.userPrincipal, record.locale));\n\t\t\t}\n\t\t\treturn keys;\n\t\t}\n\t\tcase \"byline_field\":\n\t\t\treturn [key(\"byline_field_slug\", record.slug)];\n\t\tcase \"menu\":\n\t\t\treturn [key(\"menu_name_locale\", record.name, record.locale)];\n\t\tcase \"relation\":\n\t\t\treturn [\n\t\t\t\tkey(\"relation_name_locale\", record.name, record.locale),\n\t\t\t\tkey(\"relation_group_locale\", record.translationGroup, record.locale),\n\t\t\t];\n\t\tcase \"widget_area\":\n\t\t\treturn [key(\"widget_area_name\", record.name)];\n\t\tcase \"section\":\n\t\t\treturn [key(\"section_slug\", record.slug)];\n\t\tcase \"content_reference\":\n\t\t\treturn [\n\t\t\t\tkey(\n\t\t\t\t\t\"content_reference_groups\",\n\t\t\t\t\trecord.relationGroup,\n\t\t\t\t\trecord.parentGroup,\n\t\t\t\t\trecord.childGroup,\n\t\t\t\t),\n\t\t\t];\n\t\tcase \"content_byline\":\n\t\t\treturn [\n\t\t\t\tkey(\"content_byline_entry_byline\", record.collection, record.entryId, record.bylineGroup),\n\t\t\t];\n\t\tcase \"media_folder\":\n\t\t\treturn [key(\"media_folder_name_key\", record.nameKey)];\n\t\tdefault:\n\t\t\treturn [];\n\t}\n}\n\nexport interface KeyedRecord<T> {\n\townerId: string;\n\tkeys: readonly UniqueKey[];\n\titem: T;\n}\n\nexport interface UniqueCollision<T> {\n\tconstraint: UniqueConstraint;\n\titem: T;\n\t/** Id of the record that holds the key first. */\n\tholderId: string;\n}\n\n/** Most key rows one records chunk can write (1000 records × at most 3 keys). */\nexport const MAX_KEYS_PER_CHUNK = 3000;\n\n/** Upper bound on the queries {@link findUniqueCollisions} runs for one chunk. */\nexport const UNIQUE_CHECK_QUERIES =\n\tMath.ceil(MAX_KEYS_PER_CHUNK / rowsPerInsert(4)) + Math.ceil(MAX_KEYS_PER_CHUNK / SQL_BATCH_SIZE);\n\n/**\n * Record the keys of `records` and return every record whose key is already\n * held by a different record of the package (earlier chunks included).\n */\nexport async function findUniqueCollisions<T>(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\trecords: readonly KeyedRecord<T>[],\n): Promise<UniqueCollision<T>[]> {\n\tconst rows: Array<{\n\t\tkind: string;\n\t\tid: string;\n\t\townerId: string;\n\t\titem: T;\n\t\tconstraint: UniqueConstraint;\n\t}> = [];\n\tfor (const record of records) {\n\t\tfor (const unique of record.keys) {\n\t\t\trows.push({\n\t\t\t\tkind: `${KEY_KIND_PREFIX}${unique.constraint}`,\n\t\t\t\tid: await sha256Hex(canonicalJson(unique.parts)),\n\t\t\t\townerId: record.ownerId,\n\t\t\t\titem: record.item,\n\t\t\t\tconstraint: unique.constraint,\n\t\t\t});\n\t\t}\n\t}\n\tif (rows.length === 0) return [];\n\n\tfor (const batch of chunks(rows, rowsPerInsert(4))) {\n\t\tawait db\n\t\t\t.insertInto(\"_emdash_transfer_package_index\")\n\t\t\t.values(\n\t\t\t\tbatch.map((row) => ({\n\t\t\t\t\toperation_id: operationId,\n\t\t\t\t\tkind: row.kind,\n\t\t\t\t\tid: row.id,\n\t\t\t\t\tgroup_id: row.ownerId,\n\t\t\t\t})),\n\t\t\t)\n\t\t\t.onConflict((conflict) => conflict.columns([\"operation_id\", \"kind\", \"id\"]).doNothing())\n\t\t\t.execute();\n\t}\n\n\tconst holders = new Map<string, string>();\n\tfor (const batch of chunks([...new Set(rows.map((row) => row.id))], SQL_BATCH_SIZE)) {\n\t\tconst stored = await db\n\t\t\t.selectFrom(\"_emdash_transfer_package_index\")\n\t\t\t.select([\"kind\", \"id\", \"group_id\"])\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"kind\", \"like\", `${KEY_KIND_PREFIX}%`)\n\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of stored) {\n\t\t\tif (row.group_id !== null) holders.set(`${row.kind}\\u0000${row.id}`, row.group_id);\n\t\t}\n\t}\n\n\tconst collisions: UniqueCollision<T>[] = [];\n\tfor (const row of rows) {\n\t\tconst holderId = holders.get(`${row.kind}\\u0000${row.id}`);\n\t\tif (holderId !== undefined && holderId !== row.ownerId) {\n\t\t\tcollisions.push({ constraint: row.constraint, item: row.item, holderId });\n\t\t}\n\t}\n\treturn collisions;\n}\n","/**\n * Storage-key references inside records.\n *\n * Origin storage keys are deployment state and never appear in a package.\n * The exporter replaces every reference to a local media object's storage key\n * with the placeholder `emdash-media:<mediaId>`; the importer replaces each\n * placeholder with the key it stored that media row's bytes under on the\n * target; verification turns target keys back into placeholders.\n *\n * The walker is schema-agnostic. It visits every string of a record except\n * the record's identity properties ({@link identityProperties}), including\n * strings that hold JSON (image and file field values) which it parses,\n * rewrites, and re-serializes with `JSON.stringify` only when something\n * changed. It recognizes:\n *\n * - `/_emdash/api/media/file/<key>` anywhere in a string, relative or behind\n * any origin; only the key segment is replaced, unless the caller asks to\n * relativize, in which case an absolute URL's scheme and host are dropped\n * too so the importer resolves it against the target;\n * - `meta.storageKey` of a media value object;\n * - a local media value whose `id` is a storage key (a value stored without\n * `meta.storageKey`);\n * - a bare storage key as the whole value of `seo.seoImage` or of a top-level\n * entry field.\n *\n * Text that already reads `emdash-media:` in an origin string is escaped as\n * `emdash-media::` on export and unescaped on import, so every unescaped\n * `emdash-media:` in a package is a placeholder and literal text round-trips\n * exactly. Import and escaping work on each record string as text; a string\n * holding JSON is re-serialized only when a storage key inside it was\n * rewritten.\n *\n * A key that equals some media row's id is treated as that id (ids are\n * portable) and left alone. When several media rows share a key, the smallest\n * id wins. Keys that are not in the origin `media` table are left untouched\n * and reported as `unknown_storage_key` warnings.\n */\n\nimport { measureJsonDepth } from \"./canonical.js\";\nimport { compareIds, identityProperties, type RecordKind } from \"./kinds.js\";\nimport { TRANSFER_LIMITS } from \"./limits.js\";\n\nexport const MEDIA_PLACEHOLDER_PREFIX = \"emdash-media:\";\nexport const MEDIA_FILE_PATH = \"/_emdash/api/media/file/\";\n\nconst PLACEHOLDER_ID_PATTERN = /^[0-9A-Za-z_-]{1,128}$/;\nconst PLACEHOLDER_ESCAPE = `${MEDIA_PLACEHOLDER_PREFIX}:`;\nconst PERCENT_RUN = /(?:%[0-9A-Fa-f]{2})+/g;\nconst PERCENT_ESCAPE = /%[0-9A-F]{2}/g;\nconst HARD_SEGMENT_END = /[?#\"'<>`\\r\\n\\t]/g;\nconst SOFT_SEGMENT_END = /[\\s)\\]]/g;\nconst STORAGE_KEY_CHARS = /^[A-Za-z0-9._-]+$/;\nconst KEY_TOKEN_PATTERN = /[A-Za-z0-9._-]+/g;\nconst MAX_ISSUES_PER_RECORD = 20;\n/** Characters before a media file path searched for the URL's scheme and host. */\nconst ORIGIN_WINDOW = 2048;\n\nfunction isDigit(code: number): boolean {\n\treturn code >= 48 && code <= 57;\n}\n\nfunction isLetter(code: number): boolean {\n\tconst lower = code | 0x20;\n\treturn lower >= 97 && lower <= 122;\n}\n\n/** `[A-Za-z0-9.-]` */\nfunction isHostChar(code: number): boolean {\n\treturn isLetter(code) || isDigit(code) || code === 46 || code === 45;\n}\n\n/** `[A-Za-z0-9+.-]` */\nfunction isSchemeChar(code: number): boolean {\n\treturn isHostChar(code) || code === 43;\n}\n\n/** `[0-9A-Za-z_-]` */\nfunction isPlaceholderIdChar(code: number): boolean {\n\treturn isLetter(code) || isDigit(code) || code === 95 || code === 45;\n}\n\n/**\n * One `emdash-media:` in a package string: group 1 is set for an escape\n * (`emdash-media::`, standing for the text `emdash-media:`), group 2 holds\n * the media id of a placeholder, and neither is set for a malformed one.\n */\nexport const PLACEHOLDER_TOKEN = /emdash-media:(?:(:)|([0-9A-Za-z_-]{1,128}))?/g;\n\n/** Escape every `emdash-media:` already in `value` (see {@link PLACEHOLDER_TOKEN}). */\nexport function escapePlaceholderText(value: string): string {\n\treturn value.includes(MEDIA_PLACEHOLDER_PREFIX)\n\t\t? value.replaceAll(MEDIA_PLACEHOLDER_PREFIX, PLACEHOLDER_ESCAPE)\n\t\t: value;\n}\n\nexport function canUsePlaceholder(mediaId: string): boolean {\n\treturn PLACEHOLDER_ID_PATTERN.test(mediaId);\n}\n\nexport function mediaPlaceholder(mediaId: string): string {\n\tif (!canUsePlaceholder(mediaId)) {\n\t\tthrow new TypeError(\"Media id cannot be used in a media placeholder\");\n\t}\n\treturn `${MEDIA_PLACEHOLDER_PREFIX}${mediaId}`;\n}\n\n/** The media id when `value` is exactly one placeholder, else null. */\nexport function parseMediaPlaceholder(value: string): string | null {\n\tif (!value.startsWith(MEDIA_PLACEHOLDER_PREFIX)) return null;\n\tconst id = value.slice(MEDIA_PLACEHOLDER_PREFIX.length);\n\treturn PLACEHOLDER_ID_PATTERN.test(id) ? id : null;\n}\n\nexport interface MediaKeyIndex {\n\t/** Storage key → media id (smallest id when keys are shared). */\n\treadonly keyToMediaId: ReadonlyMap<string, string>;\n\t/** Every media id; a key equal to one of these is treated as an id. */\n\treadonly mediaIds: ReadonlySet<string>;\n}\n\nexport function buildMediaKeyIndex(\n\trows: Iterable<{ id: string; storageKey: string }>,\n): MediaKeyIndex {\n\tconst keyToMediaId = new Map<string, string>();\n\tconst mediaIds = new Set<string>();\n\tfor (const row of rows) {\n\t\tmediaIds.add(row.id);\n\t\tconst existing = keyToMediaId.get(row.storageKey);\n\t\tif (existing === undefined || compareIds(row.id, existing) < 0) {\n\t\t\tkeyToMediaId.set(row.storageKey, row.id);\n\t\t}\n\t}\n\treturn { keyToMediaId, mediaIds };\n}\n\nexport type MediaRefIssueCode =\n\t/** A storage-key reference whose key is not in the origin media table. */\n\t| \"unknown_storage_key\"\n\t/** An import placeholder names a media id with no target key. */\n\t| \"unresolved_placeholder\"\n\t/** A referenced media id cannot be written as a placeholder. */\n\t| \"media_id_not_placeholderable\";\n\nexport interface MediaRefIssue {\n\tcode: MediaRefIssueCode;\n\t/** Path inside the record, e.g. `fields.content[2].asset.url`. */\n\tpath: string;\n\t/** The unknown key (export/verify) or the media id (import). */\n\tvalue: string;\n}\n\nexport type MediaRefMode = \"export\" | \"import\" | \"verify\";\n\n/**\n * - `export`: `keys` indexes the origin media table. With `relativize`, an\n * absolute URL to the media file route whose key is known loses its scheme\n * and host (declared as `media_url_relativized`).\n * - `verify`: `keys` indexes the target media table with ids mapped back to\n * portable media ids, so the result compares equal to the package record.\n * `relativize` predicts the exporter's relativization.\n * - `import`: `mediaIdToKey` maps portable media ids to target storage keys.\n */\nexport type RewriteMediaRefsOptions =\n\t| { mode: \"export\" | \"verify\"; keys: MediaKeyIndex; relativize?: boolean }\n\t| { mode: \"import\"; mediaIdToKey: ReadonlyMap<string, string> };\n\nexport interface RewriteMediaRefsResult<T> {\n\tvalue: T;\n\tchanged: boolean;\n\t/** Media ids referenced through storage keys or placeholders (sorted, unique). */\n\tmediaIds: string[];\n\t/** Non-fatal issues (at most 20 per record). */\n\twarnings: MediaRefIssue[];\n\t/** Fatal issues: the record must not be exported, imported, or verified as is. */\n\terrors: MediaRefIssue[];\n\t/** Absolute media file URLs made relative (with `relativize`). */\n\trelativized: number;\n}\n\ninterface WalkContext {\n\toptions: RewriteMediaRefsOptions;\n\tkind: RecordKind;\n\tmediaIds: Set<string>;\n\twarnings: MediaRefIssue[];\n\terrors: MediaRefIssue[];\n\trelativized: number;\n\t/** Storage keys replaced with placeholders so far. */\n\tplaceholders: number;\n}\n\n/**\n * Rewrite the storage-key references in one record. Returns the input object\n * itself when nothing changed; never mutates it.\n */\nexport function rewriteMediaRefs<T extends { kind: RecordKind }>(\n\trecord: T,\n\toptions: RewriteMediaRefsOptions,\n): RewriteMediaRefsResult<T> {\n\tconst context: WalkContext = {\n\t\toptions,\n\t\tkind: record.kind,\n\t\tmediaIds: new Set(),\n\t\twarnings: [],\n\t\terrors: [],\n\t\trelativized: 0,\n\t\tplaceholders: 0,\n\t};\n\tconst skip = identityProperties(record.kind);\n\tconst changes: Record<string, unknown> = {};\n\tlet changed = false;\n\tfor (const [property, value] of Object.entries(record)) {\n\t\tif (skip.has(property)) continue;\n\t\tconst next = walk(value, context, property, [property]);\n\t\tif (next !== value) {\n\t\t\tchanges[property] = next;\n\t\t\tchanged = true;\n\t\t}\n\t}\n\treturn {\n\t\tvalue: changed ? { ...record, ...changes } : record,\n\t\tchanged,\n\t\tmediaIds: [...context.mediaIds].toSorted(compareIds),\n\t\twarnings: context.warnings,\n\t\terrors: context.errors,\n\t\trelativized: context.relativized,\n\t};\n}\n\nfunction report(list: MediaRefIssue[], issue: MediaRefIssue): void {\n\tif (list.length < MAX_ISSUES_PER_RECORD) list.push(issue);\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isBareKeyPosition(kind: RecordKind, segments: readonly string[]): boolean {\n\tif (kind === \"seo\") return segments.length === 1 && segments[0] === \"seoImage\";\n\tif (kind === \"entry\") return segments.length === 2 && segments[0] === \"fields\";\n\treturn false;\n}\n\nfunction walk(value: unknown, context: WalkContext, path: string, segments: string[]): unknown {\n\tif (typeof value === \"string\") return rewriteString(value, context, path, segments);\n\tif (Array.isArray(value)) {\n\t\tlet changed = false;\n\t\tconst next = value.map((item, index) => {\n\t\t\tconst rewritten = walk(item, context, `${path}[${index}]`, [...segments, String(index)]);\n\t\t\tif (rewritten !== item) changed = true;\n\t\t\treturn rewritten;\n\t\t});\n\t\treturn changed ? next : value;\n\t}\n\tif (isPlainObject(value)) return rewriteObject(value, context, path, segments);\n\treturn value;\n}\n\nfunction rewriteObject(\n\tvalue: Record<string, unknown>,\n\tcontext: WalkContext,\n\tpath: string,\n\tsegments: string[],\n): Record<string, unknown> {\n\tlet changed = false;\n\tconst next: Record<string, unknown> = {};\n\tfor (const [key, child] of Object.entries(value)) {\n\t\tconst rewritten = walk(child, context, `${path}.${key}`, [...segments, key]);\n\t\tif (rewritten !== child) changed = true;\n\t\tnext[key] = rewritten;\n\t}\n\n\tif (context.options.mode !== \"import\") {\n\t\tconst { keys } = context.options;\n\t\tconst provider = value.provider;\n\t\tconst isLocal = provider === undefined || provider === null || provider === \"local\";\n\n\t\tconst meta = value.meta;\n\t\tif (isLocal && isPlainObject(meta) && typeof meta.storageKey === \"string\") {\n\t\t\tconst storageKey = meta.storageKey;\n\t\t\tconst placeholder = placeholderForKey(storageKey, keys, context, `${path}.meta.storageKey`);\n\t\t\tif (placeholder !== null) {\n\t\t\t\tconst nextMeta = isPlainObject(next.meta) ? next.meta : meta;\n\t\t\t\tnext.meta = { ...nextMeta, storageKey: placeholder };\n\t\t\t\tchanged = true;\n\t\t\t} else if (!keys.mediaIds.has(storageKey)) {\n\t\t\t\treport(context.warnings, {\n\t\t\t\t\tcode: \"unknown_storage_key\",\n\t\t\t\t\tpath: `${path}.meta.storageKey`,\n\t\t\t\t\tvalue: storageKey,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tconst id = value.id;\n\t\tif (isLocal && typeof id === \"string\" && !keys.mediaIds.has(id)) {\n\t\t\tconst placeholder = placeholderForKey(id, keys, context, `${path}.id`);\n\t\t\tif (placeholder !== null) {\n\t\t\t\tnext.id = placeholder;\n\t\t\t\tchanged = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treturn changed ? next : value;\n}\n\n/** Placeholder for a known storage key, or null when `key` is not a known key. */\nfunction placeholderForKey(\n\tkey: string,\n\tkeys: MediaKeyIndex,\n\tcontext: WalkContext,\n\tpath: string,\n): string | null {\n\tif (keys.mediaIds.has(key)) return null;\n\tconst mediaId = keys.keyToMediaId.get(key);\n\tif (mediaId === undefined) return null;\n\tif (!canUsePlaceholder(mediaId)) {\n\t\treport(context.errors, { code: \"media_id_not_placeholderable\", path, value: mediaId });\n\t\treturn null;\n\t}\n\tcontext.mediaIds.add(mediaId);\n\tcontext.placeholders++;\n\treturn `${MEDIA_PLACEHOLDER_PREFIX}${mediaId}`;\n}\n\nfunction rewriteString(\n\tvalue: string,\n\tcontext: WalkContext,\n\tpath: string,\n\tsegments: string[],\n): string {\n\tif (context.options.mode === \"import\") {\n\t\treturn resolvePlaceholders(value, context.options.mediaIdToKey, context, path);\n\t}\n\tconst { keys } = context.options;\n\n\tif (isBareKeyPosition(context.kind, segments)) {\n\t\tconst placeholder = placeholderForKey(value, keys, context, path);\n\t\tif (placeholder !== null) return placeholder;\n\t}\n\n\tconst trimmed = value.trimStart();\n\tif (trimmed.startsWith(\"{\") || trimmed.startsWith(\"[\")) {\n\t\tconst parsed = parseEmbeddedJson(value);\n\t\tif (parsed !== undefined) {\n\t\t\tconst placeholders = context.placeholders;\n\t\t\tconst rewritten = walk(parsed, context, path, segments);\n\t\t\t// Escaping the text rather than re-serializing keeps the JSON byte for byte.\n\t\t\treturn context.placeholders === placeholders\n\t\t\t\t? escapePlaceholderText(value)\n\t\t\t\t: JSON.stringify(rewritten);\n\t\t}\n\t}\n\n\tconst escaped = escapePlaceholderText(value);\n\tif (!escaped.includes(MEDIA_FILE_PATH)) return escaped;\n\treturn rewriteMediaFileUrls(escaped, keys, context, path, context.options.relativize === true);\n}\n\nfunction decodePercent(segment: string): string | null {\n\tif (!segment.includes(\"%\")) return null;\n\ttry {\n\t\treturn decodeURIComponent(segment);\n\t} catch {\n\t\treturn null;\n\t}\n}\n\n/**\n * Index of the first match of the global `pattern` at or after a start, for\n * starts that never decrease: a match found earlier is reused while it is\n * still ahead, so all calls together scan `value` once.\n */\nfunction endFinder(value: string, pattern: RegExp): (start: number) => number {\n\tlet found = -1;\n\treturn (start) => {\n\t\tif (found >= start) return found;\n\t\tpattern.lastIndex = start;\n\t\tconst match = pattern.exec(value);\n\t\tfound = match ? match.index : value.length;\n\t\treturn found;\n\t};\n}\n\n/**\n * Start of the `scheme://host[:port]` or `//host[:port]` that ends at `at`,\n * or -1. Only `value[from, at)` is examined; the scheme is the longest one\n * that fits there.\n */\nfunction originStart(value: string, from: number, at: number): number {\n\tconst floor = Math.max(from, at - ORIGIN_WINDOW);\n\tconst is = (test: (code: number) => boolean, index: number) =>\n\t\tindex >= floor && test(value.charCodeAt(index));\n\tlet end = at;\n\tlet digits = end;\n\twhile (is(isDigit, digits - 1)) digits--;\n\tif (digits < end && value[digits - 1] === \":\" && digits - 1 >= floor) end = digits - 1;\n\tlet host = end;\n\twhile (is(isHostChar, host - 1)) host--;\n\tif (host === end || host - 2 < floor || value[host - 1] !== \"/\" || value[host - 2] !== \"/\") {\n\t\treturn -1;\n\t}\n\tconst slashes = host - 2;\n\tif (slashes - 1 < floor || value[slashes - 1] !== \":\") return slashes;\n\tlet scheme = slashes - 1;\n\twhile (is(isSchemeChar, scheme - 1)) scheme--;\n\tfor (let index = scheme; index < slashes - 1; index++) {\n\t\tif (isLetter(value.charCodeAt(index))) return index;\n\t}\n\treturn slashes;\n}\n\n/**\n * Replace the key segment of every `/_emdash/api/media/file/<key>` in\n * `value`. The segment runs to the first `?#\"'<>`, backtick, or line break.\n * The longest prefix of the segment that is a known storage key, raw or\n * percent-decoded, is replaced; this covers keys with spaces, parentheses,\n * `+`, or non-ASCII characters, percent-encoded URLs, and keys followed by\n * punctuation. A segment whose prefix up to whitespace, `)` or `]` is neither\n * a key nor a media id is reported as `unknown_storage_key`. With\n * `relativize`, a replaced URL also loses the scheme and host before it.\n */\nfunction rewriteMediaFileUrls(\n\tvalue: string,\n\tkeys: MediaKeyIndex,\n\tcontext: WalkContext,\n\tpath: string,\n\trelativize: boolean,\n): string {\n\tconst maxRawLength = maxKeyLength(keys) * MAX_ENCODED_CHARS_PER_CHAR;\n\tconst hardEnd = endFinder(value, HARD_SEGMENT_END);\n\tconst softEnd = endFinder(value, SOFT_SEGMENT_END);\n\tlet output = \"\";\n\tlet cursor = 0;\n\tlet at = value.indexOf(MEDIA_FILE_PATH);\n\twhile (at !== -1) {\n\t\tconst start = at + MEDIA_FILE_PATH.length;\n\t\tconst remainder = value.slice(start, Math.min(hardEnd(start), start + maxRawLength));\n\t\tconst match = longestKeyPrefix(remainder, keys);\n\t\tconst placeholder = match ? placeholderForKey(match.key, keys, context, path) : null;\n\n\t\tif (match && placeholder !== null) {\n\t\t\tconst origin = relativize ? originStart(value, cursor, at) : -1;\n\t\t\tif (origin !== -1) context.relativized++;\n\t\t\toutput += value.slice(cursor, origin === -1 ? at : origin);\n\t\t\toutput += MEDIA_FILE_PATH + placeholder;\n\t\t\tcursor = start + match.length;\n\t\t} else {\n\t\t\toutput += value.slice(cursor, start);\n\t\t\tcursor = start;\n\t\t}\n\t\tif (!match && context.warnings.length < MAX_ISSUES_PER_RECORD) {\n\t\t\tconst end = Math.min(hardEnd(start), softEnd(start), start + MAX_MEDIA_ID_SEGMENT);\n\t\t\tconst segment = value.slice(start, end);\n\t\t\tconst decoded = decodePercent(segment);\n\t\t\tif (\n\t\t\t\tsegment.length > 0 &&\n\t\t\t\t!keys.mediaIds.has(segment) &&\n\t\t\t\t!(decoded !== null && keys.mediaIds.has(decoded))\n\t\t\t) {\n\t\t\t\treport(context.warnings, { code: \"unknown_storage_key\", path, value: segment });\n\t\t\t}\n\t\t}\n\t\tat = value.indexOf(MEDIA_FILE_PATH, Math.max(cursor, start));\n\t}\n\treturn output + value.slice(cursor);\n}\n\nfunction longestKeyPrefix(\n\tremainder: string,\n\tkeys: MediaKeyIndex,\n): { key: string; length: number } | null {\n\tconst lengths = keyLengths(keys);\n\tconst decodedEnds = decodedKeyLengthEnds(remainder, keys);\n\tconst candidates =\n\t\tdecodedEnds.size === 0\n\t\t\t? sortedKeyLengths(keys)\n\t\t\t: [...new Set([...lengths, ...decodedEnds])].toSorted((a, b) => b - a);\n\tfor (const length of candidates) {\n\t\tif (length > remainder.length || length === 0) continue;\n\t\tif (lengths.has(length)) {\n\t\t\tconst prefix = remainder.slice(0, length);\n\t\t\tif (keys.keyToMediaId.has(prefix) && !keys.mediaIds.has(prefix)) {\n\t\t\t\treturn { key: prefix, length };\n\t\t\t}\n\t\t}\n\t\tif (decodedEnds.has(length)) {\n\t\t\tconst decoded = decodePercent(remainder.slice(0, length));\n\t\t\tif (decoded !== null && keys.keyToMediaId.has(decoded) && !keys.mediaIds.has(decoded)) {\n\t\t\t\treturn { key: decoded, length };\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\nfunction hexDigit(code: number): number {\n\tif (code >= 48 && code <= 57) return code - 48;\n\tconst lower = code | 0x20;\n\treturn lower >= 97 && lower <= 102 ? lower - 87 : -1;\n}\n\n/**\n * Lengths of the prefixes of `remainder` that contain a percent escape and\n * would percent-decode to a string as long as some key, so only those are\n * decoded. Stops at the first escape that cannot start or continue a UTF-8\n * sequence, since no longer prefix decodes, and past the longest key.\n */\nfunction decodedKeyLengthEnds(remainder: string, keys: MediaKeyIndex): Set<number> {\n\tconst lengths = keyLengths(keys);\n\tconst ends = new Set<number>();\n\tlet index = remainder.indexOf(\"%\");\n\tif (index === -1) return ends;\n\tconst longest = sortedKeyLengths(keys)[0] ?? 0;\n\tlet decoded = index;\n\tlet pending = 0;\n\tlet units = 0;\n\twhile (index < remainder.length && decoded <= longest) {\n\t\tif (remainder[index] === \"%\") {\n\t\t\tconst high = hexDigit(remainder.charCodeAt(index + 1));\n\t\t\tconst low = hexDigit(remainder.charCodeAt(index + 2));\n\t\t\tif (high === -1 || low === -1) break;\n\t\t\tconst byte = high * 16 + low;\n\t\t\tindex += 3;\n\t\t\tif (pending > 0) {\n\t\t\t\tif ((byte & 0xc0) !== 0x80) break;\n\t\t\t\tpending--;\n\t\t\t\tif (pending === 0) decoded += units;\n\t\t\t} else if (byte < 0x80) {\n\t\t\t\tdecoded++;\n\t\t\t} else if ((byte & 0xe0) === 0xc0) {\n\t\t\t\tpending = 1;\n\t\t\t\tunits = 1;\n\t\t\t} else if ((byte & 0xf0) === 0xe0) {\n\t\t\t\tpending = 2;\n\t\t\t\tunits = 1;\n\t\t\t} else if ((byte & 0xf8) === 0xf0) {\n\t\t\t\tpending = 3;\n\t\t\t\tunits = 2;\n\t\t\t} else {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tif (pending > 0) break;\n\t\t\tdecoded++;\n\t\t\tindex++;\n\t\t}\n\t\tif (pending === 0 && lengths.has(decoded)) ends.add(index);\n\t}\n\treturn ends;\n}\n\n/** A UTF-8 character percent-encodes to at most 12 characters (`%XX` × 4). */\nconst MAX_ENCODED_CHARS_PER_CHAR = 12;\n\n/** Longest media file URL segment that can still spell a media id. */\nconst MAX_MEDIA_ID_SEGMENT = TRANSFER_LIMITS.idLength * MAX_ENCODED_CHARS_PER_CHAR;\n\nconst keyLengthsCache = new WeakMap<MediaKeyIndex, ReadonlySet<number>>();\n\nfunction keyLengths(keys: MediaKeyIndex): ReadonlySet<number> {\n\tlet lengths = keyLengthsCache.get(keys);\n\tif (lengths === undefined) {\n\t\tlengths = new Set(Array.from(keys.keyToMediaId.keys(), (key) => key.length));\n\t\tkeyLengthsCache.set(keys, lengths);\n\t}\n\treturn lengths;\n}\n\nconst sortedKeyLengthsCache = new WeakMap<MediaKeyIndex, readonly number[]>();\n\n/** Distinct key lengths, longest first. */\nfunction sortedKeyLengths(keys: MediaKeyIndex): readonly number[] {\n\tlet sorted = sortedKeyLengthsCache.get(keys);\n\tif (sorted === undefined) {\n\t\tsorted = [...keyLengths(keys)].toSorted((a, b) => b - a);\n\t\tsortedKeyLengthsCache.set(keys, sorted);\n\t}\n\treturn sorted;\n}\n\nfunction maxKeyLength(keys: MediaKeyIndex): number {\n\treturn sortedKeyLengths(keys)[0] ?? 0;\n}\n\nfunction parseEmbeddedJson(value: string): unknown {\n\tif (measureJsonDepth(value, TRANSFER_LIMITS.jsonDepth) > TRANSFER_LIMITS.jsonDepth) {\n\t\treturn undefined;\n\t}\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(value);\n\t\treturn typeof parsed === \"object\" && parsed !== null ? parsed : undefined;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nconst PLACEHOLDER_FILE_PATH = `${MEDIA_FILE_PATH}${MEDIA_PLACEHOLDER_PREFIX}`;\n\n/**\n * Drop the scheme and host before every placeholder media file URL. A\n * placeholder names media on the site that holds the package's data, so on\n * import its URL is the target's own relative media file route. Verification\n * applies the same normalization to package records before comparing.\n */\nexport function relativizePlaceholderUrls(value: string): string {\n\tlet output = \"\";\n\tlet cursor = 0;\n\tlet at = value.indexOf(PLACEHOLDER_FILE_PATH);\n\twhile (at !== -1) {\n\t\tconst next = at + PLACEHOLDER_FILE_PATH.length;\n\t\tif (isPlaceholderIdChar(value.charCodeAt(next))) {\n\t\t\tconst origin = originStart(value, cursor, at);\n\t\t\tif (origin !== -1) {\n\t\t\t\toutput += value.slice(cursor, origin);\n\t\t\t\tcursor = at;\n\t\t\t}\n\t\t}\n\t\tat = value.indexOf(PLACEHOLDER_FILE_PATH, next);\n\t}\n\treturn cursor === 0 ? value : output + value.slice(cursor);\n}\n\nfunction resolvePlaceholders(\n\tvalue: string,\n\tmediaIdToKey: ReadonlyMap<string, string>,\n\tcontext: WalkContext,\n\tpath: string,\n): string {\n\tif (!value.includes(MEDIA_PLACEHOLDER_PREFIX)) return value;\n\treturn relativizePlaceholderUrls(value).replace(\n\t\tPLACEHOLDER_TOKEN,\n\t\t(match, escape: string | undefined, mediaId: string | undefined) => {\n\t\t\tif (escape !== undefined) return MEDIA_PLACEHOLDER_PREFIX;\n\t\t\tif (mediaId === undefined) return match;\n\t\t\tconst key = mediaIdToKey.get(mediaId);\n\t\t\tif (key === undefined) {\n\t\t\t\treport(context.errors, { code: \"unresolved_placeholder\", path, value: mediaId });\n\t\t\t\treturn match;\n\t\t\t}\n\t\t\tcontext.mediaIds.add(mediaId);\n\t\t\treturn key;\n\t\t},\n\t);\n}\n\n/**\n * Keys suitable for {@link scanForKeys}: every storage key except those equal\n * to a media id (those are indistinguishable from the portable id).\n */\nexport function scannableKeys(keys: MediaKeyIndex): Set<string> {\n\tconst result = new Set<string>();\n\tfor (const key of keys.keyToMediaId.keys()) {\n\t\tif (!keys.mediaIds.has(key)) result.add(key);\n\t}\n\treturn result;\n}\n\n/**\n * Walker-independent check: every key from `keys` that occurs anywhere in\n * `text` as a substring, raw, percent-encoded (either hex case), or with\n * JSON string escaping (sorted, unique). Exporter self-validation runs it\n * over every record line and fails the export if anything is found.\n */\nexport function scanForKeys(text: string, keys: ReadonlySet<string>): string[] {\n\tif (keys.size === 0 || text.length === 0) return [];\n\tconst found = new Set<string>();\n\tconst lengths = new Set<number>();\n\tconst irregular: string[] = [];\n\tfor (const key of keys) {\n\t\tif (STORAGE_KEY_CHARS.test(key)) lengths.add(key.length);\n\t\telse if (key.length > 0) irregular.push(key);\n\t}\n\tconst sortedLengths = [...lengths].toSorted((a, b) => a - b);\n\tconst texts = text.includes(\"%\") ? [text, decodePercentRuns(text)] : [text];\n\tfor (const candidateText of texts) {\n\t\tfor (const match of candidateText.matchAll(KEY_TOKEN_PATTERN)) {\n\t\t\tconst token = match[0];\n\t\t\tfor (const length of sortedLengths) {\n\t\t\t\tif (length > token.length) break;\n\t\t\t\tfor (let start = 0; start + length <= token.length; start++) {\n\t\t\t\t\tconst candidate = token.slice(start, start + length);\n\t\t\t\t\tif (keys.has(candidate)) found.add(candidate);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const key of irregular) {\n\t\t\tif (keyForms(key).some((form) => candidateText.includes(form))) found.add(key);\n\t\t}\n\t}\n\treturn [...found].toSorted(compareIds);\n}\n\nfunction keyForms(key: string): string[] {\n\tconst encoded = encodeURIComponent(key);\n\treturn [\n\t\t...new Set([\n\t\t\tkey,\n\t\t\tJSON.stringify(key).slice(1, -1),\n\t\t\tencoded,\n\t\t\tencoded.replace(PERCENT_ESCAPE, (escape) => escape.toLowerCase()),\n\t\t\tencodeURI(key),\n\t\t]),\n\t];\n}\n\n/** Decode each run of `%XX` escapes that forms valid UTF-8; leave the rest. */\nfunction decodePercentRuns(text: string): string {\n\treturn text.replace(PERCENT_RUN, (run) => {\n\t\ttry {\n\t\t\treturn decodeURIComponent(run);\n\t\t} catch {\n\t\t\treturn run;\n\t\t}\n\t});\n}\n","/**\n * Per-record value checks: media placeholders and external media providers\n * inside record values, and the constraints a target database puts on stored\n * values (column types, NOT NULL, Postgres int4 / float4).\n */\n\nimport { isTransferError } from \"../errors.js\";\nimport { measureJsonDepth } from \"../format/canonical.js\";\nimport { encodeColumn } from \"../format/column-codec.js\";\nimport { codecForColumnType } from \"../format/columns.js\";\nimport { identityProperties, type EntryRecord, type SitePackageRecord } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport { PLACEHOLDER_TOKEN } from \"../format/media-refs.js\";\nimport type { PlanBlockerCode } from \"../format/plan.js\";\nimport type { FieldColumnType } from \"../format/transformations.js\";\n\nexport type TargetDialect = \"sqlite\" | \"postgres\";\n\nexport interface FieldInfo {\n\tcolumnType: FieldColumnType;\n\trequired: boolean;\n}\n\nconst PROVIDER_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;\n\n/** Reported in place of a provider id that is not a plain identifier. */\nexport const OTHER_PROVIDER = \"other\";\n\nconst INT4_MIN = -2_147_483_648;\nconst INT4_MAX = 2_147_483_647;\n\n/**\n * Top-level record properties stored in JSON (or JSON-shaped) columns. Numbers\n * directly under them are JSON numbers, not integer columns.\n */\nconst JSON_PROPERTIES: ReadonlySet<string> = new Set([\n\t\"adminConfig\",\n\t\"componentProps\",\n\t\"content\",\n\t\"data\",\n\t\"defaultValue\",\n\t\"fields\",\n\t\"keywords\",\n\t\"moderationMetadata\",\n\t\"options\",\n\t\"searchConfig\",\n\t\"validation\",\n\t\"value\",\n]);\n\n/** Top-level properties stored in REAL columns. */\nconst REAL_PROPERTIES: ReadonlySet<string> = new Set([\"focalX\", \"focalY\"]);\n\nexport interface RecordScan {\n\t/** Media ids named by `emdash-media:` placeholders. */\n\tplaceholders: Set<string>;\n\t/** `emdash-media:` occurrences that are neither a placeholder nor an escape. */\n\tmalformed: number;\n\t/** Media values whose provider is not local, by provider id. */\n\tproviders: Map<string, number>;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction parseEmbeddedJson(value: string): unknown {\n\tconst trimmed = value.trimStart();\n\tif (!trimmed.startsWith(\"{\") && !trimmed.startsWith(\"[\")) return undefined;\n\tif (measureJsonDepth(value) > TRANSFER_LIMITS.jsonDepth) return undefined;\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction scanValue(value: unknown, scan: RecordScan, embedded: boolean): void {\n\tif (typeof value === \"string\") {\n\t\tif (!embedded) {\n\t\t\tfor (const match of value.matchAll(PLACEHOLDER_TOKEN)) {\n\t\t\t\tif (match[2] !== undefined) scan.placeholders.add(match[2]);\n\t\t\t\telse if (match[1] === undefined) scan.malformed++;\n\t\t\t}\n\t\t\tconst parsed = parseEmbeddedJson(value);\n\t\t\tif (parsed !== undefined) scanValue(parsed, scan, true);\n\t\t}\n\t\treturn;\n\t}\n\tif (Array.isArray(value)) {\n\t\tfor (const item of value) scanValue(item, scan, embedded);\n\t\treturn;\n\t}\n\tif (!isPlainObject(value)) return;\n\tconst provider = value.provider;\n\tif (typeof provider === \"string\" && provider !== \"local\" && typeof value.id === \"string\") {\n\t\tconst key = PROVIDER_ID_PATTERN.test(provider) ? provider : OTHER_PROVIDER;\n\t\tscan.providers.set(key, (scan.providers.get(key) ?? 0) + 1);\n\t}\n\tfor (const child of Object.values(value)) scanValue(child, scan, embedded);\n}\n\n/**\n * Placeholders and external media values in every non-identity property of a\n * record. Placeholders are read from each string as text, the way the\n * importer resolves them, never from JSON parsed out of a string.\n */\nexport function scanRecordValues(record: SitePackageRecord): RecordScan {\n\tconst scan: RecordScan = { placeholders: new Set(), malformed: 0, providers: new Map() };\n\tconst skip = identityProperties(record.kind);\n\tfor (const [property, value] of Object.entries(record)) {\n\t\tif (!skip.has(property)) scanValue(value, scan, false);\n\t}\n\treturn scan;\n}\n\nexport interface ValueIssue {\n\tcode: Extract<PlanBlockerCode, \"integer_out_of_range\" | \"value_constraint_violation\">;\n\tmessage: string;\n\tproperty: string;\n\tfield?: string;\n}\n\nexport interface ValueCheckResult {\n\tissues: ValueIssue[];\n\t/** Values a float4 column would store differently. */\n\tfloat4Rounded: number;\n}\n\nfunction isInt4(value: number): boolean {\n\treturn value >= INT4_MIN && value <= INT4_MAX;\n}\n\nfunction roundsInFloat4(value: number): boolean {\n\treturn Math.fround(value) !== value;\n}\n\n/**\n * Top-level integer and real properties of any record against a Postgres\n * target, where `integer` is int4 and `real` is float4.\n */\nexport function checkRecordNumbers(\n\trecord: SitePackageRecord,\n\tdialect: TargetDialect,\n): ValueCheckResult {\n\tconst result: ValueCheckResult = { issues: [], float4Rounded: 0 };\n\tif (dialect !== \"postgres\") return result;\n\tfor (const [property, value] of Object.entries(record)) {\n\t\tif (typeof value !== \"number\" || JSON_PROPERTIES.has(property)) continue;\n\t\tif (REAL_PROPERTIES.has(property)) {\n\t\t\tif (roundsInFloat4(value)) result.float4Rounded++;\n\t\t} else if (!isInt4(value)) {\n\t\t\tresult.issues.push({\n\t\t\t\tcode: \"integer_out_of_range\",\n\t\t\t\tmessage: \"Integer is outside the target database's integer range\",\n\t\t\t\tproperty,\n\t\t\t});\n\t\t}\n\t}\n\treturn result;\n}\n\nfunction mismatch(field: string, message: string): ValueIssue {\n\treturn { code: \"value_constraint_violation\", message, property: \"fields\", field };\n}\n\n/**\n * Entry field values against the target column each field is stored in,\n * through the shared column codec: a value the codec cannot encode for the\n * column is an issue, as is a missing value in a NOT NULL (required) column\n * other than a JSON one (which stores it as JSON `null`) and, on Postgres,\n * an integer outside int4. Boolean fields are INTEGER\n * columns, so their values are 0/1 numbers.\n */\nexport function checkEntryFields(\n\tentry: EntryRecord,\n\tfields: ReadonlyMap<string, FieldInfo>,\n\tdialect: TargetDialect,\n): ValueCheckResult {\n\tconst result: ValueCheckResult = { issues: [], float4Rounded: 0 };\n\tfor (const [slug, value] of Object.entries(entry.fields)) {\n\t\tconst info = fields.get(slug);\n\t\tif (!info) {\n\t\t\tresult.issues.push(mismatch(slug, \"Entry has a value for a field its collection lacks\"));\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tencodeColumn(dialect, codecForColumnType(info.columnType), value);\n\t\t} catch (error) {\n\t\t\tif (!isTransferError(error)) throw error;\n\t\t\tresult.issues.push(mismatch(slug, \"Value does not fit the field's column type\"));\n\t\t\tcontinue;\n\t\t}\n\t\tif (dialect !== \"postgres\" || typeof value !== \"number\") continue;\n\t\tif (info.columnType === \"INTEGER\" && !isInt4(value)) {\n\t\t\tresult.issues.push({\n\t\t\t\tcode: \"integer_out_of_range\",\n\t\t\t\tmessage: \"Integer is outside the target database's integer range\",\n\t\t\t\tproperty: \"fields\",\n\t\t\t\tfield: slug,\n\t\t\t});\n\t\t} else if (info.columnType === \"REAL\" && roundsInFloat4(value)) {\n\t\t\tresult.float4Rounded++;\n\t\t}\n\t}\n\tfor (const [slug, info] of fields) {\n\t\tif (info.required && info.columnType !== \"JSON\" && !Object.hasOwn(entry.fields, slug)) {\n\t\t\tresult.issues.push(mismatch(slug, \"Required field has no value\"));\n\t\t}\n\t}\n\treturn result;\n}\n\n/** Kinds whose records carry a `locale`. */\nexport function recordLocale(record: SitePackageRecord): string | undefined {\n\tconst locale: unknown = Reflect.get(record, \"locale\");\n\treturn typeof locale === \"string\" ? locale : undefined;\n}\n\nexport function recordStringProperty(\n\trecord: SitePackageRecord,\n\tproperty: string,\n): string | undefined {\n\tif (!Object.hasOwn(record, property)) return undefined;\n\tconst value: unknown = Reflect.get(record, property);\n\treturn typeof value === \"string\" ? value : undefined;\n}\n","/**\n * Staged package validation in bounded steps.\n *\n * Three passes, each resumable from a JSON-serializable state:\n * - `structure`: the manifest, every index chunk (verified against the digest\n * the manifest pins), path grammar and ordering, per-kind chunk and record\n * totals, and every indexed file staged, verified, and matching its index\n * entry. Staged content files that the index does not list are rejected.\n * - `records`: every record chunk read and verified, every line strictly\n * validated, per-kind counts, stream order (topological kinds: each parent\n * earlier, depth = parent depth + 1), unique ids, and the package index\n * (`_emdash_transfer_package_index`) filled for reference resolution.\n * - `references`: every `KIND_REFERENCES` entry, and the block type\n * references held inside `blocks` fields and block types, resolved against\n * the package index with bounded lookups, media placeholders resolved to `media`\n * records, every media record's blob staged and verified, and — when a\n * target is given — values checked against the target's column\n * constraints.\n *\n * A step processes whole chunks and stops when the budget refuses the next\n * one. Nothing is held in memory between steps: all progress is in the\n * returned state and the package index.\n */\n\nimport type { Kysely } from \"kysely\";\nimport { z } from \"zod\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { MAX_SELECT_OPTIONS } from \"../../schema/byline-registry.js\";\nimport {\n\tBYLINE_FIELD_TYPES,\n\tFIELD_TYPE_TO_COLUMN,\n\tFIELD_TYPES,\n\ttype BylineFieldType,\n} from \"../../schema/types.js\";\nimport { SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { isTransferError, TransferError } from \"../errors.js\";\nimport {\n\tblocksFieldTypeSlugs,\n\tblockTypeVersionKey,\n\tcompareIds,\n\tcompareStreamOrder,\n\tKIND_REFERENCES,\n\tRECORD_KINDS,\n\tstreamOrderOf,\n\tTOPOLOGICAL_PARENT_PROPERTY,\n\ttype RecordKind,\n\ttype ReferenceKey,\n\ttype SitePackageRecord,\n\ttype StreamOrderKey,\n\ttype TopologicalKind,\n} from \"../format/kinds.js\";\nimport { rowsPerInsert, TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { PackageFileEntry, SitePackageManifest } from \"../format/manifest.js\";\nimport { mediaBlobPath, parsePackagePath, recordChunkPath } from \"../format/paths.js\";\nimport type { PlanBlocker, PlanWarning } from \"../format/plan.js\";\nimport { settingMediaIds } from \"../format/settings.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferPackageIndexRepository, type PackageIndexEntry } from \"../ops/package-index.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport type { StagedPackageReader } from \"../staging/package.js\";\nimport {\n\taddBlocker,\n\taddWarning,\n\temptyIssues,\n\tfinalWarnings,\n\tissueStateSchema,\n\ttype IssueState,\n} from \"./issues.js\";\nimport { blockerForError, decodeRecordLine, readVerifiedChunk } from \"./read.js\";\nimport { findUniqueCollisions, UNIQUE_CHECK_QUERIES, uniqueKeysOf } from \"./unique-keys.js\";\nimport {\n\tcheckEntryFields,\n\tcheckRecordNumbers,\n\trecordLocale,\n\trecordStringProperty,\n\tscanRecordValues,\n\tOTHER_PROVIDER,\n\ttype FieldInfo,\n\ttype TargetDialect,\n\ttype ValueIssue,\n} from \"./values.js\";\nimport { writeRuleIssues, type BylineFieldFacts } from \"./write-rules.js\";\n\nconst count = z.number().int().nonnegative();\nconst kindSchema = z.enum(RECORD_KINDS);\nconst kindCounts = z.array(z.tuple([kindSchema, count]));\n\nexport const VALIDATION_PHASES = [\"structure\", \"records\", \"references\", \"done\"] as const;\nexport type ValidationPhase = (typeof VALIDATION_PHASES)[number];\n\n/**\n * Serialized validation progress. Maps are stored as entry lists: keys come\n * from the package and must never become object properties.\n */\nexport const validationStateSchema = z.strictObject({\n\tversion: z.literal(1),\n\tphase: z.enum(VALIDATION_PHASES),\n\tnextIndexSeq: count,\n\tlastIndexPath: z.string().nullable(),\n\tindexedChunks: kindCounts,\n\tindexedRecords: kindCounts,\n\tindexedFiles: count,\n\tindexedBytes: count,\n\tindexedBlobs: count,\n\tindexedBlobBytes: count,\n\trecordBytes: count,\n\tkindIndex: count,\n\tseq: count,\n\tlastKey: z.strictObject({ id: z.string(), depth: count.optional() }).nullable(),\n\tseenRecords: kindCounts,\n\tunreadableKinds: z.array(kindSchema),\n\tcollections: z.array(\n\t\tz.tuple([z.string(), z.strictObject({ id: z.string(), searchEnabled: z.boolean() })]),\n\t),\n\tfields: z.array(\n\t\tz.tuple([\n\t\t\tz.string(),\n\t\t\tz.array(\n\t\t\t\tz.tuple([\n\t\t\t\t\tz.string(),\n\t\t\t\t\tz.strictObject({\n\t\t\t\t\t\tcolumnType: z.enum([\"TEXT\", \"REAL\", \"INTEGER\", \"JSON\"]),\n\t\t\t\t\t\trequired: z.boolean(),\n\t\t\t\t\t}),\n\t\t\t\t]),\n\t\t\t),\n\t\t]),\n\t),\n\tprincipals: z.array(\n\t\tz.strictObject({ id: z.string(), displayName: z.string(), email: z.string().optional() }),\n\t),\n\tprincipalReferences: z.array(z.tuple([z.string(), count])),\n\tprincipalBylineLocales: z.array(z.tuple([z.string(), z.array(z.string())])),\n\tprincipalsWithSharedLocaleBylines: z.array(z.string()),\n\tsettings: z.strictObject({ title: z.string().optional(), tagline: z.string().optional() }),\n\tbylineFields: z.array(\n\t\tz.tuple([\n\t\t\tz.string(),\n\t\t\tz.strictObject({\n\t\t\t\ttype: z.custom<BylineFieldType>(isBylineFieldType),\n\t\t\t\toptions: z.array(z.string()).optional(),\n\t\t\t}),\n\t\t]),\n\t),\n\tfloat4Rounded: count,\n\texternalProviders: z.array(z.tuple([z.string(), count])),\n\tissues: issueStateSchema,\n});\n\nexport type ValidationState = z.infer<typeof validationStateSchema>;\n\nexport interface ValidationTarget {\n\tdialect: TargetDialect;\n\t/** Largest media blob the target accepts, in bytes. */\n\tmaxBlobBytes: number;\n}\n\nexport interface ValidationOptions {\n\t/** Check values and blob sizes against a target site. */\n\ttarget?: ValidationTarget;\n}\n\nexport interface ValidateStagedPackageInput {\n\tdb: Kysely<Database>;\n\treader: StagedPackageReader;\n\t/** Operation whose staged-file rows and package index this validation uses. */\n\toperationId: string;\n\t/** State returned by the previous step, or null to start. */\n\tstate: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport interface ValidationStepResult {\n\tdone: boolean;\n\tstate: ValidationState;\n\t/** Every blocker found so far. */\n\tblockers: PlanBlocker[];\n\t/** Every warning found so far. */\n\twarnings: PlanWarning[];\n}\n\nexport interface PrincipalSummary {\n\tid: string;\n\tdisplayName: string;\n\temail?: string;\n}\n\ninterface WorkingState {\n\tphase: ValidationPhase;\n\tnextIndexSeq: number;\n\tlastIndexPath: string | null;\n\tindexedChunks: Map<RecordKind, number>;\n\tindexedRecords: Map<RecordKind, number>;\n\tindexedFiles: number;\n\tindexedBytes: number;\n\tindexedBlobs: number;\n\tindexedBlobBytes: number;\n\trecordBytes: number;\n\tkindIndex: number;\n\tseq: number;\n\tlastKey: StreamOrderKey | null;\n\tseenRecords: Map<RecordKind, number>;\n\tunreadableKinds: Set<RecordKind>;\n\tcollections: Map<string, { id: string; searchEnabled: boolean }>;\n\tfields: Map<string, Map<string, FieldInfo>>;\n\tprincipals: PrincipalSummary[];\n\tprincipalReferences: Map<string, number>;\n\tprincipalBylineLocales: Map<string, Set<string>>;\n\tprincipalsWithSharedLocaleBylines: Set<string>;\n\tsettings: { title?: string; tagline?: string };\n\tbylineFields: Map<string, BylineFieldFacts>;\n\tfloat4Rounded: number;\n\texternalProviders: Map<string, number>;\n\tissues: IssueState;\n}\n\nexport function initialValidationState(): ValidationState {\n\treturn serialize(initialWorkingState());\n}\n\nfunction initialWorkingState(): WorkingState {\n\treturn {\n\t\tphase: \"structure\",\n\t\tnextIndexSeq: 0,\n\t\tlastIndexPath: null,\n\t\tindexedChunks: new Map(),\n\t\tindexedRecords: new Map(),\n\t\tindexedFiles: 0,\n\t\tindexedBytes: 0,\n\t\tindexedBlobs: 0,\n\t\tindexedBlobBytes: 0,\n\t\trecordBytes: 0,\n\t\tkindIndex: 0,\n\t\tseq: 0,\n\t\tlastKey: null,\n\t\tseenRecords: new Map(),\n\t\tunreadableKinds: new Set(),\n\t\tcollections: new Map(),\n\t\tfields: new Map(),\n\t\tprincipals: [],\n\t\tprincipalReferences: new Map(),\n\t\tprincipalBylineLocales: new Map(),\n\t\tprincipalsWithSharedLocaleBylines: new Set(),\n\t\tsettings: {},\n\t\tbylineFields: new Map(),\n\t\tfloat4Rounded: 0,\n\t\texternalProviders: new Map(),\n\t\tissues: emptyIssues(),\n\t};\n}\n\nfunction sortedEntries<V>(map: ReadonlyMap<string, V>): Array<[string, V]> {\n\treturn [...map.entries()].toSorted(([a], [b]) => compareIds(a, b));\n}\n\nfunction serialize(state: WorkingState): ValidationState {\n\treturn {\n\t\tversion: 1,\n\t\tphase: state.phase,\n\t\tnextIndexSeq: state.nextIndexSeq,\n\t\tlastIndexPath: state.lastIndexPath,\n\t\tindexedChunks: [...state.indexedChunks.entries()],\n\t\tindexedRecords: [...state.indexedRecords.entries()],\n\t\tindexedFiles: state.indexedFiles,\n\t\tindexedBytes: state.indexedBytes,\n\t\tindexedBlobs: state.indexedBlobs,\n\t\tindexedBlobBytes: state.indexedBlobBytes,\n\t\trecordBytes: state.recordBytes,\n\t\tkindIndex: state.kindIndex,\n\t\tseq: state.seq,\n\t\tlastKey: state.lastKey\n\t\t\t? {\n\t\t\t\t\tid: state.lastKey.id,\n\t\t\t\t\t...(state.lastKey.depth === undefined ? {} : { depth: state.lastKey.depth }),\n\t\t\t\t}\n\t\t\t: null,\n\t\tseenRecords: [...state.seenRecords.entries()],\n\t\tunreadableKinds: [...state.unreadableKinds],\n\t\tcollections: sortedEntries(state.collections),\n\t\tfields: sortedEntries(state.fields).map(([slug, fields]) => [slug, sortedEntries(fields)]),\n\t\tprincipals: state.principals,\n\t\tprincipalReferences: sortedEntries(state.principalReferences),\n\t\tprincipalBylineLocales: sortedEntries(state.principalBylineLocales).map(([id, locales]) => [\n\t\t\tid,\n\t\t\t[...locales].toSorted(compareIds),\n\t\t]),\n\t\tprincipalsWithSharedLocaleBylines: [...state.principalsWithSharedLocaleBylines].toSorted(\n\t\t\tcompareIds,\n\t\t),\n\t\tsettings: state.settings,\n\t\tbylineFields: sortedEntries(state.bylineFields),\n\t\tfloat4Rounded: state.float4Rounded,\n\t\texternalProviders: sortedEntries(state.externalProviders),\n\t\tissues: state.issues,\n\t};\n}\n\nfunction deserialize(state: ValidationState): WorkingState {\n\treturn {\n\t\tphase: state.phase,\n\t\tnextIndexSeq: state.nextIndexSeq,\n\t\tlastIndexPath: state.lastIndexPath,\n\t\tindexedChunks: new Map(state.indexedChunks),\n\t\tindexedRecords: new Map(state.indexedRecords),\n\t\tindexedFiles: state.indexedFiles,\n\t\tindexedBytes: state.indexedBytes,\n\t\tindexedBlobs: state.indexedBlobs,\n\t\tindexedBlobBytes: state.indexedBlobBytes,\n\t\trecordBytes: state.recordBytes,\n\t\tkindIndex: state.kindIndex,\n\t\tseq: state.seq,\n\t\tlastKey: state.lastKey,\n\t\tseenRecords: new Map(state.seenRecords),\n\t\tunreadableKinds: new Set(state.unreadableKinds),\n\t\tcollections: new Map(state.collections),\n\t\tfields: new Map(state.fields.map(([slug, fields]) => [slug, new Map(fields)])),\n\t\tprincipals: state.principals,\n\t\tprincipalReferences: new Map(state.principalReferences),\n\t\tprincipalBylineLocales: new Map(\n\t\t\tstate.principalBylineLocales.map(([id, locales]) => [id, new Set(locales)]),\n\t\t),\n\t\tprincipalsWithSharedLocaleBylines: new Set(state.principalsWithSharedLocaleBylines),\n\t\tsettings: state.settings,\n\t\tbylineFields: new Map(state.bylineFields),\n\t\tfloat4Rounded: state.float4Rounded,\n\t\texternalProviders: new Map(state.externalProviders),\n\t\tissues: state.issues,\n\t};\n}\n\nexport function parseValidationState(value: unknown): ValidationState {\n\tconst result = validationStateSchema.safeParse(value);\n\tif (!result.success) {\n\t\tthrow new TransferError(\"TRANSFER_ANALYZE_ERROR\", \"Validation state is invalid\");\n\t}\n\treturn result.data;\n}\n\ninterface Context {\n\tdb: Kysely<Database>;\n\treader: StagedPackageReader;\n\toperationId: string;\n\tmanifest: SitePackageManifest;\n\tstate: WorkingState;\n\tstagedFiles: TransferStagedFileRepository;\n\tindex: TransferPackageIndexRepository;\n\ttarget: ValidationTarget | undefined;\n}\n\n/**\n * Run one bounded validation step. Blockers and warnings in the result are\n * cumulative; `done` is true once every pass has finished. Usable directly as\n * the exporter's self-validation hook.\n */\nexport async function validateStagedPackageStep(\n\tinput: ValidateStagedPackageInput,\n): Promise<ValidationStepResult> {\n\treturn runValidationStep(input, {});\n}\n\n/** Validate a staged package to completion in one call (small packages, tests, tools). */\nexport async function validateStagedPackage(\n\tinput: Omit<ValidateStagedPackageInput, \"state\" | \"budget\"> & {\n\t\tbudget: () => TransferStepBudget;\n\t\toptions?: ValidationOptions;\n\t},\n): Promise<ValidationStepResult> {\n\tlet state: unknown = null;\n\tfor (;;) {\n\t\tconst result = await runValidationStep(\n\t\t\t{ ...input, state, budget: input.budget() },\n\t\t\tinput.options ?? {},\n\t\t);\n\t\tif (result.done) return result;\n\t\tstate = result.state;\n\t}\n}\n\nexport async function runValidationStep(\n\tinput: ValidateStagedPackageInput,\n\toptions: ValidationOptions,\n): Promise<ValidationStepResult> {\n\tconst state = deserialize(\n\t\tinput.state === null || input.state === undefined\n\t\t\t? initialValidationState()\n\t\t\t: parseValidationState(input.state),\n\t);\n\n\tlet manifest: SitePackageManifest | null = null;\n\tif (state.phase !== \"done\") {\n\t\ttry {\n\t\t\tmanifest = await input.reader.manifest();\n\t\t} catch (error) {\n\t\t\tif (!isTransferError(error)) throw error;\n\t\t\taddBlocker(state.issues, blockerForError(error, { path: \"manifest.json\" }));\n\t\t\tstate.phase = \"done\";\n\t\t}\n\t}\n\n\tif (manifest && state.phase !== \"done\") {\n\t\tconst context: Context = {\n\t\t\tdb: input.db,\n\t\t\treader: input.reader,\n\t\t\toperationId: input.operationId,\n\t\t\tmanifest,\n\t\t\tstate,\n\t\t\tstagedFiles: new TransferStagedFileRepository(input.db),\n\t\t\tindex: new TransferPackageIndexRepository(input.db, input.operationId),\n\t\t\ttarget: options.target,\n\t\t};\n\t\twhile (context.state.phase !== \"done\") {\n\t\t\tconst bytes = await nextUnitBytes(context);\n\t\t\tif (!input.budget.canStart({ bytes, queries: unitQueries(context.state.phase) })) break;\n\t\t\tinput.budget.start(bytes);\n\t\t\tawait runUnit(context);\n\t\t}\n\t}\n\n\tconst serialized = serialize(state);\n\treturn {\n\t\tdone: state.phase === \"done\",\n\t\tstate: serialized,\n\t\tblockers: [...state.issues.blockers],\n\t\twarnings: finalWarnings(state.issues),\n\t};\n}\n\n// ── Scheduling ──────────────────────────────────────────────────\n\nfunction kindAt(index: number): RecordKind | undefined {\n\treturn RECORD_KINDS[index];\n}\n\n/** Index of the first kind at or after `from` that the manifest declares, or -1. */\nfunction nextDeclaredKind(manifest: SitePackageManifest, from: number): number {\n\tfor (let index = from; index < RECORD_KINDS.length; index++) {\n\t\tconst kind = kindAt(index);\n\t\tif (kind && manifest.records[kind]) return index;\n\t}\n\treturn -1;\n}\n\n/**\n * Upper bound on the queries one unit runs: a records chunk writes up to 1000\n * index rows and their unique keys; a references chunk looks up each\n * reference property of up to 1000 records.\n */\nfunction unitQueries(phase: ValidationPhase): number {\n\tswitch (phase) {\n\t\tcase \"records\":\n\t\t\treturn (\n\t\t\t\tMath.ceil(TRANSFER_LIMITS.chunkRecords / rowsPerInsert(7)) +\n\t\t\t\t2 * Math.ceil(TRANSFER_LIMITS.chunkRecords / SQL_BATCH_SIZE) +\n\t\t\t\tUNIQUE_CHECK_QUERIES +\n\t\t\t\t2\n\t\t\t);\n\t\tcase \"references\":\n\t\t\treturn 6 * Math.ceil(TRANSFER_LIMITS.chunkRecords / SQL_BATCH_SIZE) + 4;\n\t\tdefault:\n\t\t\treturn 4;\n\t}\n}\n\nasync function nextUnitBytes(context: Context): Promise<number> {\n\tconst { state, manifest } = context;\n\tif (state.phase === \"structure\") {\n\t\treturn manifest.index[state.nextIndexSeq]?.bytes ?? 0;\n\t}\n\tif (state.phase === \"records\" || state.phase === \"references\") {\n\t\tconst kind = kindAt(state.kindIndex);\n\t\tif (!kind) return 0;\n\t\tconst file = await context.stagedFiles.get(\n\t\t\tcontext.operationId,\n\t\t\trecordChunkPath(kind, state.seq),\n\t\t);\n\t\treturn file?.bytes ?? 0;\n\t}\n\treturn 0;\n}\n\nasync function runUnit(context: Context): Promise<void> {\n\tconst { state, manifest } = context;\n\tswitch (state.phase) {\n\t\tcase \"structure\":\n\t\t\tif (state.nextIndexSeq < manifest.index.length) await structureChunk(context);\n\t\t\telse {\n\t\t\t\tawait finishStructure(context);\n\t\t\t\tstartPass(context, \"records\");\n\t\t\t}\n\t\t\treturn;\n\t\tcase \"records\":\n\t\tcase \"references\": {\n\t\t\tconst kind = kindAt(state.kindIndex);\n\t\t\tif (!kind) {\n\t\t\t\tstate.phase = state.phase === \"records\" ? \"references\" : \"done\";\n\t\t\t\tif (state.phase === \"references\") startPass(context, \"references\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (state.phase === \"records\") await recordsChunk(context, kind);\n\t\t\telse await referencesChunk(context, kind);\n\t\t\tadvanceChunk(context, kind);\n\t\t\treturn;\n\t\t}\n\t\tcase \"done\":\n\t\t\treturn;\n\t}\n}\n\nfunction startPass(context: Context, phase: \"records\" | \"references\"): void {\n\tconst { state, manifest } = context;\n\tconst first = nextDeclaredKind(manifest, 0);\n\tstate.phase = first === -1 ? (phase === \"records\" ? \"references\" : \"done\") : phase;\n\tstate.kindIndex = first === -1 ? RECORD_KINDS.length : first;\n\tstate.seq = 0;\n\tstate.lastKey = null;\n\tif (first === -1 && phase === \"records\") startPass(context, \"references\");\n}\n\nfunction advanceChunk(context: Context, kind: RecordKind): void {\n\tconst { state, manifest } = context;\n\tstate.seq++;\n\tif (state.seq < (manifest.records[kind]?.chunks ?? 0)) return;\n\tif (state.phase === \"records\") finishKindRecords(context, kind);\n\tconst next = nextDeclaredKind(manifest, state.kindIndex + 1);\n\tstate.kindIndex = next === -1 ? RECORD_KINDS.length : next;\n\tstate.seq = 0;\n\tstate.lastKey = null;\n\tif (next === -1) {\n\t\tif (state.phase === \"records\") startPass(context, \"references\");\n\t\telse state.phase = \"done\";\n\t}\n}\n\n// ── Structure ───────────────────────────────────────────────────\n\nfunction bumpCount<K>(map: Map<K, number>, key: K, by = 1): void {\n\tmap.set(key, (map.get(key) ?? 0) + by);\n}\n\nasync function structureChunk(context: Context): Promise<void> {\n\tconst { state, manifest } = context;\n\tconst seq = state.nextIndexSeq;\n\tstate.nextIndexSeq++;\n\tconst indexPath = manifest.index[seq]?.path;\n\n\tlet entries: PackageFileEntry[];\n\ttry {\n\t\tentries = await context.reader.indexChunk(seq);\n\t} catch (error) {\n\t\tif (!isTransferError(error)) throw error;\n\t\taddBlocker(state.issues, blockerForError(error, { path: indexPath }));\n\t\treturn;\n\t}\n\n\tfor (const entry of entries) {\n\t\tif (state.lastIndexPath !== null && compareIds(state.lastIndexPath, entry.path) >= 0) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"package_invalid\",\n\t\t\t\tmessage: \"Index entries are not sorted by path or repeat a path\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t}\n\t\tstate.lastIndexPath = entry.path;\n\t\tstate.indexedFiles++;\n\t\tstate.indexedBytes += entry.bytes;\n\n\t\tconst parsed = parsePackagePath(entry.path);\n\t\tif (parsed?.type === \"records\") {\n\t\t\tconst summary = manifest.records[parsed.kind];\n\t\t\tif (!summary || parsed.seq >= summary.chunks) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"package_invalid\",\n\t\t\t\t\tmessage: \"Record chunk is not declared by the manifest\",\n\t\t\t\t\tkind: parsed.kind,\n\t\t\t\t\tdetail: { path: entry.path },\n\t\t\t\t});\n\t\t\t}\n\t\t\tbumpCount(state.indexedChunks, parsed.kind);\n\t\t\tbumpCount(state.indexedRecords, parsed.kind, entry.records ?? 0);\n\t\t\tstate.recordBytes += entry.bytes;\n\t\t} else if (parsed?.type === \"media\") {\n\t\t\tstate.indexedBlobs++;\n\t\t\tstate.indexedBlobBytes += entry.bytes;\n\t\t\tif (context.target && entry.bytes > context.target.maxBlobBytes) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"media_blob_too_large\",\n\t\t\t\t\tmessage: \"Media file is larger than this site accepts\",\n\t\t\t\t\tdetail: { path: entry.path, bytes: entry.bytes, limit: context.target.maxBlobBytes },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tconst staged = await context.stagedFiles.getMany(\n\t\tcontext.operationId,\n\t\tentries.map((entry) => entry.path),\n\t);\n\tfor (const entry of entries) {\n\t\tconst file = staged.get(entry.path);\n\t\tif (!file) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"file_missing\",\n\t\t\t\tmessage: \"Package file has not been staged\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t} else if (file.bytes !== entry.bytes || file.sha256 !== entry.sha256) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"file_mismatch\",\n\t\t\t\tmessage: \"Staged file does not match its index entry\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t} else if (file.state !== \"verified\") {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"file_missing\",\n\t\t\t\tmessage: \"Package file has not been uploaded\",\n\t\t\t\tdetail: { path: entry.path },\n\t\t\t});\n\t\t}\n\t}\n}\n\nasync function countStagedContentFiles(context: Context): Promise<number> {\n\tconst row = await context.db\n\t\t.selectFrom(\"_emdash_transfer_staged_files\")\n\t\t.select((eb) => eb.fn.countAll<number | string>().as(\"count\"))\n\t\t.where(\"operation_id\", \"=\", context.operationId)\n\t\t.where((eb) => eb.or([eb(\"path\", \"like\", \"records/%\"), eb(\"path\", \"like\", \"media/%\")]))\n\t\t.executeTakeFirstOrThrow();\n\treturn Number(row.count);\n}\n\nasync function finishStructure(context: Context): Promise<void> {\n\tconst { state, manifest } = context;\n\tfor (const kind of RECORD_KINDS) {\n\t\tconst summary = manifest.records[kind];\n\t\tconst chunks = state.indexedChunks.get(kind) ?? 0;\n\t\tconst records = state.indexedRecords.get(kind) ?? 0;\n\t\tif ((summary?.chunks ?? 0) !== chunks) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"package_invalid\",\n\t\t\t\tmessage: \"Index does not list every record chunk the manifest declares\",\n\t\t\t\tkind,\n\t\t\t\tdetail: { declared: summary?.chunks ?? 0, indexed: chunks },\n\t\t\t});\n\t\t} else if ((summary?.count ?? 0) !== records) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"record_count_mismatch\",\n\t\t\t\tmessage: \"Index record counts do not match the manifest\",\n\t\t\t\tkind,\n\t\t\t\tdetail: { declared: summary?.count ?? 0, indexed: records },\n\t\t\t});\n\t\t}\n\t}\n\tif (\n\t\tstate.indexedBlobs !== manifest.media.count ||\n\t\tstate.indexedBlobBytes !== manifest.media.totalBytes\n\t) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"package_invalid\",\n\t\t\tmessage: \"Indexed media does not match the manifest\",\n\t\t});\n\t}\n\tif (\n\t\tstate.indexedFiles !== manifest.files.count ||\n\t\tstate.indexedBytes !== manifest.files.totalBytes\n\t) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"package_invalid\",\n\t\t\tmessage: \"Indexed files do not match the manifest\",\n\t\t});\n\t}\n\tconst staged = await countStagedContentFiles(context);\n\tif (staged > state.indexedFiles) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"package_invalid\",\n\t\t\tmessage: \"Staged files are not listed in the package index\",\n\t\t\tcount: staged - state.indexedFiles,\n\t\t});\n\t}\n}\n\n// ── Records ─────────────────────────────────────────────────────\n\ninterface ChunkRecord {\n\trecord: SitePackageRecord;\n\tline: number;\n}\n\n/**\n * Decode one record chunk. With `report`, read and decode failures become\n * blockers; the references pass re-reads chunks the records pass already\n * reported and stays quiet.\n */\nasync function loadChunk(\n\tcontext: Context,\n\tkind: RecordKind,\n\treport: boolean,\n): Promise<{ records: ChunkRecord[]; lines: number; path: string } | null> {\n\tconst path = recordChunkPath(kind, context.state.seq);\n\tconst file = await context.stagedFiles.get(context.operationId, path);\n\tif (!file || file.state !== \"verified\") return null;\n\tlet lines: string[];\n\ttry {\n\t\tlines = await readVerifiedChunk(context.reader.stage, path, file);\n\t} catch (error) {\n\t\tif (!isTransferError(error)) throw error;\n\t\tif (report) addBlocker(context.state.issues, blockerForError(error, { path }));\n\t\treturn null;\n\t}\n\tconst records: ChunkRecord[] = [];\n\tlines.forEach((line, index) => {\n\t\tconst decoded = decodeRecordLine(kind, line, { path, line: index + 1 });\n\t\tif (decoded.ok) records.push({ record: decoded.record, line: index + 1 });\n\t\telse if (report) addBlocker(context.state.issues, decoded.blocker);\n\t});\n\treturn { records, lines: lines.length, path };\n}\n\nfunction groupIdOf(record: SitePackageRecord): string {\n\treturn recordStringProperty(record, \"translationGroup\") ?? record.id;\n}\n\nfunction nameKeyOf(record: SitePackageRecord): string | null {\n\tif (record.kind === \"collection\" || record.kind === \"block_type\") return record.slug;\n\tif (record.kind === \"menu\") return record.name;\n\tif (record.kind === \"block_type_version\") {\n\t\treturn blockTypeVersionKey(record.blockTypeId, record.version);\n\t}\n\treturn null;\n}\n\nfunction isTopologicalKind(kind: RecordKind): kind is TopologicalKind {\n\treturn Object.hasOwn(TOPOLOGICAL_PARENT_PROPERTY, kind);\n}\n\nfunction parentOf(kind: RecordKind, record: SitePackageRecord): string | undefined {\n\tif (!isTopologicalKind(kind)) return undefined;\n\treturn recordStringProperty(record, TOPOLOGICAL_PARENT_PROPERTY[kind]);\n}\n\nasync function recordsChunk(context: Context, kind: RecordKind): Promise<void> {\n\tconst { state, manifest } = context;\n\tconst chunk = await loadChunk(context, kind, true);\n\tif (!chunk) {\n\t\tstate.unreadableKinds.add(kind);\n\t\treturn;\n\t}\n\tbumpCount(state.seenRecords, kind, chunk.lines);\n\tconst topological = streamOrderOf(kind) === \"topological\";\n\n\tconst chunkDepths = new Map<string, number>();\n\tlet knownDepths = new Map<string, number>();\n\tif (topological) {\n\t\tconst lookups = new Set<string>();\n\t\tfor (const { record } of chunk.records) {\n\t\t\tlookups.add(record.id);\n\t\t\tconst parent = parentOf(kind, record);\n\t\t\tif (parent !== undefined) lookups.add(parent);\n\t\t}\n\t\tknownDepths = await context.index.depths(kind, [...lookups]);\n\t}\n\n\tconst usedLocales = new Set(manifest.locales.used);\n\tconst entries: PackageIndexEntry[] = [];\n\tfor (const { record, line } of chunk.records) {\n\t\tconst location = { path: chunk.path, line };\n\t\tlet depth: number | undefined;\n\t\tif (topological) {\n\t\t\tdepth = 0;\n\t\t\tconst parent = parentOf(kind, record);\n\t\t\tif (parent === record.id) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"reference_cycle\",\n\t\t\t\t\tmessage: \"Record is its own parent\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t} else if (parent !== undefined) {\n\t\t\t\tconst parentDepth = chunkDepths.get(parent) ?? knownDepths.get(parent);\n\t\t\t\tif (parentDepth === undefined) {\n\t\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\t\tcode: \"record_order_invalid\",\n\t\t\t\t\t\tmessage: \"Parent does not appear before its child\",\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tid: record.id,\n\t\t\t\t\t\tdetail: location,\n\t\t\t\t\t});\n\t\t\t\t} else depth = parentDepth + 1;\n\t\t\t}\n\t\t\tconst stored = knownDepths.get(record.id);\n\t\t\tif (chunkDepths.has(record.id) || (stored !== undefined && stored !== depth)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"duplicate_id\",\n\t\t\t\t\tmessage: \"Record id appears more than once\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t}\n\t\t\tchunkDepths.set(record.id, depth);\n\t\t}\n\n\t\tconst key: StreamOrderKey = depth === undefined ? { id: record.id } : { id: record.id, depth };\n\t\tif (state.lastKey && compareStreamOrder(kind, state.lastKey, key) >= 0) {\n\t\t\tconst duplicate = state.lastKey.id === record.id;\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: duplicate ? \"duplicate_id\" : \"record_order_invalid\",\n\t\t\t\tmessage: duplicate ? \"Record id appears more than once\" : \"Records are out of stream order\",\n\t\t\t\tkind,\n\t\t\t\tid: record.id,\n\t\t\t\tdetail: location,\n\t\t\t});\n\t\t}\n\t\tstate.lastKey = key;\n\n\t\tconst locale = recordLocale(record);\n\t\tif (locale !== undefined && !usedLocales.has(locale)) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"package_invalid\",\n\t\t\t\tmessage: \"Record locale is not listed in the manifest\",\n\t\t\t\tkind,\n\t\t\t\tid: record.id,\n\t\t\t\tdetail: location,\n\t\t\t});\n\t\t}\n\n\t\tcollectRecordFacts(context, record, location);\n\n\t\tconst parent = parentOf(kind, record);\n\t\tentries.push({\n\t\t\tkind,\n\t\t\tid: record.id,\n\t\t\tgroupId: groupIdOf(record),\n\t\t\tnameKey: nameKeyOf(record),\n\t\t\tparentId: parent ?? null,\n\t\t\tdepth: depth ?? 0,\n\t\t});\n\t}\n\tawait context.index.insertMany(entries);\n\tawait checkUniqueKeys(context, kind, chunk.records, chunk.path);\n}\n\nasync function checkUniqueKeys(\n\tcontext: Context,\n\tkind: RecordKind,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst keyed = records.map((item) => ({\n\t\townerId: item.record.id,\n\t\tkeys: uniqueKeysOf(item.record),\n\t\titem,\n\t}));\n\tconst collisions = await findUniqueCollisions(context.db, context.operationId, keyed);\n\tfor (const { constraint, item, holderId } of collisions) {\n\t\tif (constraint === \"byline_principal_locale\") {\n\t\t\tconst principal = recordStringProperty(item.record, \"userPrincipal\");\n\t\t\tif (principal !== undefined) context.state.principalsWithSharedLocaleBylines.add(principal);\n\t\t\tcontinue;\n\t\t}\n\t\taddBlocker(context.state.issues, {\n\t\t\tcode: \"unique_violation\",\n\t\t\tmessage: \"Record would duplicate another record's unique key on the target\",\n\t\t\tkind,\n\t\t\tid: item.record.id,\n\t\t\tdetail: { constraint, conflictsWith: holderId, path, line: item.line },\n\t\t});\n\t}\n}\n\nconst FIELD_TYPE_SET: ReadonlySet<string> = new Set(FIELD_TYPES);\nconst BYLINE_FIELD_TYPE_SET: ReadonlySet<unknown> = new Set(BYLINE_FIELD_TYPES);\n\nfunction isBylineFieldType(type: unknown): type is BylineFieldType {\n\treturn BYLINE_FIELD_TYPE_SET.has(type);\n}\n\n/** The string choices in a select field's `validation.options`, as the write path reads them. */\nfunction selectOptions(validation: unknown): string[] {\n\tif (typeof validation !== \"object\" || validation === null || Array.isArray(validation)) {\n\t\treturn [];\n\t}\n\tconst options: unknown = Reflect.get(validation, \"options\");\n\treturn Array.isArray(options)\n\t\t? options.filter((option): option is string => typeof option === \"string\")\n\t\t: [];\n}\n\nfunction isKnownFieldType(type: string): type is keyof typeof FIELD_TYPE_TO_COLUMN {\n\treturn FIELD_TYPE_SET.has(type);\n}\n\n/**\n * Records whose facts analysis keeps in its state. A package beyond these is\n * rejected rather than letting per-step state grow with the package.\n */\nconst MAX_TRACKED = {\n\tprincipals: 10_000,\n\tcollections: 1_000,\n\tfields: 20_000,\n\tbylineFields: 1_000,\n\tproviders: 100,\n} as const;\n\nfunction countFields(state: WorkingState): number {\n\tlet total = 0;\n\tfor (const fields of state.fields.values()) total += fields.size;\n\treturn total;\n}\n\nfunction reportTrackingLimit(state: WorkingState, kind: RecordKind): void {\n\tconst message = \"Package has more records of this kind than a site supports\";\n\tconst reported = state.issues.blockers.some(\n\t\t(blocker) =>\n\t\t\tblocker.code === \"limit_exceeded\" && blocker.kind === kind && blocker.message === message,\n\t);\n\tif (!reported) addBlocker(state.issues, { code: \"limit_exceeded\", message, kind });\n}\n\nfunction collectRecordFacts(\n\tcontext: Context,\n\trecord: SitePackageRecord,\n\tlocation: { path: string; line: number },\n): void {\n\tconst { state } = context;\n\tswitch (record.kind) {\n\t\tcase \"principal\":\n\t\t\tif (record.id === \"__proto__\") {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"record_invalid\",\n\t\t\t\t\tmessage: \"Principal id is reserved\",\n\t\t\t\t\tkind: \"principal\",\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (state.principals.length >= MAX_TRACKED.principals) {\n\t\t\t\treportTrackingLimit(state, \"principal\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.principals.push({\n\t\t\t\tid: record.id,\n\t\t\t\tdisplayName: record.displayName,\n\t\t\t\t...(record.email === undefined ? {} : { email: record.email }),\n\t\t\t});\n\t\t\treturn;\n\t\tcase \"collection\": {\n\t\t\tconst existing = state.collections.get(record.slug);\n\t\t\tif (existing && existing.id !== record.id) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"duplicate_id\",\n\t\t\t\t\tmessage: \"Collection slug appears more than once\",\n\t\t\t\t\tkind: \"collection\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst config = record.searchConfig;\n\t\t\tconst searchEnabled =\n\t\t\t\ttypeof config === \"object\" &&\n\t\t\t\tconfig !== null &&\n\t\t\t\t!Array.isArray(config) &&\n\t\t\t\tconfig.enabled === true;\n\t\t\tif (state.collections.size >= MAX_TRACKED.collections) {\n\t\t\t\treportTrackingLimit(state, \"collection\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.collections.set(record.slug, { id: record.id, searchEnabled });\n\t\t\treturn;\n\t\t}\n\t\tcase \"field\": {\n\t\t\tif (!isKnownFieldType(record.type)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"field_type_unknown\",\n\t\t\t\t\tmessage: \"Field type is not supported by this site\",\n\t\t\t\t\tkind: \"field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (FIELD_TYPE_TO_COLUMN[record.type] !== record.columnType) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"record_invalid\",\n\t\t\t\t\tmessage: \"Field column type does not match its field type\",\n\t\t\t\t\tkind: \"field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tlet collectionSlug: string | undefined;\n\t\t\tfor (const [slug, collection] of state.collections) {\n\t\t\t\tif (collection.id === record.collectionId) collectionSlug = slug;\n\t\t\t}\n\t\t\tif (collectionSlug === undefined) return;\n\t\t\tif (countFields(state) >= MAX_TRACKED.fields) {\n\t\t\t\treportTrackingLimit(state, \"field\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst fields = state.fields.get(collectionSlug) ?? new Map<string, FieldInfo>();\n\t\t\tif (fields.has(record.slug)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"duplicate_id\",\n\t\t\t\t\tmessage: \"Field slug appears more than once in its collection\",\n\t\t\t\t\tkind: \"field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfields.set(record.slug, {\n\t\t\t\tcolumnType: record.columnType,\n\t\t\t\trequired: record.required === true,\n\t\t\t});\n\t\t\tstate.fields.set(collectionSlug, fields);\n\t\t\treturn;\n\t\t}\n\t\tcase \"byline_field\": {\n\t\t\tif (!isBylineFieldType(record.type)) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"field_type_unknown\",\n\t\t\t\t\tmessage: \"Byline field type is not supported by this site\",\n\t\t\t\t\tkind: \"byline_field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: location,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst options = record.type === \"select\" ? selectOptions(record.validation) : undefined;\n\t\t\tif (options !== undefined && options.length > MAX_SELECT_OPTIONS) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"value_constraint_violation\",\n\t\t\t\t\tmessage: \"Byline field has more choices than a site supports\",\n\t\t\t\t\tkind: \"byline_field\",\n\t\t\t\t\tid: record.id,\n\t\t\t\t\tdetail: { ...location, property: \"validation\" },\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (state.bylineFields.size >= MAX_TRACKED.bylineFields) {\n\t\t\t\treportTrackingLimit(state, \"byline_field\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tstate.bylineFields.set(record.id, {\n\t\t\t\ttype: record.type,\n\t\t\t\t...(options === undefined ? {} : { options }),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tcase \"setting\":\n\t\t\tif (typeof record.value === \"string\") {\n\t\t\t\tif (\n\t\t\t\t\trecord.id === \"site:title\" ||\n\t\t\t\t\t(record.id === \"emdash:site_title\" && !state.settings.title)\n\t\t\t\t) {\n\t\t\t\t\tstate.settings.title = record.value.slice(0, 4096);\n\t\t\t\t}\n\t\t\t\tif (\n\t\t\t\t\trecord.id === \"site:tagline\" ||\n\t\t\t\t\t(record.id === \"emdash:site_tagline\" && !state.settings.tagline)\n\t\t\t\t) {\n\t\t\t\t\tstate.settings.tagline = record.value.slice(0, 4096);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn;\n\t\tdefault:\n\t\t\treturn;\n\t}\n}\n\nfunction finishKindRecords(context: Context, kind: RecordKind): void {\n\tconst { state, manifest } = context;\n\tconst declared = manifest.records[kind]?.count ?? 0;\n\tconst seen = state.seenRecords.get(kind) ?? 0;\n\tif (declared !== seen && !state.unreadableKinds.has(kind)) {\n\t\taddBlocker(state.issues, {\n\t\t\tcode: \"record_count_mismatch\",\n\t\t\tmessage: \"Record count does not match the manifest\",\n\t\t\tkind,\n\t\t\tdetail: { declared, found: seen },\n\t\t});\n\t}\n}\n\n// ── References ──────────────────────────────────────────────────\n\nfunction referenceValues(record: SitePackageRecord, property: string, many: boolean): string[] {\n\tif (!Object.hasOwn(record, property)) return [];\n\tconst raw: unknown = Reflect.get(record, property);\n\tif (many) {\n\t\treturn Array.isArray(raw)\n\t\t\t? raw.filter((value): value is string => typeof value === \"string\")\n\t\t\t: [];\n\t}\n\treturn typeof raw === \"string\" ? [raw] : [];\n}\n\nasync function referencesChunk(context: Context, kind: RecordKind): Promise<void> {\n\tconst { state } = context;\n\tconst chunk = await loadChunk(context, kind, false);\n\tif (!chunk) return;\n\n\tconst principalIds = new Set(state.principals.map((principal) => principal.id));\n\tfor (const reference of KIND_REFERENCES[kind]) {\n\t\tconst owners = new Map<string, ChunkRecord[]>();\n\t\tfor (const item of chunk.records) {\n\t\t\tfor (const value of referenceValues(\n\t\t\t\titem.record,\n\t\t\t\treference.property,\n\t\t\t\treference.many === true,\n\t\t\t)) {\n\t\t\t\tconst list = owners.get(value) ?? [];\n\t\t\t\tlist.push(item);\n\t\t\t\towners.set(value, list);\n\t\t\t\tif (reference.targets.includes(\"principal\") && principalIds.has(value)) {\n\t\t\t\t\tbumpCount(state.principalReferences, value);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (owners.size === 0) continue;\n\t\tconst missing = await context.index.findMissing(reference.targets, reference.by, [\n\t\t\t...owners.keys(),\n\t\t]);\n\t\tfor (const value of missing) {\n\t\t\tfor (const item of owners.get(value) ?? []) {\n\t\t\t\tconst detail = { property: reference.property, path: chunk.path, line: item.line };\n\t\t\t\tif (reference.soft) {\n\t\t\t\t\taddWarning(state.issues, {\n\t\t\t\t\t\tcode: \"soft_reference_dangling\",\n\t\t\t\t\t\tmessage: \"Reference does not resolve to a record in the package\",\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tid: item.record.id,\n\t\t\t\t\t\tdetail,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\t\tcode: \"dangling_reference\",\n\t\t\t\t\t\tmessage: \"Reference does not resolve to a record in the package\",\n\t\t\t\t\t\tkind,\n\t\t\t\t\t\tid: item.record.id,\n\t\t\t\t\t\tdetail,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tawait checkNestedReferences(context, kind, chunk.records, chunk.path);\n\tawait checkMediaReferences(context, kind, chunk.records, chunk.path);\n\tif (kind === \"media\") await checkMediaBlobs(context, chunk.records, chunk.path);\n\n\tfor (const { record, line } of chunk.records) {\n\t\tif (\n\t\t\trecord.kind === \"byline\" &&\n\t\t\trecord.userPrincipal !== undefined &&\n\t\t\tprincipalIds.has(record.userPrincipal)\n\t\t) {\n\t\t\tconst locales = state.principalBylineLocales.get(record.userPrincipal) ?? new Set<string>();\n\t\t\tlocales.add(record.locale);\n\t\t\tstate.principalBylineLocales.set(record.userPrincipal, locales);\n\t\t}\n\t\tif (context.target) checkTargetValues(context, record, { path: chunk.path, line });\n\t}\n}\n\ninterface NestedReference {\n\tproperty: string;\n\ttargets: readonly RecordKind[];\n\tby: ReferenceKey;\n\tvalues: (record: SitePackageRecord) => string[];\n}\n\n/**\n * References that live inside a property rather than being one: the block\n * types a `blocks` field names in `validation`, and the version a block type\n * names as current.\n */\nconst NESTED_REFERENCES: Partial<Record<RecordKind, NestedReference>> = {\n\tfield: {\n\t\tproperty: \"validation\",\n\t\ttargets: [\"block_type\"],\n\t\tby: \"slug\",\n\t\tvalues: (record) => (record.kind === \"field\" ? blocksFieldTypeSlugs(record) : []),\n\t},\n\tblock_type: {\n\t\tproperty: \"currentVersion\",\n\t\ttargets: [\"block_type_version\"],\n\t\tby: \"name\",\n\t\tvalues: (record) =>\n\t\t\trecord.kind === \"block_type\" ? [blockTypeVersionKey(record.id, record.currentVersion)] : [],\n\t},\n};\n\nasync function checkNestedReferences(\n\tcontext: Context,\n\tkind: RecordKind,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst reference = NESTED_REFERENCES[kind];\n\tif (!reference) return;\n\tconst owners = new Map<string, ChunkRecord[]>();\n\tfor (const item of records) {\n\t\tfor (const value of reference.values(item.record)) {\n\t\t\tconst list = owners.get(value) ?? [];\n\t\t\tlist.push(item);\n\t\t\towners.set(value, list);\n\t\t}\n\t}\n\tif (owners.size === 0) return;\n\tconst missing = await context.index.findMissing(reference.targets, reference.by, [\n\t\t...owners.keys(),\n\t]);\n\tfor (const value of missing) {\n\t\tfor (const item of owners.get(value) ?? []) {\n\t\t\taddBlocker(context.state.issues, {\n\t\t\t\tcode: \"dangling_reference\",\n\t\t\t\tmessage: \"Reference does not resolve to a record in the package\",\n\t\t\t\tkind,\n\t\t\t\tid: item.record.id,\n\t\t\t\tdetail: { property: reference.property, path, line: item.line },\n\t\t\t});\n\t\t}\n\t}\n}\n\nasync function checkMediaReferences(\n\tcontext: Context,\n\tkind: RecordKind,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst { state } = context;\n\tconst placeholderOwners = new Map<string, ChunkRecord[]>();\n\tconst settingOwners = new Map<string, ChunkRecord[]>();\n\tfor (const item of records) {\n\t\tconst scan = scanRecordValues(item.record);\n\t\tif (scan.malformed > 0) {\n\t\t\taddBlocker(state.issues, {\n\t\t\t\tcode: \"media_ref_invalid\",\n\t\t\t\tmessage: \"Record holds media placeholder text that is not a placeholder or an escape\",\n\t\t\t\tkind,\n\t\t\t\tid: item.record.id,\n\t\t\t\tdetail: { path, line: item.line },\n\t\t\t});\n\t\t}\n\t\tfor (const mediaId of scan.placeholders) {\n\t\t\tconst list = placeholderOwners.get(mediaId) ?? [];\n\t\t\tlist.push(item);\n\t\t\tplaceholderOwners.set(mediaId, list);\n\t\t}\n\t\tfor (const [provider, uses] of scan.providers) {\n\t\t\tconst key =\n\t\t\t\tstate.externalProviders.has(provider) ||\n\t\t\t\tstate.externalProviders.size < MAX_TRACKED.providers\n\t\t\t\t\t? provider\n\t\t\t\t\t: OTHER_PROVIDER;\n\t\t\tbumpCount(state.externalProviders, key, uses);\n\t\t}\n\t\tif (item.record.kind === \"setting\") {\n\t\t\tfor (const mediaId of settingMediaIds(item.record.id, item.record.value)) {\n\t\t\t\tconst list = settingOwners.get(mediaId) ?? [];\n\t\t\t\tlist.push(item);\n\t\t\t\tsettingOwners.set(mediaId, list);\n\t\t\t}\n\t\t}\n\t}\n\tif (placeholderOwners.size > 0) {\n\t\tconst missing = await context.index.findMissing([\"media\"], \"id\", [...placeholderOwners.keys()]);\n\t\tfor (const mediaId of missing) {\n\t\t\tfor (const item of placeholderOwners.get(mediaId) ?? []) {\n\t\t\t\taddBlocker(state.issues, {\n\t\t\t\t\tcode: \"media_ref_invalid\",\n\t\t\t\t\tmessage: \"Media placeholder does not name a media record in the package\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: item.record.id,\n\t\t\t\t\tdetail: { path, line: item.line },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\tif (settingOwners.size > 0) {\n\t\tconst missing = await context.index.findMissing([\"media\"], \"id\", [...settingOwners.keys()]);\n\t\tfor (const mediaId of missing) {\n\t\t\tfor (const item of settingOwners.get(mediaId) ?? []) {\n\t\t\t\taddWarning(state.issues, {\n\t\t\t\t\tcode: \"media_row_missing\",\n\t\t\t\t\tmessage: \"Setting refers to media that is not in the package\",\n\t\t\t\t\tkind,\n\t\t\t\t\tid: item.record.id,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n}\n\nasync function checkMediaBlobs(\n\tcontext: Context,\n\trecords: readonly ChunkRecord[],\n\tpath: string,\n): Promise<void> {\n\tconst blobPaths = new Map<string, ChunkRecord[]>();\n\tfor (const item of records) {\n\t\tif (item.record.kind !== \"media\") continue;\n\t\tconst blobPath = mediaBlobPath(item.record.blob);\n\t\tconst list = blobPaths.get(blobPath) ?? [];\n\t\tlist.push(item);\n\t\tblobPaths.set(blobPath, list);\n\t}\n\tif (blobPaths.size === 0) return;\n\tconst staged = await context.stagedFiles.getMany(context.operationId, [...blobPaths.keys()]);\n\tfor (const [blobPath, items] of blobPaths) {\n\t\tconst file = staged.get(blobPath);\n\t\tif (file && file.state === \"verified\") continue;\n\t\tfor (const item of items) {\n\t\t\taddBlocker(context.state.issues, {\n\t\t\t\tcode: \"media_blob_missing\",\n\t\t\t\tmessage: \"Media record's file is not in the package\",\n\t\t\t\tkind: \"media\",\n\t\t\t\tid: item.record.id,\n\t\t\t\tdetail: { path, line: item.line },\n\t\t\t});\n\t\t}\n\t}\n}\n\nfunction reportValueIssues(\n\tcontext: Context,\n\trecord: SitePackageRecord,\n\tissues: readonly ValueIssue[],\n\tlocation: { path: string; line: number },\n): void {\n\tfor (const issue of issues) {\n\t\taddBlocker(context.state.issues, {\n\t\t\tcode: issue.code,\n\t\t\tmessage: issue.message,\n\t\t\tkind: record.kind,\n\t\t\tid: record.id,\n\t\t\tdetail: {\n\t\t\t\t...location,\n\t\t\t\tproperty: issue.property,\n\t\t\t\t...(issue.field === undefined ? {} : { field: issue.field }),\n\t\t\t},\n\t\t});\n\t}\n}\n\nfunction checkTargetValues(\n\tcontext: Context,\n\trecord: SitePackageRecord,\n\tlocation: { path: string; line: number },\n): void {\n\tconst target = context.target;\n\tif (!target) return;\n\tconst numbers = checkRecordNumbers(record, target.dialect);\n\tcontext.state.float4Rounded += numbers.float4Rounded;\n\treportValueIssues(context, record, numbers.issues, location);\n\treportValueIssues(\n\t\tcontext,\n\t\trecord,\n\t\twriteRuleIssues(record, { bylineFields: context.state.bylineFields }),\n\t\tlocation,\n\t);\n\tif (record.kind === \"entry\") {\n\t\tconst fields = context.state.fields.get(record.collection);\n\t\tif (!fields) return;\n\t\tconst values = checkEntryFields(record, fields, target.dialect);\n\t\tcontext.state.float4Rounded += values.float4Rounded;\n\t\treportValueIssues(context, record, values.issues, location);\n\t}\n}\n\n// ── Summary for analysis ────────────────────────────────────────\n\nexport interface ValidationSummary {\n\trecordBytes: number;\n\tprincipals: PrincipalSummary[];\n\tprincipalReferences: ReadonlyMap<string, number>;\n\tprincipalBylineLocales: ReadonlyMap<string, ReadonlySet<string>>;\n\t/** Principals linked to more than one byline in some locale. */\n\tprincipalsWithSharedLocaleBylines: ReadonlySet<string>;\n\tsettings: { title?: string; tagline?: string };\n\t/** Slugs of the package's collections. */\n\tcollectionSlugs: string[];\n\t/** Collections whose search config enables full-text search. */\n\tsearchEnabledCollections: string[];\n\tfloat4Rounded: number;\n\texternalProviders: ReadonlyMap<string, number>;\n}\n\nexport function summarizeValidation(state: ValidationState): ValidationSummary {\n\tconst working = deserialize(state);\n\treturn {\n\t\trecordBytes: working.recordBytes,\n\t\tprincipals: working.principals,\n\t\tprincipalReferences: working.principalReferences,\n\t\tprincipalBylineLocales: working.principalBylineLocales,\n\t\tprincipalsWithSharedLocaleBylines: working.principalsWithSharedLocaleBylines,\n\t\tsettings: working.settings,\n\t\tcollectionSlugs: [...working.collections.keys()].toSorted(compareIds),\n\t\tsearchEnabledCollections: [...working.collections.values()]\n\t\t\t.filter((collection) => collection.searchEnabled)\n\t\t\t.map((collection) => collection.id)\n\t\t\t.toSorted(compareIds),\n\t\tfloat4Rounded: working.float4Rounded,\n\t\texternalProviders: working.externalProviders,\n\t};\n}\n","/**\n * The import analysis operation: validation, target inspection, and the plan,\n * driven in bounded steps under the operation's lease.\n *\n * Progress lives in the operation cursor plus a state file in the\n * operation's staging area keyed by that cursor's digest. A step writes the\n * state for its new cursor before it moves the cursor, so a step that dies\n * midway leaves the previous cursor and its state intact and the next step\n * repeats the work (package index writes are insert-if-absent).\n */\n\nimport type { Kysely } from \"kysely\";\nimport { z } from \"zod\";\n\nimport { detectDialect } from \"../../database/dialect-helpers.js\";\nimport { OptionsRepository } from \"../../database/repositories/options.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { isTransferError, TransferError } from \"../errors.js\";\nimport { canonicalJson, parseCanonicalJson } from \"../format/canonical.js\";\nimport { canonicalDigest, planDigest, sha256Hex, type Sha256Digest } from \"../format/digest.js\";\nimport { compareIds, portableIdSchema, RECORD_KINDS } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport { MANIFEST_PATH, recordChunkPath } from \"../format/paths.js\";\nimport {\n\tmergeDecisions,\n\tsiteImportDecisionsInputSchema,\n\tsiteImportPlanSchema,\n\ttype SiteImportPlan,\n} from \"../format/plan.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferOperationRepository, type TransferOperation } from \"../ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport { analysisCursorSchema, type AnalysisCursor, type TransferProgress } from \"../ops/states.js\";\nimport { getOrCreateSiteId } from \"../site-id.js\";\nimport { stagingPrefix } from \"../staging/keys.js\";\nimport { StagedPackageReader } from \"../staging/package.js\";\nimport { readStreamBytes, TransferStage } from \"../staging/stage.js\";\nimport {\n\tapplyDecisions,\n\tbuildBlockedPlan,\n\tbuildPlan,\n\tdefaultDecisions,\n\ttype PrincipalBylines,\n} from \"./plan.js\";\nimport {\n\tcheckLocales,\n\tlocaleRecasing,\n\tfindMissingUsers,\n\tfindRedirectLoops,\n\tinspectTargetDomain,\n\tsuggestPrincipalUsers,\n\ttype AnalysisTargetContext,\n} from \"./target.js\";\nimport {\n\tinitialValidationState,\n\tparseValidationState,\n\trunValidationStep,\n\tsummarizeValidation,\n\ttype ValidationState,\n\ttype ValidationStepResult,\n} from \"./validate.js\";\n\nconst ANALYSIS_DIRECTORY = \"_analysis/\";\nconst MAX_STATE_BYTES = 64 * 1024 * 1024;\nconst MAX_PLAN_BYTES = 64 * 1024 * 1024;\n\nconst ANALYZABLE_STATES = [\"uploading\", \"analyzing\"] as const;\n\nexport interface AnalyzeImportStepInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/** A lease the caller already holds on the operation; claimed here when omitted. */\n\tleaseToken?: string;\n\tbudget: TransferStepBudget;\n\ttargetContext: AnalysisTargetContext;\n}\n\nexport interface AnalyzeImportStepResult {\n\toperation: TransferOperation;\n\t/** True once the operation is `planned` (or ended); false when more steps are needed. */\n\tdone: boolean;\n\tplan: SiteImportPlan | null;\n\tplanDigest: Sha256Digest | null;\n}\n\nconst analysisContextSchema = z.strictObject({\n\tversion: z.literal(1),\n\tprincipalBylineLocales: z.array(z.tuple([z.string(), z.array(z.string())])),\n\tprincipalsWithSharedLocaleBylines: z.array(z.string()),\n});\n\ntype AnalysisContextFile = z.infer<typeof analysisContextSchema>;\n\nfunction stageFor(storage: Storage, operation: TransferOperation): TransferStage {\n\treturn new TransferStage(storage, stagingPrefix(\"import\", operation.id, operation.stagingSecret));\n}\n\nasync function stateKey(stage: TransferStage, cursor: AnalysisCursor): Promise<string> {\n\treturn `${stage.prefix}${ANALYSIS_DIRECTORY}state-${await sha256Hex(canonicalJson(cursor))}.json`;\n}\n\nfunction contextKey(stage: TransferStage): string {\n\treturn `${stage.prefix}${ANALYSIS_DIRECTORY}context.json`;\n}\n\nasync function readJson(storage: Storage, key: string, maxBytes: number): Promise<unknown> {\n\tif (!(await storage.exists(key))) return null;\n\tconst download = await storage.download(key);\n\treturn JSON.parse(new TextDecoder().decode(await readStreamBytes(download.body, maxBytes)));\n}\n\nasync function writeJson(storage: Storage, key: string, value: unknown): Promise<void> {\n\tawait storage.upload({\n\t\tkey,\n\t\tbody: new TextEncoder().encode(JSON.stringify(value)),\n\t\tcontentType: \"application/json\",\n\t});\n}\n\nfunction cursorFor(state: ValidationState): AnalysisCursor {\n\tconst kind = RECORD_KINDS[state.kindIndex];\n\tswitch (state.phase) {\n\t\tcase \"structure\":\n\t\t\treturn { stage: \"analyze_structure\", nextIndexSeq: state.nextIndexSeq };\n\t\tcase \"records\":\n\t\t\tif (kind) {\n\t\t\t\treturn { stage: \"analyze_records\", position: { kind, seq: state.seq, line: 0 } };\n\t\t\t}\n\t\t\treturn { stage: \"analyze_references\", check: state.kindIndex, after: null };\n\t\tcase \"references\":\n\t\t\treturn {\n\t\t\t\tstage: \"analyze_references\",\n\t\t\t\tcheck: state.kindIndex,\n\t\t\t\tafter: kind && state.seq > 0 ? recordChunkPath(kind, state.seq - 1) : null,\n\t\t\t};\n\t\tcase \"done\":\n\t\t\treturn { stage: \"analyze_target\" };\n\t}\n}\n\nfunction chunksBefore(\n\tmanifest: SitePackageManifest | null,\n\tkindIndex: number,\n\tseq: number,\n): { before: number; total: number } {\n\tlet before = 0;\n\tlet total = 0;\n\tRECORD_KINDS.forEach((kind, index) => {\n\t\tconst chunks = manifest?.records[kind]?.chunks ?? 0;\n\t\ttotal += chunks;\n\t\tif (index < kindIndex) before += chunks;\n\t});\n\treturn { before: before + seq, total };\n}\n\nfunction progressFor(\n\tstate: ValidationState,\n\tmanifest: SitePackageManifest | null,\n): TransferProgress {\n\tconst indexChunks = manifest?.index.length ?? 0;\n\tconst { before, total: recordChunks } = chunksBefore(manifest, state.kindIndex, state.seq);\n\tconst total = indexChunks + 2 * recordChunks + 1;\n\tswitch (state.phase) {\n\t\tcase \"structure\":\n\t\t\treturn { done: Math.min(state.nextIndexSeq, indexChunks), total };\n\t\tcase \"records\":\n\t\t\treturn { done: indexChunks + before, total };\n\t\tcase \"references\":\n\t\t\treturn { done: indexChunks + recordChunks + before, total };\n\t\tcase \"done\":\n\t\t\treturn { done: total - 1, total };\n\t}\n}\n\nasync function loadValidationState(\n\tstage: TransferStage,\n\tcursor: TransferOperation[\"cursor\"],\n): Promise<ValidationState> {\n\tconst analysisCursor = analysisCursorSchema.safeParse(cursor);\n\tif (!analysisCursor.success) return initialValidationState();\n\tconst raw = await readJson(\n\t\tstage.storage,\n\t\tawait stateKey(stage, analysisCursor.data),\n\t\tMAX_STATE_BYTES,\n\t);\n\treturn raw === null ? initialValidationState() : parseValidationState(raw);\n}\n\nasync function readManifestSafely(\n\treader: StagedPackageReader,\n): Promise<SitePackageManifest | null> {\n\ttry {\n\t\treturn await reader.manifest();\n\t} catch (error) {\n\t\tif (isTransferError(error)) return null;\n\t\tthrow error;\n\t}\n}\n\nconst looseIdentitySchema = z.looseObject({\n\tpackageId: portableIdSchema,\n\toriginSiteId: portableIdSchema,\n\tcreatedAt: z.string().min(1).max(64),\n\tcreatedByEmDashVersion: z.string().min(1).max(128),\n});\n\n/**\n * Identity and digest of a manifest that failed full validation, when its\n * identity fields are still well-formed.\n */\nasync function looseManifestIdentity(stage: TransferStage): Promise<{\n\tdigest: Sha256Digest;\n\torigin: z.infer<typeof looseIdentitySchema>;\n} | null> {\n\ttry {\n\t\tconst bytes = await stage.readBytes(MANIFEST_PATH, TRANSFER_LIMITS.manifestBytes);\n\t\tconst raw = parseCanonicalJson(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes));\n\t\tconst identity = looseIdentitySchema.safeParse(raw);\n\t\tif (!identity.success) return null;\n\t\treturn { digest: await canonicalDigest(raw), origin: identity.data };\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nasync function readTargetSettings(\n\tdb: Kysely<Database>,\n): Promise<{ title?: string; tagline?: string }> {\n\tconst options = new OptionsRepository(db);\n\tconst title = await options.get(\"site:title\");\n\tconst tagline = await options.get(\"site:tagline\");\n\treturn {\n\t\t...(typeof title === \"string\" ? { title } : {}),\n\t\t...(typeof tagline === \"string\" ? { tagline } : {}),\n\t};\n}\n\nfunction principalBylinesFrom(file: AnalysisContextFile): PrincipalBylines {\n\treturn {\n\t\tlocales: new Map(file.principalBylineLocales.map(([id, locales]) => [id, new Set(locales)])),\n\t\tsharedLocale: new Set(file.principalsWithSharedLocaleBylines),\n\t};\n}\n\nasync function storePlan(\n\tstage: TransferStage,\n\tplan: SiteImportPlan,\n\tcontext: AnalysisContextFile,\n): Promise<Sha256Digest> {\n\tawait writeJson(stage.storage, contextKey(stage), context);\n\tawait stage.putAux(\"plan\", canonicalJson(plan));\n\treturn planDigest(plan);\n}\n\nasync function buildAnalysisPlan(\n\tinput: AnalyzeImportStepInput,\n\tstage: TransferStage,\n\treader: StagedPackageReader,\n\tvalidation: ValidationStepResult,\n): Promise<{ plan: SiteImportPlan; context: AnalysisContextFile } | null> {\n\tconst { db, targetContext } = input;\n\tconst target = {\n\t\tsiteId: await getOrCreateSiteId(db),\n\t\tdialect: detectDialect(db),\n\t\temdashVersion: targetContext.emdashVersion,\n\t};\n\tconst manifest = await readManifestSafely(reader);\n\tif (!manifest) {\n\t\tconst identity = await looseManifestIdentity(stage);\n\t\tif (!identity) return null;\n\t\treturn {\n\t\t\tplan: buildBlockedPlan({\n\t\t\t\tpackageDigest: identity.digest,\n\t\t\t\torigin: {\n\t\t\t\t\tsiteId: identity.origin.originSiteId,\n\t\t\t\t\tpackageId: identity.origin.packageId,\n\t\t\t\t\tcreatedAt: identity.origin.createdAt,\n\t\t\t\t\tcreatedByEmDashVersion: identity.origin.createdByEmDashVersion,\n\t\t\t\t},\n\t\t\t\ttarget,\n\t\t\t\tblockers: validation.blockers,\n\t\t\t\twarnings: validation.warnings,\n\t\t\t}),\n\t\t\tcontext: { version: 1, principalBylineLocales: [], principalsWithSharedLocaleBylines: [] },\n\t\t};\n\t}\n\n\tconst summary = summarizeValidation(validation.state);\n\tconst domain = await inspectTargetDomain(db, summary.collectionSlugs);\n\tconst redirectLoops = await findRedirectLoops(\n\t\tmanifest,\n\t\tstage,\n\t\tnew TransferStagedFileRepository(db),\n\t\tinput.operationId,\n\t);\n\tconst context: AnalysisContextFile = {\n\t\tversion: 1,\n\t\tprincipalBylineLocales: Array.from(\n\t\t\tsummary.principalBylineLocales,\n\t\t\t([id, locales]): [string, string[]] => [id, [...locales].toSorted(compareIds)],\n\t\t).toSorted(([a], [b]) => compareIds(a, b)),\n\t\tprincipalsWithSharedLocaleBylines: [...summary.principalsWithSharedLocaleBylines].toSorted(\n\t\t\tcompareIds,\n\t\t),\n\t};\n\tconst plan = buildPlan(\n\t\t{\n\t\t\tpackageDigest: await reader.digest(),\n\t\t\tmanifest,\n\t\t\ttarget,\n\t\t\tsummary,\n\t\t\tvalidationBlockers: validation.blockers,\n\t\t\tvalidationWarnings: validation.warnings,\n\t\t\ttargetBlockers: [...domain.blockers, ...checkLocales(manifest, targetContext)],\n\t\t\tscaffold: domain.scaffold,\n\t\t\tredirectLoops,\n\t\t\tlocaleRecasing: localeRecasing(manifest, targetContext),\n\t\t\tsuggestions: await suggestPrincipalUsers(db, summary.principals),\n\t\t\ttargetSettings: await readTargetSettings(db),\n\t\t},\n\t\tprincipalBylinesFrom(context),\n\t);\n\treturn { plan, context };\n}\n\nasync function claimForAnalysis(\n\trepo: TransferOperationRepository,\n\tinput: AnalyzeImportStepInput,\n): Promise<{ operation: TransferOperation; leaseToken: string } | { planned: TransferOperation }> {\n\tif (input.leaseToken !== undefined) {\n\t\tconst operation = await repo.require(input.operationId);\n\t\tif (operation.leaseToken !== input.leaseToken) {\n\t\t\tthrow new TransferError(\"TRANSFER_LEASE_LOST\", \"Transfer operation lease was lost\");\n\t\t}\n\t\tif (operation.kind !== \"import\" || !isAnalyzable(operation.state)) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be analyzed in this state\");\n\t\t}\n\t\treturn { operation, leaseToken: input.leaseToken };\n\t}\n\tconst claim = await repo.claim(input.operationId, ANALYZABLE_STATES);\n\tswitch (claim.outcome) {\n\t\tcase \"claimed\":\n\t\t\tif (claim.operation.kind !== \"import\") {\n\t\t\t\tawait repo.release(claim.operation.id, claim.leaseToken);\n\t\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Only imports can be analyzed\");\n\t\t\t}\n\t\t\treturn { operation: claim.operation, leaseToken: claim.leaseToken };\n\t\tcase \"lease_active\":\n\t\t\tthrow new TransferError(\"TRANSFER_LEASE_ACTIVE\", \"Another step is running\");\n\t\tcase \"invalid_state\":\n\t\t\tif (claim.operation.kind === \"import\" && claim.operation.state === \"planned\") {\n\t\t\t\treturn { planned: claim.operation };\n\t\t\t}\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be analyzed in this state\");\n\t}\n}\n\nfunction isAnalyzable(state: string): boolean {\n\treturn (ANALYZABLE_STATES as readonly string[]).includes(state);\n}\n\n/**\n * Run one bounded analysis step. The final step stores the plan (default\n * decisions) in staging as `_plan.json` and moves the operation to\n * `planned`. Calling it on a planned operation returns the stored plan.\n */\nexport async function analyzeImportStep(\n\tinput: AnalyzeImportStepInput,\n): Promise<AnalyzeImportStepResult> {\n\tconst repo = new TransferOperationRepository(input.db);\n\tconst claimed = await claimForAnalysis(repo, input);\n\tif (\"planned\" in claimed) {\n\t\tconst plan = await loadImportPlan(input.storage, claimed.planned);\n\t\treturn {\n\t\t\toperation: claimed.planned,\n\t\t\tdone: true,\n\t\t\tplan,\n\t\t\tplanDigest: plan ? await planDigest(plan) : null,\n\t\t};\n\t}\n\tconst { operation, leaseToken } = claimed;\n\n\ttry {\n\t\tif (operation.cancelRequestedAt !== null) {\n\t\t\treturn {\n\t\t\t\toperation: await repo.finishCancelled(operation.id, leaseToken),\n\t\t\t\tdone: true,\n\t\t\t\tplan: null,\n\t\t\t\tplanDigest: null,\n\t\t\t};\n\t\t}\n\n\t\tconst stage = stageFor(input.storage, operation);\n\t\tconst reader = new StagedPackageReader(stage);\n\t\tconst validationState = await loadValidationState(stage, operation.cursor);\n\t\tconst validation = await runValidationStep(\n\t\t\t{\n\t\t\t\tdb: input.db,\n\t\t\t\treader,\n\t\t\t\toperationId: operation.id,\n\t\t\t\tstate: validationState,\n\t\t\t\tbudget: input.budget,\n\t\t\t},\n\t\t\t{\n\t\t\t\ttarget: {\n\t\t\t\t\tdialect: detectDialect(input.db),\n\t\t\t\t\tmaxBlobBytes: input.targetContext.maxUploadSize,\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\t\tconst manifest = await readManifestSafely(reader);\n\t\tconst cursor = cursorFor(validation.state);\n\n\t\tif (!validation.done || !input.budget.canStart()) {\n\t\t\tawait writeJson(input.storage, await stateKey(stage, cursor), validation.state);\n\t\t\tconst updated = await repo.release(operation.id, leaseToken, {\n\t\t\t\tstate: \"analyzing\",\n\t\t\t\tstage: cursor.stage,\n\t\t\t\tcursor,\n\t\t\t\tprogress: progressFor(validation.state, manifest),\n\t\t\t});\n\t\t\treturn { operation: updated, done: false, plan: null, planDigest: null };\n\t\t}\n\t\tinput.budget.start();\n\n\t\tconst built = await buildAnalysisPlan(input, stage, reader, validation);\n\t\tif (!built) {\n\t\t\tconst first = validation.blockers[0];\n\t\t\treturn {\n\t\t\t\toperation: await repo.fail(operation.id, leaseToken, {\n\t\t\t\t\tcode: \"TRANSFER_MANIFEST_INVALID\",\n\t\t\t\t\tdetail: first ? { blocker: first.code } : undefined,\n\t\t\t\t}),\n\t\t\t\tdone: true,\n\t\t\t\tplan: null,\n\t\t\t\tplanDigest: null,\n\t\t\t};\n\t\t}\n\t\tconst digest = await storePlan(stage, built.plan, built.context);\n\t\tconst progress = progressFor(validation.state, manifest);\n\t\tconst updated = await repo.releaseUnlessCancelled(operation.id, leaseToken, \"planned\", {\n\t\t\tstage: null,\n\t\t\tcursor: null,\n\t\t\tplanDigest: digest,\n\t\t\tprogress: { done: progress.total, total: progress.total },\n\t\t});\n\t\tif (updated.state === \"cancelled\") {\n\t\t\treturn { operation: updated, done: true, plan: null, planDigest: null };\n\t\t}\n\t\treturn { operation: updated, done: true, plan: built.plan, planDigest: digest };\n\t} catch (error) {\n\t\tif (!(isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\")) {\n\t\t\tawait repo.release(operation.id, leaseToken).catch(() => undefined);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** The stored plan of an analyzed import, or null when none has been stored. */\nexport async function loadImportPlan(\n\tstorage: Storage,\n\toperation: TransferOperation,\n): Promise<SiteImportPlan | null> {\n\tconst text = await stageFor(storage, operation).readAux(\"plan\", MAX_PLAN_BYTES);\n\tif (text === null) return null;\n\treturn siteImportPlanSchema.parse(JSON.parse(text));\n}\n\nexport interface FinalizePlanInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/** Decisions to apply over the plan's defaults (unvalidated caller input). */\n\tdecisions: unknown;\n}\n\n/**\n * Apply submitted decisions to a planned import: validate them, recompute the\n * decision-dependent blockers, warnings, and transformations, store the plan,\n * and record its digest on the operation. Unknown principal ids and mappings\n * to users that do not exist are rejected with `TRANSFER_DECISIONS_INVALID`.\n * Once execution is requested the plan is frozen: `TRANSFER_INVALID_STATE`.\n */\nexport async function finalizePlan(\n\tinput: FinalizePlanInput,\n): Promise<{ plan: SiteImportPlan; planDigest: Sha256Digest }> {\n\tconst parsed = siteImportDecisionsInputSchema.safeParse(input.decisions);\n\tif (!parsed.success) {\n\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"Decisions are malformed\");\n\t}\n\n\tconst repo = new TransferOperationRepository(input.db);\n\tconst claim = await repo.claim(input.operationId, [\"planned\"]);\n\tif (claim.outcome === \"lease_active\") {\n\t\tthrow new TransferError(\"TRANSFER_LEASE_ACTIVE\", \"Another step is running\");\n\t}\n\tif (claim.outcome === \"invalid_state\" || claim.operation.kind !== \"import\") {\n\t\tif (claim.outcome === \"claimed\") await repo.release(claim.operation.id, claim.leaseToken);\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has not been analyzed\");\n\t}\n\tif (claim.operation.stage === \"reserve\") {\n\t\tawait repo.release(claim.operation.id, claim.leaseToken);\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\"Import execution was requested; its plan can no longer change\",\n\t\t);\n\t}\n\tconst { operation, leaseToken } = claim;\n\n\ttry {\n\t\tconst stage = stageFor(input.storage, operation);\n\t\tconst stored = await loadImportPlan(input.storage, operation);\n\t\tconst contextRaw = await readJson(input.storage, contextKey(stage), MAX_STATE_BYTES);\n\t\tconst context = analysisContextSchema.safeParse(contextRaw);\n\t\tif (!stored || !context.success) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has no stored plan\");\n\t\t}\n\n\t\tconst known = new Set(stored.principals.map((principal) => principal.id));\n\t\tconst submitted = Object.entries(parsed.data.principalMappings ?? {});\n\t\tconst unknown = submitted.filter(([principalId]) => !known.has(principalId));\n\t\tif (unknown.length > 0) {\n\t\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"Decisions name unknown principals\", {\n\t\t\t\tdetail: { principals: unknown.length },\n\t\t\t});\n\t\t}\n\t\tconst missingUsers = await findMissingUsers(\n\t\t\tinput.db,\n\t\t\tsubmitted.flatMap(([, userId]) => (userId === null ? [] : [userId])),\n\t\t);\n\t\tif (missingUsers.length > 0) {\n\t\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"Decisions name unknown users\", {\n\t\t\t\tdetail: { users: missingUsers.length },\n\t\t\t});\n\t\t}\n\n\t\tconst decisions = mergeDecisions(defaultDecisions(stored.principals), parsed.data);\n\t\tconst plan = applyDecisions(stored, decisions, principalBylinesFrom(context.data));\n\t\tconst digest = await storePlan(stage, plan, context.data);\n\t\tawait repo.release(operation.id, leaseToken, { planDigest: digest });\n\t\treturn { plan, planDigest: digest };\n\t} catch (error) {\n\t\tif (!(isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\")) {\n\t\t\tawait repo.release(operation.id, leaseToken).catch(() => undefined);\n\t\t}\n\t\tthrow error;\n\t}\n}\n","/**\n * Audit log entries for transfer actions. Entries carry operation and\n * approval ids, digests, counts, and error codes, never package content.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport {\n\tAuditRepository,\n\ttype AuditAction,\n\ttype AuditStatus,\n} from \"../database/repositories/audit.js\";\nimport type { Database } from \"../database/types.js\";\n\nexport interface TransferAuditEntry {\n\tactorId: string;\n\taction: Extract<AuditAction, `transfer_${string}`>;\n\tresourceType: \"transfer_operation\" | \"transfer_approval\";\n\tresourceId: string;\n\tdetails?: Record<string, string | number | null>;\n\tstatus?: AuditStatus;\n}\n\n/**\n * Write an audit entry for a transfer action that has already taken effect.\n * A failed write is logged, not thrown, so it never reports a completed\n * action as failed.\n */\nexport async function recordTransferAudit(\n\tdb: Kysely<Database>,\n\tentry: TransferAuditEntry,\n): Promise<void> {\n\ttry {\n\t\tawait new AuditRepository(db).log({ status: \"success\", ...entry });\n\t} catch (error) {\n\t\tconsole.error(\"[transfer] Failed to write an audit log entry:\", error);\n\t}\n}\n","/**\n * Work budget for one `advance` step.\n *\n * Queries are counted by the request's `metrics.dbCount` (the Kysely log hook\n * bumps it), so the budget also covers queries the request ran before the\n * step. A unit of work may start only if its estimated query cost still fits\n * under the ceiling with `stepClosingQueries` to spare for the writes that end\n * the step, and only if its bytes fit the step's byte budget. The\n * byte check skips the first unit of a step, so one blob larger than the byte\n * budget gets a step of its own.\n */\n\nimport { getRequestContext } from \"../../request-context.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\n\nexport interface StepBudget {\n\tqueries: number;\n\tbytes: number;\n}\n\nexport interface StepBudgetOptions {\n\t/** Stop starting units once the request has run this many queries. */\n\tqueryCeiling?: number;\n\t/** Media bytes per step. */\n\tbytes?: number;\n\t/** Query counter; defaults to the current request's metrics. */\n\tmetrics?: { dbCount: number };\n}\n\nexport class TransferStepBudget {\n\treadonly #queryCeiling: number;\n\treadonly #byteLimit: number;\n\treadonly #metrics: { dbCount: number } | undefined;\n\t#bytesUsed = 0;\n\t#units = 0;\n\n\tget #unitCeiling(): number {\n\t\treturn this.#queryCeiling - TRANSFER_LIMITS.stepClosingQueries;\n\t}\n\n\tconstructor(options: StepBudgetOptions = {}) {\n\t\tthis.#queryCeiling = options.queryCeiling ?? TRANSFER_LIMITS.stepQueryCeiling;\n\t\tthis.#byteLimit = options.bytes ?? TRANSFER_LIMITS.stepBytes;\n\t\tthis.#metrics = options.metrics ?? getRequestContext()?.metrics;\n\t}\n\n\t/**\n\t * Whether a unit costing `cost` may start. Defaults to the standard unit\n\t * query cost and no bytes. Without request metrics only bytes are limited.\n\t */\n\tcanStart(cost: Partial<StepBudget> = {}): boolean {\n\t\tconst queries = cost.queries ?? TRANSFER_LIMITS.stepQueries;\n\t\tconst bytes = cost.bytes ?? 0;\n\t\tif (this.#metrics && this.#metrics.dbCount + queries > this.#unitCeiling) return false;\n\t\tif (this.#units === 0) return true;\n\t\treturn bytes === 0 || this.#bytesUsed + bytes <= this.#byteLimit;\n\t}\n\n\t/** Record that a unit started, with the bytes it will move. */\n\tstart(bytes = 0): void {\n\t\tthis.#units++;\n\t\tthis.#bytesUsed += bytes;\n\t}\n\n\tget units(): number {\n\t\treturn this.#units;\n\t}\n\n\tget bytesUsed(): number {\n\t\treturn this.#bytesUsed;\n\t}\n\n\t/** Remaining budget, for display and for sizing batch reads. */\n\tremaining(): StepBudget {\n\t\treturn {\n\t\t\tqueries: this.#metrics\n\t\t\t\t? Math.max(0, this.#unitCeiling - this.#metrics.dbCount)\n\t\t\t\t: Number.POSITIVE_INFINITY,\n\t\t\tbytes: Math.max(0, this.#byteLimit - this.#bytesUsed),\n\t\t};\n\t}\n}\n","/**\n * Export-side record of each exported media row's blob digest and size,\n * computed by hashing the origin object during the export's media stage.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { bytewise } from \"./collation.js\";\n\nexport interface MediaBlobEntry {\n\tmediaId: string;\n\tsha256: string;\n\tbytes: number;\n}\n\nexport class TransferMediaBlobRepository {\n\tconstructor(\n\t\tprivate readonly db: Kysely<Database>,\n\t\tprivate readonly operationId: string,\n\t) {}\n\n\t/** Record blobs; re-recording a media id (retried batch) overwrites it with the new hash. */\n\tasync putMany(entries: readonly MediaBlobEntry[]): Promise<void> {\n\t\tfor (const batch of chunks([...entries], rowsPerInsert(4))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_media_blobs\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((entry) => ({\n\t\t\t\t\t\toperation_id: this.operationId,\n\t\t\t\t\t\tmedia_id: entry.mediaId,\n\t\t\t\t\t\tsha256: entry.sha256,\n\t\t\t\t\t\tbytes: entry.bytes,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) =>\n\t\t\t\t\tconflict.columns([\"operation_id\", \"media_id\"]).doUpdateSet({\n\t\t\t\t\t\tsha256: (eb) => eb.ref(\"excluded.sha256\"),\n\t\t\t\t\t\tbytes: (eb) => eb.ref(\"excluded.bytes\"),\n\t\t\t\t\t}),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t}\n\t}\n\n\tasync getMany(mediaIds: readonly string[]): Promise<Map<string, MediaBlobEntry>> {\n\t\tconst result = new Map<string, MediaBlobEntry>();\n\t\tfor (const batch of chunks([...new Set(mediaIds)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t\t.select([\"media_id\", \"sha256\", \"bytes\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"media_id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) {\n\t\t\t\tresult.set(row.media_id, {\n\t\t\t\t\tmediaId: row.media_id,\n\t\t\t\t\tsha256: row.sha256,\n\t\t\t\t\tbytes: Number(row.bytes),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Blob entries in media-id order. */\n\tasync list(options: { after?: string; limit?: number } = {}): Promise<MediaBlobEntry[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select([\"media_id\", \"sha256\", \"bytes\"])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId);\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"media_id\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"media_id\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map((row) => ({\n\t\t\tmediaId: row.media_id,\n\t\t\tsha256: row.sha256,\n\t\t\tbytes: Number(row.bytes),\n\t\t}));\n\t}\n\n\t/** Distinct blobs (by digest) with their size, in digest order. */\n\tasync listDistinctBlobs(\n\t\toptions: { after?: string; limit?: number } = {},\n\t): Promise<Array<{ sha256: string; bytes: number }>> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select([\"sha256\", (eb) => eb.fn.max(\"bytes\").as(\"bytes\")])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.groupBy(\"sha256\");\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"sha256\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"sha256\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map((row) => ({ sha256: row.sha256, bytes: Number(row.bytes) }));\n\t}\n\n\tasync totals(): Promise<{ mediaRows: number; blobs: number; blobBytes: number }> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select((eb) => [\n\t\t\t\teb.fn.countAll<number | string>().as(\"media_rows\"),\n\t\t\t\teb.fn.count<number | string>(\"sha256\").distinct().as(\"blobs\"),\n\t\t\t])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.executeTakeFirstOrThrow();\n\t\tconst bytes = await this.db\n\t\t\t.selectFrom(\n\t\t\t\tthis.db\n\t\t\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t\t\t.select([\"sha256\", (eb) => eb.fn.max(\"bytes\").as(\"bytes\")])\n\t\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t\t.groupBy(\"sha256\")\n\t\t\t\t\t.as(\"blob\"),\n\t\t\t)\n\t\t\t.select((eb) => eb.fn.sum<number | string | null>(\"blob.bytes\").as(\"total\"))\n\t\t\t.executeTakeFirstOrThrow();\n\t\treturn {\n\t\t\tmediaRows: Number(row.media_rows),\n\t\t\tblobs: Number(row.blobs),\n\t\t\tblobBytes: Number(bytes.total ?? 0),\n\t\t};\n\t}\n}\n","/**\n * Optimistic-read fence for an export: per portable table, the row count,\n * the latest `updated_at` (or `created_at`), and the largest id. A write that\n * changes none of these (an in-place edit of a table without `updated_at`) is\n * caught by the operation's `write_epoch`, which fenced writes bump.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { validateIdentifier } from \"../../database/validate.js\";\nimport { CONTENT_TABLE_PREFIX, PORTABLE_TABLES } from \"../format/columns.js\";\nimport type { ExportFence } from \"../ops/states.js\";\n\ntype Db = Kysely<Database>;\n\ninterface FencedTable {\n\ttable: string;\n\tchanged: string | null;\n\tid: string | null;\n}\n\nasync function fencedTables(db: Db): Promise<FencedTable[]> {\n\tconst tables: FencedTable[] = PORTABLE_TABLES.map((spec) => ({\n\t\ttable: spec.table,\n\t\tchanged: Object.hasOwn(spec.columns, \"updated_at\")\n\t\t\t? \"updated_at\"\n\t\t\t: Object.hasOwn(spec.columns, \"created_at\")\n\t\t\t\t? \"created_at\"\n\t\t\t\t: null,\n\t\tid: Object.hasOwn(spec.columns, \"id\") ? \"id\" : null,\n\t}));\n\ttables.push({ table: \"users\", changed: \"updated_at\", id: \"id\" });\n\tconst collections = await db\n\t\t.selectFrom(\"_emdash_collections\")\n\t\t.select(\"slug\")\n\t\t.orderBy(\"slug\")\n\t\t.execute();\n\tfor (const { slug } of collections) {\n\t\tvalidateIdentifier(slug, \"collection slug\");\n\t\ttables.push({ table: `${CONTENT_TABLE_PREFIX}${slug}`, changed: \"updated_at\", id: \"id\" });\n\t}\n\treturn tables.toSorted((a, b) => (a.table < b.table ? -1 : a.table > b.table ? 1 : 0));\n}\n\nfunction optionalText(value: unknown): string | undefined {\n\tif (typeof value === \"string\") return value;\n\tif (typeof value === \"number\" || typeof value === \"bigint\") return String(value);\n\tif (value instanceof Date) return value.toISOString();\n\treturn undefined;\n}\n\nexport async function captureFence(db: Db, writeEpoch: number): Promise<ExportFence> {\n\tconst result: ExportFence = { writeEpoch, tables: [] };\n\tfor (const table of await fencedTables(db)) {\n\t\tconst changed = table.changed ? sql`MAX(${sql.ref(table.changed)})` : sql`NULL`;\n\t\tconst id = table.id ? sql`MAX(${sql.ref(table.id)})` : sql`NULL`;\n\t\tconst row = await sql<{ n: unknown; changed: unknown; id: unknown }>`\n\t\t\tSELECT COUNT(*) AS n, ${changed} AS changed, ${id} AS id FROM ${sql.ref(table.table)}\n\t\t`.execute(db);\n\t\tconst values = row.rows[0];\n\t\tresult.tables.push({\n\t\t\ttable: table.table,\n\t\t\tcount: Number(values?.n ?? 0),\n\t\t\tmaxChanged: optionalText(values?.changed),\n\t\t\tmaxId: optionalText(values?.id),\n\t\t});\n\t}\n\treturn result;\n}\n\nexport function fencesEqual(a: ExportFence, b: ExportFence): boolean {\n\tif (a.writeEpoch !== b.writeEpoch || a.tables.length !== b.tables.length) return false;\n\treturn a.tables.every((table, index) => {\n\t\tconst other = b.tables[index];\n\t\treturn (\n\t\t\tother !== undefined &&\n\t\t\tother.table === table.table &&\n\t\t\tother.count === table.count &&\n\t\t\tother.maxChanged === table.maxChanged &&\n\t\t\tother.maxId === table.maxId\n\t\t);\n\t});\n}\n","/**\n * Media for an export: which rows are exported, their blob digests, and the\n * storage-key index the reference walker needs.\n *\n * A media row is exported when it is `ready`, or when a byline avatar or a\n * section preview references it and its object exists. Its object is hashed\n * once from the origin key; the bytes are never copied into staging.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { createSha256 } from \"../format/digest.js\";\nimport {\n\tbuildMediaKeyIndex,\n\tMEDIA_PLACEHOLDER_PREFIX,\n\ttype MediaKeyIndex,\n} from \"../format/media-refs.js\";\nimport { bytewise } from \"../ops/collation.js\";\n\ntype Db = Kysely<Database>;\n\nconst KEY_INDEX_PAGE = 1000;\n\nexport interface MediaCandidate {\n\tid: string;\n\tstorageKey: string;\n\tstatus: string;\n\tsize: number | null;\n}\n\n/** Media rows eligible for export after `after`, in id order. */\nexport async function listMediaCandidates(\n\tdb: Db,\n\tafter: string | null,\n\tlimit: number,\n): Promise<MediaCandidate[]> {\n\tlet query = db\n\t\t.selectFrom(\"media\")\n\t\t.select([\"id\", \"storage_key\", \"status\", \"size\"])\n\t\t.where((eb) =>\n\t\t\teb.or([\n\t\t\t\teb(\"status\", \"=\", \"ready\"),\n\t\t\t\teb(\n\t\t\t\t\t\"id\",\n\t\t\t\t\t\"in\",\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_bylines\")\n\t\t\t\t\t\t.select(\"avatar_media_id\")\n\t\t\t\t\t\t.where(\"avatar_media_id\", \"is not\", null)\n\t\t\t\t\t\t.$castTo<string>(),\n\t\t\t\t),\n\t\t\t\teb(\n\t\t\t\t\t\"id\",\n\t\t\t\t\t\"in\",\n\t\t\t\t\teb\n\t\t\t\t\t\t.selectFrom(\"_emdash_sections\")\n\t\t\t\t\t\t.select(\"preview_media_id\")\n\t\t\t\t\t\t.where(\"preview_media_id\", \"is not\", null)\n\t\t\t\t\t\t.$castTo<string>(),\n\t\t\t\t),\n\t\t\t]),\n\t\t);\n\tif (after !== null) query = query.where(sql<boolean>`${bytewise(db, \"id\")} > ${after}`);\n\tconst rows = await query.orderBy(bytewise(db, \"id\")).limit(limit).execute();\n\treturn rows.map((row) => ({\n\t\tid: row.id,\n\t\tstorageKey: row.storage_key,\n\t\tstatus: row.status,\n\t\tsize: row.size === null ? null : Number(row.size),\n\t}));\n}\n\n/**\n * SHA-256 and size of a stored object, counted from the bytes actually\n * streamed. Returns null when the object does not exist, and `\"too_large\"`\n * (after cancelling the download) as soon as more than `maxBytes` arrive.\n */\nexport async function hashStoredObject(\n\tstorage: Storage,\n\tkey: string,\n\toptions: { maxBytes?: number } = {},\n): Promise<{ sha256: string; bytes: number } | null | \"too_large\"> {\n\tif (!(await storage.exists(key))) return null;\n\tconst download = await storage.download(key);\n\tconst hasher = await createSha256();\n\tconst reader = download.body.getReader();\n\tlet bytes = 0;\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbytes += value.byteLength;\n\t\t\tif (options.maxBytes !== undefined && bytes > options.maxBytes) {\n\t\t\t\tawait reader.cancel().catch(() => undefined);\n\t\t\t\treturn \"too_large\";\n\t\t\t}\n\t\t\thasher.update(value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\treturn { sha256: await hasher.digest(), bytes };\n}\n\n/** Every media row's id and storage key, in id order. */\nexport async function loadMediaKeyRows(db: Db): Promise<Array<{ id: string; storageKey: string }>> {\n\tconst rows: Array<{ id: string; storageKey: string }> = [];\n\tlet after: string | null = null;\n\tfor (;;) {\n\t\tlet query = db.selectFrom(\"media\").select([\"id\", \"storage_key\"]);\n\t\tif (after !== null) query = query.where(sql<boolean>`${bytewise(db, \"id\")} > ${after}`);\n\t\tconst page = await query.orderBy(bytewise(db, \"id\")).limit(KEY_INDEX_PAGE).execute();\n\t\tfor (const row of page) rows.push({ id: row.id, storageKey: row.storage_key });\n\t\tconst last = page.at(-1);\n\t\tif (page.length < KEY_INDEX_PAGE || !last) break;\n\t\tafter = last.id;\n\t}\n\treturn rows;\n}\n\n/** Every media row's storage key, for the reference walker and the key scan. */\nexport async function loadMediaKeyIndex(db: Db): Promise<MediaKeyIndex> {\n\treturn buildMediaKeyIndex(await loadMediaKeyRows(db));\n}\n\nconst PLACEHOLDER = new RegExp(`${MEDIA_PLACEHOLDER_PREFIX}([0-9A-Za-z_-]{1,128})`, \"g\");\n\nfunction unlinkValue(\n\tvalue: unknown,\n\tdrop: ReadonlySet<string>,\n\tcounter: { count: number },\n): unknown {\n\tif (typeof value === \"string\") {\n\t\tif (!value.includes(MEDIA_PLACEHOLDER_PREFIX)) return value;\n\t\treturn value.replace(PLACEHOLDER, (match, mediaId: string) => {\n\t\t\tif (!drop.has(mediaId)) return match;\n\t\t\tcounter.count++;\n\t\t\treturn \"\";\n\t\t});\n\t}\n\tif (Array.isArray(value)) return value.map((item) => unlinkValue(item, drop, counter));\n\tif (typeof value === \"object\" && value !== null) {\n\t\treturn Object.fromEntries(\n\t\t\tObject.entries(value).map(([key, item]) => [key, unlinkValue(item, drop, counter)]),\n\t\t);\n\t}\n\treturn value;\n}\n\n/**\n * Remove placeholders naming media that is not in the package, leaving the\n * rest of each string. Returns the record unchanged when there are none.\n */\nexport function unlinkMediaPlaceholders<T extends { kind: string; id: string }>(\n\trecord: T,\n\tdrop: ReadonlySet<string>,\n): { record: T; count: number } {\n\tif (drop.size === 0) return { record, count: 0 };\n\tconst counter = { count: 0 };\n\tconst next = unlinkValue(record, drop, counter);\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- same record with some placeholder substrings removed\n\treturn counter.count === 0 ? { record, count: 0 } : { record: next as T, count: counter.count };\n}\n","/**\n * Per-kind readers: turn portable rows into strict package records.\n *\n * A reader pages through its kind in package stream order (`id` order, or\n * `(depth, id)` for the tree kinds) and can also fetch rows by id. The\n * exporter uses the paging side against the origin; import verification\n * uses the same readers against the target, so any database works.\n *\n * When paging, rows a package must not contain are left out: rows whose\n * reference (hard or soft) names a row that does not exist, tree rows below\n * such a row, and (for an export) media rows that were not hashed. Optional\n * references to missing rows are removed from the record instead and\n * reported as adjustments. A real database can hold any of these orphans,\n * because not every reference has a foreign key on every dialect and\n * installation. The number of rows a reader leaves out of a kind is\n * `countRows() - exported`. `byIds` never filters.\n */\n\nimport { sql, type Kysely, type RawBuilder } from \"kysely\";\n\nimport { isPostgres, listTableColumns } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { validateIdentifier } from \"../../database/validate.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport { decodeContentRow, decodeRow, selectExportedColumns } from \"../format/column-codec.js\";\nimport {\n\tassertColumnCoverage,\n\tassertLoadedColumnCoverage,\n\tCONTENT_TABLE_PREFIX,\n\tcontentColumnSpecs,\n\tgetPortableTableSpecForKind,\n\ttype ColumnSpec,\n} from \"../format/columns.js\";\nimport {\n\tcompareStreamOrder,\n\tsyntheticId,\n\tisRecordOfKind,\n\tvalidateRecord,\n\ttype RecordKind,\n\ttype SitePackageRecord,\n\ttype RecordOfKind,\n\ttype StreamOrderKey,\n} from \"../format/kinds.js\";\nimport { PORTABLE_SETTING_NAMES } from \"../format/settings.js\";\nimport type { ExportTransformationCode } from \"../format/transformations.js\";\n\ntype Db = Kysely<Database>;\ntype Row = Record<string, unknown>;\n\nexport interface ReadRow<K extends RecordKind> {\n\tkey: StreamOrderKey;\n\t/** `null` when the row is left out of the package. */\n\trecord: RecordOfKind<K> | null;\n\t/** In-record changes made while reading (e.g. a nulled avatar reference). */\n\tadjustments: ReadAdjustment[];\n}\n\nexport interface ReadAdjustment {\n\tcode: ExportTransformationCode;\n\tcount: number;\n}\n\nexport interface ReadPage<K extends RecordKind> {\n\trows: Array<ReadRow<K>>;\n\t/** No rows follow the last row of this page. */\n\tdone: boolean;\n}\n\nexport interface KindReader<K extends RecordKind> {\n\treadonly kind: K;\n\t/** Up to `limit` rows after `after` in stream order. */\n\tpage(after: StreamOrderKey | null, limit: number): Promise<ReadPage<K>>;\n\t/**\n\t * Records by id, without export-only filtering. Missing ids are absent.\n\t * `collections` maps entry ids to the collection each is looked up in;\n\t * an entry id it does not name is looked up in every collection.\n\t */\n\tbyIds(\n\t\tids: readonly string[],\n\t\tcollections?: ReadonlyMap<string, string>,\n\t): Promise<Map<string, RecordOfKind<K>>>;\n\t/** Rows stored for this kind, or null when the kind has no table of its own. */\n\tcountRows(): Promise<number | null>;\n}\n\nexport interface ReaderOptions {\n\t/**\n\t * Export operation whose hashed media (`_emdash_transfer_media_blobs`)\n\t * defines the exported media set. Without it every media row is read and\n\t * no reference is nulled.\n\t */\n\texportOperationId?: string;\n\t/** Blob digest per media id; media records carry it as `blob`. */\n\tmediaBlobs: (mediaIds: readonly string[]) => Promise<ReadonlyMap<string, string>>;\n\t/** Whether comments exist for the principal reader. Defaults to true. */\n\tcomments?: boolean;\n}\n\n// ── SQL helpers ─────────────────────────────────────────────────\n\nfunction bytewiseExpr(db: Db, expr: RawBuilder<unknown>): RawBuilder<string> {\n\treturn isPostgres(db) ? sql<string>`(${expr}) COLLATE \"C\"` : sql<string>`${expr}`;\n}\n\nfunction count(value: unknown): number {\n\treturn Number(value ?? 0);\n}\n\nfunction invalidRecord(kind: RecordKind, id: string, field: string, reason: string): TransferError {\n\treturn new TransferError(\"TRANSFER_EXPORT_ERROR\", \"Stored row does not form a valid record\", {\n\t\tdetail: { kind, id, field, reason },\n\t});\n}\n\nfunction toRecord<K extends RecordKind>(kind: K, raw: Row): RecordOfKind<K> {\n\tconst result = validateRecord(kind, raw);\n\tif (!result.success) {\n\t\tconst issue = result.issues[0];\n\t\tthrow invalidRecord(\n\t\t\tkind,\n\t\t\ttypeof raw.id === \"string\" ? raw.id : \"\",\n\t\t\tissue?.path ?? \"\",\n\t\t\tissue?.message ?? \"invalid\",\n\t\t);\n\t}\n\treturn result.record;\n}\n\nfunction stringOf(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\n/** Rows of `table` whose group (`translation_group`, else `id`) is one of `groups`. */\nasync function existingGroups(\n\tdb: Db,\n\ttable: string,\n\tgroups: readonly string[],\n): Promise<Set<string>> {\n\tconst found = new Set<string>();\n\t// Each value is bound twice.\n\tfor (const batch of chunks([...new Set(groups)], Math.floor(SQL_BATCH_SIZE / 2))) {\n\t\tconst result = await sql<{ id: string; translation_group: string | null }>`\n\t\t\tSELECT id, translation_group FROM ${sql.ref(table)}\n\t\t\tWHERE translation_group IN (${sql.join(batch)})\n\t\t\t\tOR (translation_group IS NULL AND id IN (${sql.join(batch)}))\n\t\t`.execute(db);\n\t\tfor (const row of result.rows) found.add(row.translation_group ?? row.id);\n\t}\n\treturn found;\n}\n\nasync function collectionSlugs(db: Db): Promise<string[]> {\n\tconst rows = await db.selectFrom(\"_emdash_collections\").select(\"slug\").execute();\n\treturn rows.map((row) => row.slug).toSorted();\n}\n\nfunction contentTable(slug: string): string {\n\tvalidateIdentifier(slug, \"collection slug\");\n\treturn `${CONTENT_TABLE_PREFIX}${slug}`;\n}\n\n/**\n * A collection slug as an SQL literal. Filters compare against every\n * collection slug; as bound parameters they exceed D1's 100-parameter limit\n * on sites with many collections.\n */\nfunction slugLiteral(slug: string): RawBuilder<unknown> {\n\tvalidateIdentifier(slug, \"collection slug\");\n\treturn sql.lit(slug);\n}\n\ninterface FilterContext {\n\tdb: Db;\n\toptions: ReaderOptions;\n\t/** Every collection slug, sorted. */\n\tslugs: readonly string[];\n}\n\nconst NEVER = sql<boolean>`1 = 0`;\n\nfunction anyOf(parts: ReadonlyArray<RawBuilder<boolean>>): RawBuilder<boolean> {\n\treturn parts.length === 0 ? NEVER : sql<boolean>`(${sql.join(parts, sql` OR `)})`;\n}\n\n/** An entry with id `id` exists in the content table of collection `collection`. */\nfunction entryExists(\n\tcontext: FilterContext,\n\tcollection: RawBuilder<unknown>,\n\tid: RawBuilder<unknown>,\n): RawBuilder<boolean> {\n\treturn anyOf(\n\t\tcontext.slugs.map(\n\t\t\t(slug) => sql<boolean>`(${collection} = ${slugLiteral(slug)} AND EXISTS (\n\t\t\t\tSELECT 1 FROM ${sql.ref(contentTable(slug))} AS __entry WHERE __entry.id = ${id}\n\t\t\t))`,\n\t\t),\n\t);\n}\n\n/** A row of `table` has translation group (or, without one, id) `group`. */\nfunction groupExists(table: string, group: RawBuilder<unknown>): RawBuilder<boolean> {\n\treturn sql<boolean>`EXISTS (\n\t\tSELECT 1 FROM ${sql.ref(table)} AS __grouped\n\t\tWHERE __grouped.translation_group = ${group}\n\t\t\tOR (__grouped.translation_group IS NULL AND __grouped.id = ${group})\n\t)`;\n}\n\n/** An entry of collection `collection` has translation group `group`. */\nfunction entryGroupExists(\n\tcontext: FilterContext,\n\tcollection: RawBuilder<unknown>,\n\tgroup: RawBuilder<unknown>,\n): RawBuilder<boolean> {\n\treturn anyOf(\n\t\tcontext.slugs.map(\n\t\t\t(slug) =>\n\t\t\t\tsql<boolean>`(${collection} = ${slugLiteral(slug)} AND ${groupExists(contentTable(slug), group)})`,\n\t\t),\n\t);\n}\n\nfunction col(table: string, column: string): RawBuilder<unknown> {\n\treturn sql`${sql.ref(`${table}.${column}`)}`;\n}\n\n/**\n * Ids of `table` reachable from a root (`parentColumn IS NULL`) through rows\n * that each satisfy `valid`: the tree rows an export keeps.\n */\nfunction treeIds(\n\ttable: string,\n\tparentColumn: string,\n\tvalid: RawBuilder<boolean>,\n): RawBuilder<unknown> {\n\treturn sql`(\n\t\tWITH RECURSIVE __kept(__node) AS (\n\t\t\tSELECT ${col(table, \"id\")} FROM ${sql.ref(table)}\n\t\t\tWHERE ${col(table, parentColumn)} IS NULL AND ${valid}\n\t\t\tUNION ALL\n\t\t\tSELECT ${col(table, \"id\")} FROM ${sql.ref(table)}\n\t\t\tINNER JOIN __kept ON ${col(table, parentColumn)} = __kept.__node\n\t\t\tWHERE ${valid}\n\t\t)\n\t\tSELECT __node FROM __kept\n\t)`;\n}\n\nfunction commentValid(context: FilterContext): RawBuilder<boolean> {\n\treturn entryExists(\n\t\tcontext,\n\t\tcol(\"_emdash_comments\", \"collection\"),\n\t\tcol(\"_emdash_comments\", \"content_id\"),\n\t);\n}\n\nfunction revisionValid(context: FilterContext): RawBuilder<boolean> {\n\treturn entryExists(context, col(\"revisions\", \"collection\"), col(\"revisions\", \"entry_id\"));\n}\n\n/** Media ids among `ids` that the export operation hashed. */\nasync function exportedMediaIds(\n\tdb: Db,\n\toperationId: string,\n\tids: readonly string[],\n): Promise<Set<string>> {\n\tconst found = new Set<string>();\n\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\tconst rows = await db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.select(\"media_id\")\n\t\t\t.where(\"operation_id\", \"=\", operationId)\n\t\t\t.where(\"media_id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of rows) found.add(row.media_id);\n\t}\n\treturn found;\n}\n\n// ── Table readers ───────────────────────────────────────────────\n\ninterface TransformContext {\n\tdb: Db;\n\toptions: ReaderOptions;\n\t/** True when reading pages for an export (not `byIds`). */\n\tpaging: boolean;\n}\n\ninterface TransformResult<K extends RecordKind = RecordKind> {\n\trecords: Array<RecordOfKind<K> | null>;\n\t/** Per record, parallel to `records`; absent when nothing was adjusted. */\n\tadjustments?: Array<ReadAdjustment[]>;\n}\n\ntype Transform = (\n\trecords: SitePackageRecord[],\n\tcontext: TransformContext,\n) => Promise<TransformResult>;\n\n/** Adapt a transform written for one kind to the reader's record list. */\nfunction forKind<K extends RecordKind>(\n\tkind: K,\n\ttransform: (\n\t\trecords: Array<RecordOfKind<K>>,\n\t\tcontext: TransformContext,\n\t) => Promise<TransformResult<K>>,\n): Transform {\n\treturn (records, context) => {\n\t\tconst typed = records.filter((record): record is RecordOfKind<K> =>\n\t\t\tisRecordOfKind(record, kind),\n\t\t);\n\t\tif (typed.length !== records.length) throw new Error(`Expected only ${kind} records`);\n\t\treturn transform(typed, context);\n\t};\n}\n\ninterface TableReaderConfig {\n\tkind: RecordKind;\n\ttable: string;\n\t/** Key expression; defaults to the `id` column. */\n\tkey?: (db: Db) => RawBuilder<unknown>;\n\t/** Rows kept when paging. */\n\tfilter?: (context: FilterContext) => RawBuilder<boolean> | null;\n\t/** Rows `countRows` counts (defaults to every row). */\n\tcountFilter?: () => RawBuilder<boolean>;\n\t/** Tree kinds: parent column; pages are ordered by `(depth, id)`. */\n\tparentColumn?: string;\n\t/** Tree kinds: rows kept when paging; a row below a dropped row is dropped too. */\n\ttreeValid?: (context: FilterContext) => RawBuilder<boolean>;\n\t/** Adds properties that do not come from columns, before validation. */\n\tprepare?: (raws: Row[], options: ReaderOptions) => Promise<void>;\n\t/** Post-processing of decoded records (may drop rows or change properties). */\n\ttransform?: Transform;\n}\n\nclass TableReader implements KindReader<RecordKind> {\n\treadonly kind: RecordKind;\n\treadonly #db: Db;\n\treadonly #config: TableReaderConfig;\n\treadonly #options: ReaderOptions;\n\treadonly #columns: Readonly<Record<string, ColumnSpec>>;\n\t#covered = false;\n\t#slugs: readonly string[] = [];\n\n\tconstructor(db: Db, config: TableReaderConfig, options: ReaderOptions) {\n\t\tconst spec = getPortableTableSpecForKind(config.kind);\n\t\tif (!spec) throw new Error(`No table for kind ${config.kind}`);\n\t\tthis.kind = config.kind;\n\t\tthis.#db = db;\n\t\tthis.#config = config;\n\t\tthis.#options = options;\n\t\tthis.#columns = spec.columns;\n\t}\n\n\tprivate async ensureCoverage(): Promise<void> {\n\t\tif (this.#covered) return;\n\t\tawait assertColumnCoverage(this.#db, this.#config.table);\n\t\tthis.#slugs = await collectionSlugs(this.#db);\n\t\tthis.#covered = true;\n\t}\n\n\tprivate keyExpr(): RawBuilder<unknown> {\n\t\treturn this.#config.key?.(this.#db) ?? sql`${sql.ref(`${this.#config.table}.id`)}`;\n\t}\n\n\tprivate selectList(): RawBuilder<unknown> {\n\t\treturn sql.join(selectExportedColumns(this.#db, this.#columns));\n\t}\n\n\tprivate decodeRaw(row: Row): Row {\n\t\tconst properties = decodeRow(this.#db, this.#columns, row);\n\t\tconst raw: Row = { kind: this.kind, ...properties };\n\t\tif (\n\t\t\tthis.kind === \"content_term\" ||\n\t\t\tthis.kind === \"seo\" ||\n\t\t\tthis.kind === \"byline_field_value\" ||\n\t\t\tthis.kind === \"byline_field_group_value\"\n\t\t) {\n\t\t\traw.id = syntheticId(toSyntheticParts(this.kind, raw));\n\t\t}\n\t\treturn raw;\n\t}\n\n\tprivate async decode(rows: Row[]): Promise<Array<SitePackageRecord>> {\n\t\tconst raws = rows.map((row) => this.decodeRaw(row));\n\t\tawait this.#config.prepare?.(raws, this.#options);\n\t\treturn raws.map((raw) => toRecord(this.kind, raw));\n\t}\n\n\tprivate async finish(\n\t\trecords: Array<SitePackageRecord>,\n\t\tpaging: boolean,\n\t): Promise<TransformResult> {\n\t\tif (!this.#config.transform) return { records };\n\t\treturn this.#config.transform(records, { db: this.#db, options: this.#options, paging });\n\t}\n\n\tasync page(after: StreamOrderKey | null, limit: number): Promise<ReadPage<RecordKind>> {\n\t\tawait this.ensureCoverage();\n\t\tconst db = this.#db;\n\t\tconst table = sql.ref(this.#config.table);\n\t\tconst context: FilterContext = { db, options: this.#options, slugs: this.#slugs };\n\t\tconst filter = this.#config.filter?.(context) ?? null;\n\t\tconst conditions: Array<RawBuilder<unknown>> = [];\n\t\tif (filter) conditions.push(filter);\n\n\t\tlet result: { rows: Row[] };\n\t\tif (this.#config.parentColumn) {\n\t\t\tconst parent = sql.ref(`${this.#config.table}.${this.#config.parentColumn}`);\n\t\t\tconst idRef = sql.ref(`${this.#config.table}.id`);\n\t\t\tconst valid = this.#config.treeValid?.(context) ?? sql<boolean>`1 = 1`;\n\t\t\tif (after) {\n\t\t\t\tconst depth = after.depth ?? 0;\n\t\t\t\tconditions.push(\n\t\t\t\t\tsql`(__tree.__level > ${depth} OR (__tree.__level = ${depth} AND ${bytewiseExpr(db, idRef)} > ${after.id}))`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst where = conditions.length > 0 ? sql`WHERE ${sql.join(conditions, sql` AND `)}` : sql``;\n\t\t\tresult = await sql<Row>`\n\t\t\t\tWITH RECURSIVE __tree(__node, __level) AS (\n\t\t\t\t\tSELECT ${idRef}, 0 FROM ${table} WHERE ${parent} IS NULL AND ${valid}\n\t\t\t\t\tUNION ALL\n\t\t\t\t\tSELECT ${idRef}, __tree.__level + 1 FROM ${table}\n\t\t\t\t\tINNER JOIN __tree ON ${parent} = __tree.__node\n\t\t\t\t\tWHERE ${valid}\n\t\t\t\t)\n\t\t\t\tSELECT ${this.selectList()}, __tree.__level AS __depth\n\t\t\t\tFROM ${table} INNER JOIN __tree ON __tree.__node = ${idRef}\n\t\t\t\t${where}\n\t\t\t\tORDER BY __tree.__level, ${bytewiseExpr(db, idRef)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t} else {\n\t\t\tconst key = this.keyExpr();\n\t\t\tif (after) conditions.push(sql`${bytewiseExpr(db, key)} > ${after.id}`);\n\t\t\tconst where = conditions.length > 0 ? sql`WHERE ${sql.join(conditions, sql` AND `)}` : sql``;\n\t\t\tresult = await sql<Row>`\n\t\t\t\tSELECT ${this.selectList()}\n\t\t\t\tFROM ${table}\n\t\t\t\t${where}\n\t\t\t\tORDER BY ${bytewiseExpr(db, key)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t}\n\n\t\tconst done = result.rows.length <= limit;\n\t\tconst rows = result.rows.slice(0, limit);\n\t\tconst records = await this.decode(rows);\n\t\tconst keys = rows.map((row, index) => {\n\t\t\tconst id = records[index]?.id ?? \"\";\n\t\t\treturn this.#config.parentColumn ? { id, depth: count(row.__depth) } : { id };\n\t\t});\n\t\tconst transformed = await this.finish(records, true);\n\t\treturn {\n\t\t\trows: keys.map((key, index) => ({\n\t\t\t\tkey,\n\t\t\t\trecord: transformed.records[index] ?? null,\n\t\t\t\tadjustments: transformed.adjustments?.[index] ?? [],\n\t\t\t})),\n\t\t\tdone,\n\t\t};\n\t}\n\n\tasync byIds(ids: readonly string[]): Promise<Map<string, SitePackageRecord>> {\n\t\tawait this.ensureCoverage();\n\t\tconst db = this.#db;\n\t\tconst result = new Map<string, SitePackageRecord>();\n\t\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await sql<Row>`\n\t\t\t\tSELECT ${this.selectList()}\n\t\t\t\tFROM ${sql.ref(this.#config.table)}\n\t\t\t\tWHERE ${this.keyExpr()} IN (${sql.join(batch)})\n\t\t\t`.execute(db);\n\t\t\tconst records = await this.decode(rows.rows);\n\t\t\tconst transformed = await this.finish(records, false);\n\t\t\tfor (const record of transformed.records) {\n\t\t\t\tif (record) result.set(record.id, record);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync countRows(): Promise<number> {\n\t\tconst filter = this.#config.countFilter?.() ?? null;\n\t\tconst where = filter ? sql`WHERE ${filter}` : sql``;\n\t\tconst result = await sql<{ n: unknown }>`\n\t\t\tSELECT COUNT(*) AS n FROM ${sql.ref(this.#config.table)} ${where}\n\t\t`.execute(this.#db);\n\t\treturn count(result.rows[0]?.n);\n\t}\n}\n\nfunction toSyntheticParts(kind: RecordKind, raw: Row): Parameters<typeof syntheticId>[0] {\n\tconst part = (name: string) => stringOf(raw[name]) ?? \"\";\n\tswitch (kind) {\n\t\tcase \"content_term\":\n\t\t\treturn {\n\t\t\t\tkind,\n\t\t\t\tcollection: part(\"collection\"),\n\t\t\t\tentryGroup: part(\"entryGroup\"),\n\t\t\t\ttermGroup: part(\"termGroup\"),\n\t\t\t};\n\t\tcase \"seo\":\n\t\t\treturn { kind, collection: part(\"collection\"), entryId: part(\"entryId\") };\n\t\tcase \"byline_field_value\":\n\t\t\treturn { kind, bylineId: part(\"bylineId\"), fieldId: part(\"fieldId\") };\n\t\tdefault:\n\t\t\treturn {\n\t\t\t\tkind: \"byline_field_group_value\",\n\t\t\t\tbylineGroup: part(\"bylineGroup\"),\n\t\t\t\tfieldId: part(\"fieldId\"),\n\t\t\t};\n\t}\n}\n\nfunction concatKey(...parts: string[]): (db: Db) => RawBuilder<unknown> {\n\treturn () =>\n\t\tsql.join(\n\t\t\tparts.flatMap((part, index) =>\n\t\t\t\tindex === 0 ? [sql.ref(part)] : [sql.lit(\":\"), sql.ref(part)],\n\t\t\t),\n\t\t\tsql` || `,\n\t\t);\n}\n\n// ── Transforms ──────────────────────────────────────────────────\n\nasync function nullUnexportedMedia<K extends \"byline\" | \"section\">(\n\trecords: Array<RecordOfKind<K>>,\n\tcontext: TransformContext,\n\tproperty: \"avatarMediaId\" | \"previewMediaId\",\n): Promise<TransformResult<K>> {\n\tconst operationId = context.options.exportOperationId;\n\tif (!operationId || !context.paging) return { records };\n\tconst ids = records.flatMap((record) => {\n\t\tconst value: unknown = Reflect.get(record, property);\n\t\treturn typeof value === \"string\" ? [value] : [];\n\t});\n\tif (ids.length === 0) return { records };\n\tconst exported = await exportedMediaIds(context.db, operationId, ids);\n\tconst adjustments: Array<ReadAdjustment[]> = [];\n\tconst next = records.map((record) => {\n\t\tconst value: unknown = Reflect.get(record, property);\n\t\tif (typeof value !== \"string\" || exported.has(value)) {\n\t\t\tadjustments.push([]);\n\t\t\treturn record;\n\t\t}\n\t\tadjustments.push([{ code: \"avatar_nulled\", count: 1 }]);\n\t\tconst copy = { ...record };\n\t\tReflect.deleteProperty(copy, property);\n\t\treturn copy;\n\t});\n\treturn { records: next, adjustments };\n}\n\nasync function nullMissingFolders(\n\trecords: Array<RecordOfKind<\"media\">>,\n\tcontext: TransformContext,\n): Promise<TransformResult<\"media\">> {\n\tif (!context.paging) return { records };\n\tconst ids = [...new Set(records.flatMap((r) => (r.folderId === undefined ? [] : [r.folderId])))];\n\tif (ids.length === 0) return { records };\n\tconst found = new Set<string>();\n\tfor (const batch of chunks(ids, SQL_BATCH_SIZE)) {\n\t\tconst rows = await context.db\n\t\t\t.selectFrom(\"media_folders\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of rows) found.add(row.id);\n\t}\n\tconst adjustments: Array<ReadAdjustment[]> = [];\n\tconst next = records.map((record) => {\n\t\tif (record.folderId === undefined || found.has(record.folderId)) {\n\t\t\tadjustments.push([]);\n\t\t\treturn record;\n\t\t}\n\t\tadjustments.push([{ code: \"orphan_reference_nulled\", count: 1 }]);\n\t\tconst { folderId: _missing, ...rest } = record;\n\t\treturn rest;\n\t});\n\treturn { records: next, adjustments };\n}\n\nasync function filterTaxonomyCollections(\n\trecords: Array<RecordOfKind<\"taxonomy_def\">>,\n\tcontext: TransformContext,\n): Promise<TransformResult<\"taxonomy_def\">> {\n\tif (!context.paging) return { records };\n\tconst slugs = new Set(await collectionSlugs(context.db));\n\tconst adjustments: Array<ReadAdjustment[]> = [];\n\tconst next = records.map((record) => {\n\t\tconst kept = record.collections?.filter((slug) => slugs.has(slug));\n\t\tif (!record.collections || !kept || kept.length === record.collections.length) {\n\t\t\tadjustments.push([]);\n\t\t\treturn record;\n\t\t}\n\t\tadjustments.push([\n\t\t\t{ code: \"soft_orphan_dropped\", count: record.collections.length - kept.length },\n\t\t]);\n\t\treturn { ...record, collections: kept };\n\t});\n\treturn { records: next, adjustments };\n}\n\nasync function attachBlobs(raws: Row[], options: ReaderOptions): Promise<void> {\n\tconst ids = raws.flatMap((raw) => (typeof raw.id === \"string\" ? [raw.id] : []));\n\tif (ids.length === 0) return;\n\tconst blobs = await options.mediaBlobs(ids);\n\tfor (const raw of raws) {\n\t\tconst blob = typeof raw.id === \"string\" ? blobs.get(raw.id) : undefined;\n\t\tif (blob !== undefined) raw.blob = blob;\n\t}\n}\n\n// ── Reader table ────────────────────────────────────────────────\n\nconst PORTABLE_SETTINGS_FILTER = (): RawBuilder<boolean> =>\n\tsql<boolean>`${sql.ref(\"options.name\")} IN (${sql.join(PORTABLE_SETTING_NAMES.map((name) => sql.lit(name)))})`;\n\nconst REDIRECT_FILTER = (): RawBuilder<boolean> => sql<boolean>`(\n\t_emdash_redirects.source_guard = 1\n\tOR (\n\t\tNOT EXISTS (\n\t\t\tSELECT 1 FROM _emdash_redirects AS guarded\n\t\t\tWHERE guarded.source = _emdash_redirects.source AND guarded.source_guard = 1\n\t\t)\n\t\tAND _emdash_redirects.id = (\n\t\t\tSELECT MIN(first.id) FROM _emdash_redirects AS first\n\t\t\tWHERE first.source = _emdash_redirects.source\n\t\t)\n\t)\n)`;\n\nconst COLLECTION_SLUGS = sql`(SELECT slug FROM _emdash_collections)`;\n\nfunction tableConfig(kind: RecordKind): TableReaderConfig {\n\tconst spec = getPortableTableSpecForKind(kind);\n\tif (!spec) throw new Error(`No table for kind ${kind}`);\n\treturn { kind, table: spec.table };\n}\n\nfunction configFor(kind: RecordKind): TableReaderConfig {\n\tswitch (kind) {\n\t\tcase \"block_type_version\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: () =>\n\t\t\t\t\tsql<boolean>`_emdash_block_type_versions.block_type_id IN (SELECT id FROM _emdash_block_types)`,\n\t\t\t};\n\t\tcase \"field\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: () =>\n\t\t\t\t\tsql<boolean>`_emdash_fields.collection_id IN (SELECT id FROM _emdash_collections)`,\n\t\t\t};\n\t\tcase \"taxonomy_def\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\ttransform: forKind(\"taxonomy_def\", filterTaxonomyCollections),\n\t\t\t};\n\t\tcase \"relation\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t_emdash_relations.parent_collection IN ${COLLECTION_SLUGS}\n\t\t\t\t\tAND _emdash_relations.child_collection IN ${COLLECTION_SLUGS}\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"media\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"media\"),\n\t\t\t\tfilter: ({ options }) =>\n\t\t\t\t\toptions.exportOperationId === undefined\n\t\t\t\t\t\t? null\n\t\t\t\t\t\t: sql<boolean>`media.id IN (\n\t\t\t\t\t\t\tSELECT media_id FROM _emdash_transfer_media_blobs\n\t\t\t\t\t\t\tWHERE operation_id = ${options.exportOperationId}\n\t\t\t\t\t\t)`,\n\t\t\t\tprepare: attachBlobs,\n\t\t\t\ttransform: forKind(\"media\", nullMissingFolders),\n\t\t\t};\n\t\tcase \"term\":\n\t\t\treturn { ...tableConfig(\"term\"), parentColumn: \"parent_id\" };\n\t\tcase \"comment\":\n\t\t\treturn { ...tableConfig(\"comment\"), parentColumn: \"parent_id\", treeValid: commentValid };\n\t\tcase \"comment_reaction\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: (context) =>\n\t\t\t\t\tsql<boolean>`_emdash_comment_reactions.comment_id IN ${treeIds(\n\t\t\t\t\t\t\"_emdash_comments\",\n\t\t\t\t\t\t\"parent_id\",\n\t\t\t\t\t\tcommentValid(context),\n\t\t\t\t\t)}`,\n\t\t\t};\n\t\tcase \"menu_item\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"menu_item\"),\n\t\t\t\tparentColumn: \"parent_id\",\n\t\t\t\ttreeValid: (context) => {\n\t\t\t\t\tconst reference = col(\"_emdash_menu_items\", \"reference_id\");\n\t\t\t\t\treturn sql<boolean>`(\n\t\t\t\t\t\t_emdash_menu_items.menu_id IN (SELECT id FROM _emdash_menus)\n\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\t${reference} IS NULL\n\t\t\t\t\t\t\tOR ${groupExists(\"taxonomies\", reference)}\n\t\t\t\t\t\t\tOR ${anyOf(context.slugs.map((slug) => groupExists(contentTable(slug), reference)))}\n\t\t\t\t\t\t)\n\t\t\t\t\t)`;\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"byline\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"byline\"),\n\t\t\t\ttransform: forKind(\"byline\", (records, context) =>\n\t\t\t\t\tnullUnexportedMedia(records, context, \"avatarMediaId\"),\n\t\t\t\t),\n\t\t\t};\n\t\tcase \"section\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"section\"),\n\t\t\t\ttransform: forKind(\"section\", (records, context) =>\n\t\t\t\t\tnullUnexportedMedia(records, context, \"previewMediaId\"),\n\t\t\t\t),\n\t\t\t};\n\t\tcase \"byline_field_value\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: concatKey(\"byline_id\", \"field_id\"),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t_emdash_byline_field_values.byline_id IN (SELECT id FROM _emdash_bylines)\n\t\t\t\t\tAND _emdash_byline_field_values.field_id IN (SELECT id FROM _emdash_byline_fields)\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"byline_field_group_value\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: concatKey(\"translation_group\", \"field_id\"),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t${groupExists(\"_emdash_bylines\", col(\"_emdash_byline_field_group_values\", \"translation_group\"))}\n\t\t\t\t\tAND _emdash_byline_field_group_values.field_id IN (SELECT id FROM _emdash_byline_fields)\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"revision\":\n\t\t\treturn { ...tableConfig(kind), filter: revisionValid };\n\t\tcase \"content_term\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"content_term\"),\n\t\t\t\tkey: concatKey(\"collection\", \"entry_id\", \"taxonomy_id\"),\n\t\t\t\tfilter: (context) => sql<boolean>`(\n\t\t\t\t\t${entryGroupExists(context, col(\"content_taxonomies\", \"collection\"), col(\"content_taxonomies\", \"entry_id\"))}\n\t\t\t\t\tAND ${groupExists(\"taxonomies\", col(\"content_taxonomies\", \"taxonomy_id\"))}\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"content_byline\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tfilter: (context) => sql<boolean>`(\n\t\t\t\t\t${entryExists(context, col(\"_emdash_content_bylines\", \"collection_slug\"), col(\"_emdash_content_bylines\", \"content_id\"))}\n\t\t\t\t\tAND ${groupExists(\"_emdash_bylines\", col(\"_emdash_content_bylines\", \"byline_id\"))}\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"content_reference\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"content_reference\"),\n\t\t\t\tfilter: (context) => {\n\t\t\t\t\tconst references = \"_emdash_content_references\";\n\t\t\t\t\treturn sql<boolean>`EXISTS (\n\t\t\t\t\t\tSELECT 1 FROM _emdash_relations AS __relation\n\t\t\t\t\t\tWHERE (\n\t\t\t\t\t\t\t__relation.translation_group = ${col(references, \"relation_group\")}\n\t\t\t\t\t\t\tOR (__relation.translation_group IS NULL AND __relation.id = ${col(references, \"relation_group\")})\n\t\t\t\t\t\t)\n\t\t\t\t\t\tAND ${entryGroupExists(context, sql`__relation.parent_collection`, col(references, \"parent_group\"))}\n\t\t\t\t\t\tAND ${entryGroupExists(context, sql`__relation.child_collection`, col(references, \"child_group\"))}\n\t\t\t\t\t)`;\n\t\t\t\t},\n\t\t\t};\n\t\tcase \"seo\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: concatKey(\"collection\", \"content_id\"),\n\t\t\t\tfilter: (context) =>\n\t\t\t\t\tentryExists(context, col(\"_emdash_seo\", \"collection\"), col(\"_emdash_seo\", \"content_id\")),\n\t\t\t};\n\t\tcase \"widget\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(\"widget\"),\n\t\t\t\tfilter: () => sql<boolean>`(\n\t\t\t\t\t_emdash_widgets.area_id IN (SELECT id FROM _emdash_widget_areas)\n\t\t\t\t\tAND (\n\t\t\t\t\t\t_emdash_widgets.menu_name IS NULL\n\t\t\t\t\t\tOR _emdash_widgets.menu_name IN (SELECT name FROM _emdash_menus)\n\t\t\t\t\t)\n\t\t\t\t)`,\n\t\t\t};\n\t\tcase \"redirect\":\n\t\t\treturn { ...tableConfig(kind), filter: REDIRECT_FILTER };\n\t\tcase \"setting\":\n\t\t\treturn {\n\t\t\t\t...tableConfig(kind),\n\t\t\t\tkey: () => sql`${sql.ref(\"options.name\")}`,\n\t\t\t\tfilter: PORTABLE_SETTINGS_FILTER,\n\t\t\t\tcountFilter: PORTABLE_SETTINGS_FILTER,\n\t\t\t};\n\t\tdefault:\n\t\t\treturn tableConfig(kind);\n\t}\n}\n\n// ── Entries ─────────────────────────────────────────────────────\n\ninterface ContentCollection {\n\tslug: string;\n\ttable: string;\n\tcolumns: Readonly<Record<string, ColumnSpec>>;\n}\n\ntype FieldColumns = ReadonlyArray<{ slug: string; column_type: string }>;\n\nclass EntryReader implements KindReader<\"entry\"> {\n\treadonly kind = \"entry\";\n\treadonly #db: Db;\n\t#fields: Promise<ReadonlyMap<string, FieldColumns>> | null = null;\n\treadonly #collections = new Map<string, Promise<ContentCollection>>();\n\n\tconstructor(db: Db) {\n\t\tthis.#db = db;\n\t}\n\n\t/** Registered fields of every collection, by collection slug, in one query. */\n\tprivate fields(): Promise<ReadonlyMap<string, FieldColumns>> {\n\t\tthis.#fields ??= this.#db\n\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t.leftJoin(\"_emdash_fields\", \"_emdash_fields.collection_id\", \"_emdash_collections.id\")\n\t\t\t.select([\n\t\t\t\t\"_emdash_collections.slug as collection\",\n\t\t\t\t\"_emdash_fields.slug as slug\",\n\t\t\t\t\"_emdash_fields.column_type as column_type\",\n\t\t\t])\n\t\t\t.execute()\n\t\t\t.then((rows) => {\n\t\t\t\tconst fields = new Map<string, Array<{ slug: string; column_type: string }>>();\n\t\t\t\tfor (const row of rows) {\n\t\t\t\t\tconst list = fields.get(row.collection) ?? [];\n\t\t\t\t\tif (row.slug !== null && row.column_type !== null) {\n\t\t\t\t\t\tlist.push({ slug: row.slug, column_type: row.column_type });\n\t\t\t\t\t}\n\t\t\t\t\tfields.set(row.collection, list);\n\t\t\t\t}\n\t\t\t\treturn fields;\n\t\t\t});\n\t\treturn this.#fields;\n\t}\n\n\tprivate async slugs(): Promise<string[]> {\n\t\treturn [...(await this.fields()).keys()].toSorted();\n\t}\n\n\t/** A collection's table and column specs, loaded once and checked for coverage. */\n\tprivate collection(slug: string): Promise<ContentCollection> {\n\t\tlet pending = this.#collections.get(slug);\n\t\tif (!pending) {\n\t\t\tpending = (async () => {\n\t\t\t\tconst table = contentTable(slug);\n\t\t\t\tconst fields = (await this.fields()).get(slug) ?? [];\n\t\t\t\tconst tableColumns = await listTableColumns(this.#db, table);\n\t\t\t\tconst columns = contentColumnSpecs(fields, tableColumns);\n\t\t\t\tassertLoadedColumnCoverage(table, columns, tableColumns);\n\t\t\t\treturn { slug, table, columns };\n\t\t\t})();\n\t\t\tthis.#collections.set(slug, pending);\n\t\t}\n\t\treturn pending;\n\t}\n\n\tprivate async collections(): Promise<ContentCollection[]> {\n\t\tconst result = [];\n\t\tfor (const slug of await this.slugs()) result.push(await this.collection(slug));\n\t\treturn result;\n\t}\n\n\tprivate decode(collection: ContentCollection, row: Row): RecordOfKind<\"entry\"> {\n\t\tconst { properties, fields } = decodeContentRow(this.#db, collection.columns, row);\n\t\treturn toRecord(\"entry\", {\n\t\t\tkind: \"entry\",\n\t\t\tcollection: collection.slug,\n\t\t\t...properties,\n\t\t\tfields,\n\t\t});\n\t}\n\n\tprivate selectList(collection: ContentCollection): RawBuilder<unknown> {\n\t\treturn sql.join(selectExportedColumns(this.#db, collection.columns));\n\t}\n\n\tasync page(after: StreamOrderKey | null, limit: number): Promise<ReadPage<\"entry\">> {\n\t\tconst db = this.#db;\n\t\tconst merged: Array<RecordOfKind<\"entry\">> = [];\n\t\tfor (const collection of await this.collections()) {\n\t\t\tconst idRef = sql.ref(`${collection.table}.id`);\n\t\t\tconst where = after ? sql`WHERE ${bytewiseExpr(db, idRef)} > ${after.id}` : sql``;\n\t\t\tconst result = await sql<Row>`\n\t\t\t\tSELECT ${this.selectList(collection)}\n\t\t\t\tFROM ${sql.ref(collection.table)}\n\t\t\t\t${where}\n\t\t\t\tORDER BY ${bytewiseExpr(db, idRef)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t\tfor (const row of result.rows) merged.push(this.decode(collection, row));\n\t\t}\n\t\tmerged.sort((a, b) => compareStreamOrder(\"entry\", a, b));\n\t\tconst page = merged.slice(0, limit);\n\t\tconst nulled = await this.nullMissingReferences(page);\n\t\treturn {\n\t\t\trows: nulled.map(({ record, adjustments }) => ({\n\t\t\t\tkey: { id: record.id },\n\t\t\t\trecord,\n\t\t\t\tadjustments,\n\t\t\t})),\n\t\t\tdone: merged.length <= limit,\n\t\t};\n\t}\n\n\t/**\n\t * Remove revision pointers to revisions an export leaves out and primary\n\t * bylines that do not exist, keeping the entry.\n\t */\n\tprivate async nullMissingReferences(\n\t\trecords: Array<RecordOfKind<\"entry\">>,\n\t): Promise<Array<{ record: RecordOfKind<\"entry\">; adjustments: ReadAdjustment[] }>> {\n\t\tconst db = this.#db;\n\t\tconst revisionIds = [\n\t\t\t...new Set(\n\t\t\t\trecords.flatMap((record) =>\n\t\t\t\t\t[record.liveRevisionId, record.draftRevisionId].filter(\n\t\t\t\t\t\t(id): id is string => id !== undefined,\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t),\n\t\t];\n\t\tconst revisions = new Set<string>();\n\t\tconst context: FilterContext = {\n\t\t\tdb,\n\t\t\toptions: { mediaBlobs: async () => new Map() },\n\t\t\tslugs: await this.slugs(),\n\t\t};\n\t\tfor (const batch of chunks(revisionIds, SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await sql<{ id: string }>`\n\t\t\t\tSELECT id FROM revisions\n\t\t\t\tWHERE id IN (${sql.join(batch)}) AND ${revisionValid(context)}\n\t\t\t`.execute(db);\n\t\t\tfor (const row of rows.rows) revisions.add(row.id);\n\t\t}\n\t\tconst bylineGroups = await existingGroups(\n\t\t\tdb,\n\t\t\t\"_emdash_bylines\",\n\t\t\trecords.flatMap((record) =>\n\t\t\t\trecord.primaryBylineGroup === undefined ? [] : [record.primaryBylineGroup],\n\t\t\t),\n\t\t);\n\t\treturn records.map((record) => {\n\t\t\tconst next: Record<string, unknown> = { ...record };\n\t\t\tlet nulled = 0;\n\t\t\tfor (const property of [\"liveRevisionId\", \"draftRevisionId\"] as const) {\n\t\t\t\tconst id = record[property];\n\t\t\t\tif (id !== undefined && !revisions.has(id)) {\n\t\t\t\t\tdelete next[property];\n\t\t\t\t\tnulled++;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (record.primaryBylineGroup !== undefined && !bylineGroups.has(record.primaryBylineGroup)) {\n\t\t\t\tdelete next.primaryBylineGroup;\n\t\t\t\tnulled++;\n\t\t\t}\n\t\t\tif (nulled === 0) return { record, adjustments: [] };\n\t\t\treturn {\n\t\t\t\trecord: toRecord(\"entry\", next),\n\t\t\t\tadjustments: [{ code: \"orphan_reference_nulled\", count: nulled }],\n\t\t\t};\n\t\t});\n\t}\n\n\tasync byIds(\n\t\tids: readonly string[],\n\t\tcollections?: ReadonlyMap<string, string>,\n\t): Promise<Map<string, RecordOfKind<\"entry\">>> {\n\t\tconst slugs = new Set(await this.slugs());\n\t\tconst bySlug = new Map<string, string[]>();\n\t\tconst anywhere: string[] = [];\n\t\tfor (const id of new Set(ids)) {\n\t\t\tconst slug = collections?.get(id);\n\t\t\tif (slug === undefined) {\n\t\t\t\tanywhere.push(id);\n\t\t\t} else if (slugs.has(slug)) {\n\t\t\t\tconst list = bySlug.get(slug) ?? [];\n\t\t\t\tlist.push(id);\n\t\t\t\tbySlug.set(slug, list);\n\t\t\t}\n\t\t}\n\t\tif (anywhere.length > 0) {\n\t\t\tfor (const slug of slugs) bySlug.set(slug, [...(bySlug.get(slug) ?? []), ...anywhere]);\n\t\t}\n\n\t\tconst result = new Map<string, RecordOfKind<\"entry\">>();\n\t\tfor (const [slug, slugIds] of bySlug) {\n\t\t\tconst collection = await this.collection(slug);\n\t\t\tfor (const batch of chunks(slugIds, SQL_BATCH_SIZE)) {\n\t\t\t\tconst rows = await sql<Row>`\n\t\t\t\t\tSELECT ${this.selectList(collection)}\n\t\t\t\t\tFROM ${sql.ref(collection.table)}\n\t\t\t\t\tWHERE ${sql.ref(`${collection.table}.id`)} IN (${sql.join(batch)})\n\t\t\t\t`.execute(this.#db);\n\t\t\t\tfor (const row of rows.rows) {\n\t\t\t\t\tconst record = this.decode(collection, row);\n\t\t\t\t\tresult.set(record.id, record);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync countRows(): Promise<number> {\n\t\tlet total = 0;\n\t\tfor (const collection of await this.collections()) {\n\t\t\tconst result = await sql<{ n: unknown }>`\n\t\t\t\tSELECT COUNT(*) AS n FROM ${sql.ref(collection.table)}\n\t\t\t`.execute(this.#db);\n\t\t\ttotal += count(result.rows[0]?.n);\n\t\t}\n\t\treturn total;\n\t}\n}\n\n// ── Principals ──────────────────────────────────────────────────\n\ninterface PrincipalSource {\n\ttable: string;\n\tcolumn: string;\n\tfilter?: RawBuilder<boolean>;\n}\n\n/**\n * Principals are the origin users referenced by exported rows. Nothing but\n * the id, name, and email of a user ever leaves the `users` table.\n */\nclass PrincipalReader implements KindReader<\"principal\"> {\n\treadonly kind = \"principal\";\n\treadonly #db: Db;\n\treadonly #options: ReaderOptions;\n\n\tconstructor(db: Db, options: ReaderOptions) {\n\t\tthis.#db = db;\n\t\tthis.#options = options;\n\t}\n\n\tprivate async sources(): Promise<PrincipalSource[]> {\n\t\tconst sources: PrincipalSource[] = [];\n\t\tconst slugs = await collectionSlugs(this.#db);\n\t\tconst context: FilterContext = { db: this.#db, options: this.#options, slugs };\n\t\tfor (const slug of slugs) {\n\t\t\tsources.push({ table: contentTable(slug), column: \"author_id\" });\n\t\t}\n\t\tsources.push({ table: \"revisions\", column: \"author_id\", filter: revisionValid(context) });\n\t\tconst operationId = this.#options.exportOperationId;\n\t\tsources.push({\n\t\t\ttable: \"media\",\n\t\t\tcolumn: \"author_id\",\n\t\t\tfilter:\n\t\t\t\toperationId === undefined\n\t\t\t\t\t? undefined\n\t\t\t\t\t: sql<boolean>`media.id IN (\n\t\t\t\t\t\tSELECT media_id FROM _emdash_transfer_media_blobs WHERE operation_id = ${operationId}\n\t\t\t\t\t)`,\n\t\t});\n\t\tsources.push({ table: \"_emdash_bylines\", column: \"user_id\" });\n\t\tif (this.#options.comments ?? true) {\n\t\t\tsources.push({\n\t\t\t\ttable: \"_emdash_comments\",\n\t\t\t\tcolumn: \"author_user_id\",\n\t\t\t\tfilter: sql<boolean>`_emdash_comments.id IN ${treeIds(\n\t\t\t\t\t\"_emdash_comments\",\n\t\t\t\t\t\"parent_id\",\n\t\t\t\t\tcommentValid(context),\n\t\t\t\t)}`,\n\t\t\t});\n\t\t}\n\t\treturn sources;\n\t}\n\n\tasync page(after: StreamOrderKey | null, limit: number): Promise<ReadPage<\"principal\">> {\n\t\tconst db = this.#db;\n\t\tconst ids = new Set<string>();\n\t\tfor (const source of await this.sources()) {\n\t\t\tconst column = sql.ref(`${source.table}.${source.column}`);\n\t\t\tconst conditions: Array<RawBuilder<unknown>> = [sql`${column} IS NOT NULL`];\n\t\t\tif (after) conditions.push(sql`${bytewiseExpr(db, column)} > ${after.id}`);\n\t\t\tif (source.filter) conditions.push(source.filter);\n\t\t\tconst result = await sql<{ id: string }>`\n\t\t\t\tSELECT ${column} AS id FROM ${sql.ref(source.table)}\n\t\t\t\tWHERE ${sql.join(conditions, sql` AND `)}\n\t\t\t\tGROUP BY ${column}\n\t\t\t\tORDER BY ${bytewiseExpr(db, column)}\n\t\t\t\tLIMIT ${limit + 1}\n\t\t\t`.execute(db);\n\t\t\tfor (const row of result.rows) ids.add(row.id);\n\t\t}\n\t\tconst sorted = [...ids].toSorted((a, b) =>\n\t\t\tcompareStreamOrder(\"principal\", { id: a }, { id: b }),\n\t\t);\n\t\tconst pageIds = sorted.slice(0, limit);\n\t\tconst records = await this.byIds(pageIds);\n\t\treturn {\n\t\t\trows: pageIds.map((id) => ({\n\t\t\t\tkey: { id },\n\t\t\t\trecord:\n\t\t\t\t\trecords.get(id) ?? toRecord(\"principal\", { kind: \"principal\", id, displayName: \"\" }),\n\t\t\t\tadjustments: [],\n\t\t\t})),\n\t\t\tdone: sorted.length <= limit,\n\t\t};\n\t}\n\n\tasync byIds(ids: readonly string[]): Promise<Map<string, RecordOfKind<\"principal\">>> {\n\t\tconst result = new Map<string, RecordOfKind<\"principal\">>();\n\t\tfor (const batch of chunks([...new Set(ids)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.#db\n\t\t\t\t.selectFrom(\"users\")\n\t\t\t\t.select([\"id\", \"name\", \"email\"])\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) {\n\t\t\t\tresult.set(\n\t\t\t\t\trow.id,\n\t\t\t\t\ttoRecord(\"principal\", {\n\t\t\t\t\t\tkind: \"principal\",\n\t\t\t\t\t\tid: row.id,\n\t\t\t\t\t\tdisplayName: row.name || row.email,\n\t\t\t\t\t\temail: row.email,\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n\n\tasync countRows(): Promise<null> {\n\t\treturn null;\n\t}\n}\n\n// ── Factory ─────────────────────────────────────────────────────\n\nexport function createReader(\n\tdb: Db,\n\tkind: RecordKind,\n\toptions: ReaderOptions,\n): KindReader<RecordKind> {\n\tif (kind === \"entry\") return new EntryReader(db);\n\tif (kind === \"principal\") return new PrincipalReader(db, options);\n\treturn new TableReader(db, configFor(kind), options);\n}\n","/**\n * The export operation, advanced in bounded steps.\n *\n * Each `advanceExport` call claims the operation's lease, runs units of work\n * until the step budget is spent, persists the cursor after every unit, and\n * releases the lease. Stages, in order:\n *\n * - fence capture (on the first step), then `export_media`: hash every\n * exported media object from its origin key and record the blob;\n * - `export_records`: every record kind in package order, one chunk per unit;\n * - `export_finalize`: re-check the fence (restart the export on a change,\n * up to the attempt limit), declare dropped rows, write the index chunks\n * and the manifest;\n * - `export_validate`: re-read every record chunk, check digests and scan\n * for storage keys, then run the injected package validator.\n *\n * Media blobs are never copied: the index lists `media/<sha256>` and the\n * bytes are served from the origin object ({@link ExportPackageReader}).\n */\n\nimport type { Kysely } from \"kysely\";\nimport { ulid } from \"ulidx\";\nimport { z } from \"zod\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { getI18nConfig } from \"../../i18n/config.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { VERSION } from \"../../version.js\";\nimport { TransferError, isTransferError, type TransferErrorCode } from \"../errors.js\";\nimport { compareUtf16 } from \"../format/canonical.js\";\nimport { KIND_FEATURE, requiredFeaturesFor, type SitePackageFeature } from \"../format/features.js\";\nimport { RECORD_KINDS, type RecordKind, type SitePackageRecord } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tindexChunkRefSchema,\n\ttype IndexChunkRef,\n\ttype PackageFileEntry,\n\ttype SitePackageManifest,\n} from \"../format/manifest.js\";\nimport {\n\trewriteMediaRefs,\n\tscanForKeys,\n\tscannableKeys,\n\ttype MediaKeyIndex,\n} from \"../format/media-refs.js\";\nimport { mediaBlobPath, parsePackagePath, recordChunkPath } from \"../format/paths.js\";\nimport type { PlanBlocker, PlanWarning } from \"../format/plan.js\";\nimport { encodeRecordLine } from \"../format/records.js\";\nimport {\n\tEXPORT_TRANSFORMATION_CODES,\n\ttype ExportTransformation,\n\ttype ExportTransformationCode,\n} from \"../format/transformations.js\";\nimport {\n\tSITE_PACKAGE_FORMAT,\n\tSITE_PACKAGE_FORMAT_VERSION,\n\tSITE_PACKAGE_PROFILE,\n} from \"../format/version.js\";\nimport { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferMediaBlobRepository } from \"../ops/media-blobs.js\";\nimport { TransferOperationRepository, type TransferOperation } from \"../ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport type { ExportCursor, ExportFence, TransferCursor, TransferProgress } from \"../ops/states.js\";\nimport { getOrCreateSiteId } from \"../site-id.js\";\nimport { stagingPrefix } from \"../staging/keys.js\";\nimport { StagedPackageReader, StagedPackageWriter } from \"../staging/package.js\";\nimport { TransferStage } from \"../staging/stage.js\";\nimport { captureFence, fencesEqual } from \"./fence.js\";\nimport {\n\thashStoredObject,\n\tlistMediaCandidates,\n\tloadMediaKeyIndex,\n\tunlinkMediaPlaceholders,\n} from \"./media.js\";\nimport { createReader, type KindReader, type ReaderOptions } from \"./readers.js\";\n\ntype Db = Kysely<Database>;\n\nconst encoder = new TextEncoder();\nconst PAGE_ROWS = 250;\nconst MEDIA_CANDIDATES_PER_PAGE = 50;\n/** Sorts after every `index/<seq>.ndjson` path and before `media/`. */\nconst INDEX_PATHS_END = \"index/~\";\n\n// ── Options ─────────────────────────────────────────────────────\n\nexport const exportOptionsSchema = z.strictObject({\n\tcomments: z.boolean().optional(),\n});\n\nexport type ExportOptions = z.infer<typeof exportOptionsSchema>;\n\nexport interface CreateExportInput {\n\tdb: Db;\n\tcreatedBy: string;\n\toptions?: ExportOptions;\n\tidempotencyKey?: string;\n}\n\nfunction includesComments(options: unknown): boolean {\n\treturn exportOptionsSchema.parse(options ?? {}).comments ?? true;\n}\n\n/**\n * Create a pending export operation, or return the existing one for the same\n * idempotency key. Reusing a key with different options fails with\n * `TRANSFER_IDEMPOTENCY_CONFLICT`.\n */\nexport async function createExport(\n\tinput: CreateExportInput,\n): Promise<{ operation: TransferOperation; created: boolean }> {\n\tconst options = exportOptionsSchema.parse(input.options ?? {});\n\tconst result = await new TransferOperationRepository(input.db).create({\n\t\tkind: \"export\",\n\t\tcreatedBy: input.createdBy,\n\t\tidempotencyKey: input.idempotencyKey,\n\t\toptions,\n\t});\n\tif (!result.created && includesComments(result.operation.options) !== includesComments(options)) {\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_IDEMPOTENCY_CONFLICT\",\n\t\t\t\"Idempotency key was already used for an export with different options\",\n\t\t);\n\t}\n\treturn result;\n}\n\n// ── Validator hook ──────────────────────────────────────────────\n\nexport interface ExportPackageValidatorInput {\n\tdb: Db;\n\t/** The finished package; blobs stream from their origin objects. */\n\treader: StagedPackageReader;\n\toperationId: string;\n\t/** Opaque JSON state returned by the previous call, or null on the first. */\n\tstate: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport interface ExportPackageValidatorResult {\n\tdone: boolean;\n\tstate: unknown;\n\tblockers: PlanBlocker[];\n\twarnings: PlanWarning[];\n}\n\n/** Package validation run over the finished export before it completes. */\nexport type ExportPackageValidator = (\n\tinput: ExportPackageValidatorInput,\n) => Promise<ExportPackageValidatorResult>;\n\n// ── Summary carried in the cursor ───────────────────────────────\n\nconst count = z.number().int().nonnegative();\n\nconst exportSummarySchema = z.strictObject({\n\t/** Records per chunk, by kind. */\n\tchunks: z.record(z.string(), z.array(count)),\n\tlocales: z.array(z.string()),\n\ttrash: z.boolean(),\n\t/** `code:kind` → count of declared export transformations. */\n\tadjustments: z.record(z.string(), count),\n\tfenceVerified: z.boolean(),\n\tindex: z.array(indexChunkRefSchema),\n\tfiles: z.strictObject({ count, bytes: count }),\n});\n\ntype ExportSummary = z.infer<typeof exportSummarySchema>;\n\nfunction emptySummary(): ExportSummary {\n\treturn {\n\t\tchunks: {},\n\t\tlocales: [],\n\t\ttrash: false,\n\t\tadjustments: {},\n\t\tfenceVerified: false,\n\t\tindex: [],\n\t\tfiles: { count: 0, bytes: 0 },\n\t};\n}\n\nfunction readSummary(value: unknown): ExportSummary {\n\treturn value === undefined ? emptySummary() : exportSummarySchema.parse(value);\n}\n\nfunction recordsWritten(summary: ExportSummary): number {\n\tlet total = 0;\n\tfor (const counts of Object.values(summary.chunks)) {\n\t\tfor (const records of counts) total += records;\n\t}\n\treturn total;\n}\n\nconst validationSchema = z.strictObject({\n\tphase: z.literal(\"validator\"),\n\tstate: z.json().nullable(),\n});\n\nfunction addAdjustment(\n\tsummary: ExportSummary,\n\tcode: ExportTransformationCode,\n\tkind: RecordKind,\n\tamount: number,\n): void {\n\tif (amount <= 0) return;\n\tconst key = `${code}:${kind}`;\n\tsummary.adjustments[key] = (summary.adjustments[key] ?? 0) + amount;\n}\n\n/** Rows a reader leaves out of each kind, and how the package declares them. */\nconst DROP_CODES: Partial<Record<RecordKind, ExportTransformationCode>> = {\n\tfield: \"orphan_dropped\",\n\trelation: \"orphan_dropped\",\n\tterm: \"orphan_dropped\",\n\tbyline_field_value: \"orphan_dropped\",\n\tbyline_field_group_value: \"orphan_dropped\",\n\trevision: \"orphan_dropped\",\n\tcontent_byline: \"orphan_dropped\",\n\tseo: \"orphan_dropped\",\n\tcomment: \"orphan_dropped\",\n\tcomment_reaction: \"orphan_dropped\",\n\tmenu_item: \"soft_orphan_dropped\",\n\tcontent_term: \"soft_orphan_dropped\",\n\tcontent_reference: \"soft_orphan_dropped\",\n\twidget: \"soft_orphan_dropped\",\n\tredirect: \"redirect_duplicate_dropped\",\n\tmedia: \"media_not_ready_dropped\",\n};\n\n// ── Advancing ───────────────────────────────────────────────────\n\nexport interface AdvanceExportInput {\n\tdb: Db;\n\tstorage: Storage;\n\toperationId: string;\n\t/** A lease the caller already holds; otherwise the step claims one. */\n\tleaseToken?: string;\n\tbudget?: TransferStepBudget;\n\t/** Defaults to the site's configured default locale. */\n\tdefaultLocale?: string;\n\temdashVersion?: string;\n\tvalidatePackage?: ExportPackageValidator;\n}\n\nexport type AdvanceExportOutcome = \"advanced\" | \"complete\" | \"failed\" | \"busy\" | \"finished\";\n\nexport interface AdvanceExportResult {\n\toperation: TransferOperation;\n\t/**\n\t * `advanced`: more steps needed; `complete`/`failed`: this step finished\n\t * the export; `busy`: another caller holds the lease; `finished`: the\n\t * export was already terminal.\n\t */\n\toutcome: AdvanceExportOutcome;\n}\n\n/** Codes a later step may not hit again. */\nconst TRANSIENT_CODES: ReadonlySet<TransferErrorCode> = new Set([\n\t\"TRANSFER_STORAGE_ERROR\",\n\t\"TRANSFER_LEASE_LOST\",\n]);\n\ntype UnitResult =\n\t| { type: \"cursor\"; cursor: ExportCursor; endStep?: boolean }\n\t| { type: \"yield\" }\n\t| { type: \"complete\" }\n\t| { type: \"fail\"; code: TransferErrorCode; detail?: Record<string, string | number | null> };\n\n/**\n * Run one bounded step of an export. Transient failures (storage errors,\n * a lost lease, non-transfer errors) release the lease and rethrow so a\n * later call resumes from the last persisted cursor; any other transfer\n * error fails the operation.\n */\nexport async function advanceExport(input: AdvanceExportInput): Promise<AdvanceExportResult> {\n\tconst operations = new TransferOperationRepository(input.db);\n\tlet operation: TransferOperation;\n\tlet leaseToken = input.leaseToken;\n\tif (leaseToken === undefined) {\n\t\tconst claim = await operations.claim(input.operationId, [\"pending\", \"running\"]);\n\t\tif (claim.outcome === \"lease_active\") return { operation: claim.operation, outcome: \"busy\" };\n\t\tif (claim.outcome === \"invalid_state\") {\n\t\t\treturn { operation: claim.operation, outcome: \"finished\" };\n\t\t}\n\t\toperation = claim.operation;\n\t\tleaseToken = claim.leaseToken;\n\t} else {\n\t\toperation = await operations.require(input.operationId);\n\t\tif (operation.kind !== \"export\" || operation.leaseToken !== leaseToken) {\n\t\t\tthrow new TransferError(\"TRANSFER_LEASE_LOST\", \"Transfer operation lease was lost\");\n\t\t}\n\t}\n\tif (operation.kind !== \"export\") {\n\t\tawait operations.release(operation.id, leaseToken);\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an export\");\n\t}\n\n\tconst step = new ExportStep(input, operation, leaseToken);\n\ttry {\n\t\tconst result = await step.run();\n\t\treturn result;\n\t} catch (error) {\n\t\tif (isTransferError(error) && !TRANSIENT_CODES.has(error.code)) {\n\t\t\tconst failed = await operations.fail(operation.id, leaseToken, {\n\t\t\t\tcode: error.code,\n\t\t\t\tdetail: error.detail,\n\t\t\t});\n\t\t\treturn { operation: failed, outcome: \"failed\" };\n\t\t}\n\t\tif (!(isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\")) {\n\t\t\tawait operations.release(operation.id, leaseToken).catch(() => undefined);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\nclass ExportStep {\n\treadonly #input: AdvanceExportInput;\n\treadonly #db: Db;\n\treadonly #operations: TransferOperationRepository;\n\treadonly #stagedFiles: TransferStagedFileRepository;\n\treadonly #blobs: TransferMediaBlobRepository;\n\treadonly #budget: TransferStepBudget;\n\treadonly #stage: TransferStage;\n\treadonly #writer: StagedPackageWriter;\n\treadonly #options: ExportOptions;\n\treadonly #leaseToken: string;\n\t#operation: TransferOperation;\n\t#keys: MediaKeyIndex | null = null;\n\t#scannable: Set<string> | null = null;\n\t#readers = new Map<RecordKind, KindReader<RecordKind>>();\n\t#packageReader: ExportPackageReader | null = null;\n\treadonly #mediaExported = new Map<string, boolean>();\n\n\tconstructor(input: AdvanceExportInput, operation: TransferOperation, leaseToken: string) {\n\t\tthis.#input = input;\n\t\tthis.#db = input.db;\n\t\tthis.#operation = operation;\n\t\tthis.#leaseToken = leaseToken;\n\t\tthis.#operations = new TransferOperationRepository(input.db);\n\t\tthis.#stagedFiles = new TransferStagedFileRepository(input.db);\n\t\tthis.#blobs = new TransferMediaBlobRepository(input.db, operation.id);\n\t\tthis.#budget = input.budget ?? new TransferStepBudget();\n\t\tthis.#stage = new TransferStage(\n\t\t\tinput.storage,\n\t\t\tstagingPrefix(\"export\", operation.id, operation.stagingSecret),\n\t\t);\n\t\tthis.#writer = new StagedPackageWriter(this.#stage);\n\t\tthis.#options = exportOptionsSchema.parse(operation.options ?? {});\n\t}\n\n\tget #comments(): boolean {\n\t\treturn this.#options.comments ?? true;\n\t}\n\n\tasync run(): Promise<AdvanceExportResult> {\n\t\tlet cursor = this.currentCursor();\n\t\tif (cursor === null) {\n\t\t\tcursor = await this.start(1);\n\t\t\tawait this.persist(cursor, \"running\");\n\t\t}\n\t\tfor (;;) {\n\t\t\tconst result = await this.unit(cursor);\n\t\t\tswitch (result.type) {\n\t\t\t\tcase \"yield\": {\n\t\t\t\t\tconst released = await this.#operations.release(this.#operation.id, this.#leaseToken);\n\t\t\t\t\treturn { operation: released, outcome: \"advanced\" };\n\t\t\t\t}\n\t\t\t\tcase \"complete\": {\n\t\t\t\t\tconst total = this.progressTotal();\n\t\t\t\t\tconst last = this.#operation.progress;\n\t\t\t\t\tconst completed = await this.#operations.complete(this.#operation.id, this.#leaseToken, {\n\t\t\t\t\t\tttlSeconds: TRANSFER_LIMITS.exportTtlSeconds,\n\t\t\t\t\t\tprogress: {\n\t\t\t\t\t\t\t...last,\n\t\t\t\t\t\t\tdone: total,\n\t\t\t\t\t\t\ttotal,\n\t\t\t\t\t\t\t...(last?.bytesDone === undefined ? {} : { bytesTotal: last.bytesDone }),\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\treturn { operation: completed, outcome: \"complete\" };\n\t\t\t\t}\n\t\t\t\tcase \"fail\": {\n\t\t\t\t\tconst failed = await this.#operations.fail(this.#operation.id, this.#leaseToken, {\n\t\t\t\t\t\tcode: result.code,\n\t\t\t\t\t\tdetail: result.detail,\n\t\t\t\t\t});\n\t\t\t\t\treturn { operation: failed, outcome: \"failed\" };\n\t\t\t\t}\n\t\t\t\tcase \"cursor\":\n\t\t\t\t\tcursor = result.cursor;\n\t\t\t\t\tif (result.endStep) {\n\t\t\t\t\t\tconst released = await this.#operations.release(this.#operation.id, this.#leaseToken, {\n\t\t\t\t\t\t\tcursor,\n\t\t\t\t\t\t\tstage: cursor.stage,\n\t\t\t\t\t\t\tprogress: this.progressFor(cursor),\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn { operation: released, outcome: \"advanced\" };\n\t\t\t\t\t}\n\t\t\t\t\tawait this.persist(cursor);\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate currentCursor(): ExportCursor | null {\n\t\tconst cursor: TransferCursor | null = this.#operation.cursor;\n\t\tif (cursor === null) return null;\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"export_records\":\n\t\t\tcase \"export_media\":\n\t\t\tcase \"export_finalize\":\n\t\t\tcase \"export_validate\":\n\t\t\t\treturn cursor;\n\t\t\tdefault:\n\t\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Export cursor is not an export stage\");\n\t\t}\n\t}\n\n\tprivate async persist(cursor: ExportCursor, state?: \"running\"): Promise<void> {\n\t\tthis.#operation = await this.#operations.advance(this.#operation.id, this.#leaseToken, {\n\t\t\tcursor,\n\t\t\tstage: cursor.stage,\n\t\t\tprogress: this.progressFor(cursor),\n\t\t\t...(state ? { state } : {}),\n\t\t});\n\t}\n\n\t/** Media, each exported record kind, finalize, and validate. */\n\tprivate progressTotal(): number {\n\t\treturn this.exportedKinds().length + 3;\n\t}\n\n\tprivate progressFor(cursor: ExportCursor): TransferProgress {\n\t\tconst kinds = this.exportedKinds();\n\t\tconst total = this.progressTotal();\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"export_media\":\n\t\t\t\treturn { done: 0, total, records: 0 };\n\t\t\tcase \"export_records\":\n\t\t\t\treturn {\n\t\t\t\t\tdone: 1 + kinds.indexOf(cursor.kind),\n\t\t\t\t\ttotal,\n\t\t\t\t\trecords: recordsWritten(readSummary(cursor.summary)),\n\t\t\t\t};\n\t\t\tcase \"export_finalize\": {\n\t\t\t\tconst summary = readSummary(cursor.summary);\n\t\t\t\treturn {\n\t\t\t\t\tdone: 1 + kinds.length,\n\t\t\t\t\ttotal,\n\t\t\t\t\trecords: recordsWritten(summary),\n\t\t\t\t\tbytesDone: summary.files.bytes,\n\t\t\t\t};\n\t\t\t}\n\t\t\tcase \"export_validate\":\n\t\t\t\treturn { ...this.#operation.progress, done: 2 + kinds.length, total };\n\t\t}\n\t}\n\n\t/** Capture the fence and start an attempt at the media stage. */\n\tprivate async start(attempt: number): Promise<ExportCursor> {\n\t\tconst fence: ExportFence = await captureFence(this.#db, this.#operation.writeEpoch);\n\t\treturn {\n\t\t\tstage: \"export_media\",\n\t\t\tattempt,\n\t\t\tfence,\n\t\t\tafterMediaId: null,\n\t\t\tsummary: emptySummary(),\n\t\t};\n\t}\n\n\tprivate async unit(cursor: ExportCursor): Promise<UnitResult> {\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"export_media\":\n\t\t\t\treturn this.restartOnChangedFile(cursor.attempt, () => this.mediaUnit(cursor));\n\t\t\tcase \"export_records\":\n\t\t\t\treturn this.restartOnChangedFile(cursor.attempt, () => this.recordsUnit(cursor));\n\t\t\tcase \"export_finalize\":\n\t\t\t\treturn this.finalizeUnit(cursor);\n\t\t\tcase \"export_validate\":\n\t\t\t\treturn this.validateUnit(cursor);\n\t\t}\n\t}\n\n\t/**\n\t * A file this attempt already staged under the same path with other bytes\n\t * means the site changed since it was written (the step that wrote it did\n\t * not persist its cursor): start a new attempt.\n\t */\n\tprivate async restartOnChangedFile(\n\t\tattempt: number,\n\t\trun: () => Promise<UnitResult>,\n\t): Promise<UnitResult> {\n\t\ttry {\n\t\t\treturn await run();\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_FILE_DIGEST_MISMATCH\") {\n\t\t\t\treturn this.restart(attempt);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\t// ── Media ──\n\n\tprivate async mediaUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_media\" }>,\n\t): Promise<UnitResult> {\n\t\tif (!this.#budget.canStart()) return { type: \"yield\" };\n\t\tthis.#budget.start();\n\t\tconst candidates = await listMediaCandidates(\n\t\t\tthis.#db,\n\t\t\tcursor.afterMediaId,\n\t\t\tMEDIA_CANDIDATES_PER_PAGE,\n\t\t);\n\t\tif (candidates.length === 0) {\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor: {\n\t\t\t\t\tstage: \"export_records\",\n\t\t\t\t\tattempt: cursor.attempt,\n\t\t\t\t\tfence: cursor.fence,\n\t\t\t\t\tkind: RECORD_KINDS[0],\n\t\t\t\t\tafter: null,\n\t\t\t\t\tnextSeq: 0,\n\t\t\t\t\tsummary: cursor.summary,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tlet after = cursor.afterMediaId;\n\t\tfor (const candidate of candidates) {\n\t\t\t// The first object of a step may be any size; later ones must fit what is left.\n\t\t\tconst first = this.#budget.bytesUsed === 0;\n\t\t\tif (!first && !this.#budget.canStart({ queries: 5, bytes: 1 })) break;\n\t\t\tconst hashed = await hashStoredObject(this.#input.storage, candidate.storageKey, {\n\t\t\t\tmaxBytes: first ? undefined : this.#budget.remaining().bytes,\n\t\t\t});\n\t\t\tif (hashed === \"too_large\") break;\n\t\t\tthis.#budget.start(hashed?.bytes ?? 0);\n\t\t\tif (hashed === null) {\n\t\t\t\tif (candidate.status === \"ready\") {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_BLOB_MISSING\",\n\t\t\t\t\t\t\"Media file is missing from storage\",\n\t\t\t\t\t\t{ detail: { mediaId: candidate.id } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tawait this.#blobs.putMany([\n\t\t\t\t\t{ mediaId: candidate.id, sha256: hashed.sha256, bytes: hashed.bytes },\n\t\t\t\t]);\n\t\t\t\tawait this.#stagedFiles.declareMany(\n\t\t\t\t\tthis.#operation.id,\n\t\t\t\t\t[{ path: mediaBlobPath(hashed.sha256), bytes: hashed.bytes, sha256: hashed.sha256 }],\n\t\t\t\t\t\"verified\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tafter = candidate.id;\n\t\t}\n\t\tif (after === cursor.afterMediaId) return { type: \"yield\" };\n\t\treturn { type: \"cursor\", cursor: { ...cursor, afterMediaId: after } };\n\t}\n\n\t// ── Records ──\n\n\tprivate reader(kind: RecordKind): KindReader<RecordKind> {\n\t\tlet reader = this.#readers.get(kind);\n\t\tif (!reader) {\n\t\t\tconst options: ReaderOptions = {\n\t\t\t\texportOperationId: this.#operation.id,\n\t\t\t\tcomments: this.#comments,\n\t\t\t\tmediaBlobs: async (ids) => {\n\t\t\t\t\tconst entries = await this.#blobs.getMany(ids);\n\t\t\t\t\treturn new Map(Array.from(entries, ([id, entry]) => [id, entry.sha256]));\n\t\t\t\t},\n\t\t\t};\n\t\t\treader = createReader(this.#db, kind, options);\n\t\t\tthis.#readers.set(kind, reader);\n\t\t}\n\t\treturn reader;\n\t}\n\n\t/** Media ids among `ids` that this export did not hash (not in the package). */\n\tprivate async unexportedMedia(ids: readonly string[]): Promise<Set<string>> {\n\t\tconst unknown = ids.filter((id) => !this.#mediaExported.has(id));\n\t\tif (unknown.length > 0) {\n\t\t\tconst exported = await this.#blobs.getMany(unknown);\n\t\t\tfor (const id of unknown) this.#mediaExported.set(id, exported.has(id));\n\t\t}\n\t\treturn new Set(ids.filter((id) => this.#mediaExported.get(id) === false));\n\t}\n\n\tprivate async keyIndex(): Promise<{ keys: MediaKeyIndex; scannable: Set<string> }> {\n\t\tif (!this.#keys || !this.#scannable) {\n\t\t\tthis.#keys = await loadMediaKeyIndex(this.#db);\n\t\t\tthis.#scannable = scannableKeys(this.#keys);\n\t\t}\n\t\treturn { keys: this.#keys, scannable: this.#scannable };\n\t}\n\n\tprivate exportedKinds(): RecordKind[] {\n\t\treturn RECORD_KINDS.filter(\n\t\t\t(kind) => this.#comments || (kind !== \"comment\" && kind !== \"comment_reaction\"),\n\t\t);\n\t}\n\n\tprivate nextKind(kind: RecordKind): RecordKind | null {\n\t\tconst kinds = this.exportedKinds();\n\t\treturn kinds[kinds.indexOf(kind) + 1] ?? null;\n\t}\n\n\tprivate async recordsUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_records\" }>,\n\t): Promise<UnitResult> {\n\t\tif (!this.#budget.canStart({ bytes: 1 })) return { type: \"yield\" };\n\t\tconst summary = readSummary(cursor.summary);\n\t\tconst { keys, scannable } = await this.keyIndex();\n\t\tconst reader = this.reader(cursor.kind);\n\n\t\tconst records: SitePackageRecord[] = [];\n\t\tconst lines: string[] = [];\n\t\tconst locales = new Set(summary.locales);\n\t\tlet bytes = 0;\n\t\tlet after = cursor.after;\n\t\tlet kindDone = false;\n\t\tfill: while (records.length < TRANSFER_LIMITS.chunkRecords) {\n\t\t\tconst page = await reader.page(\n\t\t\t\tafter,\n\t\t\t\tMath.min(PAGE_ROWS, TRANSFER_LIMITS.chunkRecords - records.length),\n\t\t\t);\n\t\t\tfor (const row of page.rows) {\n\t\t\t\tif (row.record === null) {\n\t\t\t\t\tafter = row.key;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst rewritten = rewriteMediaRefs(row.record, {\n\t\t\t\t\tmode: \"export\",\n\t\t\t\t\tkeys,\n\t\t\t\t\trelativize: true,\n\t\t\t\t});\n\t\t\t\tconst error = rewritten.errors[0];\n\t\t\t\tif (error) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_REF_INVALID\",\n\t\t\t\t\t\t\"Record holds a media reference that cannot be exported\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdetail: {\n\t\t\t\t\t\t\t\tkind: cursor.kind,\n\t\t\t\t\t\t\t\tid: row.record.id,\n\t\t\t\t\t\t\t\treason: error.code,\n\t\t\t\t\t\t\t\tpath: error.path,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst unlinked = unlinkMediaPlaceholders(\n\t\t\t\t\trewritten.value,\n\t\t\t\t\tawait this.unexportedMedia(rewritten.mediaIds),\n\t\t\t\t);\n\t\t\t\tconst record = unlinked.record;\n\t\t\t\tconst line = encodeRecordLine(record);\n\t\t\t\tif (scanForKeys(line, scannable).length > 0) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_REF_INVALID\",\n\t\t\t\t\t\t\"Record still holds an origin storage key\",\n\t\t\t\t\t\t{ detail: { kind: cursor.kind, id: record.id } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst lineBytes = encoder.encode(line).byteLength + 1;\n\t\t\t\tif (records.length > 0 && bytes + lineBytes > TRANSFER_LIMITS.chunkBytes) break fill;\n\t\t\t\trecords.push(record);\n\t\t\t\tlines.push(line);\n\t\t\t\tbytes += lineBytes;\n\t\t\t\tafter = row.key;\n\t\t\t\tfor (const adjustment of row.adjustments) {\n\t\t\t\t\taddAdjustment(summary, adjustment.code, cursor.kind, adjustment.count);\n\t\t\t\t}\n\t\t\t\taddAdjustment(summary, \"media_url_relativized\", cursor.kind, rewritten.relativized);\n\t\t\t\taddAdjustment(summary, \"media_ref_unlinked\", cursor.kind, unlinked.count);\n\t\t\t\tif (rewritten.warnings.some((warning) => warning.code === \"unknown_storage_key\")) {\n\t\t\t\t\taddAdjustment(summary, \"unknown_storage_key\", cursor.kind, 1);\n\t\t\t\t}\n\t\t\t\tif (\"locale\" in record && typeof record.locale === \"string\") locales.add(record.locale);\n\t\t\t\tif (record.kind === \"entry\" && record.deletedAt !== undefined) summary.trash = true;\n\t\t\t}\n\t\t\tif (page.done) {\n\t\t\t\tkindDone = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (records.length > 0) {\n\t\t\tconst entry = await this.#writer.writeRecordChunk(cursor.kind, cursor.nextSeq, records);\n\t\t\tawait this.#stagedFiles.declareMany(\n\t\t\t\tthis.#operation.id,\n\t\t\t\t[{ path: entry.path, bytes: entry.bytes, sha256: entry.sha256 }],\n\t\t\t\t\"verified\",\n\t\t\t);\n\t\t\tthis.#budget.start(entry.bytes);\n\t\t\tsummary.chunks[cursor.kind] = [...(summary.chunks[cursor.kind] ?? []), records.length];\n\t\t} else {\n\t\t\tthis.#budget.start(0);\n\t\t}\n\t\tsummary.locales = [...locales].toSorted(compareUtf16);\n\n\t\tconst nextSeq = records.length > 0 ? cursor.nextSeq + 1 : cursor.nextSeq;\n\t\tif (!kindDone) {\n\t\t\treturn { type: \"cursor\", cursor: { ...cursor, after, nextSeq, summary } };\n\t\t}\n\t\tconst next = this.nextKind(cursor.kind);\n\t\tif (next === null) {\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor: {\n\t\t\t\t\tstage: \"export_finalize\",\n\t\t\t\t\tattempt: cursor.attempt,\n\t\t\t\t\tfence: cursor.fence,\n\t\t\t\t\tnextIndexSeq: 0,\n\t\t\t\t\tafterPath: null,\n\t\t\t\t\tsummary,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\ttype: \"cursor\",\n\t\t\tcursor: { ...cursor, kind: next, after: null, nextSeq: 0, summary },\n\t\t};\n\t}\n\n\t// ── Finalize ──\n\n\tprivate async finalizeUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_finalize\" }>,\n\t): Promise<UnitResult> {\n\t\tif (!this.#budget.canStart()) return { type: \"yield\" };\n\t\tthis.#budget.start();\n\t\tconst summary = readSummary(cursor.summary);\n\n\t\tif (!summary.fenceVerified) {\n\t\t\tconst current = await this.#operations.require(this.#operation.id);\n\t\t\tconst fence = await captureFence(this.#db, current.writeEpoch);\n\t\t\tif (!fencesEqual(cursor.fence, fence)) return this.restart(cursor.attempt);\n\t\t\tawait this.declareDrops(summary);\n\t\t\tsummary.fenceVerified = true;\n\t\t\treturn { type: \"cursor\", cursor: { ...cursor, summary } };\n\t\t}\n\n\t\tconst files = await this.#stagedFiles.list(this.#operation.id, {\n\t\t\tstate: \"verified\",\n\t\t\tafter: cursor.afterPath ?? INDEX_PATHS_END,\n\t\t\tlimit: TRANSFER_LIMITS.chunkRecords,\n\t\t});\n\t\tconst entries: PackageFileEntry[] = [];\n\t\tlet bytes = 0;\n\t\tfor (const file of files) {\n\t\t\tconst parsed = parsePackagePath(file.path);\n\t\t\tif (!parsed || (parsed.type !== \"records\" && parsed.type !== \"media\")) continue;\n\t\t\tconst entry: PackageFileEntry = { path: file.path, bytes: file.bytes, sha256: file.sha256 };\n\t\t\tif (parsed.type === \"records\") {\n\t\t\t\tconst records = summary.chunks[parsed.kind]?.[parsed.seq];\n\t\t\t\tif (records === undefined) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_EXPORT_ERROR\",\n\t\t\t\t\t\t\"Staged chunk is not part of the export\",\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tdetail: { path: file.path },\n\t\t\t\t\t\t},\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tentry.records = records;\n\t\t\t}\n\t\t\tconst size = encoder.encode(JSON.stringify(entry)).byteLength + 1;\n\t\t\tif (entries.length > 0 && bytes + size > TRANSFER_LIMITS.chunkBytes) break;\n\t\t\tentries.push(entry);\n\t\t\tbytes += size;\n\t\t}\n\n\t\tconst lastEntry = entries.at(-1);\n\t\tif (lastEntry) {\n\t\t\tconst ref: IndexChunkRef = await this.#writer.writeIndexChunk(cursor.nextIndexSeq, entries);\n\t\t\tawait this.#stagedFiles.declareMany(\n\t\t\t\tthis.#operation.id,\n\t\t\t\t[{ path: ref.path, bytes: ref.bytes, sha256: ref.sha256 }],\n\t\t\t\t\"verified\",\n\t\t\t);\n\t\t\tsummary.index = [...summary.index, ref];\n\t\t\tsummary.files = {\n\t\t\t\tcount: summary.files.count + entries.length,\n\t\t\t\tbytes: summary.files.bytes + entries.reduce((sum, entry) => sum + entry.bytes, 0),\n\t\t\t};\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor: {\n\t\t\t\t\t...cursor,\n\t\t\t\t\tnextIndexSeq: cursor.nextIndexSeq + 1,\n\t\t\t\t\tafterPath: lastEntry.path,\n\t\t\t\t\tsummary,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tconst manifest = await this.buildManifest(summary, cursor.attempt);\n\t\tconst digest = await this.#writer.writeManifest(manifest);\n\t\tthis.#operation = await this.#operations.advance(this.#operation.id, this.#leaseToken, {\n\t\t\tpackageDigest: digest,\n\t\t});\n\t\treturn { type: \"cursor\", cursor: { stage: \"export_validate\", position: null } };\n\t}\n\n\tprivate async declareDrops(summary: ExportSummary): Promise<void> {\n\t\tfor (const kind of this.exportedKinds()) {\n\t\t\tconst rows = await this.reader(kind).countRows();\n\t\t\tif (rows === null) continue;\n\t\t\tconst exported = (summary.chunks[kind] ?? []).reduce((sum, n) => sum + n, 0);\n\t\t\tconst dropped = rows - exported;\n\t\t\tif (dropped === 0) continue;\n\t\t\tconst code = DROP_CODES[kind];\n\t\t\tif (!code || dropped < 0) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_EXPORT_ERROR\", \"Rows could not be exported\", {\n\t\t\t\t\tdetail: { kind, rows, exported },\n\t\t\t\t});\n\t\t\t}\n\t\t\taddAdjustment(summary, code, kind, dropped);\n\t\t}\n\t}\n\n\tprivate async restart(attempt: number): Promise<UnitResult> {\n\t\tif (attempt >= TRANSFER_LIMITS.exportFenceAttempts) {\n\t\t\treturn {\n\t\t\t\ttype: \"fail\",\n\t\t\t\tcode: \"TRANSFER_EXPORT_CONCURRENT_WRITES\",\n\t\t\t\tdetail: { attempts: attempt },\n\t\t\t};\n\t\t}\n\t\tlet deleted: number;\n\t\tdo {\n\t\t\tdeleted = await this.#stagedFiles.deleteForOperation(this.#operation.id);\n\t\t} while (deleted > 0);\n\t\tawait this.#db\n\t\t\t.deleteFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.where(\"operation_id\", \"=\", this.#operation.id)\n\t\t\t.execute();\n\t\tthis.#operation = await this.#operations.require(this.#operation.id);\n\t\treturn { type: \"cursor\", cursor: await this.start(attempt + 1) };\n\t}\n\n\tprivate async buildManifest(\n\t\tsummary: ExportSummary,\n\t\tattempts: number,\n\t): Promise<SitePackageManifest> {\n\t\tconst totals = await this.#blobs.totals();\n\t\tconst features = new Set<SitePackageFeature>();\n\t\tconst records: SitePackageManifest[\"records\"] = {};\n\t\tfor (const kind of RECORD_KINDS) {\n\t\t\tconst chunks = summary.chunks[kind];\n\t\t\tif (!chunks || chunks.length === 0) continue;\n\t\t\trecords[kind] = { count: chunks.reduce((sum, n) => sum + n, 0), chunks: chunks.length };\n\t\t\tfeatures.add(KIND_FEATURE[kind]);\n\t\t}\n\t\tif (this.#comments) features.add(\"comments\");\n\t\tif (totals.blobs > 0) features.add(\"media\");\n\t\tconst defaultLocale =\n\t\t\tthis.#input.defaultLocale ?? getI18nConfig()?.defaultLocale ?? summary.locales[0] ?? \"en\";\n\t\tconst locales = new Set([...summary.locales, defaultLocale]);\n\t\tif (locales.size > 1) features.add(\"i18n\");\n\t\tif (summary.trash) features.add(\"trash\");\n\t\tconst featureList = [...features].toSorted(compareUtf16);\n\n\t\tconst transformations: ExportTransformation[] = [];\n\t\tfor (const [key, amount] of Object.entries(summary.adjustments)) {\n\t\t\tconst [code, kind] = key.split(\":\");\n\t\t\tconst known = EXPORT_TRANSFORMATION_CODES.find((candidate) => candidate === code);\n\t\t\tconst recordKind = RECORD_KINDS.find((candidate) => candidate === kind);\n\t\t\tif (!known || !recordKind || amount === 0) continue;\n\t\t\ttransformations.push({ code: known, kind: recordKind, count: amount });\n\t\t}\n\t\ttransformations.sort((a, b) => compareUtf16(a.code, b.code) || compareUtf16(a.kind, b.kind));\n\n\t\treturn {\n\t\t\tformat: SITE_PACKAGE_FORMAT,\n\t\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\t\tpackageId: ulid(),\n\t\t\toriginSiteId: await getOrCreateSiteId(this.#db),\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\tcreatedByEmDashVersion: this.#input.emdashVersion ?? VERSION,\n\t\t\tprofile: SITE_PACKAGE_PROFILE,\n\t\t\tfeatures: featureList,\n\t\t\trequiredFeatures: requiredFeaturesFor(featureList),\n\t\t\tlocales: { default: defaultLocale, used: [...locales].toSorted(compareUtf16) },\n\t\t\trecords,\n\t\t\tmedia: { count: totals.blobs, totalBytes: totals.blobBytes },\n\t\t\tfiles: { count: summary.files.count, totalBytes: summary.files.bytes },\n\t\t\tindex: summary.index,\n\t\t\ttransformations,\n\t\t\tfence: { attempts },\n\t\t};\n\t}\n\n\t// ── Validate ──\n\n\tprivate packageReader(): ExportPackageReader {\n\t\tthis.#packageReader ??= new ExportPackageReader(\n\t\t\tthis.#stage,\n\t\t\tthis.#db,\n\t\t\tthis.#input.storage,\n\t\t\tthis.#operation.id,\n\t\t);\n\t\treturn this.#packageReader;\n\t}\n\n\tprivate async validateUnit(\n\t\tcursor: Extract<ExportCursor, { stage: \"export_validate\" }>,\n\t): Promise<UnitResult> {\n\t\tconst reader = this.packageReader();\n\t\tif (cursor.validation === undefined) {\n\t\t\tconst manifest = await reader.manifest();\n\t\t\tconst position = cursor.position ?? firstChunk(manifest);\n\t\t\tif (position === null) {\n\t\t\t\treturn {\n\t\t\t\t\ttype: \"cursor\",\n\t\t\t\t\tcursor: { ...cursor, position: null, validation: { phase: \"validator\", state: null } },\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst path = recordChunkPath(position.kind, position.seq);\n\t\t\tconst staged = await this.#stagedFiles.get(this.#operation.id, path);\n\t\t\tif (!staged) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Record chunk was not staged\", {\n\t\t\t\t\tdetail: { path },\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (!this.#budget.canStart({ bytes: staged.bytes })) return { type: \"yield\" };\n\t\t\tthis.#budget.start(staged.bytes);\n\t\t\tconst { scannable } = await this.keyIndex();\n\t\t\tconst chunk = await reader.readChunk(position.kind, position.seq, staged);\n\t\t\tfor (const record of chunk) {\n\t\t\t\tif (scanForKeys(record.line, scannable).length > 0) {\n\t\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\t\"TRANSFER_MEDIA_REF_INVALID\",\n\t\t\t\t\t\t\"Package holds an origin storage key\",\n\t\t\t\t\t\t{ detail: { kind: position.kind, id: record.record.id } },\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst next = nextChunk(manifest, position);\n\t\t\treturn {\n\t\t\t\ttype: \"cursor\",\n\t\t\t\tcursor:\n\t\t\t\t\tnext === null\n\t\t\t\t\t\t? { ...cursor, position: null, validation: { phase: \"validator\", state: null } }\n\t\t\t\t\t\t: { ...cursor, position: next },\n\t\t\t};\n\t\t}\n\n\t\tconst validation = validationSchema.parse(cursor.validation);\n\t\tconst validate = this.#input.validatePackage;\n\t\tif (!validate) return { type: \"complete\" };\n\t\t// The validator gets a fresh step so its first unit can always start.\n\t\tif (this.#budget.units > 0 || !this.#budget.canStart()) return { type: \"yield\" };\n\t\tconst result = await validate({\n\t\t\tdb: this.#db,\n\t\t\treader,\n\t\t\toperationId: this.#operation.id,\n\t\t\tstate: validation.state,\n\t\t\tbudget: this.#budget,\n\t\t});\n\t\tconst blocker = result.blockers[0];\n\t\tif (blocker) {\n\t\t\treturn {\n\t\t\t\ttype: \"fail\",\n\t\t\t\tcode: \"TRANSFER_EXPORT_ERROR\",\n\t\t\t\tdetail: {\n\t\t\t\t\treason: \"package_invalid\",\n\t\t\t\t\tblocker: blocker.code,\n\t\t\t\t\tkind: blocker.kind ?? null,\n\t\t\t\t\tid: blocker.id ?? null,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (result.done) return { type: \"complete\" };\n\t\treturn {\n\t\t\ttype: \"cursor\",\n\t\t\tcursor: {\n\t\t\t\t...cursor,\n\t\t\t\tvalidation: { phase: \"validator\", state: z.json().parse(result.state ?? null) },\n\t\t\t},\n\t\t\tendStep: true,\n\t\t};\n\t}\n}\n\nfunction firstChunk(\n\tmanifest: SitePackageManifest,\n): { kind: RecordKind; seq: number; line: number } | null {\n\tfor (const kind of RECORD_KINDS) {\n\t\tif ((manifest.records[kind]?.chunks ?? 0) > 0) return { kind, seq: 0, line: 0 };\n\t}\n\treturn null;\n}\n\nfunction nextChunk(\n\tmanifest: SitePackageManifest,\n\tposition: { kind: RecordKind; seq: number },\n): { kind: RecordKind; seq: number; line: number } | null {\n\tif (position.seq + 1 < (manifest.records[position.kind]?.chunks ?? 0)) {\n\t\treturn { kind: position.kind, seq: position.seq + 1, line: 0 };\n\t}\n\tfor (const kind of RECORD_KINDS.slice(RECORD_KINDS.indexOf(position.kind) + 1)) {\n\t\tif ((manifest.records[kind]?.chunks ?? 0) > 0) return { kind, seq: 0, line: 0 };\n\t}\n\treturn null;\n}\n\n// ── Reading a finished export ───────────────────────────────────\n\n/**\n * Reader over an export's staging area. Record and index chunks come from\n * staging; `media/<sha256>` streams from the origin object of a media row\n * hashed to that digest.\n */\nexport class ExportPackageReader extends StagedPackageReader {\n\treadonly #db: Db;\n\treadonly #storage: Storage;\n\treadonly #operationId: string;\n\n\tconstructor(stage: TransferStage, db: Db, storage: Storage, operationId: string) {\n\t\tsuper(stage);\n\t\tthis.#db = db;\n\t\tthis.#storage = storage;\n\t\tthis.#operationId = operationId;\n\t}\n\n\toverride async blob(sha256: string): Promise<ReadableStream<Uint8Array>> {\n\t\tconst row = await this.#db\n\t\t\t.selectFrom(\"_emdash_transfer_media_blobs\")\n\t\t\t.innerJoin(\"media\", \"media.id\", \"_emdash_transfer_media_blobs.media_id\")\n\t\t\t.select([\"media.storage_key as storage_key\"])\n\t\t\t.where(\"_emdash_transfer_media_blobs.operation_id\", \"=\", this.#operationId)\n\t\t\t.where(\"_emdash_transfer_media_blobs.sha256\", \"=\", sha256)\n\t\t\t.orderBy(\"_emdash_transfer_media_blobs.media_id\")\n\t\t\t.executeTakeFirst();\n\t\tif (!row) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Blob is not part of this export\", {\n\t\t\t\tdetail: { path: mediaBlobPath(sha256) },\n\t\t\t});\n\t\t}\n\t\ttry {\n\t\t\treturn (await this.#storage.download(row.storage_key)).body;\n\t\t} catch (error) {\n\t\t\tthrow new TransferError(\"TRANSFER_MEDIA_BLOB_MISSING\", \"Media file is missing from storage\", {\n\t\t\t\tdetail: { path: mediaBlobPath(sha256) },\n\t\t\t\tcause: error,\n\t\t\t});\n\t\t}\n\t}\n}\n\n/** Open a completed (or finalized) export's package for reading. */\nexport function openExportPackage(input: {\n\tdb: Db;\n\tstorage: Storage;\n\toperation: Pick<TransferOperation, \"id\" | \"stagingSecret\">;\n}): ExportPackageReader {\n\tconst stage = new TransferStage(\n\t\tinput.storage,\n\t\tstagingPrefix(\"export\", input.operation.id, input.operation.stagingSecret),\n\t);\n\treturn new ExportPackageReader(stage, input.db, input.storage, input.operation.id);\n}\n","/**\n * `(operation, kind, portableId) → targetId` mappings for one import.\n *\n * Portable ids are written verbatim whenever possible, and a verbatim id\n * needs no row. Rows exist only for rewritten ids and for derived target\n * values (media storage keys, recorded under kind `media_storage_key`).\n * Mappings are scoped to the import operation, so a later import of the same\n * origin after an abandoned one starts with a clean namespace.\n * `origin_site_id` is recorded for diagnostics only.\n */\n\nimport { sql, type Kysely } from \"kysely\";\n\nimport type { Database } from \"../../database/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { bytewise } from \"./collation.js\";\n\n/** Identity-map kind for a media row's target storage key. */\nexport const MEDIA_STORAGE_KEY_ENTITY = \"media_storage_key\";\n\nexport interface IdentityMapping {\n\tportableId: string;\n\ttargetId: string;\n}\n\nexport class TransferIdentityMapRepository {\n\tconstructor(\n\t\tprivate readonly db: Kysely<Database>,\n\t\tprivate readonly originSiteId: string,\n\t\tprivate readonly operationId: string,\n\t) {}\n\n\t/**\n\t * Record mappings; re-recording the same mapping is a no-op. Throws\n\t * `TRANSFER_REFERENCE_INVALID` if a portable id is already mapped to a\n\t * different target id in this operation.\n\t */\n\tasync putMany(entityKind: string, mappings: readonly IdentityMapping[]): Promise<void> {\n\t\tif (mappings.length === 0) return;\n\t\tfor (const batch of chunks([...mappings], rowsPerInsert(5))) {\n\t\t\tawait this.db\n\t\t\t\t.insertInto(\"_emdash_transfer_identity_map\")\n\t\t\t\t.values(\n\t\t\t\t\tbatch.map((mapping) => ({\n\t\t\t\t\t\torigin_site_id: this.originSiteId,\n\t\t\t\t\t\tentity_kind: entityKind,\n\t\t\t\t\t\tportable_id: mapping.portableId,\n\t\t\t\t\t\ttarget_id: mapping.targetId,\n\t\t\t\t\t\toperation_id: this.operationId,\n\t\t\t\t\t})),\n\t\t\t\t)\n\t\t\t\t.onConflict((conflict) =>\n\t\t\t\t\tconflict.columns([\"operation_id\", \"entity_kind\", \"portable_id\"]).doNothing(),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t}\n\t\tconst stored = await this.getMany(\n\t\t\tentityKind,\n\t\t\tmappings.map((mapping) => mapping.portableId),\n\t\t);\n\t\tfor (const mapping of mappings) {\n\t\t\tif (stored.get(mapping.portableId) !== mapping.targetId) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_REFERENCE_INVALID\", \"Conflicting identity mapping\", {\n\t\t\t\t\tdetail: { kind: entityKind, id: mapping.portableId },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\n\tasync put(entityKind: string, mapping: IdentityMapping): Promise<void> {\n\t\tawait this.putMany(entityKind, [mapping]);\n\t}\n\n\tasync get(entityKind: string, portableId: string): Promise<string | null> {\n\t\tconst row = await this.db\n\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t.select(\"target_id\")\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.where(\"entity_kind\", \"=\", entityKind)\n\t\t\t.where(\"portable_id\", \"=\", portableId)\n\t\t\t.executeTakeFirst();\n\t\treturn row?.target_id ?? null;\n\t}\n\n\t/** Mapped target ids by portable id (missing ids are absent from the map). */\n\tasync getMany(entityKind: string, portableIds: readonly string[]): Promise<Map<string, string>> {\n\t\tconst result = new Map<string, string>();\n\t\tfor (const batch of chunks([...new Set(portableIds)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t.select([\"portable_id\", \"target_id\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"entity_kind\", \"=\", entityKind)\n\t\t\t\t.where(\"portable_id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.portable_id, row.target_id);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Portable ids by target id (reverse lookup for verification). */\n\tasync getPortableIds(\n\t\tentityKind: string,\n\t\ttargetIds: readonly string[],\n\t): Promise<Map<string, string>> {\n\t\tconst result = new Map<string, string>();\n\t\tfor (const batch of chunks([...new Set(targetIds)], SQL_BATCH_SIZE)) {\n\t\t\tconst rows = await this.db\n\t\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t.select([\"portable_id\", \"target_id\"])\n\t\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t\t.where(\"entity_kind\", \"=\", entityKind)\n\t\t\t\t.where(\"target_id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of rows) result.set(row.target_id, row.portable_id);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/** Mappings of one kind in portable-id order, for bounded iteration. */\n\tasync list(\n\t\tentityKind: string,\n\t\toptions: { after?: string; limit?: number } = {},\n\t): Promise<IdentityMapping[]> {\n\t\tlet query = this.db\n\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t.select([\"portable_id\", \"target_id\"])\n\t\t\t.where(\"operation_id\", \"=\", this.operationId)\n\t\t\t.where(\"entity_kind\", \"=\", entityKind);\n\t\tconst after = options.after;\n\t\tif (after !== undefined) {\n\t\t\tquery = query.where(sql<boolean>`${bytewise(this.db, \"portable_id\")} > ${after}`);\n\t\t}\n\t\tconst rows = await query\n\t\t\t.orderBy(bytewise(this.db, \"portable_id\"))\n\t\t\t.limit(Math.min(Math.max(options.limit ?? 500, 1), 1000))\n\t\t\t.execute();\n\t\treturn rows.map((row) => ({ portableId: row.portable_id, targetId: row.target_id }));\n\t}\n}\n","/**\n * State shared by one `advanceImport` step.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { isPostgres } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { TransferError } from \"../errors.js\";\nimport {\n\tKIND_REFERENCES,\n\tRECORD_KINDS,\n\ttype RecordKind,\n\ttype RecordOfKind,\n} from \"../format/kinds.js\";\nimport type { SitePackageManifest } from \"../format/manifest.js\";\nimport {\n\tMEDIA_PLACEHOLDER_PREFIX,\n\tPLACEHOLDER_TOKEN,\n\trewriteMediaRefs,\n} from \"../format/media-refs.js\";\nimport type { SiteImportPlan } from \"../format/plan.js\";\nimport type { FieldColumnType } from \"../format/transformations.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { MEDIA_STORAGE_KEY_ENTITY, TransferIdentityMapRepository } from \"../ops/identity-map.js\";\nimport type { TransferOperation, TransferOperationRepository } from \"../ops/operations.js\";\nimport type { StreamPosition } from \"../ops/states.js\";\nimport type { StagedPackageReader, StagedRecord } from \"../staging/package.js\";\n\nconst RECORD_KIND_NAMES: ReadonlySet<string> = new Set(RECORD_KINDS);\n\n/** Identity-map kind marking record-stage units that have started. */\nexport const IMPORT_UNIT_ENTITY = \"import_unit\";\n\ninterface CollectionFields {\n\tcolumns: ReadonlyMap<string, FieldColumnType>;\n\trequired: ReadonlySet<string>;\n}\n\nexport class ImportContext {\n\treadonly float4: boolean;\n\treadonly identity: TransferIdentityMapRepository;\n\treadonly #chunks = new Map<string, Promise<Array<StagedRecord<RecordKind>>>>();\n\treadonly #fields = new Map<string, Promise<CollectionFields>>();\n\t#rewrittenKinds: Promise<Set<string>> | undefined;\n\t/** Whether the running unit is on its first attempt (see `beginUnit`). */\n\tfirstAttempt = false;\n\n\tconstructor(\n\t\treadonly db: Kysely<Database>,\n\t\treadonly storage: Storage,\n\t\treadonly ops: TransferOperationRepository,\n\t\tpublic operation: TransferOperation,\n\t\treadonly leaseToken: string,\n\t\treadonly plan: SiteImportPlan,\n\t\treadonly manifest: SitePackageManifest,\n\t\treadonly reader: StagedPackageReader,\n\t\treadonly budget: TransferStepBudget,\n\t) {\n\t\tthis.float4 = isPostgres(db);\n\t\tthis.identity = new TransferIdentityMapRepository(db, manifest.originSiteId, operation.id);\n\t}\n\n\tget operationId(): string {\n\t\treturn this.operation.id;\n\t}\n\n\tchunkCount(kind: RecordKind): number {\n\t\treturn this.manifest.records[kind]?.chunks ?? 0;\n\t}\n\n\t/** Records of one chunk, parsed once per step. */\n\tasync chunk<K extends RecordKind>(kind: K, seq: number): Promise<Array<StagedRecord<K>>> {\n\t\tconst key = `${kind}/${seq}`;\n\t\tlet pending = this.#chunks.get(key);\n\t\tif (!pending) {\n\t\t\tpending = this.reader.readChunk(kind, seq);\n\t\t\tthis.#chunks.set(key, pending);\n\t\t}\n\t\treturn pending;\n\t}\n\n\t/** Every record of `kind`, for small kinds read as a whole (collections, fields). */\n\tasync allRecords<K extends RecordKind>(kind: K): Promise<Array<RecordOfKind<K>>> {\n\t\tconst records: Array<RecordOfKind<K>> = [];\n\t\tfor (let seq = 0; seq < this.chunkCount(kind); seq++) {\n\t\t\tfor (const staged of await this.chunk(kind, seq)) records.push(staged.record);\n\t\t}\n\t\treturn records;\n\t}\n\n\t/** Target column type of each field of a collection, from the imported schema. */\n\tasync fieldColumns(collection: string): Promise<ReadonlyMap<string, FieldColumnType>> {\n\t\treturn (await this.fields(collection)).columns;\n\t}\n\n\t/** Slugs of a collection's required (NOT NULL) fields, from the imported schema. */\n\tasync requiredFields(collection: string): Promise<ReadonlySet<string>> {\n\t\treturn (await this.fields(collection)).required;\n\t}\n\n\tprivate fields(collection: string): Promise<CollectionFields> {\n\t\tlet pending = this.#fields.get(collection);\n\t\tif (!pending) {\n\t\t\tpending = this.db\n\t\t\t\t.selectFrom(\"_emdash_fields\")\n\t\t\t\t.innerJoin(\"_emdash_collections\", \"_emdash_collections.id\", \"_emdash_fields.collection_id\")\n\t\t\t\t.select([\n\t\t\t\t\t\"_emdash_fields.slug as slug\",\n\t\t\t\t\t\"_emdash_fields.column_type as column_type\",\n\t\t\t\t\t\"_emdash_fields.required as required\",\n\t\t\t\t])\n\t\t\t\t.where(\"_emdash_collections.slug\", \"=\", collection)\n\t\t\t\t.execute()\n\t\t\t\t.then((rows) => ({\n\t\t\t\t\tcolumns: new Map(\n\t\t\t\t\t\trows.map((row) => [row.slug, toFieldColumnType(row.column_type)] as const),\n\t\t\t\t\t),\n\t\t\t\t\trequired: new Set(\n\t\t\t\t\t\trows.filter((row) => Number(row.required) === 1).map((row) => row.slug),\n\t\t\t\t\t),\n\t\t\t\t}));\n\t\t\tthis.#fields.set(collection, pending);\n\t\t}\n\t\treturn pending;\n\t}\n\n\t/**\n\t * Record that the unit at `position` of `stage` is starting and set\n\t * `firstAttempt`: false when an earlier, interrupted step already started\n\t * it, so rows it finds may be its own partial writes.\n\t */\n\tasync beginUnit(stage: string, position: StreamPosition): Promise<void> {\n\t\tconst result = await this.db\n\t\t\t.insertInto(\"_emdash_transfer_identity_map\")\n\t\t\t.values({\n\t\t\t\torigin_site_id: this.manifest.originSiteId,\n\t\t\t\toperation_id: this.operation.id,\n\t\t\t\tentity_kind: IMPORT_UNIT_ENTITY,\n\t\t\t\tportable_id: `${stage}:${position.kind}:${position.seq}:${position.line}`,\n\t\t\t\ttarget_id: \"started\",\n\t\t\t})\n\t\t\t.onConflict((conflict) =>\n\t\t\t\tconflict.columns([\"operation_id\", \"entity_kind\", \"portable_id\"]).doNothing(),\n\t\t\t)\n\t\t\t.executeTakeFirst();\n\t\tthis.firstAttempt = Number(result.numInsertedOrUpdatedRows ?? 0n) > 0;\n\t}\n\n\tprincipalTarget(principal: string | undefined): string | null {\n\t\tif (principal === undefined) return null;\n\t\tconst mappings = this.plan.decisions.principalMappings;\n\t\treturn Object.hasOwn(mappings, principal) ? (mappings[principal] ?? null) : null;\n\t}\n\n\t/**\n\t * Replace every `emdash-media:` placeholder in `records` with the target\n\t * storage key the media stage recorded, and unescape escaped placeholder\n\t * text. Throws `TRANSFER_MEDIA_REF_INVALID` for a placeholder whose media\n\t * was not imported.\n\t */\n\tasync resolveMediaRefs<R extends { kind: RecordKind; id: string }>(\n\t\trecords: readonly R[],\n\t\tlines: readonly string[],\n\t): Promise<R[]> {\n\t\tconst mediaIds = new Set<string>();\n\t\tlet marked = false;\n\t\tfor (const line of lines) {\n\t\t\tif (!line.includes(MEDIA_PLACEHOLDER_PREFIX)) continue;\n\t\t\tmarked = true;\n\t\t\tfor (const match of line.matchAll(PLACEHOLDER_TOKEN)) {\n\t\t\t\tif (match[2] !== undefined) mediaIds.add(match[2]);\n\t\t\t}\n\t\t}\n\t\tif (!marked) return [...records];\n\t\tconst mediaIdToKey = await this.identity.getMany(MEDIA_STORAGE_KEY_ENTITY, [...mediaIds]);\n\t\treturn records.map((record) => {\n\t\t\tconst result = rewriteMediaRefs(record, { mode: \"import\", mediaIdToKey });\n\t\t\tconst error = result.errors[0];\n\t\t\tif (error) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_MEDIA_REF_INVALID\", \"Unresolved media reference\", {\n\t\t\t\t\tdetail: { kind: record.kind, id: record.id, path: error.path },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn result.value;\n\t\t});\n\t}\n\n\t/** Record kinds that have at least one rewritten id in this import. */\n\trewrittenKinds(): Promise<Set<string>> {\n\t\tthis.#rewrittenKinds ??= this.db\n\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t.select(\"entity_kind\")\n\t\t\t.distinct()\n\t\t\t.where(\"operation_id\", \"=\", this.operation.id)\n\t\t\t.execute()\n\t\t\t.then((rows) => new Set(rows.map((row) => row.entity_kind).filter(isRecordKindName)));\n\t\treturn this.#rewrittenKinds;\n\t}\n\n\tnoteRewrite(kind: RecordKind): void {\n\t\tconst current = this.#rewrittenKinds;\n\t\tthis.#rewrittenKinds = (current ?? Promise.resolve(new Set<string>())).then((kinds) =>\n\t\t\tkinds.add(kind),\n\t\t);\n\t}\n\n\t/**\n\t * Target ids for the records' own ids and every `by: \"id\"` reference,\n\t * keyed `kind\\u0000portableId`. Ids without a rewrite are absent.\n\t */\n\tasync rewrittenIds(\n\t\tkind: RecordKind,\n\t\trecords: ReadonlyArray<Record<string, unknown>>,\n\t): Promise<Map<string, string>> {\n\t\tconst rewritten = await this.rewrittenKinds();\n\t\tconst result = new Map<string, string>();\n\t\tif (rewritten.size === 0) return result;\n\t\tconst wanted = new Map<string, Set<string>>();\n\t\tconst want = (targetKind: RecordKind, id: unknown) => {\n\t\t\tif (typeof id !== \"string\" || !rewritten.has(targetKind)) return;\n\t\t\tlet ids = wanted.get(targetKind);\n\t\t\tif (!ids) wanted.set(targetKind, (ids = new Set()));\n\t\t\tids.add(id);\n\t\t};\n\t\tfor (const record of records) {\n\t\t\twant(kind, record.id);\n\t\t\tfor (const reference of KIND_REFERENCES[kind]) {\n\t\t\t\tif (reference.by !== \"id\") continue;\n\t\t\t\tfor (const target of reference.targets) want(target, record[reference.property]);\n\t\t\t}\n\t\t}\n\t\tfor (const [targetKind, ids] of wanted) {\n\t\t\tfor (const [portableId, targetId] of await this.identity.getMany(targetKind, [...ids])) {\n\t\t\t\tresult.set(`${targetKind}\\u0000${portableId}`, targetId);\n\t\t\t}\n\t\t}\n\t\treturn result;\n\t}\n}\n\nfunction isRecordKindName(value: string): boolean {\n\treturn RECORD_KIND_NAMES.has(value);\n}\n\nfunction toFieldColumnType(value: string): FieldColumnType {\n\tswitch (value) {\n\t\tcase \"REAL\":\n\t\tcase \"INTEGER\":\n\t\tcase \"JSON\":\n\t\t\treturn value;\n\t\tdefault:\n\t\t\treturn \"TEXT\";\n\t}\n}\n\n/** Apply rewritten ids to a record's own id and `by: \"id\"` references. */\nexport function applyRewrittenIds<R extends { kind: RecordKind; id: string }>(\n\trecord: R,\n\trewritten: ReadonlyMap<string, string>,\n): R {\n\tif (rewritten.size === 0) return record;\n\tconst next: Record<string, unknown> = { ...record };\n\tconst own = rewritten.get(`${record.kind}\\u0000${record.id}`);\n\tif (own !== undefined) next.id = own;\n\tfor (const reference of KIND_REFERENCES[record.kind]) {\n\t\tif (reference.by !== \"id\") continue;\n\t\tconst value = next[reference.property];\n\t\tif (typeof value !== \"string\") continue;\n\t\tfor (const target of reference.targets) {\n\t\t\tconst mapped = rewritten.get(`${target}\\u0000${value}`);\n\t\t\tif (mapped !== undefined) {\n\t\t\t\tnext[reference.property] = mapped;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- same record with id-valued properties replaced\n\treturn next as R;\n}\n","/**\n * Deterministic ids and opaque values derived from an import operation, so a\n * replayed batch writes exactly what the interrupted attempt wrote.\n */\n\nimport { sha256Hex } from \"../format/digest.js\";\n\nconst CROCKFORD = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\n\n/**\n * A ULID-shaped id (26 Crockford base32 characters) derived from the SHA-256\n * of `parts`. Stable for the same inputs; the leading character is always in\n * `0`–`7`, as in a real ULID.\n */\nexport async function ulidFromHash(...parts: string[]): Promise<string> {\n\tconst hex = await sha256Hex(parts.join(\"\\u0000\"));\n\tlet bits = BigInt(`0x${hex.slice(0, 32)}`);\n\tlet id = \"\";\n\tfor (let index = 0; index < 26; index++) {\n\t\tid = CROCKFORD[Number(bits & 31n)] + id;\n\t\tbits >>= 5n;\n\t}\n\treturn id;\n}\n\n/** Hex HMAC-SHA-256 of `message` under `secret`. */\nexport async function hmacHex(secret: string, message: string): Promise<string> {\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tencoder.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"sign\"],\n\t);\n\tconst signature = await crypto.subtle.sign(\"HMAC\", key, encoder.encode(message));\n\treturn Array.from(new Uint8Array(signature), (byte) => byte.toString(16).padStart(2, \"0\")).join(\n\t\t\"\",\n\t);\n}\n","/**\n * Per-kind writers for every record kind that maps to one row of a fixed\n * table (everything except collections, fields, and entries).\n *\n * A batch is inserted with `ON CONFLICT DO NOTHING` and read back; each\n * stored row must equal the row the importer meant to write, so replaying a\n * batch after an interruption is a no-op. When a row keyed by a portable id\n * already exists with different content, that id belongs to an unrelated\n * target row: the record is written under a deterministic rewritten id,\n * recorded in the identity map, and later `by: \"id\"` references follow it.\n * Any other conflict (another unique constraint, a row that differs after a\n * rewrite) fails the batch with `TRANSFER_IMPORT_ERROR`; where the database\n * has transactions, the failed batch leaves no rows behind.\n */\n\nimport { sql } from \"kysely\";\nimport { ulid } from \"ulidx\";\n\nimport { withTransaction } from \"../../database/transaction.js\";\nimport { fingerprintBlockFields } from \"../../schema/block-type-contract.js\";\nimport type { BlockFieldDefinition } from \"../../schema/block-types.js\";\nimport { TransferError } from \"../errors.js\";\nimport { getPortableTableSpecForKind } from \"../format/columns.js\";\nimport type { ColumnCodec } from \"../format/columns.js\";\nimport type { RecordKind, RecordOfKind, SitePackageRecord } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { DECIDED_SETTING_NAMES } from \"../format/settings.js\";\nimport { applyTransformations } from \"../format/transformations.js\";\nimport { applyRewrittenIds, type ImportContext } from \"./context.js\";\nimport { hmacHex, ulidFromHash } from \"./ids.js\";\nimport { encodeRecord, firstDifference, recordCodecs, type Row } from \"./rows.js\";\nimport { estimateStatements, insertRows, selectByKeys, type ConflictAction } from \"./sql.js\";\n\nexport type FlatKind = Exclude<RecordKind, \"principal\" | \"collection\" | \"field\" | \"entry\">;\n\ninterface FlatKindConfig {\n\t/** Columns identifying a row. Only `[\"id\"]` kinds can have their id rewritten. */\n\tkey: readonly string[];\n\tconflict?: ConflictAction;\n\t/** Columns the importer fills that records do not carry. */\n\tderived?: (context: ImportContext, record: SitePackageRecord) => Promise<Row> | Row;\n}\n\nconst ID_KEY = [\"id\"] as const;\n\nasync function blockTypeVersionFingerprint(record: SitePackageRecord): Promise<Row> {\n\tif (record.kind !== \"block_type_version\") throw new Error(\"Expected a block type version\");\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- analysis refuses fields that `validateBlockFields` rejects\n\tconst fields = record.fields as unknown as BlockFieldDefinition[];\n\treturn { fingerprint: await fingerprintBlockFields(fields) };\n}\n\nconst FLAT_KINDS: Readonly<Record<FlatKind, FlatKindConfig>> = {\n\tblock_type: { key: ID_KEY },\n\tblock_type_version: {\n\t\tkey: ID_KEY,\n\t\tderived: (_context, record) => blockTypeVersionFingerprint(record),\n\t},\n\ttaxonomy_def: { key: ID_KEY },\n\trelation: { key: ID_KEY },\n\tbyline_field: { key: ID_KEY },\n\tmedia_folder: { key: ID_KEY },\n\tmedia: { key: ID_KEY },\n\tterm: { key: ID_KEY },\n\tbyline: { key: ID_KEY },\n\tbyline_field_value: { key: [\"byline_id\", \"field_id\"] },\n\tbyline_field_group_value: { key: [\"translation_group\", \"field_id\"] },\n\trevision: { key: ID_KEY },\n\tcontent_term: { key: [\"collection\", \"entry_id\", \"taxonomy_id\"] },\n\tcontent_byline: { key: ID_KEY },\n\tcontent_reference: { key: ID_KEY },\n\tseo: { key: [\"collection\", \"content_id\"] },\n\tmenu: { key: ID_KEY },\n\tmenu_item: { key: ID_KEY },\n\twidget_area: { key: ID_KEY },\n\twidget: { key: ID_KEY },\n\tsection: { key: ID_KEY },\n\tredirect: {\n\t\tkey: ID_KEY,\n\t\tderived: () => ({ config_revision: ulid(), source_guard: 1, write_generation: 0 }),\n\t},\n\tcomment: { key: ID_KEY },\n\tcomment_reaction: {\n\t\tkey: ID_KEY,\n\t\tderived: async (context, record) => ({\n\t\t\tvoter_hash: await hmacHex(context.operation.stagingSecret, `comment_reaction:${record.id}`),\n\t\t}),\n\t},\n\tsetting: {\n\t\tkey: [\"name\"],\n\t\tconflict: { type: \"update\", target: [\"name\"], update: [\"value\", \"revision\"] },\n\t\tderived: () => ({ revision: ulid() }),\n\t},\n};\n\nconst NO_FIELD_COLUMNS = new Map();\n\n/**\n * Identity-map kind recording each redirect the importer wrote disabled\n * because it would close a loop with the redirects written before it.\n * Verification reads it to predict those redirects.\n */\nexport const REDIRECT_LOOP_ENTITY = \"redirect_loop_disabled\";\n\n/** Redirects checked for loops per query: up to three bound parameters each. */\nconst REDIRECT_LOOP_BATCH = rowsPerInsert(3);\n\nexport function isFlatKind(kind: RecordKind): kind is FlatKind {\n\treturn Object.hasOwn(FLAT_KINDS, kind);\n}\n\nfunction tableOf(kind: FlatKind) {\n\tconst spec = getPortableTableSpecForKind(kind);\n\tif (!spec) throw new Error(`No table for kind ${kind}`);\n\treturn spec;\n}\n\n/** Statements one `writeRecords` call for `count` records of `kind` needs. */\nexport function estimateWrite(kind: FlatKind, count: number): number {\n\tconst spec = tableOf(kind);\n\tconst statements = (rows: number) =>\n\t\testimateStatements(rows, Object.keys(spec.columns).length, FLAT_KINDS[kind].key.length) + 3;\n\tif (kind !== \"redirect\") return statements(count);\n\tconst batches = Math.ceil(count / REDIRECT_LOOP_BATCH);\n\treturn batches * (3 + statements(REDIRECT_LOOP_BATCH));\n}\n\nexport interface WriteInput<K extends RecordKind> {\n\trecord: RecordOfKind<K>;\n\t/** The record's canonical line, scanned for media placeholders. */\n\tline: string;\n}\n\nexport interface WriteOptions {\n\t/** Extra columns per portable id, compared like record columns. */\n\textra?: (record: { id: string }) => { row: Row; codecs: Readonly<Record<string, ColumnCodec>> };\n}\n\n/** Records that were actually written (decided settings may be skipped). */\nexport async function writeRecords<K extends FlatKind>(\n\tcontext: ImportContext,\n\tkind: K,\n\tinputs: ReadonlyArray<WriteInput<K>>,\n\toptions: WriteOptions = {},\n): Promise<Array<RecordOfKind<K>>> {\n\tconst skipped = skippedSettings(context);\n\tconst selected = inputs.filter((input) => kind !== \"setting\" || !skipped.has(input.record.id));\n\tif (selected.length === 0) return [];\n\tconst transformed = selected.map((input) =>\n\t\tapplyTransformations(input.record, context.plan, { fieldColumnTypes: NO_FIELD_COLUMNS }),\n\t);\n\tconst resolved = await context.resolveMediaRefs(\n\t\ttransformed,\n\t\tselected.map((input) => input.line),\n\t);\n\tif (kind !== \"redirect\") {\n\t\tawait writeResolved(context, kind, resolved, options, false);\n\t\treturn resolved;\n\t}\n\tconst written: Array<RecordOfKind<K>> = [];\n\tfor (let start = 0; start < resolved.length; start += REDIRECT_LOOP_BATCH) {\n\t\tconst batch = resolved.slice(start, start + REDIRECT_LOOP_BATCH);\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- kind is \"redirect\"\n\t\tconst redirects = await disableLoopClosers(context, batch as Array<RecordOfKind<\"redirect\">>);\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- the same redirect records\n\t\tconst records = redirects as unknown as Array<RecordOfKind<K>>;\n\t\tawait writeResolved(context, kind, records, options, false);\n\t\twritten.push(...records);\n\t}\n\treturn written;\n}\n\n/**\n * The database refuses an enabled redirect that closes a loop of enabled\n * redirects (by exact source and destination). An origin can still hold such\n * a loop, and analysis only finds loops in packages of up to\n * `MAX_LOOP_CHECKED_REDIRECTS` redirects, so each redirect that would close\n * one with the redirects written before it (target rows, then the enabled\n * earlier records of `records`) is written disabled and recorded under\n * {@link REDIRECT_LOOP_ENTITY}. Rows of `records` already in the table (from\n * an interrupted attempt) are ignored, so a replay decides the same way.\n */\nasync function disableLoopClosers(\n\tcontext: ImportContext,\n\trecords: ReadonlyArray<RecordOfKind<\"redirect\">>,\n): Promise<Array<RecordOfKind<\"redirect\">>> {\n\tconst candidates = records.filter((record) => record.enabled && record.destination !== \"\");\n\tif (candidates.length === 0) return [...records];\n\tconst reach = await reachableSources(context, candidates);\n\n\tconst closers = new Set<string>();\n\tcandidates.forEach((record, index) => {\n\t\tconst earlier = candidates.slice(0, index).filter((other) => !closers.has(other.id));\n\t\tconst queue = [{ node: record.destination, moved: false }];\n\t\tconst taken = new Set<string>();\n\t\twhile (queue.length > 0) {\n\t\t\tconst { node, moved } = queue.shift()!;\n\t\t\tfor (const source of reach.get(node) ?? []) {\n\t\t\t\t// Reaching the start node itself without following a redirect is not a loop.\n\t\t\t\tif (source === record.source && (moved || source !== node)) {\n\t\t\t\t\tclosers.add(record.id);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const other of earlier) {\n\t\t\t\t\tif (other.source !== source || taken.has(other.id)) continue;\n\t\t\t\t\ttaken.add(other.id);\n\t\t\t\t\tqueue.push({ node: other.destination, moved: true });\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t});\n\tif (closers.size === 0) return [...records];\n\tawait context.identity.putMany(\n\t\tREDIRECT_LOOP_ENTITY,\n\t\tArray.from(closers, (id) => ({ portableId: id, targetId: id })),\n\t);\n\treturn records.map((record) => (closers.has(record.id) ? { ...record, enabled: false } : record));\n}\n\n/**\n * For each candidate's destination, the candidate sources reachable from it\n * through enabled target redirects (including the destination itself when it\n * is one). Follows `idx_redirects_source` from each destination only;\n * `enabled <> 0` rather than `enabled = 1` keeps SQLite from choosing\n * `idx_redirects_enabled` and scanning every enabled redirect per step.\n */\nasync function reachableSources(\n\tcontext: ImportContext,\n\tcandidates: ReadonlyArray<RecordOfKind<\"redirect\">>,\n): Promise<Map<string, Set<string>>> {\n\tconst starts = [...new Set(candidates.map((record) => record.destination))];\n\tconst sources = [...new Set(candidates.map((record) => record.source))];\n\tconst result = await sql<{ start: string; node: string }>`\n\t\tWITH RECURSIVE starts(node) AS (VALUES ${sql.join(starts.map((node) => sql`(${node})`))}),\n\t\treach(start, node) AS (\n\t\t\tSELECT node, node FROM starts\n\t\t\tUNION\n\t\t\tSELECT reach.start, redirect.destination\n\t\t\tFROM reach JOIN _emdash_redirects AS redirect ON redirect.source = reach.node\n\t\t\tWHERE redirect.enabled <> 0 AND redirect.destination <> ''\n\t\t\t\tAND redirect.id NOT IN (${sql.join(candidates.map((record) => record.id))})\n\t\t)\n\t\tSELECT start, node FROM reach WHERE node IN (${sql.join(sources)})\n\t`.execute(context.db);\n\tconst reach = new Map<string, Set<string>>();\n\tfor (const row of result.rows) {\n\t\tconst reached = reach.get(row.start) ?? new Set<string>();\n\t\treached.add(row.node);\n\t\treach.set(row.start, reached);\n\t}\n\treturn reach;\n}\n\nfunction skippedSettings(context: ImportContext): ReadonlySet<string> {\n\tconst { decisions } = context.plan;\n\treturn new Set<string>([\n\t\t...(decisions.siteTitle === \"target\" ? DECIDED_SETTING_NAMES.title : []),\n\t\t...(decisions.siteTagline === \"target\" ? DECIDED_SETTING_NAMES.tagline : []),\n\t]);\n}\n\nfunction keyString(key: readonly string[], row: Row): string {\n\treturn key.map((column) => String(row[column])).join(\"\\u0000\");\n}\n\nexport function uniqueConflict(kind: RecordKind, id: string): TransferError {\n\treturn new TransferError(\n\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\"Record conflicts with another target row on a unique key\",\n\t\t{ detail: { kind, id, reason: \"unique_conflict\" } },\n\t);\n}\n\n/**\n * Decide what a stored row that differs from its record means. The row can\n * be one this import wrote in an interrupted attempt of the same unit: then\n * the difference is an importer defect, never a collision, and the import\n * fails with `stored_row_mismatch`. Only on a unit's first attempt can the row\n * predate the import, and only a row keyed by the record's own id can then\n * move aside: the record is rewritten to a new id. Anything else is a\n * `collision` the import cannot resolve.\n */\nexport function assertRewritable(\n\tcontext: ImportContext,\n\trow: { kind: RecordKind; id: string; column: string; idKeyed: boolean; rewritten: boolean },\n): void {\n\tconst detail = { kind: row.kind, id: row.id, column: row.column };\n\tif (!context.firstAttempt) {\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\"A row this import wrote does not read back as its record\",\n\t\t\t{ detail: { ...detail, reason: \"stored_row_mismatch\" } },\n\t\t);\n\t}\n\tif (!row.idKeyed || row.rewritten) {\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\"Record collides with an existing target row\",\n\t\t\t{\n\t\t\t\tdetail: { ...detail, reason: \"collision\" },\n\t\t\t},\n\t\t);\n\t}\n}\n\nasync function writeResolved<K extends FlatKind>(\n\tcontext: ImportContext,\n\tkind: K,\n\trecords: ReadonlyArray<RecordOfKind<K>>,\n\toptions: WriteOptions,\n\tretry: boolean,\n): Promise<void> {\n\tconst spec = tableOf(kind);\n\tconst config = FLAT_KINDS[kind];\n\tconst rewritten = await context.rewrittenIds(kind, records);\n\tconst codecs: Record<string, ColumnCodec> = { ...recordCodecs(spec.columns) };\n\tconst rows: Row[] = [];\n\tfor (const record of records) {\n\t\tconst target = applyRewrittenIds(record, rewritten);\n\t\tconst row = {\n\t\t\t...encodeRecord(context.db, spec.columns, target, { kind, id: record.id }),\n\t\t\t...(config.derived ? await config.derived(context, record) : {}),\n\t\t};\n\t\tconst extra = options.extra?.(record);\n\t\tif (extra) {\n\t\t\tObject.assign(row, extra.row);\n\t\t\tObject.assign(codecs, extra.codecs);\n\t\t}\n\t\trows.push(row);\n\t}\n\tconst columns = Object.keys(rows[0] ?? {});\n\tconst collisions = await withTransaction(context.db, async (trx) => {\n\t\tawait insertRows(trx, spec.table, columns, rows, config.conflict);\n\t\tconst stored = new Map(\n\t\t\t(await selectByKeys(trx, spec.table, config.key, rows)).map((row) => [\n\t\t\t\tkeyString(config.key, row),\n\t\t\t\trow,\n\t\t\t]),\n\t\t);\n\t\tconst found: Array<RecordOfKind<K>> = [];\n\t\trows.forEach((row, index) => {\n\t\t\tconst record = records[index];\n\t\t\tif (!record) return;\n\t\t\tconst existing = stored.get(keyString(config.key, row));\n\t\t\tif (!existing) throw uniqueConflict(kind, record.id);\n\t\t\tconst column = firstDifference(context.db, codecs, row, existing, { float4: context.float4 });\n\t\t\tif (column === null) return;\n\t\t\tassertRewritable(context, {\n\t\t\t\tkind,\n\t\t\t\tid: record.id,\n\t\t\t\tcolumn,\n\t\t\t\tidKeyed: config.key === ID_KEY,\n\t\t\t\trewritten: retry || rewritten.has(`${kind}\\u0000${record.id}`),\n\t\t\t});\n\t\t\tfound.push(record);\n\t\t});\n\t\treturn found;\n\t});\n\tif (collisions.length === 0) return;\n\n\tconst mappings = await Promise.all(\n\t\tcollisions.map(async (record) => ({\n\t\t\tportableId: record.id,\n\t\t\ttargetId: await ulidFromHash(context.operationId, kind, record.id),\n\t\t})),\n\t);\n\tawait context.identity.putMany(kind, mappings);\n\tcontext.noteRewrite(kind);\n\tawait writeResolved(context, kind, collisions, options, true);\n}\n","/**\n * Entry writer: rows of the dynamic `ec_*` content tables.\n *\n * Standard columns come from `CONTENT_TABLE_COLUMNS`, field columns from the\n * imported `_emdash_fields` rows. A row that needs more bound parameters than\n * one D1 statement allows is inserted with its standard columns first and\n * its field columns set by batched `UPDATE`s, after checking that the stored\n * standard columns are the importer's own.\n */\n\nimport type { Kysely } from \"kysely\";\n\nimport { withTransaction } from \"../../database/transaction.js\";\nimport type { Database } from \"../../database/types.js\";\nimport { validateIdentifier } from \"../../database/validate.js\";\nimport { TransferError } from \"../errors.js\";\nimport {\n\tcodecForColumnType,\n\tCONTENT_TABLE_COLUMNS,\n\tCONTENT_TABLE_PREFIX,\n} from \"../format/columns.js\";\nimport type { ColumnCodec } from \"../format/columns.js\";\nimport type { EntryRecord } from \"../format/kinds.js\";\nimport { rowsPerInsert } from \"../format/limits.js\";\nimport { applyTransformations, type FieldColumnType } from \"../format/transformations.js\";\nimport { applyRewrittenIds, type ImportContext } from \"./context.js\";\nimport { ulidFromHash } from \"./ids.js\";\nimport { encodeRecord, encodeValue, firstDifference, recordCodecs, type Row } from \"./rows.js\";\nimport { estimateStatements, insertRows, selectByKeys, updateColumns } from \"./sql.js\";\nimport { assertRewritable, uniqueConflict, type WriteInput } from \"./writers.js\";\n\nconst STANDARD_CODECS = recordCodecs(CONTENT_TABLE_COLUMNS);\nconst STANDARD_COLUMNS = Object.keys(STANDARD_CODECS);\n\nexport function contentTable(collection: string): string {\n\tvalidateIdentifier(collection, \"collection slug\");\n\treturn `${CONTENT_TABLE_PREFIX}${collection}`;\n}\n\n/** Statements for `count` entries of a collection with `fieldCount` fields. */\nexport function estimateEntryWrite(count: number, fieldCount: number): number {\n\tconst columns = STANDARD_COLUMNS.length + fieldCount;\n\tif (rowsPerInsert(columns) === 0) {\n\t\treturn count * (2 + Math.ceil(fieldCount / 99)) + Math.ceil(count / 100) + 3;\n\t}\n\treturn estimateStatements(count, columns) + 3;\n}\n\nexport async function writeEntries(\n\tcontext: ImportContext,\n\tinputs: ReadonlyArray<WriteInput<\"entry\">>,\n): Promise<void> {\n\tconst byCollection = new Map<string, Array<WriteInput<\"entry\">>>();\n\tfor (const input of inputs) {\n\t\tconst list = byCollection.get(input.record.collection) ?? [];\n\t\tlist.push(input);\n\t\tbyCollection.set(input.record.collection, list);\n\t}\n\tfor (const [collection, group] of byCollection) {\n\t\tconst fieldColumns = await context.fieldColumns(collection);\n\t\tconst fieldColumnTypes = new Map([[collection, fieldColumns]]);\n\t\tconst transformed = group.map((input) =>\n\t\t\tapplyTransformations(input.record, context.plan, { fieldColumnTypes }),\n\t\t);\n\t\tconst resolved = await context.resolveMediaRefs(\n\t\t\ttransformed,\n\t\t\tgroup.map((input) => input.line),\n\t\t);\n\t\tawait writeCollectionEntries(context, collection, fieldColumns, resolved, false);\n\t}\n}\n\nfunction fieldCodecs(\n\tfieldColumns: ReadonlyMap<string, FieldColumnType>,\n): Record<string, ColumnCodec> {\n\tconst codecs: Record<string, ColumnCodec> = {};\n\tfor (const [slug, columnType] of fieldColumns) codecs[slug] = codecForColumnType(columnType);\n\treturn codecs;\n}\n\nfunction entryRow(\n\tdb: Kysely<Database>,\n\trecord: EntryRecord,\n\tcodecs: Readonly<Record<string, ColumnCodec>>,\n\trequired: ReadonlySet<string>,\n): Row {\n\tconst row = encodeRecord(db, CONTENT_TABLE_COLUMNS, record, { kind: \"entry\", id: record.id });\n\tfor (const slug of Object.keys(record.fields)) {\n\t\tif (!Object.hasOwn(codecs, slug)) {\n\t\t\tthrow new TransferError(\"TRANSFER_RECORD_INVALID\", \"Entry has a field its collection lacks\", {\n\t\t\t\tdetail: { kind: \"entry\", id: record.id, field: slug },\n\t\t\t});\n\t\t}\n\t}\n\tfor (const [slug, codec] of Object.entries(codecs)) {\n\t\trow[slug] = encodeValue(\n\t\t\tdb,\n\t\t\tcodec,\n\t\t\trecord.fields[slug],\n\t\t\t{ kind: \"entry\", id: record.id, column: slug },\n\t\t\t{ notNull: required.has(slug) },\n\t\t);\n\t}\n\treturn row;\n}\n\nasync function writeCollectionEntries(\n\tcontext: ImportContext,\n\tcollection: string,\n\tfieldColumns: ReadonlyMap<string, FieldColumnType>,\n\trecords: readonly EntryRecord[],\n\tretry: boolean,\n): Promise<void> {\n\tconst table = contentTable(collection);\n\tconst fields = fieldCodecs(fieldColumns);\n\tconst required = await context.requiredFields(collection);\n\tconst codecs = { ...STANDARD_CODECS, ...fields };\n\tconst rewritten = await context.rewrittenIds(\"entry\", records);\n\tconst rows = records.map((record) =>\n\t\tentryRow(context.db, applyRewrittenIds(record, rewritten), fields, required),\n\t);\n\tconst columns = Object.keys(codecs);\n\tconst wide = rowsPerInsert(columns.length) === 0;\n\n\tconst collisions = await withTransaction(context.db, async (trx) => {\n\t\tawait insertRows(trx, table, wide ? STANDARD_COLUMNS : columns, rows);\n\t\tlet stored = await storedById(trx, table, rows);\n\t\tif (wide) {\n\t\t\tconst fieldSlugs = Object.keys(fields);\n\t\t\tfor (const row of rows) {\n\t\t\t\tconst existing = stored.get(String(row.id));\n\t\t\t\tif (\n\t\t\t\t\t!existing ||\n\t\t\t\t\tfirstDifference(context.db, STANDARD_CODECS, row, existing, {\n\t\t\t\t\t\tfloat4: context.float4,\n\t\t\t\t\t}) !== null\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tawait updateColumns(trx, table, \"id\", String(row.id), row, fieldSlugs);\n\t\t\t}\n\t\t\tstored = await storedById(trx, table, rows);\n\t\t}\n\n\t\tconst found: EntryRecord[] = [];\n\t\trows.forEach((row, index) => {\n\t\t\tconst record = records[index];\n\t\t\tif (!record) return;\n\t\t\tconst existing = stored.get(String(row.id));\n\t\t\tif (!existing) throw uniqueConflict(\"entry\", record.id);\n\t\t\tconst column = firstDifference(context.db, codecs, row, existing, {\n\t\t\t\tfloat4: context.float4,\n\t\t\t});\n\t\t\tif (column === null) return;\n\t\t\tassertRewritable(context, {\n\t\t\t\tkind: \"entry\",\n\t\t\t\tid: record.id,\n\t\t\t\tcolumn,\n\t\t\t\tidKeyed: true,\n\t\t\t\trewritten: retry || rewritten.has(`entry\\u0000${record.id}`),\n\t\t\t});\n\t\t\tfound.push(record);\n\t\t});\n\t\treturn found;\n\t});\n\tif (collisions.length === 0) return;\n\n\tconst mappings = await Promise.all(\n\t\tcollisions.map(async (record) => ({\n\t\t\tportableId: record.id,\n\t\t\ttargetId: await ulidFromHash(context.operationId, \"entry\", record.id),\n\t\t})),\n\t);\n\tawait context.identity.putMany(\"entry\", mappings);\n\tcontext.noteRewrite(\"entry\");\n\tawait writeCollectionEntries(context, collection, fieldColumns, collisions, true);\n}\n\nasync function storedById(\n\tdb: Kysely<Database>,\n\ttable: string,\n\trows: readonly Row[],\n): Promise<Map<string, Row>> {\n\tconst stored = await selectByKeys(db, table, [\"id\"], rows);\n\treturn new Map(stored.map((row) => [String(row.id), row]));\n}\n","/**\n * Media writer: one target object per media row.\n *\n * Each media row's bytes are copied from its staged blob to a deterministic\n * target key, `${ulidFromHash(operationId, mediaId)}${ext}`, so an\n * interrupted copy is simply repeated. An upload attempt is registered before\n * the copy so media cleanup reclaims the object if the import is abandoned\n * before the row exists. The copy is verified against the blob's declared\n * size and SHA-256, and the row's `content_hash` is recomputed from the bytes\n * exactly as uploads do (SHA-1, only up to `MAX_CONTENT_HASH_BYTES`).\n */\n\nimport mime from \"mime/lite\";\n\nimport { MediaRepository } from \"../../database/repositories/media.js\";\nimport { computeContentHash, MAX_CONTENT_HASH_BYTES } from \"../../utils/hash.js\";\nimport { TransferError } from \"../errors.js\";\nimport type { MediaRecord } from \"../format/kinds.js\";\nimport { mediaBlobPath } from \"../format/paths.js\";\nimport { MEDIA_STORAGE_KEY_ENTITY } from \"../ops/identity-map.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport { putVerified } from \"../staging/stage.js\";\nimport type { ImportContext } from \"./context.js\";\nimport { ulidFromHash } from \"./ids.js\";\nimport { writeRecords, type WriteInput } from \"./writers.js\";\n\nconst EXTENSION = /\\.[A-Za-z0-9]{1,16}$/;\nconst MIME_EXTENSION = /^[a-z0-9]{1,16}$/;\n\nexport function mediaExtension(record: Pick<MediaRecord, \"filename\" | \"mimeType\">): string {\n\tconst fromName = EXTENSION.exec(record.filename)?.[0];\n\tif (fromName) return fromName.toLowerCase();\n\tconst fromType = mime.getExtension(record.mimeType);\n\treturn fromType && MIME_EXTENSION.test(fromType) ? `.${fromType}` : \"\";\n}\n\nexport async function mediaStorageKey(\n\tcontext: ImportContext,\n\trecord: MediaRecord,\n): Promise<string> {\n\treturn `${await ulidFromHash(context.operationId, \"media\", record.id)}${mediaExtension(record)}`;\n}\n\n/** Declared size of a media row's staged blob. */\nexport async function blobBytes(context: ImportContext, record: MediaRecord): Promise<number> {\n\tconst staged = await new TransferStagedFileRepository(context.db).get(\n\t\tcontext.operationId,\n\t\tmediaBlobPath(record.blob),\n\t);\n\tif (!staged || staged.state !== \"verified\") {\n\t\tthrow new TransferError(\"TRANSFER_MEDIA_BLOB_MISSING\", \"Media blob is not staged\", {\n\t\t\tdetail: { kind: \"media\", id: record.id },\n\t\t});\n\t}\n\treturn staged.bytes;\n}\n\n/** Statements `writeMedia` needs for one row. */\nexport const MEDIA_ROW_STATEMENTS = 12;\n\nexport async function writeMedia(\n\tcontext: ImportContext,\n\tinput: WriteInput<\"media\">,\n\tbytes: number,\n): Promise<void> {\n\tconst record = input.record;\n\tconst storageKey = await mediaStorageKey(context, record);\n\tawait context.identity.put(MEDIA_STORAGE_KEY_ENTITY, {\n\t\tportableId: record.id,\n\t\ttargetId: storageKey,\n\t});\n\n\tconst rewritten = await context.rewrittenIds(\"media\", [record]);\n\tconst targetId = rewritten.get(`media\\u0000${record.id}`) ?? record.id;\n\tconst existing = await context.db\n\t\t.selectFrom(\"media\")\n\t\t.select([\"storage_key\", \"status\"])\n\t\t.where(\"id\", \"=\", targetId)\n\t\t.executeTakeFirst();\n\n\tlet contentHash: string | null = null;\n\tconst ours = existing?.storage_key === storageKey;\n\tif (ours) {\n\t\tconst stored = await context.db\n\t\t\t.selectFrom(\"media\")\n\t\t\t.select(\"content_hash\")\n\t\t\t.where(\"id\", \"=\", targetId)\n\t\t\t.executeTakeFirstOrThrow();\n\t\tcontentHash = stored.content_hash;\n\t} else {\n\t\tconst media = new MediaRepository(context.db);\n\t\tif (!(await media.hasUploadAttempt(storageKey))) {\n\t\t\tawait media.createUploadAttempt(targetId, storageKey);\n\t\t}\n\t\tcontentHash = await copyBlob(context, record, storageKey, bytes);\n\t}\n\n\tawait writeRecords(context, \"media\", [input], {\n\t\textra: () => ({\n\t\t\trow: { storage_key: storageKey, content_hash: contentHash, status: \"ready\" },\n\t\t\tcodecs: { storage_key: \"text\", status: \"text\" },\n\t\t}),\n\t});\n\tif (!ours) await new MediaRepository(context.db).deleteUploadAttempt(storageKey);\n}\n\nasync function copyBlob(\n\tcontext: ImportContext,\n\trecord: MediaRecord,\n\tstorageKey: string,\n\tbytes: number,\n): Promise<string | null> {\n\tconst retained: Uint8Array[] = [];\n\tlet retainedBytes = 0;\n\tconst keepForHash = bytes > 0 && bytes <= MAX_CONTENT_HASH_BYTES;\n\tconst tap = new TransformStream<Uint8Array, Uint8Array>({\n\t\ttransform(chunk, controller) {\n\t\t\tif (keepForHash && retainedBytes + chunk.byteLength <= MAX_CONTENT_HASH_BYTES) {\n\t\t\t\tretained.push(chunk.slice());\n\t\t\t\tretainedBytes += chunk.byteLength;\n\t\t\t}\n\t\t\tcontroller.enqueue(chunk);\n\t\t},\n\t});\n\tconst body = (await context.reader.blob(record.blob)).pipeThrough(tap);\n\tawait putVerified(\n\t\tcontext.storage,\n\t\tstorageKey,\n\t\tbody,\n\t\t{ bytes, sha256: record.blob },\n\t\t{ contentType: record.mimeType },\n\t);\n\tif (!keepForHash || retainedBytes !== bytes) return null;\n\tconst all = new Uint8Array(retainedBytes);\n\tlet offset = 0;\n\tfor (const part of retained) {\n\t\tall.set(part, offset);\n\t\toffset += part.byteLength;\n\t}\n\treturn computeContentHash(all);\n}\n","/**\n * The record stages of an import: each walks its kinds' package streams in\n * order and writes them in bounded units, checkpointing the stream position\n * after every unit.\n */\n\nimport { sql } from \"kysely\";\n\nimport { SchemaError, SchemaRegistry } from \"../../schema/registry.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { TransferError } from \"../errors.js\";\nimport {\n\tIMPORT_STAGE_KINDS,\n\tinferredCreditId,\n\ttype ContentBylineRecord,\n\ttype EntryRecord,\n\ttype ImportRecordStage,\n\ttype RecordKind,\n\ttype RecordOfKind,\n} from \"../format/kinds.js\";\nimport type { StreamPosition } from \"../ops/states.js\";\nimport type { StagedRecord } from \"../staging/package.js\";\nimport { applyRewrittenIds, type ImportContext } from \"./context.js\";\nimport { estimateEntryWrite, writeEntries } from \"./entries.js\";\nimport { blobBytes, MEDIA_ROW_STATEMENTS, writeMedia } from \"./media.js\";\nimport { estimateWrite, isFlatKind, writeRecords, type WriteInput } from \"./writers.js\";\n\n/** Identity-map kind linking an unmapped principal's byline, per locale, to its group. */\nexport const PRINCIPAL_BYLINE_ENTITY = \"principal_byline\";\n\n/**\n * Identity-map kind recording each materialized inferred credit: the\n * `content_byline` row id (`inferredCreditId`) mapped to its byline group.\n * Only these rows are materialized credits; a package's own `inferred:` rows\n * are explicit credits like any other.\n */\nexport const INFERRED_CREDIT_ENTITY = \"inferred_credit\";\n\n/**\n * Streams walked by each record stage. Fields are written together with\n * their collection. The relations stage walks the entry stream a second\n * time, after explicit credits exist, to materialize inferred credits.\n */\nexport const STAGE_STREAMS: Readonly<Record<ImportRecordStage, readonly RecordKind[]>> = {\n\t...IMPORT_STAGE_KINDS,\n\tschema: IMPORT_STAGE_KINDS.schema.filter((kind) => kind !== \"field\"),\n\trelations: IMPORT_STAGE_KINDS.relations.flatMap((kind): RecordKind[] =>\n\t\tkind === \"content_byline\" ? [kind, \"entry\"] : [kind],\n\t),\n};\n\nconst DEFAULT_BATCH = 100;\nconst ENTRY_BATCH = 50;\nconst COLLECTION_STATEMENTS = 80;\n\n/** Thrown out of a stage when the operation was asked to cancel. */\nexport class ImportCancelledSignal extends Error {}\n\nexport type Checkpoint = (position: StreamPosition) => Promise<void>;\n\nexport function firstPosition(stage: ImportRecordStage): StreamPosition {\n\tconst kind = STAGE_STREAMS[stage][0];\n\tif (!kind) throw new Error(`Stage ${stage} has no streams`);\n\treturn { kind, seq: 0, line: 0 };\n}\n\n/**\n * Run units of `stage` from `position` until the stage is done (returns\n * null) or the step budget is spent (returns the next position).\n */\nexport async function runRecordStage(\n\tcontext: ImportContext,\n\tstage: ImportRecordStage,\n\tstart: StreamPosition,\n\tcheckpoint: Checkpoint,\n): Promise<StreamPosition | null> {\n\tconst streams = STAGE_STREAMS[stage];\n\tlet position: StreamPosition | null = start;\n\twhile (position) {\n\t\tconst kindIndex = streams.indexOf(position.kind);\n\t\tif (kindIndex === -1) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cursor names an unknown stream\");\n\t\t}\n\t\tif (position.seq >= context.chunkCount(position.kind)) {\n\t\t\tconst next = streams[kindIndex + 1];\n\t\t\tposition = next ? { kind: next, seq: 0, line: 0 } : null;\n\t\t\tcontinue;\n\t\t}\n\t\tconst chunk = await context.chunk(position.kind, position.seq);\n\t\tif (position.line >= chunk.length) {\n\t\t\tposition = { kind: position.kind, seq: position.seq + 1, line: 0 };\n\t\t\tcontinue;\n\t\t}\n\t\tconst unit = await planUnit(context, stage, position, chunk);\n\t\tif (!context.budget.canStart({ queries: unit.queries + 3, bytes: unit.bytes })) {\n\t\t\treturn position;\n\t\t}\n\t\tcontext.budget.start(unit.bytes);\n\t\tawait context.beginUnit(stage, position);\n\t\tawait unit.run();\n\t\tconst line = position.line + unit.count;\n\t\tposition =\n\t\t\tline >= chunk.length\n\t\t\t\t? { kind: position.kind, seq: position.seq + 1, line: 0 }\n\t\t\t\t: { kind: position.kind, seq: position.seq, line };\n\t\tawait checkpoint(position);\n\t}\n\treturn null;\n}\n\ninterface Unit {\n\tcount: number;\n\tqueries: number;\n\tbytes: number;\n\trun: () => Promise<void>;\n}\n\nasync function planUnit(\n\tcontext: ImportContext,\n\tstage: ImportRecordStage,\n\tposition: StreamPosition,\n\tchunk: ReadonlyArray<StagedRecord<RecordKind>>,\n): Promise<Unit> {\n\tconst kind = position.kind;\n\tconst rest = chunk.slice(position.line);\n\n\tif (kind === \"collection\") {\n\t\tconst [staged] = rest;\n\t\tif (!staged || staged.record.kind !== \"collection\") throw new Error(\"Expected a collection\");\n\t\tconst record = staged.record;\n\t\treturn {\n\t\t\tcount: 1,\n\t\t\tqueries: COLLECTION_STATEMENTS,\n\t\t\tbytes: 0,\n\t\t\trun: () => importCollection(context, record),\n\t\t};\n\t}\n\n\tif (kind === \"media\") {\n\t\tconst [staged] = rest;\n\t\tif (!staged || staged.record.kind !== \"media\") throw new Error(\"Expected a media record\");\n\t\tconst input = { record: staged.record, line: staged.line };\n\t\tconst bytes = await blobBytes(context, staged.record);\n\t\treturn {\n\t\t\tcount: 1,\n\t\t\tqueries: MEDIA_ROW_STATEMENTS,\n\t\t\tbytes,\n\t\t\trun: () => writeMedia(context, input, bytes),\n\t\t};\n\t}\n\n\tif (kind === \"entry\") {\n\t\tconst batch = inputsOf(\"entry\", rest.slice(0, ENTRY_BATCH));\n\t\tif (stage === \"relations\") {\n\t\t\treturn {\n\t\t\t\tcount: batch.length,\n\t\t\t\tqueries:\n\t\t\t\t\t4 +\n\t\t\t\t\tMath.ceil(batch.length / SQL_BATCH_SIZE) * 2 +\n\t\t\t\t\testimateWrite(\"content_byline\", batch.length),\n\t\t\t\tbytes: 0,\n\t\t\t\trun: () => materializeInferredCredits(context, batch),\n\t\t\t};\n\t\t}\n\t\tlet queries = 3;\n\t\tconst perCollection = new Map<string, number>();\n\t\tfor (const input of batch) {\n\t\t\tperCollection.set(\n\t\t\t\tinput.record.collection,\n\t\t\t\t(perCollection.get(input.record.collection) ?? 0) + 1,\n\t\t\t);\n\t\t}\n\t\tfor (const [collection, count] of perCollection) {\n\t\t\tconst fields = await context.fieldColumns(collection);\n\t\t\tqueries += estimateEntryWrite(count, fields.size);\n\t\t}\n\t\treturn { count: batch.length, queries, bytes: 0, run: () => writeEntries(context, batch) };\n\t}\n\n\tif (!isFlatKind(kind)) {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cursor names an unknown stream\");\n\t}\n\tconst batch = rest.slice(0, DEFAULT_BATCH);\n\treturn {\n\t\tcount: batch.length,\n\t\tqueries: estimateWrite(kind, batch.length),\n\t\tbytes: 0,\n\t\trun: async () => {\n\t\t\tconst inputs = batch.map((staged) => ({ record: staged.record, line: staged.line }));\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- records of one chunk share its kind\n\t\t\tawait writeRecords(context, kind, inputs as Array<WriteInput<typeof kind>>);\n\t\t\tif (kind === \"byline\") {\n\t\t\t\tawait recordUnmappedBylines(context, inputsOf(\"byline\", batch));\n\t\t\t}\n\t\t},\n\t};\n}\n\nfunction inputsOf<K extends RecordKind>(\n\tkind: K,\n\tstaged: ReadonlyArray<StagedRecord<RecordKind>>,\n): Array<WriteInput<K>> {\n\treturn staged.map((item) => {\n\t\tif (item.record.kind !== kind) throw new Error(`Expected ${kind} records`);\n\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- kind checked above\n\t\treturn { record: item.record as RecordOfKind<K>, line: item.line };\n\t});\n}\n\nasync function importCollection(\n\tcontext: ImportContext,\n\trecord: RecordOfKind<\"collection\">,\n): Promise<void> {\n\tconst fields = (await context.allRecords(\"field\")).filter(\n\t\t(field) => field.collectionId === record.id,\n\t);\n\ttry {\n\t\tawait new SchemaRegistry(context.db).importCollection(record, fields, { resume: true });\n\t} catch (error) {\n\t\tif (error instanceof SchemaError) {\n\t\t\tthrow new TransferError(\"TRANSFER_IMPORT_ERROR\", \"Collection could not be imported\", {\n\t\t\t\tdetail: { kind: \"collection\", id: record.id, reason: error.code },\n\t\t\t\tcause: error,\n\t\t\t});\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/**\n * Remember which byline an unmapped principal owns in each locale, so the\n * relations stage can keep that principal's inferred author credits.\n */\nasync function recordUnmappedBylines(\n\tcontext: ImportContext,\n\tinputs: ReadonlyArray<WriteInput<\"byline\">>,\n): Promise<void> {\n\tconst mappings = inputs.flatMap(({ record }) =>\n\t\trecord.userPrincipal !== undefined && context.principalTarget(record.userPrincipal) === null\n\t\t\t? [\n\t\t\t\t\t{\n\t\t\t\t\t\tportableId: `${record.locale}:${record.userPrincipal}`,\n\t\t\t\t\t\ttargetId: record.translationGroup ?? record.id,\n\t\t\t\t\t},\n\t\t\t\t]\n\t\t\t: [],\n\t);\n\tawait context.identity.putMany(PRINCIPAL_BYLINE_ENTITY, mappings);\n}\n\n/**\n * Explicit `content_byline` rows for entries whose author credit would\n * otherwise be inferred from an unmapped principal and vanish on the target:\n * the author is unmapped, the entry has no explicit credit, and the author\n * has a byline in the entry's locale.\n */\nasync function materializeInferredCredits(\n\tcontext: ImportContext,\n\tinputs: ReadonlyArray<WriteInput<\"entry\">>,\n): Promise<void> {\n\tconst candidates = inputs\n\t\t.map((input) => input.record)\n\t\t.filter(\n\t\t\t(record): record is EntryRecord & { authorPrincipal: string } =>\n\t\t\t\trecord.authorPrincipal !== undefined &&\n\t\t\t\trecord.primaryBylineGroup === undefined &&\n\t\t\t\tcontext.principalTarget(record.authorPrincipal) === null,\n\t\t);\n\tif (candidates.length === 0) return;\n\tconst groups = await context.identity.getMany(\n\t\tPRINCIPAL_BYLINE_ENTITY,\n\t\tcandidates.map((record) => `${record.locale}:${record.authorPrincipal}`),\n\t);\n\tconst credited = candidates.filter((record) =>\n\t\tgroups.has(`${record.locale}:${record.authorPrincipal}`),\n\t);\n\tif (credited.length === 0) return;\n\n\tconst rewritten = await context.rewrittenIds(\"entry\", credited);\n\tconst targetIds = credited.map((record) => applyRewrittenIds(record, rewritten).id);\n\tconst explicit = new Set<string>();\n\tfor (const batch of chunks(targetIds, SQL_BATCH_SIZE)) {\n\t\tconst rows = await context.db\n\t\t\t.selectFrom(\"_emdash_content_bylines\")\n\t\t\t.select([\"collection_slug\", \"content_id\"])\n\t\t\t.where(\"content_id\", \"in\", batch)\n\t\t\t.where(({ exists, not, selectFrom }) =>\n\t\t\t\tnot(\n\t\t\t\t\texists(\n\t\t\t\t\t\tselectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t.where(\"_emdash_transfer_identity_map.operation_id\", \"=\", context.operationId)\n\t\t\t\t\t\t\t.where(\"_emdash_transfer_identity_map.entity_kind\", \"=\", INFERRED_CREDIT_ENTITY)\n\t\t\t\t\t\t\t.whereRef(\n\t\t\t\t\t\t\t\t\"_emdash_transfer_identity_map.portable_id\",\n\t\t\t\t\t\t\t\t\"=\",\n\t\t\t\t\t\t\t\t\"_emdash_content_bylines.id\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.execute();\n\t\tfor (const row of rows) explicit.add(`${row.collection_slug}\\u0000${row.content_id}`);\n\t}\n\n\tconst credits: Array<WriteInput<\"content_byline\">> = [];\n\tcredited.forEach((record, index) => {\n\t\tif (explicit.has(`${record.collection}\\u0000${targetIds[index]}`)) return;\n\t\tconst bylineGroup = groups.get(`${record.locale}:${record.authorPrincipal}`);\n\t\tif (bylineGroup === undefined) return;\n\t\tconst credit: ContentBylineRecord = {\n\t\t\tkind: \"content_byline\",\n\t\t\tid: inferredCreditId(record.collection, record.id),\n\t\t\tcollection: record.collection,\n\t\t\tentryId: record.id,\n\t\t\tbylineGroup,\n\t\t\tsortOrder: 0,\n\t\t\t...(record.createdAt === undefined ? {} : { createdAt: record.createdAt }),\n\t\t};\n\t\tcredits.push({ record: credit, line: \"\" });\n\t});\n\tif (credits.length === 0) return;\n\t// Recorded before writing: a resumed unit must still see a written credit as materialized.\n\tawait context.identity.putMany(\n\t\tINFERRED_CREDIT_ENTITY,\n\t\tcredits.map(({ record }) => ({ portableId: record.id, targetId: record.bylineGroup })),\n\t);\n\tawait writeRecords(context, \"content_byline\", credits);\n}\n","/**\n * Import verification: re-read the target through the exporter's readers and\n * compare it to the package, in bounded steps.\n *\n * For every package record chunk (except principals, which are never\n * written), each record's predicted target form is\n * `applyTransformations(record, plan)`. The target row is read with the same\n * reader the exporter uses, rewritten ids are mapped back to portable ids\n * through the identity map, and target storage keys become placeholders\n * again (`rewriteMediaRefs` verify mode). A record verifies when both forms\n * have the same canonical JSON. Each chunk's logical hash is stored on its\n * staged file; the logical digest is computed from those at the end.\n *\n * Redirects the importer disabled because they would close a loop (listed\n * in the identity map) are predicted disabled.\n *\n * After the records, every inferred credit this import materialized (listed\n * in the identity map) must exist as recorded, the number of target rows per\n * kind must equal the package count (plus those credits for\n * `content_byline`), and every media object is downloaded again and must hash\n * to its blob.\n */\n\nimport type { Kysely } from \"kysely\";\nimport { z } from \"zod\";\n\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { isTransferError, TransferError } from \"../errors.js\";\nimport { canonicalJson } from \"../format/canonical.js\";\nimport {\n\tchunkLogicalSha256,\n\tlogicalDigest,\n\trecordSha256,\n\ttype Sha256Digest,\n} from \"../format/digest.js\";\nimport {\n\tKIND_REFERENCES,\n\tRECORD_KINDS,\n\tsyntheticId,\n\tSYNTHETIC_ID_KINDS,\n\ttype RecordKind,\n\ttype SitePackageRecord,\n} from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport {\n\tbuildMediaKeyIndex,\n\trelativizePlaceholderUrls,\n\trewriteMediaRefs,\n\ttype MediaKeyIndex,\n} from \"../format/media-refs.js\";\nimport { recordChunkPath } from \"../format/paths.js\";\nimport type { SiteImportPlan } from \"../format/plan.js\";\nimport { DECIDED_SETTING_NAMES } from \"../format/settings.js\";\nimport {\n\tapplyTransformations,\n\ttype FieldColumnType,\n\ttype TransformationContext,\n} from \"../format/transformations.js\";\nimport { INFERRED_CREDIT_ENTITY } from \"../import/stages.js\";\nimport { REDIRECT_LOOP_ENTITY } from \"../import/writers.js\";\nimport type { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferIdentityMapRepository } from \"../ops/identity-map.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport { StagedPackageReader } from \"../staging/package.js\";\nimport { hashStoredObject, loadMediaKeyRows } from \"./media.js\";\nimport { createReader, type KindReader, type ReaderOptions } from \"./readers.js\";\n\ntype Db = Kysely<Database>;\n\nexport interface VerifyImportStepInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/**\n\t * The staged package being imported. Record chunks are read from its\n\t * stage and checked against the digests they were verified with.\n\t */\n\treader: StagedPackageReader;\n\tplan: SiteImportPlan;\n\t/** The cursor returned by the previous step, or null on the first. */\n\tcursor: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport interface VerificationMismatch {\n\tkind: string;\n\tid: string;\n\treason: string;\n}\n\nexport type VerifyImportStepResult =\n\t| { done: false; cursor: unknown }\n\t| {\n\t\t\tdone: true;\n\t\t\tlogicalDigest: Sha256Digest;\n\t\t\tcounts: Record<string, number>;\n\t\t\tmismatches: VerificationMismatch[];\n\t };\n\nconst recordKindSchema = z.enum(RECORD_KINDS);\nconst nonNegative = z.number().int().nonnegative();\n\nconst verifyCursorSchema = z.strictObject({\n\tphase: z.enum([\"records\", \"credits\", \"counts\", \"media\", \"digest\"]),\n\tkind: recordKindSchema,\n\tseq: nonNegative,\n\tline: nonNegative,\n\tcounts: z.record(z.string(), nonNegative),\n\t/** Inferred credits checked so far, and the last one checked. */\n\tcredits: z.strictObject({ checked: nonNegative, after: z.string().nullable() }),\n\tmismatches: z\n\t\t.array(z.strictObject({ kind: z.string(), id: z.string(), reason: z.string() }))\n\t\t.max(TRANSFER_LIMITS.verificationMismatches),\n});\n\ntype VerifyCursor = z.infer<typeof verifyCursorSchema>;\n\n/** Kinds that are written to a target, in package order. */\nconst VERIFIED_KINDS: readonly RecordKind[] = RECORD_KINDS.filter((kind) => kind !== \"principal\");\n\n/** Kinds whose target row count must equal the package count. */\nconst COUNTED_KINDS: readonly RecordKind[] = VERIFIED_KINDS.filter((kind) => kind !== \"setting\");\n\nconst CREDITS_PER_UNIT = 500;\n\n/**\n * Run one bounded verification step. Returns `done: false` with a cursor to\n * pass to the next call, or the logical digest, verified counts per kind, and\n * at most `TRANSFER_LIMITS.verificationMismatches` mismatches.\n */\nexport async function verifyImportStep(\n\tinput: VerifyImportStepInput,\n): Promise<VerifyImportStepResult> {\n\treturn new VerifyStep(input).run();\n}\n\nfunction initialCursor(): VerifyCursor {\n\treturn {\n\t\tphase: \"records\",\n\t\tkind: VERIFIED_KINDS[0] ?? \"collection\",\n\t\tseq: 0,\n\t\tline: 0,\n\t\tcounts: {},\n\t\tcredits: { checked: 0, after: null },\n\t\tmismatches: [],\n\t};\n}\n\nclass VerifyStep {\n\treadonly #input: VerifyImportStepInput;\n\treadonly #db: Db;\n\treadonly #identity: TransferIdentityMapRepository;\n\treadonly #reader: StagedPackageReader;\n\treadonly #readers = new Map<RecordKind, KindReader<RecordKind>>();\n\t#cursor: VerifyCursor;\n\t#rewrites: boolean | null = null;\n\t#keys: MediaKeyIndex | null = null;\n\t#context: TransformationContext | null = null;\n\t#packageBlobs = new Map<string, string>();\n\n\tconstructor(input: VerifyImportStepInput) {\n\t\tthis.#input = input;\n\t\tthis.#db = input.db;\n\t\tthis.#reader = new StagedPackageReader(\n\t\t\tinput.reader.stage,\n\t\t\tnew TransferStagedFileRepository(input.db).verifiedDigests(input.operationId),\n\t\t);\n\t\tthis.#identity = new TransferIdentityMapRepository(\n\t\t\tinput.db,\n\t\t\tinput.plan.origin.siteId,\n\t\t\tinput.operationId,\n\t\t);\n\t\tthis.#cursor =\n\t\t\tinput.cursor === null || input.cursor === undefined\n\t\t\t\t? initialCursor()\n\t\t\t\t: verifyCursorSchema.parse(input.cursor);\n\t}\n\n\tasync run(): Promise<VerifyImportStepResult> {\n\t\tif ((await this.#reader.digest()) !== this.#input.plan.packageDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Staged package does not match\");\n\t\t}\n\t\tfor (;;) {\n\t\t\tconst progressed = await this.unit();\n\t\t\tif (progressed === \"done\") return this.finish();\n\t\t\tif (progressed === \"yield\") return { done: false, cursor: this.#cursor };\n\t\t}\n\t}\n\n\tprivate mismatch(kind: string, id: string, reason: string): void {\n\t\tif (this.#cursor.mismatches.length < TRANSFER_LIMITS.verificationMismatches) {\n\t\t\tthis.#cursor.mismatches.push({ kind, id, reason });\n\t\t}\n\t}\n\n\tprivate async unit(): Promise<\"continue\" | \"yield\" | \"done\"> {\n\t\tconst budget = this.#input.budget;\n\t\tif (!budget.canStart({ bytes: 1 })) return \"yield\";\n\t\tswitch (this.#cursor.phase) {\n\t\t\tcase \"records\":\n\t\t\t\tbudget.start(1);\n\t\t\t\tawait this.recordsUnit();\n\t\t\t\treturn \"continue\";\n\t\t\tcase \"credits\":\n\t\t\t\tbudget.start(1);\n\t\t\t\tawait this.creditsUnit();\n\t\t\t\treturn \"continue\";\n\t\t\tcase \"counts\":\n\t\t\t\tbudget.start(1);\n\t\t\t\tawait this.countsUnit();\n\t\t\t\treturn \"continue\";\n\t\t\tcase \"media\":\n\t\t\t\treturn this.mediaUnit();\n\t\t\tcase \"digest\":\n\t\t\t\treturn \"done\";\n\t\t}\n\t}\n\n\t// ── Shared ──\n\n\tprivate reader(kind: RecordKind): KindReader<RecordKind> {\n\t\tlet reader = this.#readers.get(kind);\n\t\tif (!reader) {\n\t\t\tconst options: ReaderOptions = {\n\t\t\t\tmediaBlobs: async (ids) => {\n\t\t\t\t\tconst portable = await this.portableIds(\"media\", ids);\n\t\t\t\t\tconst found = new Map<string, string>();\n\t\t\t\t\tfor (const id of ids) {\n\t\t\t\t\t\tconst blob = this.#packageBlobs.get(portable.get(id) ?? id);\n\t\t\t\t\t\tif (blob !== undefined) found.set(id, blob);\n\t\t\t\t\t}\n\t\t\t\t\treturn found;\n\t\t\t\t},\n\t\t\t};\n\t\t\treader = createReader(this.#db, kind, options);\n\t\t\tthis.#readers.set(kind, reader);\n\t\t}\n\t\treturn reader;\n\t}\n\n\t/** Whether any record id was rewritten on import. */\n\tprivate async hasRewrites(): Promise<boolean> {\n\t\tif (this.#rewrites === null) {\n\t\t\tconst row = await this.#db\n\t\t\t\t.selectFrom(\"_emdash_transfer_identity_map\")\n\t\t\t\t.select(\"portable_id\")\n\t\t\t\t.where(\"operation_id\", \"=\", this.#input.operationId)\n\t\t\t\t.where(\"entity_kind\", \"in\", [...RECORD_KINDS])\n\t\t\t\t.limit(1)\n\t\t\t\t.executeTakeFirst();\n\t\t\tthis.#rewrites = row !== undefined;\n\t\t}\n\t\treturn this.#rewrites;\n\t}\n\n\tprivate async targetIds(kind: RecordKind, ids: readonly string[]): Promise<Map<string, string>> {\n\t\tif (!(await this.hasRewrites()) || ids.length === 0) return new Map();\n\t\treturn this.#identity.getMany(kind, ids);\n\t}\n\n\tprivate async portableIds(\n\t\tkind: RecordKind,\n\t\tids: readonly string[],\n\t): Promise<Map<string, string>> {\n\t\tif (!(await this.hasRewrites()) || ids.length === 0) return new Map();\n\t\treturn this.#identity.getPortableIds(kind, ids);\n\t}\n\n\t/** Map a record's own id and its `by: \"id\"` references through `lookup`. */\n\tprivate async mapIds(\n\t\trecords: SitePackageRecord[],\n\t\tlookup: (kind: RecordKind, ids: readonly string[]) => Promise<Map<string, string>>,\n\t): Promise<SitePackageRecord[]> {\n\t\tif (!(await this.hasRewrites()) || records.length === 0) return records;\n\t\tconst kind = records[0]?.kind;\n\t\tif (!kind) return records;\n\t\tconst properties: Array<{ property: string; target: RecordKind }> = [];\n\t\tif (!isSyntheticKind(kind) && kind !== \"setting\")\n\t\t\tproperties.push({ property: \"id\", target: kind });\n\t\tfor (const reference of KIND_REFERENCES[kind]) {\n\t\t\tconst target = reference.targets[0];\n\t\t\tif (reference.by !== \"id\" || !target || target === \"principal\") continue;\n\t\t\tproperties.push({ property: reference.property, target });\n\t\t}\n\t\tconst maps = new Map<string, Map<string, string>>();\n\t\tfor (const { property, target } of properties) {\n\t\t\tconst values = records.flatMap((record) => {\n\t\t\t\tconst value: unknown = Reflect.get(record, property);\n\t\t\t\treturn typeof value === \"string\" ? [value] : [];\n\t\t\t});\n\t\t\tmaps.set(property, await lookup(target, values));\n\t\t}\n\t\treturn records.map((record) => {\n\t\t\tconst next: Record<string, unknown> = { ...record };\n\t\t\tfor (const { property } of properties) {\n\t\t\t\tconst value = next[property];\n\t\t\t\tconst mapped = typeof value === \"string\" ? maps.get(property)?.get(value) : undefined;\n\t\t\t\tif (mapped !== undefined) next[property] = mapped;\n\t\t\t}\n\t\t\tif (isSyntheticRecord(next)) next.id = syntheticId(next);\n\t\t\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- same record with id-valued properties replaced by other ids\n\t\t\treturn next as SitePackageRecord;\n\t\t});\n\t}\n\n\tprivate async keyIndex(): Promise<MediaKeyIndex> {\n\t\tif (!this.#keys) {\n\t\t\tconst rows = await loadMediaKeyRows(this.#db);\n\t\t\tconst portable = await this.portableIds(\n\t\t\t\t\"media\",\n\t\t\t\trows.map((row) => row.id),\n\t\t\t);\n\t\t\tthis.#keys = buildMediaKeyIndex(\n\t\t\t\trows.map((row) => ({ id: portable.get(row.id) ?? row.id, storageKey: row.storageKey })),\n\t\t\t);\n\t\t}\n\t\treturn this.#keys;\n\t}\n\n\tprivate async transformationContext(): Promise<TransformationContext> {\n\t\tif (this.#context) return this.#context;\n\t\tconst reader = this.#reader;\n\t\tconst collections = new Map<string, string>();\n\t\tfor await (const { record } of reader.records(\"collection\")) {\n\t\t\tcollections.set(record.id, record.slug);\n\t\t}\n\t\tconst types = new Map<string, Map<string, FieldColumnType>>();\n\t\tfor await (const { record } of reader.records(\"field\")) {\n\t\t\tconst slug = collections.get(record.collectionId);\n\t\t\tif (slug === undefined) continue;\n\t\t\tconst fields = types.get(slug) ?? new Map<string, FieldColumnType>();\n\t\t\tfields.set(record.slug, record.columnType);\n\t\t\ttypes.set(slug, fields);\n\t\t}\n\t\tthis.#context = { fieldColumnTypes: types };\n\t\treturn this.#context;\n\t}\n\n\tprivate excludedSettings(): ReadonlySet<string> {\n\t\tconst excluded = new Set<string>();\n\t\tconst { decisions } = this.#input.plan;\n\t\tif (decisions.siteTitle === \"target\") {\n\t\t\tfor (const name of DECIDED_SETTING_NAMES.title) excluded.add(name);\n\t\t}\n\t\tif (decisions.siteTagline === \"target\") {\n\t\t\tfor (const name of DECIDED_SETTING_NAMES.tagline) excluded.add(name);\n\t\t}\n\t\treturn excluded;\n\t}\n\n\tprivate chunkCount(\n\t\tkind: RecordKind,\n\t\tmanifest: Awaited<ReturnType<StagedPackageReader[\"manifest\"]>>,\n\t) {\n\t\treturn manifest.records[kind]?.chunks ?? 0;\n\t}\n\n\t// ── Records ──\n\n\tprivate async recordsUnit(): Promise<void> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst { kind, seq } = this.#cursor;\n\t\tif (seq >= this.chunkCount(kind, manifest)) {\n\t\t\tthis.advanceKind();\n\t\t\treturn;\n\t\t}\n\n\t\tconst chunk = await this.#reader.readChunk(kind, seq);\n\t\tconst context = await this.transformationContext();\n\t\tconst excluded = kind === \"setting\" ? this.excludedSettings() : new Set<string>();\n\t\tconst packageRecords = chunk\n\t\t\t.map((staged) => staged.record)\n\t\t\t.filter((record) => !excluded.has(record.id));\n\t\tif (kind === \"media\") {\n\t\t\tfor (const record of packageRecords) {\n\t\t\t\tif (record.kind === \"media\") this.#packageBlobs.set(record.id, record.blob);\n\t\t\t}\n\t\t}\n\t\tconst predicted = await this.disabledLoopClosers(\n\t\t\tpackageRecords.map((record) =>\n\t\t\t\tpredictRelativeMediaUrls(applyTransformations(record, this.#input.plan, context)),\n\t\t\t),\n\t\t);\n\n\t\tconst forward = await this.mapIds(predicted, (target, ids) => this.targetIds(target, ids));\n\t\tconst lookup = forward.map((record) => record.id);\n\t\tconst collections = new Map(\n\t\t\tforward.flatMap((record) =>\n\t\t\t\trecord.kind === \"entry\" ? [[record.id, record.collection] as const] : [],\n\t\t\t),\n\t\t);\n\t\tconst found = await this.readTargets(kind, lookup, collections);\n\t\tconst targets = await this.mapIds(\n\t\t\tlookup.flatMap((id) => {\n\t\t\t\tconst record = found.get(id);\n\t\t\t\treturn record ? [record] : [];\n\t\t\t}),\n\t\t\t(target, ids) => this.portableIds(target, ids),\n\t\t);\n\t\tconst byPortableId = new Map(targets.map((record) => [record.id, record]));\n\t\tconst keys = await this.keyIndex();\n\n\t\tconst hashes: Array<[string, string]> = [];\n\t\tlet verified = 0;\n\t\tfor (const expected of predicted) {\n\t\t\tconst target = byPortableId.get(expected.id);\n\t\t\tif (!target) {\n\t\t\t\tthis.mismatch(kind, expected.id, \"missing\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst rewritten = rewriteMediaRefs(target, { mode: \"verify\", keys, relativize: true });\n\t\t\tif (rewritten.errors.length > 0) {\n\t\t\t\tthis.mismatch(kind, expected.id, `media_ref_${rewritten.errors[0]?.code ?? \"invalid\"}`);\n\t\t\t}\n\t\t\tconst actual =\n\t\t\t\trewritten.value.kind === \"media\" && expected.kind === \"media\"\n\t\t\t\t\t? { ...rewritten.value, blob: expected.blob }\n\t\t\t\t\t: rewritten.value;\n\t\t\thashes.push([expected.id, await recordSha256(actual)]);\n\t\t\tif (canonicalJson(actual) === canonicalJson(expected)) verified++;\n\t\t\telse this.mismatch(kind, expected.id, \"different\");\n\t\t}\n\n\t\tawait new TransferStagedFileRepository(this.#db).setLogicalSha256(\n\t\t\tthis.#input.operationId,\n\t\t\trecordChunkPath(kind, seq),\n\t\t\tawait chunkLogicalSha256(hashes),\n\t\t);\n\t\tthis.#cursor.counts[kind] = (this.#cursor.counts[kind] ?? 0) + verified;\n\t\tthis.#cursor.seq = seq + 1;\n\t}\n\n\t/** Redirects the importer wrote disabled because they would close a loop. */\n\tprivate async disabledLoopClosers(records: SitePackageRecord[]): Promise<SitePackageRecord[]> {\n\t\tconst redirects = records.flatMap((record) => (record.kind === \"redirect\" ? [record.id] : []));\n\t\tif (redirects.length === 0) return records;\n\t\tconst closers = await this.#identity.getMany(REDIRECT_LOOP_ENTITY, redirects);\n\t\tif (closers.size === 0) return records;\n\t\treturn records.map((record) =>\n\t\t\trecord.kind === \"redirect\" && closers.has(record.id) ? { ...record, enabled: false } : record,\n\t\t);\n\t}\n\n\tprivate async readTargets(\n\t\tkind: RecordKind,\n\t\tids: readonly string[],\n\t\tcollections: ReadonlyMap<string, string>,\n\t) {\n\t\ttry {\n\t\t\treturn await this.reader(kind).byIds(ids, collections);\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_EXPORT_ERROR\") {\n\t\t\t\tthrow new TransferError(\n\t\t\t\t\t\"TRANSFER_VERIFICATION_FAILED\",\n\t\t\t\t\t\"Target row is not a valid record\",\n\t\t\t\t\t{\n\t\t\t\t\t\tdetail: { ...error.detail, kind },\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t},\n\t\t\t\t);\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\tprivate advanceKind(): void {\n\t\tconst next = VERIFIED_KINDS[VERIFIED_KINDS.indexOf(this.#cursor.kind) + 1];\n\t\tif (next) {\n\t\t\tthis.#cursor.kind = next;\n\t\t\tthis.#cursor.seq = 0;\n\t\t\treturn;\n\t\t}\n\t\tthis.#cursor.phase = \"credits\";\n\t\tthis.#cursor.seq = 0;\n\t}\n\n\t// ── Inferred credits ──\n\n\tprivate async creditsUnit(): Promise<void> {\n\t\tconst mappings = await this.#identity.list(INFERRED_CREDIT_ENTITY, {\n\t\t\tafter: this.#cursor.credits.after ?? undefined,\n\t\t\tlimit: CREDITS_PER_UNIT,\n\t\t});\n\t\tconst rows = new Map<\n\t\t\tstring,\n\t\t\t{ byline_id: string; sort_order: unknown; role_label: string | null }\n\t\t>();\n\t\tfor (const batch of chunks(\n\t\t\tmappings.map((mapping) => mapping.portableId),\n\t\t\tSQL_BATCH_SIZE,\n\t\t)) {\n\t\t\tconst found = await this.#db\n\t\t\t\t.selectFrom(\"_emdash_content_bylines\")\n\t\t\t\t.select([\"id\", \"byline_id\", \"sort_order\", \"role_label\"])\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of found) rows.set(row.id, row);\n\t\t}\n\t\tfor (const mapping of mappings) {\n\t\t\tconst row = rows.get(mapping.portableId);\n\t\t\tif (!row) this.mismatch(\"content_byline\", mapping.portableId, \"inferred_credit_missing\");\n\t\t\telse if (\n\t\t\t\trow.byline_id !== mapping.targetId ||\n\t\t\t\tNumber(row.sort_order) !== 0 ||\n\t\t\t\trow.role_label !== null\n\t\t\t) {\n\t\t\t\tthis.mismatch(\"content_byline\", mapping.portableId, \"inferred_credit_different\");\n\t\t\t}\n\t\t}\n\t\tthis.#cursor.credits.checked += mappings.length;\n\t\tconst last = mappings.at(-1);\n\t\tif (last && mappings.length === CREDITS_PER_UNIT) {\n\t\t\tthis.#cursor.credits.after = last.portableId;\n\t\t\treturn;\n\t\t}\n\t\tthis.#cursor.phase = \"counts\";\n\t\tthis.#cursor.kind = COUNTED_KINDS[0] ?? \"collection\";\n\t}\n\n\t// ── Counts ──\n\n\tprivate async countsUnit(): Promise<void> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst kind = this.#cursor.kind;\n\t\tconst rows = await this.reader(kind).countRows();\n\t\tlet expected = manifest.records[kind]?.count ?? 0;\n\t\tif (kind === \"content_byline\") expected += this.#cursor.credits.checked;\n\t\tif (rows !== null && rows !== expected) {\n\t\t\tthis.mismatch(kind, \"*\", `row_count expected=${expected} actual=${rows}`);\n\t\t}\n\n\t\tconst next = COUNTED_KINDS[COUNTED_KINDS.indexOf(kind) + 1];\n\t\tif (next) {\n\t\t\tthis.#cursor.kind = next;\n\t\t\treturn;\n\t\t}\n\t\tthis.#cursor.phase = \"media\";\n\t\tthis.#cursor.kind = \"media\";\n\t\tthis.#cursor.seq = 0;\n\t\tthis.#cursor.line = 0;\n\t}\n\n\t// ── Media ──\n\n\t#mediaChunk: { seq: number; records: SitePackageRecord[]; keys: Map<string, string> } | null =\n\t\tnull;\n\n\tprivate async mediaUnit(): Promise<\"continue\" | \"yield\" | \"done\"> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst { seq, line } = this.#cursor;\n\t\tif (seq >= this.chunkCount(\"media\", manifest)) {\n\t\t\tthis.#cursor.phase = \"digest\";\n\t\t\treturn \"continue\";\n\t\t}\n\t\tif (this.#mediaChunk?.seq !== seq) {\n\t\t\tconst records = (await this.#reader.readChunk(\"media\", seq)).map((s) => s.record);\n\t\t\tconst targetIds = await this.targetIds(\n\t\t\t\t\"media\",\n\t\t\t\trecords.map((record) => record.id),\n\t\t\t);\n\t\t\tconst ids = records.map((record) => targetIds.get(record.id) ?? record.id);\n\t\t\tconst keys = new Map<string, string>();\n\t\t\tfor (const row of await this.targetMediaKeys(ids)) keys.set(row.id, row.storageKey);\n\t\t\tconst mapped = new Map<string, string>();\n\t\t\trecords.forEach((record, index) => {\n\t\t\t\tconst key = keys.get(ids[index] ?? record.id);\n\t\t\t\tif (key !== undefined) mapped.set(record.id, key);\n\t\t\t});\n\t\t\tthis.#mediaChunk = { seq, records, keys: mapped };\n\t\t}\n\n\t\tconst record = this.#mediaChunk.records[line];\n\t\tif (!record || record.kind !== \"media\") {\n\t\t\tthis.#cursor.seq = seq + 1;\n\t\t\tthis.#cursor.line = 0;\n\t\t\treturn \"continue\";\n\t\t}\n\t\tconst budget = this.#input.budget;\n\t\t// The first object of a step may be any size; later ones must fit what is left.\n\t\tconst first = budget.bytesUsed === 0;\n\t\tif (!first && !budget.canStart({ bytes: 1 })) return \"yield\";\n\n\t\tconst key = this.#mediaChunk.keys.get(record.id);\n\t\tif (key === undefined) {\n\t\t\tbudget.start(1);\n\t\t\tthis.mismatch(\"media\", record.id, \"missing\");\n\t\t} else {\n\t\t\tconst hashed = await hashStoredObject(this.#input.storage, key, {\n\t\t\t\tmaxBytes: first ? undefined : budget.remaining().bytes,\n\t\t\t});\n\t\t\tif (hashed === \"too_large\") return \"yield\";\n\t\t\tbudget.start(Math.max(hashed?.bytes ?? 0, 1));\n\t\t\tif (hashed === null) this.mismatch(\"media\", record.id, \"blob_missing\");\n\t\t\telse if (hashed.sha256 !== record.blob) this.mismatch(\"media\", record.id, \"blob_mismatch\");\n\t\t}\n\t\tthis.#cursor.line = line + 1;\n\t\treturn \"continue\";\n\t}\n\n\tprivate async targetMediaKeys(ids: readonly string[]) {\n\t\tconst rows: Array<{ id: string; storageKey: string }> = [];\n\t\tfor (const batch of chunks([...ids], SQL_BATCH_SIZE)) {\n\t\t\tconst found = await this.#db\n\t\t\t\t.selectFrom(\"media\")\n\t\t\t\t.select([\"id\", \"storage_key\"])\n\t\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t\t.execute();\n\t\t\tfor (const row of found) rows.push({ id: row.id, storageKey: row.storage_key });\n\t\t}\n\t\treturn rows;\n\t}\n\n\t// ── Digest ──\n\n\tprivate async finish(): Promise<VerifyImportStepResult> {\n\t\tconst manifest = await this.#reader.manifest();\n\t\tconst staged = new TransferStagedFileRepository(this.#db);\n\t\tconst recordChunks: Array<[string, number]> = [];\n\t\tfor (const kind of VERIFIED_KINDS) {\n\t\t\tfor (let seq = 0; seq < this.chunkCount(kind, manifest); seq++) {\n\t\t\t\trecordChunks.push([kind, seq]);\n\t\t\t}\n\t\t}\n\t\tconst files = await staged.getMany(\n\t\t\tthis.#input.operationId,\n\t\t\trecordChunks.map(([kind, seq]) => recordChunkPath(kindOf(kind), seq)),\n\t\t);\n\t\tconst tuples: Array<[string, number, string]> = [];\n\t\tfor (const [kind, seq] of recordChunks) {\n\t\t\tconst hash = files.get(recordChunkPath(kindOf(kind), seq))?.logicalSha256;\n\t\t\tif (!hash) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_IMPORT_ERROR\", \"Chunk was not verified\", {\n\t\t\t\t\tdetail: { kind, seq },\n\t\t\t\t});\n\t\t\t}\n\t\t\ttuples.push([kind, seq, hash]);\n\t\t}\n\t\treturn {\n\t\t\tdone: true,\n\t\t\tlogicalDigest: await logicalDigest(tuples),\n\t\t\tcounts: { ...this.#cursor.counts },\n\t\t\tmismatches: [...this.#cursor.mismatches],\n\t\t};\n\t}\n}\n\n/**\n * The importer writes a placeholder media URL relative to the target, so an\n * absolute one in a package record is predicted without its scheme and host.\n */\nfunction predictRelativeMediaUrls(record: SitePackageRecord): SitePackageRecord {\n\tconst text = canonicalJson(record);\n\tconst relative = relativizePlaceholderUrls(text);\n\tif (relative === text) return record;\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- the same record with some URL prefixes removed\n\treturn JSON.parse(relative) as SitePackageRecord;\n}\n\nfunction kindOf(kind: string): RecordKind {\n\tconst found = RECORD_KINDS.find((candidate) => candidate === kind);\n\tif (!found) throw new Error(`Unknown record kind ${kind}`);\n\treturn found;\n}\n\nconst SYNTHETIC: ReadonlySet<string> = new Set(SYNTHETIC_ID_KINDS);\n\nfunction isSyntheticKind(kind: RecordKind): boolean {\n\treturn SYNTHETIC.has(kind);\n}\n\nfunction isSyntheticRecord(\n\trecord: Record<string, unknown>,\n): record is Parameters<typeof syntheticId>[0] & Record<string, unknown> {\n\treturn typeof record.kind === \"string\" && SYNTHETIC.has(record.kind);\n}\n","/**\n * The `rebuild` stage: derived state the importer does not write row by row.\n *\n * - `search`: full-text indexes for collections whose package search config\n * is enabled, populated in rowid ranges, then the collection's final\n * `search_config` (SQLite only; the plan declares `search_unsupported`\n * elsewhere).\n * - `media_usage`: every imported collection is marked stale so the\n * media-usage maintenance engine re-indexes it.\n * - `options`: `POST_IMPORT_OPTION_RESETS`.\n * - `taxonomies`: each taxonomy's structure group, rebuilt from its imported\n * definitions; a group whose name no definition has any more is deleted.\n * - `caches`: isolate caches and every object-cache namespace.\n */\n\nimport { sql } from \"kysely\";\n\nimport { isSqlite } from \"../../database/dialect-helpers.js\";\nimport { parseTaxonomyCollections } from \"../../database/repositories/taxonomy-def.js\";\nimport { markContentMediaUsageCollectionStale } from \"../../media/usage/content-refresh.js\";\nimport {\n\tCacheNamespace,\n\tinvalidateCollectionCache,\n\tinvalidateObjectCache,\n} from \"../../object-cache/index.js\";\nimport { resetRegisteredCollectionsCache } from \"../../schema/collection-slugs-cache.js\";\nimport { invalidateSchemaCache } from \"../../schema/zod-generator.js\";\nimport { FTSManager } from \"../../search/fts-manager.js\";\nimport type { SearchTokenizer } from \"../../search/types.js\";\nimport { SEARCH_TOKENIZERS } from \"../../search/types.js\";\nimport { invalidateSiteSettingsCache } from \"../../settings/index.js\";\nimport { TransferError } from \"../errors.js\";\nimport { compareIds, type CollectionRecord } from \"../format/kinds.js\";\nimport { POST_IMPORT_OPTION_RESETS } from \"../format/settings.js\";\nimport { applyTransformations } from \"../format/transformations.js\";\nimport { REBUILD_STEPS, type RebuildStep } from \"../ops/states.js\";\nimport type { ImportContext } from \"./context.js\";\nimport { ulidFromHash } from \"./ids.js\";\n\nconst FTS_ROWS_PER_UNIT = 500;\nconst FTS_SETUP_STATEMENTS = 20;\nconst FTS_POPULATE_STATEMENTS = 4;\nconst STALE_STATEMENTS = 4;\nconst OPTION_STATEMENTS = 4;\nconst TAXONOMY_STATEMENTS = 4;\n/** Cache invalidation runs no queries; its checkpoint does. */\nconst CACHE_STATEMENTS = 1;\n\nexport interface RebuildPosition {\n\tstep: RebuildStep;\n\tafter: string | null;\n}\n\nexport type RebuildCheckpoint = (position: RebuildPosition) => Promise<void>;\n\n/** Run rebuild units from `position`; returns null when the stage is done. */\nexport async function runRebuild(\n\tcontext: ImportContext,\n\tstart: RebuildPosition,\n\tcheckpoint: RebuildCheckpoint,\n): Promise<RebuildPosition | null> {\n\tlet position: RebuildPosition | null = start;\n\twhile (position) {\n\t\tconst next: RebuildPosition | null | \"budget\" = await runUnit(context, position);\n\t\tif (next === \"budget\") return position;\n\t\tif (next) await checkpoint(next);\n\t\tposition = next;\n\t}\n\treturn null;\n}\n\nfunction nextStep(step: RebuildStep): RebuildPosition | null {\n\tconst following = REBUILD_STEPS[REBUILD_STEPS.indexOf(step) + 1];\n\treturn following ? { step: following, after: null } : null;\n}\n\nasync function collections(context: ImportContext): Promise<CollectionRecord[]> {\n\treturn (await context.allRecords(\"collection\")).toSorted((a, b) => compareIds(a.slug, b.slug));\n}\n\nasync function runUnit(\n\tcontext: ImportContext,\n\tposition: RebuildPosition,\n): Promise<RebuildPosition | null | \"budget\"> {\n\tswitch (position.step) {\n\t\tcase \"search\":\n\t\t\treturn searchUnit(context, position.after);\n\t\tcase \"media_usage\": {\n\t\t\tconst collection = (await collections(context)).find(\n\t\t\t\t(candidate) => position.after === null || compareIds(candidate.slug, position.after) > 0,\n\t\t\t);\n\t\t\tif (!collection) return nextStep(\"media_usage\");\n\t\t\tif (!context.budget.canStart({ queries: STALE_STATEMENTS })) return \"budget\";\n\t\t\tcontext.budget.start();\n\t\t\tawait markContentMediaUsageCollectionStale(\n\t\t\t\tcontext.db,\n\t\t\t\tcollection.slug,\n\t\t\t\t\"CONTENT_USAGE_STALE\",\n\t\t\t);\n\t\t\treturn { step: \"media_usage\", after: collection.slug };\n\t\t}\n\t\tcase \"options\": {\n\t\t\tif (!context.budget.canStart({ queries: OPTION_STATEMENTS })) return \"budget\";\n\t\t\tcontext.budget.start();\n\t\t\tfor (const name of POST_IMPORT_OPTION_RESETS.bumpVersion) {\n\t\t\t\tawait sql`\n\t\t\t\t\tINSERT INTO options (name, value)\n\t\t\t\t\tVALUES (${name}, '2')\n\t\t\t\t\tON CONFLICT(name) DO UPDATE SET value = CASE\n\t\t\t\t\t\tWHEN CAST(options.value AS INTEGER) % 2 = 0\n\t\t\t\t\t\t\tTHEN CAST(CAST(options.value AS INTEGER) + 2 AS TEXT)\n\t\t\t\t\t\tELSE CAST(CAST(options.value AS INTEGER) + 1 AS TEXT)\n\t\t\t\t\tEND\n\t\t\t\t`.execute(context.db);\n\t\t\t}\n\t\t\tawait context.db\n\t\t\t\t.deleteFrom(\"options\")\n\t\t\t\t.where(\"name\", \"in\", [...POST_IMPORT_OPTION_RESETS.delete])\n\t\t\t\t.execute();\n\t\t\treturn nextStep(\"options\");\n\t\t}\n\t\tcase \"taxonomies\":\n\t\t\treturn taxonomyUnit(context, position.after);\n\t\tcase \"caches\":\n\t\t\tif (!context.budget.canStart({ queries: CACHE_STATEMENTS })) return \"budget\";\n\t\t\tcontext.budget.start();\n\t\t\tawait invalidateCaches(context);\n\t\t\treturn nextStep(\"caches\");\n\t}\n}\n\nfunction isTokenizer(value: unknown): value is SearchTokenizer {\n\treturn SEARCH_TOKENIZERS.some((tokenizer) => tokenizer === value);\n}\n\ninterface SearchTarget {\n\trecord: CollectionRecord;\n\tconfig: Record<string, unknown>;\n}\n\nasync function searchTargets(context: ImportContext): Promise<SearchTarget[]> {\n\tconst targets: SearchTarget[] = [];\n\tfor (const record of await collections(context)) {\n\t\tconst final = applyTransformations(record, context.plan, { fieldColumnTypes: new Map() });\n\t\tconst config = final.searchConfig;\n\t\tif (typeof config !== \"object\" || config === null || Array.isArray(config)) continue;\n\t\tif (config.enabled !== true) continue;\n\t\tif (!isSqlite(context.db)) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\t\"Full-text search is not available on this target\",\n\t\t\t\t{ detail: { kind: \"collection\", id: record.id } },\n\t\t\t);\n\t\t}\n\t\ttargets.push({ record, config });\n\t}\n\treturn targets;\n}\n\n/** `after`: null, `slug` (done), or `slug:rowid` (index created, rows ≤ rowid indexed). */\nasync function searchUnit(\n\tcontext: ImportContext,\n\tafter: string | null,\n): Promise<RebuildPosition | null | \"budget\"> {\n\tconst [doneSlug, rowidText] = after?.split(\":\") ?? [];\n\tconst inProgress = rowidText === undefined ? null : Number(rowidText);\n\tconst target = (await searchTargets(context)).find((candidate) =>\n\t\tinProgress === null\n\t\t\t? doneSlug === undefined || compareIds(candidate.record.slug, doneSlug) > 0\n\t\t\t: candidate.record.slug === doneSlug,\n\t);\n\tif (!target) return nextStep(\"search\");\n\tconst slug = target.record.slug;\n\tconst fts = new FTSManager(context.db);\n\n\tif (inProgress === null) {\n\t\tif (!context.budget.canStart({ queries: FTS_SETUP_STATEMENTS })) return \"budget\";\n\t\tcontext.budget.start();\n\t\tconst fields = await fts.getSearchableFields(slug);\n\t\tif (fields.length > 0) {\n\t\t\tconst weights = target.config.weights;\n\t\t\tawait fts.dropFtsTable(slug);\n\t\t\tawait fts.createFtsTable(\n\t\t\t\tslug,\n\t\t\t\tfields,\n\t\t\t\ttypeof weights === \"object\" && weights !== null\n\t\t\t\t\t? Object.fromEntries(\n\t\t\t\t\t\t\tObject.entries(weights).filter(\n\t\t\t\t\t\t\t\t(entry): entry is [string, number] => typeof entry[1] === \"number\",\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t)\n\t\t\t\t\t: undefined,\n\t\t\t\tisTokenizer(target.config.tokenize) ? target.config.tokenize : undefined,\n\t\t\t);\n\t\t}\n\t\treturn { step: \"search\", after: `${slug}:0` };\n\t}\n\n\tif (!context.budget.canStart({ queries: FTS_POPULATE_STATEMENTS })) return \"budget\";\n\tcontext.budget.start();\n\tconst fields = await fts.getSearchableFields(slug);\n\tconst last =\n\t\tfields.length > 0 ? await fts.populateRange(slug, fields, inProgress, FTS_ROWS_PER_UNIT) : null;\n\tif (last !== null) return { step: \"search\", after: `${slug}:${last}` };\n\tawait context.db\n\t\t.updateTable(\"_emdash_collections\")\n\t\t.set({ search_config: JSON.stringify(target.config) })\n\t\t.where(\"id\", \"=\", target.record.id)\n\t\t.execute();\n\treturn { step: \"search\", after: slug };\n}\n\n/**\n * `after`: the last taxonomy name whose group was rebuilt, or null.\n *\n * The group becomes hierarchical if any definition is and lists every collection\n * any definition lists. The definitions keep the package's values, which the\n * verify stage compares; they differ from the group only where the exporting\n * site's locales disagreed.\n */\nasync function taxonomyUnit(\n\tcontext: ImportContext,\n\tafter: string | null,\n): Promise<RebuildPosition | null | \"budget\"> {\n\tif (!context.budget.canStart({ queries: TAXONOMY_STATEMENTS })) return \"budget\";\n\tcontext.budget.start();\n\tconst db = context.db;\n\tlet nextName = db\n\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t.select((eb) => eb.fn.min(\"name\").as(\"name\"));\n\tif (after !== null) nextName = nextName.where(\"name\", \">\", after);\n\tconst defs = await db\n\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t.select([\"id\", \"name\", \"hierarchical\", \"collections\", \"translation_group\"])\n\t\t.where(\"name\", \"=\", nextName)\n\t\t.orderBy(\"id\")\n\t\t.execute();\n\tconst name = defs[0]?.name;\n\tif (name === undefined) {\n\t\tawait db\n\t\t\t.deleteFrom(\"_emdash_taxonomy_def_groups\")\n\t\t\t.where((eb) =>\n\t\t\t\teb.not(\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"_emdash_taxonomy_defs\")\n\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t.whereRef(\"_emdash_taxonomy_defs.name\", \"=\", \"_emdash_taxonomy_def_groups.name\"),\n\t\t\t\t\t),\n\t\t\t\t),\n\t\t\t)\n\t\t\t.execute();\n\t\treturn nextStep(\"taxonomies\");\n\t}\n\n\tconst groupId = defs\n\t\t.map((def) => def.translation_group ?? def.id)\n\t\t.reduce((lowest, candidate) => (candidate < lowest ? candidate : lowest));\n\tconst collectionSlugs = [\n\t\t...new Set(defs.flatMap((def) => parseTaxonomyCollections(def.collections))),\n\t];\n\tconst hierarchical = defs.some((def) => def.hierarchical === 1) ? 1 : 0;\n\tconst taken = await db\n\t\t.selectFrom(\"_emdash_taxonomy_def_groups\")\n\t\t.select(\"id\")\n\t\t.where(\"id\", \"=\", groupId)\n\t\t.where(\"name\", \"!=\", name)\n\t\t.executeTakeFirst();\n\tconst id = taken ? await ulidFromHash(context.operationId, \"taxonomy_group\", name) : groupId;\n\tawait db\n\t\t.insertInto(\"_emdash_taxonomy_def_groups\")\n\t\t.values({ id, name, hierarchical, collections: JSON.stringify(collectionSlugs) })\n\t\t.onConflict((oc) =>\n\t\t\toc\n\t\t\t\t.column(\"name\")\n\t\t\t\t.doUpdateSet({ id, hierarchical, collections: JSON.stringify(collectionSlugs) }),\n\t\t)\n\t\t.execute();\n\treturn { step: \"taxonomies\", after: name };\n}\n\nasync function invalidateCaches(context: ImportContext): Promise<void> {\n\tfor (const namespace of Object.values(CacheNamespace)) invalidateObjectCache(namespace);\n\tfor (const collection of await collections(context)) {\n\t\tinvalidateCollectionCache(collection.slug);\n\t\tinvalidateSchemaCache(collection.slug);\n\t}\n\tinvalidateSiteSettingsCache();\n\tresetRegisteredCollectionsCache();\n\tconst { invalidateTermCache, invalidateTaxonomyDefsCache } =\n\t\tawait import(\"../../taxonomies/index.js\");\n\tconst { invalidateBylineCache } = await import(\"../../bylines/index.js\");\n\tconst { invalidateRedirectCache } = await import(\"../../redirects/cache.js\");\n\tconst { invalidateUrlPatternCache } = await import(\"../../query.js\");\n\tinvalidateTermCache();\n\tinvalidateTaxonomyDefsCache();\n\tinvalidateBylineCache();\n\tinvalidateRedirectCache();\n\tinvalidateUrlPatternCache();\n}\n","/**\n * The `clear_scaffold` stage: delete the seeded scaffold the plan declared\n * (`seeded_scaffold_removed`), one item per unit, then wait until\n * media-usage collection deletions of removed collections have finished so\n * the package may reuse their slugs.\n */\n\nimport { sql } from \"kysely\";\n\nimport { processDueMediaUsageCollectionDeletions } from \"../../media/usage/collection-deletion-processor.js\";\nimport { SchemaError, SchemaRegistry } from \"../../schema/registry.js\";\nimport { TransferError } from \"../errors.js\";\nimport type { ImportTransformation } from \"../format/transformations.js\";\nimport type { ImportContext } from \"./context.js\";\n\nexport type ScaffoldItemRef = Extract<\n\tImportTransformation,\n\t{ code: \"seeded_scaffold_removed\" }\n>[\"items\"][number];\n\nconst ITEM_STATEMENTS = 40;\n\nexport function declaredScaffold(context: ImportContext): readonly ScaffoldItemRef[] {\n\treturn context.plan.transformations.flatMap((transformation) =>\n\t\ttransformation.code === \"seeded_scaffold_removed\" ? transformation.items : [],\n\t);\n}\n\nexport type ScaffoldProgress =\n\t| { state: \"continue\"; step: number }\n\t| { state: \"wait\"; step: number }\n\t| { state: \"done\" };\n\n/**\n * Delete declared items from `step` on. Each item is removed only if it is\n * still the scaffold it was when analyzed (an unassigned term, an empty menu,\n * an empty widget area, a theme section, a seeded block type); deleting an already-deleted item\n * is a no-op.\n */\nexport async function clearScaffold(\n\tcontext: ImportContext,\n\tstep: number,\n\tcheckpoint: (step: number) => Promise<void>,\n): Promise<ScaffoldProgress> {\n\tconst items = declaredScaffold(context);\n\tlet next = step;\n\twhile (next < items.length) {\n\t\tconst item = items[next];\n\t\tif (!item) break;\n\t\tif (!context.budget.canStart({ queries: ITEM_STATEMENTS })) {\n\t\t\treturn { state: \"continue\", step: next };\n\t\t}\n\t\tcontext.budget.start();\n\t\tawait removeItem(context, item);\n\t\tnext++;\n\t\tawait checkpoint(next);\n\t}\n\n\tconst collectionIds = items.flatMap((item) => (item.type === \"collection\" ? [item.id] : []));\n\twhile (collectionIds.length > 0) {\n\t\tif (!context.budget.canStart({ queries: ITEM_STATEMENTS })) {\n\t\t\treturn { state: \"continue\", step: next };\n\t\t}\n\t\tcontext.budget.start();\n\t\tconst pending = await context.db\n\t\t\t.selectFrom(\"_emdash_media_usage_collection_deletions\")\n\t\t\t.select(\"collection_id\")\n\t\t\t.where(\"collection_id\", \"in\", collectionIds)\n\t\t\t.execute();\n\t\tif (pending.length === 0) break;\n\t\tconst tick = await processDueMediaUsageCollectionDeletions(context.db);\n\t\tif (tick.outcome === \"idle\" || tick.outcome === \"claim_lost\" || tick.outcome === \"retry\") {\n\t\t\treturn { state: \"wait\", step: next };\n\t\t}\n\t\tif (tick.outcome === \"failed\") {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_IMPORT_ERROR\",\n\t\t\t\t\"Removing the seeded scaffold collections failed\",\n\t\t\t);\n\t\t}\n\t}\n\treturn { state: \"done\" };\n}\n\nasync function removeItem(context: ImportContext, item: ScaffoldItemRef): Promise<void> {\n\tconst db = context.db;\n\tswitch (item.type) {\n\t\tcase \"collection\": {\n\t\t\tconst row =\n\t\t\t\t(await db\n\t\t\t\t\t.selectFrom(\"_emdash_collections\")\n\t\t\t\t\t.select(\"slug\")\n\t\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t\t.executeTakeFirst()) ??\n\t\t\t\t(await db\n\t\t\t\t\t.selectFrom(\"_emdash_media_usage_collection_deletions\")\n\t\t\t\t\t.select(\"collection_slug as slug\")\n\t\t\t\t\t.where(\"collection_id\", \"=\", item.id)\n\t\t\t\t\t.executeTakeFirst());\n\t\t\tif (!row) return;\n\t\t\ttry {\n\t\t\t\tawait new SchemaRegistry(db).deleteCollection(row.slug);\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof SchemaError && error.code === \"COLLECTION_NOT_FOUND\") return;\n\t\t\t\tif (error instanceof SchemaError) {\n\t\t\t\t\tthrow new TransferError(\"TRANSFER_TARGET_NOT_EMPTY\", \"Scaffold collection is in use\", {\n\t\t\t\t\t\tdetail: { type: item.type, id: item.id, reason: error.code },\n\t\t\t\t\t\tcause: error,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\tcase \"term\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"taxonomies\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"content_taxonomies\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.where(\n\t\t\t\t\t\t\t\t\t\"content_taxonomies.taxonomy_id\",\n\t\t\t\t\t\t\t\t\t\"=\",\n\t\t\t\t\t\t\t\t\teb.fn.coalesce(\"taxonomies.translation_group\", \"taxonomies.id\"),\n\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"menu_item\":\n\t\t\tawait db.deleteFrom(\"_emdash_menu_items\").where(\"id\", \"=\", item.id).execute();\n\t\t\treturn;\n\t\tcase \"widget\":\n\t\t\tawait db.deleteFrom(\"_emdash_widgets\").where(\"id\", \"=\", item.id).execute();\n\t\t\treturn;\n\t\tcase \"taxonomy_def\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_taxonomy_defs\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"taxonomies\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.whereRef(\"taxonomies.name\", \"=\", \"_emdash_taxonomy_defs.name\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"menu\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_menus\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"_emdash_menu_items\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.whereRef(\"_emdash_menu_items.menu_id\", \"=\", \"_emdash_menus.id\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"widget_area\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_widget_areas\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.not(\n\t\t\t\t\t\teb.exists(\n\t\t\t\t\t\t\teb\n\t\t\t\t\t\t\t\t.selectFrom(\"_emdash_widgets\")\n\t\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t\t.whereRef(\"_emdash_widgets.area_id\", \"=\", \"_emdash_widget_areas.id\"),\n\t\t\t\t\t\t),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"section\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_sections\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where(\"source\", \"=\", \"theme\")\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tcase \"block_type\":\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_block_type_versions\")\n\t\t\t\t.where(\"block_type_id\", \"=\", item.id)\n\t\t\t\t.where((eb) =>\n\t\t\t\t\teb.exists(\n\t\t\t\t\t\teb\n\t\t\t\t\t\t\t.selectFrom(\"_emdash_block_types\")\n\t\t\t\t\t\t\t.select(sql`1`.as(\"one\"))\n\t\t\t\t\t\t\t.where(\"_emdash_block_types.id\", \"=\", item.id)\n\t\t\t\t\t\t\t.where(\"_emdash_block_types.source\", \"=\", \"seed\"),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t\t.execute();\n\t\t\tawait db\n\t\t\t\t.deleteFrom(\"_emdash_block_types\")\n\t\t\t\t.where(\"id\", \"=\", item.id)\n\t\t\t\t.where(\"source\", \"=\", \"seed\")\n\t\t\t\t.execute();\n\t\t\treturn;\n\t\tdefault:\n\t\t\tthrow new TransferError(\"TRANSFER_IMPORT_ERROR\", \"Unknown scaffold item type\", {\n\t\t\t\tdetail: { type: item.type, id: item.id },\n\t\t\t});\n\t}\n}\n","/**\n * Import execution: one bounded `advanceImport` step at a time.\n *\n * Stages (`IMPORT_STAGES`): reserve → clear_scaffold → schema → media →\n * terms_bylines → content → relations → presentation → rebuild → verify.\n * Every step claims the operation's lease, runs units until the stage work\n * or the step budget runs out, and checkpoints the typed cursor after each\n * unit through the lease-fenced operation repository. Every unit is\n * idempotent, so an interrupted step is resumed by advancing again (after\n * the lease expires if the interrupted caller still held it). Cancellation\n * requested while a step runs is honored at the next checkpoint.\n */\n\nimport type { Kysely } from \"kysely\";\nimport type { z } from \"zod\";\n\nimport { isPostgres } from \"../../database/dialect-helpers.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { Storage } from \"../../storage/types.js\";\nimport { chunks, SQL_BATCH_SIZE } from \"../../utils/chunks.js\";\nimport { isMissingTableError } from \"../../utils/db-errors.js\";\nimport { VERSION } from \"../../version.js\";\nimport { inspectPortableDomain } from \"../domain.js\";\nimport { isTransferError, TransferError, type TransferErrorCode } from \"../errors.js\";\nimport { planDigest, type Sha256Digest } from \"../format/digest.js\";\nimport { IMPORT_RECORD_STAGES } from \"../format/kinds.js\";\nimport { TRANSFER_LIMITS } from \"../format/limits.js\";\nimport { isPlanExecutable, siteImportPlanSchema, type SiteImportPlan } from \"../format/plan.js\";\nimport { sealReceipt } from \"../format/receipt.js\";\nimport { SITE_PACKAGE_FORMAT_VERSION } from \"../format/version.js\";\nimport { TransferStepBudget } from \"../ops/budget.js\";\nimport { TransferOperationRepository, type TransferOperation } from \"../ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../ops/staged-files.js\";\nimport {\n\tEXECUTING_IMPORT_STATES,\n\ttype ImportCursor,\n\tIMPORT_STAGES,\n\ttype ImportStage,\n\tisTerminalState,\n} from \"../ops/states.js\";\nimport { getOrCreateSiteId } from \"../site-id.js\";\nimport { stagingPrefix } from \"../staging/keys.js\";\nimport { StagedPackageReader } from \"../staging/package.js\";\nimport { TransferStage } from \"../staging/stage.js\";\nimport { ImportContext } from \"./context.js\";\nimport { runRebuild } from \"./rebuild.js\";\nimport { clearScaffold, declaredScaffold } from \"./scaffold.js\";\nimport { firstPosition, ImportCancelledSignal, runRecordStage } from \"./stages.js\";\n\n/** Delay the caller should wait before advancing again after a retry-later step. */\nexport const IMPORT_RETRY_MS = 2000;\n\nexport interface VerifyImportStepInput {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\treader: StagedPackageReader;\n\tplan: SiteImportPlan;\n\t/** The verifier's cursor from its previous step, or null on the first step. */\n\tcursor: unknown;\n\tbudget: TransferStepBudget;\n}\n\nexport type VerifyImportStepResult =\n\t| { done: false; cursor: unknown }\n\t| {\n\t\t\tdone: true;\n\t\t\tlogicalDigest: Sha256Digest;\n\t\t\tcounts: Record<string, number>;\n\t\t\tmismatches: Array<{ kind: string; id: string; reason: string }>;\n\t };\n\nexport type VerifyImportStep = (input: VerifyImportStepInput) => Promise<VerifyImportStepResult>;\n\nexport interface AdvanceImportOptions {\n\tdb: Kysely<Database>;\n\tstorage: Storage;\n\toperationId: string;\n\t/** Verification step (`verifyImportStep` from `transfer/export/verify.ts`). */\n\tverify: VerifyImportStep;\n\t/** Defaults to a budget over the current request's query metrics. */\n\tbudget?: TransferStepBudget;\n}\n\nexport interface AdvanceImportResult {\n\toperation: TransferOperation;\n\t/** When to advance again; null once the operation is terminal. */\n\tnextRequestInMs: number | null;\n\t/** Whether this step moved the import to a terminal state. */\n\tended: boolean;\n}\n\ntype StepResult = Omit<AdvanceImportResult, \"ended\">;\n\n/** Errors another caller's lease explains; the step is abandoned without touching the operation. */\nconst LEASE_CODES: ReadonlySet<TransferErrorCode> = new Set([\n\t\"TRANSFER_LEASE_LOST\",\n\t\"TRANSFER_LEASE_ACTIVE\",\n]);\n\n/**\n * Failures a later step may not hit again, and how many consecutive steps\n * may fail without progress before the import fails. A staged file that\n * cannot be read is usually gone for good, so it gets few attempts; storage\n * and database errors are more often passing. Every other transfer error\n * fails the import at once.\n */\nconst RETRY_LIMITS: Readonly<Partial<Record<TransferErrorCode, number>>> = {\n\tTRANSFER_FILE_MISSING: 3,\n\tTRANSFER_STORAGE_ERROR: 8,\n\tTRANSFER_IMPORT_ERROR: 8,\n};\n\nconst MAX_RETRY_DELAY_MS = 60_000;\n\n/** Delay before the `attempts`th retry: doubling from `IMPORT_RETRY_MS`. */\nexport function importRetryDelay(attempts: number): number {\n\treturn Math.min(IMPORT_RETRY_MS * 2 ** Math.max(0, attempts - 1), MAX_RETRY_DELAY_MS);\n}\n\nconst EXECUTABLE_STATES = [\"planned\", \"running\", \"verifying\"] as const;\n\nfunction result(operation: TransferOperation, nextRequestInMs: number): StepResult {\n\treturn {\n\t\toperation,\n\t\tnextRequestInMs: isTerminalState(operation.kind, operation.state) ? null : nextRequestInMs,\n\t};\n}\n\n/**\n * Mark a planned import for execution. Requires the digests the caller\n * reviewed; the first `advanceImport` then reserves the target. Repeating\n * the request for an import that already started returns it unchanged, with\n * `requested` false.\n */\nexport async function requestImportExecution(input: {\n\tdb: Kysely<Database>;\n\toperationId: string;\n\tpackageDigest: Sha256Digest;\n\tplanDigest: Sha256Digest;\n}): Promise<{ operation: TransferOperation; requested: boolean }> {\n\tconst ops = new TransferOperationRepository(input.db);\n\tconst operation = await ops.require(input.operationId);\n\tif (operation.kind !== \"import\") {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an import\");\n\t}\n\tif (operation.packageDigest !== input.packageDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Package digest does not match\");\n\t}\n\tif (operation.planDigest === null || operation.planDigest !== input.planDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan digest does not match\");\n\t}\n\tif (operation.state !== \"planned\" || operation.stage === \"reserve\") {\n\t\tconst started =\n\t\t\t(EXECUTING_IMPORT_STATES as readonly string[]).includes(operation.state) ||\n\t\t\toperation.mutationStartedAt !== null;\n\t\tif (operation.state === \"planned\" || started) return { operation, requested: false };\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be executed in its state\");\n\t}\n\tconst claim = await ops.claim(operation.id, [\"planned\"]);\n\tif (claim.outcome === \"lease_active\") {\n\t\tthrow new TransferError(\"TRANSFER_LEASE_ACTIVE\", \"Import is busy; try again\");\n\t}\n\tif (claim.outcome === \"invalid_state\") {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import cannot be executed in its state\");\n\t}\n\tconst requested = await ops.release(operation.id, claim.leaseToken, {\n\t\tstage: \"reserve\",\n\t\tcursor: { stage: \"reserve\" },\n\t});\n\treturn { operation: requested, requested: true };\n}\n\nexport async function advanceImport(options: AdvanceImportOptions): Promise<AdvanceImportResult> {\n\tconst ops = new TransferOperationRepository(options.db);\n\tconst claim = await ops.claim(options.operationId, EXECUTABLE_STATES);\n\tif (claim.outcome !== \"claimed\") {\n\t\tif (claim.operation.kind !== \"import\") {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an import\");\n\t\t}\n\t\treturn { ...result(claim.operation, IMPORT_RETRY_MS), ended: false };\n\t}\n\t// Only the lease holder moves a claimed import to a terminal state.\n\tconst step = await advanceClaimed(options, ops, claim.operation, claim.leaseToken);\n\treturn { ...step, ended: isTerminalState(step.operation.kind, step.operation.state) };\n}\n\nasync function advanceClaimed(\n\toptions: AdvanceImportOptions,\n\tops: TransferOperationRepository,\n\toperation: TransferOperation,\n\tleaseToken: string,\n): Promise<StepResult> {\n\tif (\n\t\toperation.kind !== \"import\" ||\n\t\t(operation.state === \"planned\" && operation.stage !== \"reserve\")\n\t) {\n\t\tawait ops.release(operation.id, leaseToken);\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\"Import has not been requested for execution\",\n\t\t);\n\t}\n\n\ttry {\n\t\tif (await mediaUsageActivating(options.db)) {\n\t\t\treturn result(await ops.release(operation.id, leaseToken), IMPORT_RETRY_MS);\n\t\t}\n\t\tconst context = await loadContext(options, ops, operation, leaseToken);\n\t\treturn await runStep(context, options.verify);\n\t} catch (error) {\n\t\tif (error instanceof ImportCancelledSignal) {\n\t\t\treturn result(await ops.finishCancelled(operation.id, leaseToken), 0);\n\t\t}\n\t\tif (isTransferError(error) && LEASE_CODES.has(error.code)) throw error;\n\t\tconst code: TransferErrorCode = isTransferError(error) ? error.code : \"TRANSFER_IMPORT_ERROR\";\n\t\tconst detail = isTransferError(error) ? error.detail : undefined;\n\t\tconst limit = RETRY_LIMITS[code];\n\t\tif (limit === undefined || (isTransferError(error) && code === \"TRANSFER_IMPORT_ERROR\")) {\n\t\t\treturn result(await ops.fail(operation.id, leaseToken, { code, detail }), 0);\n\t\t}\n\t\tif (!isTransferError(error)) console.error(\"[transfer] import step failed:\", error);\n\t\tconst latest = await ops.require(operation.id);\n\t\tconst attempts = retryAttempts(latest) + 1;\n\t\tconst retryDetail = { ...detail, attempts };\n\t\tif (attempts >= limit) {\n\t\t\treturn result(await ops.fail(operation.id, leaseToken, { code, detail: retryDetail }), 0);\n\t\t}\n\t\tconst released = await ops.release(operation.id, leaseToken, {\n\t\t\tretryError: { code, detail: retryDetail },\n\t\t});\n\t\treturn result(released, importRetryDelay(attempts));\n\t}\n}\n\n/** Consecutive failed steps recorded since the import last made progress. */\nfunction retryAttempts(operation: TransferOperation): number {\n\tif (operation.errorCode === null || isTerminalState(operation.kind, operation.state)) return 0;\n\tconst attempts = operation.errorDetail?.attempts;\n\treturn typeof attempts === \"number\" ? attempts : 0;\n}\n\nasync function mediaUsageActivating(db: Kysely<Database>): Promise<boolean> {\n\ttry {\n\t\tconst row = await db\n\t\t\t.selectFrom(\"_emdash_media_usage_activation\")\n\t\t\t.select(\"state\")\n\t\t\t.where(\"task_key\", \"=\", \"incremental_capture\")\n\t\t\t.executeTakeFirst();\n\t\treturn row?.state === \"activating\";\n\t} catch (error) {\n\t\tif (isMissingTableError(error)) return false;\n\t\tthrow error;\n\t}\n}\n\nasync function loadContext(\n\toptions: AdvanceImportOptions,\n\tops: TransferOperationRepository,\n\toperation: TransferOperation,\n\tleaseToken: string,\n): Promise<ImportContext> {\n\tconst stage = new TransferStage(\n\t\toptions.storage,\n\t\tstagingPrefix(\"import\", operation.id, operation.stagingSecret),\n\t);\n\tconst reader = new StagedPackageReader(\n\t\tstage,\n\t\tnew TransferStagedFileRepository(options.db).verifiedDigests(operation.id),\n\t);\n\tconst manifest = await reader.manifest();\n\tconst packageDigest = await reader.digest();\n\tif (operation.packageDigest !== packageDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Staged package does not match\");\n\t}\n\tconst planText = await stage.readAux(\"plan\", TRANSFER_LIMITS.manifestBytes);\n\tif (planText === null) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Import plan is missing\");\n\t}\n\tconst parsed = siteImportPlanSchema.safeParse(JSON.parse(planText));\n\tif (!parsed.success || (await planDigest(parsed.data)) !== operation.planDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Import plan does not match\");\n\t}\n\tconst plan = parsed.data;\n\tif (plan.packageDigest !== packageDigest) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan is for another package\");\n\t}\n\tif (!isPlanExecutable(plan)) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_BLOCKED\", \"Import plan has blockers\");\n\t}\n\treturn new ImportContext(\n\t\toptions.db,\n\t\toptions.storage,\n\t\tops,\n\t\toperation,\n\t\tleaseToken,\n\t\tplan,\n\t\tmanifest,\n\t\treader,\n\t\toptions.budget ?? new TransferStepBudget(),\n\t);\n}\n\nfunction stageProgress(stage: ImportStage) {\n\treturn { done: IMPORT_STAGES.indexOf(stage), total: IMPORT_STAGES.length };\n}\n\nasync function checkpoint(\n\tcontext: ImportContext,\n\tcursor: ImportCursor,\n\tpatch: { state?: \"running\" | \"verifying\"; markMutationStarted?: true } = {},\n): Promise<void> {\n\tconst operation = await context.ops.advance(context.operationId, context.leaseToken, {\n\t\t...patch,\n\t\t...(context.operation.errorCode === null ? {} : { retryError: null }),\n\t\tstage: cursor.stage,\n\t\tcursor,\n\t\tprogress: stageProgress(cursor.stage),\n\t});\n\tcontext.operation = operation;\n\tif (operation.cancelRequestedAt !== null) throw new ImportCancelledSignal();\n}\n\nfunction currentCursor(operation: TransferOperation): ImportCursor {\n\tconst cursor = operation.cursor;\n\tif (cursor === null) return { stage: \"reserve\" };\n\tif (!(IMPORT_STAGES as readonly string[]).includes(cursor.stage)) {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation cursor is not an import cursor\");\n\t}\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- stage checked against IMPORT_STAGES\n\treturn cursor as ImportCursor;\n}\n\nfunction nextRecordStageCursor(stage: ImportStage): ImportCursor {\n\tconst next = IMPORT_STAGES[IMPORT_STAGES.indexOf(stage) + 1];\n\tif (next === \"rebuild\") return { stage: \"rebuild\", step: \"search\", after: null };\n\tconst recordStage = IMPORT_RECORD_STAGES.find((candidate: string) => candidate === next);\n\tif (!recordStage) throw new Error(`No record stage follows ${stage}`);\n\treturn { stage: recordStage, position: firstPosition(recordStage) };\n}\n\n/** The checkpoint that moves the cursor to the next stage. */\nconst TRANSITION_STATEMENTS = 1;\n\nasync function yieldStep(context: ImportContext, nextRequestInMs: number): Promise<StepResult> {\n\treturn result(\n\t\tawait context.ops.release(context.operationId, context.leaseToken),\n\t\tnextRequestInMs,\n\t);\n}\n\nasync function runStep(context: ImportContext, verify: VerifyImportStep): Promise<StepResult> {\n\tfor (;;) {\n\t\tconst cursor = currentCursor(context.operation);\n\t\tswitch (cursor.stage) {\n\t\t\tcase \"reserve\":\n\t\t\t\tawait reserve(context);\n\t\t\t\tbreak;\n\t\t\tcase \"clear_scaffold\": {\n\t\t\t\tconst progress = await clearScaffold(context, cursor.step, (step) =>\n\t\t\t\t\tcheckpoint(context, { stage: \"clear_scaffold\", step }),\n\t\t\t\t);\n\t\t\t\tif (progress.state === \"continue\") return yieldStep(context, 0);\n\t\t\t\tif (progress.state === \"wait\") return yieldStep(context, IMPORT_RETRY_MS);\n\t\t\t\tif (!context.budget.canStart({ queries: TRANSITION_STATEMENTS })) {\n\t\t\t\t\treturn yieldStep(context, 0);\n\t\t\t\t}\n\t\t\t\tawait checkpoint(context, { stage: \"schema\", position: firstPosition(\"schema\") });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"schema\":\n\t\t\tcase \"media\":\n\t\t\tcase \"terms_bylines\":\n\t\t\tcase \"content\":\n\t\t\tcase \"relations\":\n\t\t\tcase \"presentation\": {\n\t\t\t\tconst stage = cursor.stage;\n\t\t\t\tconst remaining = await runRecordStage(context, stage, cursor.position, (position) =>\n\t\t\t\t\tcheckpoint(context, { stage, position }),\n\t\t\t\t);\n\t\t\t\tif (remaining || !context.budget.canStart({ queries: TRANSITION_STATEMENTS })) {\n\t\t\t\t\treturn yieldStep(context, 0);\n\t\t\t\t}\n\t\t\t\tawait checkpoint(context, nextRecordStageCursor(stage));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"rebuild\": {\n\t\t\t\tconst remaining = await runRebuild(\n\t\t\t\t\tcontext,\n\t\t\t\t\t{ step: cursor.step, after: cursor.after },\n\t\t\t\t\t(position) => checkpoint(context, { stage: \"rebuild\", ...position }),\n\t\t\t\t);\n\t\t\t\tif (remaining) return yieldStep(context, 0);\n\t\t\t\tawait checkpoint(\n\t\t\t\t\tcontext,\n\t\t\t\t\t{ stage: \"verify\", position: null, mediaAfter: null, mismatches: 0 },\n\t\t\t\t\t{ state: \"verifying\" },\n\t\t\t\t);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"verify\":\n\t\t\t\treturn runVerify(context, verify, cursor.verifier ?? null);\n\t\t}\n\t}\n}\n\nasync function reserve(context: ImportContext): Promise<void> {\n\t// Running fences site writes before the checks below, so none can slip in\n\t// between them and the first write; a failed check leaves no fence behind\n\t// because the mutation has not started.\n\tawait checkpoint(context, { stage: \"reserve\" }, { state: \"running\" });\n\tconst siteId = await getOrCreateSiteId(context.db);\n\tconst dialect = isPostgres(context.db) ? \"postgres\" : \"sqlite\";\n\tif (siteId !== context.plan.target.siteId || dialect !== context.plan.target.dialect) {\n\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan was made for another target\");\n\t}\n\tawait assertMappedUsersExist(context);\n\tconst domain = await inspectPortableDomain(context.db);\n\tconst declared = new Set(declaredScaffold(context).map((item) => `${item.type}:${item.id}`));\n\tconst undeclared = domain.seededScaffold.filter(\n\t\t(item) => !declared.has(`${item.type}:${item.id}`),\n\t);\n\tif (!domain.empty || undeclared.length > 0) {\n\t\tthrow new TransferError(\"TRANSFER_TARGET_NOT_EMPTY\", \"The target site is not empty\", {\n\t\t\tdetail: { blockers: domain.blockers.length, undeclaredScaffold: undeclared.length },\n\t\t});\n\t}\n\tawait checkpoint(context, { stage: \"clear_scaffold\", step: 0 }, { markMutationStarted: true });\n}\n\nasync function assertMappedUsersExist(context: ImportContext): Promise<void> {\n\tconst mappings = Object.entries(context.plan.decisions.principalMappings);\n\tconst userIds = [...new Set(mappings.flatMap(([, userId]) => (userId === null ? [] : [userId])))];\n\tconst found = new Set<string>();\n\tfor (const batch of chunks(userIds, SQL_BATCH_SIZE)) {\n\t\tconst rows = await context.db\n\t\t\t.selectFrom(\"users\")\n\t\t\t.select(\"id\")\n\t\t\t.where(\"id\", \"in\", batch)\n\t\t\t.execute();\n\t\tfor (const row of rows) found.add(row.id);\n\t}\n\tconst missing = mappings.find(([, userId]) => userId !== null && !found.has(userId));\n\tif (missing) {\n\t\tthrow new TransferError(\"TRANSFER_DECISIONS_INVALID\", \"A mapped target user no longer exists\", {\n\t\t\tdetail: { principal: missing[0] },\n\t\t});\n\t}\n}\n\nasync function runVerify(\n\tcontext: ImportContext,\n\tverify: VerifyImportStep,\n\tstart: unknown,\n): Promise<StepResult> {\n\tconst step = await verify({\n\t\tdb: context.db,\n\t\tstorage: context.storage,\n\t\toperationId: context.operationId,\n\t\treader: context.reader,\n\t\tplan: context.plan,\n\t\tcursor: start,\n\t\tbudget: context.budget,\n\t});\n\t// The verifier runs until its budget is spent, so an unfinished step ends this one.\n\tif (!step.done) {\n\t\tawait checkpoint(context, {\n\t\t\tstage: \"verify\",\n\t\t\tposition: null,\n\t\t\tmediaAfter: null,\n\t\t\tmismatches: 0,\n\t\t\tverifier: toJson(step.cursor),\n\t\t});\n\t\treturn yieldStep(context, 0);\n\t}\n\tif (step.mismatches.length > 0) {\n\t\tconst detail: Record<string, string | number> = { mismatches: step.mismatches.length };\n\t\tstep.mismatches.slice(0, TRANSFER_LIMITS.verificationMismatches).forEach((mismatch, index) => {\n\t\t\tdetail[`mismatch_${index}`] = `${mismatch.kind}:${mismatch.id}:${mismatch.reason}`.slice(\n\t\t\t\t0,\n\t\t\t\t512,\n\t\t\t);\n\t\t});\n\t\tthrow new TransferError(\n\t\t\t\"TRANSFER_VERIFICATION_FAILED\",\n\t\t\t\"Imported site does not match the package\",\n\t\t\t{\n\t\t\t\tdetail,\n\t\t\t},\n\t\t);\n\t}\n\tconst operation = context.operation;\n\tif (operation.packageDigest === null || operation.planDigest === null) {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import digests are missing\");\n\t}\n\tconst receipt = await sealReceipt({\n\t\toperationId: operation.id,\n\t\tpackageDigest: operation.packageDigest,\n\t\tplanDigest: operation.planDigest,\n\t\ttargetSiteId: context.plan.target.siteId,\n\t\toriginSiteId: context.manifest.originSiteId,\n\t\tformatVersion: SITE_PACKAGE_FORMAT_VERSION,\n\t\timporterEmDashVersion: VERSION,\n\t\tcompletedAt: new Date().toISOString(),\n\t\tlogicalDigest: step.logicalDigest,\n\t\tcounts: step.counts,\n\t\twarnings: context.plan.warnings\n\t\t\t.slice(0, 500)\n\t\t\t.map((warning) => ({ code: warning.code, message: warning.message })),\n\t\tverification: \"verified\",\n\t});\n\tconst completed = await context.ops.complete(operation.id, context.leaseToken, {\n\t\treceipt,\n\t\tprogress: { done: IMPORT_STAGES.length, total: IMPORT_STAGES.length },\n\t});\n\treturn result(completed, 0);\n}\n\nfunction toJson(value: unknown): z.infer<ReturnType<typeof z.json>> {\n\t// eslint-disable-next-line typescript/no-unsafe-type-assertion -- the verifier's cursor is plain JSON by contract; the cursor schema validates it on write\n\treturn value as z.infer<ReturnType<typeof z.json>>;\n}\n","/**\n * Site transfer handlers: capabilities, exports and their downloads, staged\n * import uploads, analysis, execution, operation status and control, and MCP\n * approval grants.\n *\n * Operations are always serialized with `toPublicOperation`, which drops the\n * staging secret and lease token.\n *\n * Import upload flow: `POST imports` with the manifest stages it and declares\n * the index chunks the manifest pins. Each index chunk upload declares every\n * file that chunk lists. A client uploads whatever `missing` lists, then asks\n * for `missing` again, until it is empty; index paths sort before record and\n * media paths, so they are listed first.\n */\n\nimport type { Permission, RoleLevel } from \"@emdash-cms/auth\";\nimport { hasPermission } from \"@emdash-cms/auth\";\nimport type { Kysely } from \"kysely\";\n\nimport {\n\tdecodeCursor,\n\tencodeCursor,\n\tInvalidCursorError,\n} from \"../../database/repositories/types.js\";\nimport type { Database } from \"../../database/types.js\";\nimport type { DownloadResult, Storage } from \"../../storage/types.js\";\nimport { analyzeImportStep, finalizePlan, loadImportPlan } from \"../../transfer/analyze/step.js\";\nimport type { AnalysisTargetContext } from \"../../transfer/analyze/target.js\";\nimport { validateStagedPackageStep } from \"../../transfer/analyze/validate.js\";\nimport { recordTransferAudit } from \"../../transfer/audit.js\";\nimport type { TransferApprovalAction } from \"../../transfer/auth.js\";\nimport { packSitePackage, type PackageFileSource } from \"../../transfer/container/tar.js\";\nimport { inspectPortableDomain } from \"../../transfer/domain.js\";\nimport { isTransferError, TransferError } from \"../../transfer/errors.js\";\nimport {\n\tadvanceExport,\n\tcreateExport,\n\texportOptionsSchema,\n\topenExportPackage,\n\ttype ExportOptions,\n\ttype ExportPackageValidator,\n} from \"../../transfer/export/exporter.js\";\nimport { verifyImportStep } from \"../../transfer/export/verify.js\";\nimport {\n\tcanonicalDigest,\n\tcreateHashingStream,\n\tcreateSha256,\n\tpackageDigest,\n\tsha256Hex,\n\ttype Sha256Digest,\n} from \"../../transfer/format/digest.js\";\nimport { OPTIONAL_FEATURES, SITE_PACKAGE_FEATURES } from \"../../transfer/format/features.js\";\nimport { TRANSFER_LIMITS } from \"../../transfer/format/limits.js\";\nimport { parseManifest, type SitePackageManifest } from \"../../transfer/format/manifest.js\";\nimport { MANIFEST_PATH, parsePackagePath } from \"../../transfer/format/paths.js\";\nimport {\n\tisPlanExecutable,\n\ttype SiteImportDecisionsInput,\n\ttype SiteImportPlan,\n} from \"../../transfer/format/plan.js\";\nimport type { SiteImportReceipt } from \"../../transfer/format/receipt.js\";\nimport { SUPPORTED_FORMAT_VERSIONS } from \"../../transfer/format/version.js\";\nimport { advanceImport, requestImportExecution } from \"../../transfer/import/index.js\";\nimport {\n\tTransferApprovalRepository,\n\ttype ApprovalStatus,\n\ttype TransferApproval,\n} from \"../../transfer/ops/approvals.js\";\nimport { TransferStepBudget } from \"../../transfer/ops/budget.js\";\nimport {\n\ttoPublicOperation,\n\tTransferOperationRepository,\n\ttype PublicTransferOperation,\n\ttype TransferOperation,\n} from \"../../transfer/ops/operations.js\";\nimport { TransferStagedFileRepository } from \"../../transfer/ops/staged-files.js\";\nimport { stagingPrefix } from \"../../transfer/staging/keys.js\";\nimport { StagedPackageReader } from \"../../transfer/staging/package.js\";\nimport { TransferStage } from \"../../transfer/staging/stage.js\";\nimport type { ApiResult } from \"../types.js\";\n\n/** Poll delay suggested while another request holds an operation's lease. */\nconst LEASE_RETRY_MS = 1000;\n\nfunction isLeaseError(error: unknown): boolean {\n\treturn (\n\t\tisTransferError(error) &&\n\t\t(error.code === \"TRANSFER_LEASE_LOST\" || error.code === \"TRANSFER_LEASE_ACTIVE\")\n\t);\n}\n\nconst PAGE_LIMIT_DEFAULT = 50;\nconst PAGE_LIMIT_MAX = 100;\n\ntype ErrorResult = Extract<ApiResult<never>, { success: false }>;\n\nfunction failure(code: string, message: string, details?: Record<string, unknown>): ErrorResult {\n\treturn {\n\t\tsuccess: false,\n\t\terror: details === undefined ? { code, message } : { code, message, details },\n\t};\n}\n\nfunction errorResult(error: unknown, fallbackCode: string, fallbackMessage: string): ErrorResult {\n\tif (isTransferError(error)) {\n\t\treturn failure(error.code, error.message, error.detail ? { ...error.detail } : undefined);\n\t}\n\tif (error instanceof InvalidCursorError) {\n\t\treturn failure(\"INVALID_CURSOR\", \"Invalid pagination cursor\");\n\t}\n\tconsole.error(`[transfer] ${fallbackMessage}:`, error);\n\treturn failure(fallbackCode, fallbackMessage);\n}\n\nfunction pageLimit(limit: number | undefined): number {\n\treturn Math.min(Math.max(Math.trunc(limit ?? PAGE_LIMIT_DEFAULT), 1), PAGE_LIMIT_MAX);\n}\n\nfunction decodeTimeCursor(\n\tcursor: string | undefined,\n): { createdAt: string; id: string } | undefined {\n\tif (cursor === undefined) return undefined;\n\tconst { orderValue, id } = decodeCursor(cursor);\n\treturn { createdAt: orderValue, id };\n}\n\nfunction stageFor(storage: Storage, operation: TransferOperation): TransferStage {\n\treturn new TransferStage(\n\t\tstorage,\n\t\tstagingPrefix(operation.kind, operation.id, operation.stagingSecret),\n\t);\n}\n\nasync function requireImport(\n\toperations: TransferOperationRepository,\n\toperationId: string,\n): Promise<TransferOperation> {\n\tconst operation = await operations.get(operationId);\n\tif (!operation || operation.kind !== \"import\") {\n\t\tthrow new TransferError(\"TRANSFER_OPERATION_NOT_FOUND\", \"Transfer operation not found\");\n\t}\n\treturn operation;\n}\n\n// ── Capabilities ────────────────────────────────────────────────\n\nexport interface TransferCapabilities {\n\tformatVersions: string[];\n\tfeatures: string[];\n\toptionalFeatures: string[];\n\tlimits: {\n\t\tmanifestBytes: number;\n\t\trecordLineBytes: number;\n\t\tchunkBytes: number;\n\t\tchunkRecords: number;\n\t\ttotalRecords: number;\n\t\ttotalFiles: number;\n\t\tindexChunks: number;\n\t\tjsonDepth: number;\n\t\tmaxBlobBytes: number;\n\t};\n\tportableDomain: {\n\t\tempty: boolean;\n\t\tblockers: Array<Record<string, string>>;\n\t\tseededScaffold: Array<Record<string, string>>;\n\t};\n}\n\nexport async function handleTransferCapabilities(\n\tdb: Kysely<Database>,\n\ttarget: AnalysisTargetContext,\n): Promise<ApiResult<TransferCapabilities>> {\n\ttry {\n\t\tconst domain = await inspectPortableDomain(db);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\tformatVersions: [...SUPPORTED_FORMAT_VERSIONS],\n\t\t\t\tfeatures: [...SITE_PACKAGE_FEATURES],\n\t\t\t\toptionalFeatures: [...OPTIONAL_FEATURES].toSorted(),\n\t\t\t\tlimits: {\n\t\t\t\t\tmanifestBytes: TRANSFER_LIMITS.manifestBytes,\n\t\t\t\t\trecordLineBytes: TRANSFER_LIMITS.recordLineBytes,\n\t\t\t\t\tchunkBytes: TRANSFER_LIMITS.chunkBytes,\n\t\t\t\t\tchunkRecords: TRANSFER_LIMITS.chunkRecords,\n\t\t\t\t\ttotalRecords: TRANSFER_LIMITS.totalRecords,\n\t\t\t\t\ttotalFiles: TRANSFER_LIMITS.totalFiles,\n\t\t\t\t\tindexChunks: TRANSFER_LIMITS.indexChunks,\n\t\t\t\t\tjsonDepth: TRANSFER_LIMITS.jsonDepth,\n\t\t\t\t\tmaxBlobBytes: target.maxUploadSize,\n\t\t\t\t},\n\t\t\t\tportableDomain: {\n\t\t\t\t\tempty: domain.empty,\n\t\t\t\t\tblockers: domain.blockers.map((blocker) => ({ ...blocker })),\n\t\t\t\t\tseededScaffold: domain.seededScaffold.map((item) => ({ ...item })),\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_ANALYZE_ERROR\", \"Failed to read transfer capabilities\");\n\t}\n}\n\n// ── Imports: creation and uploads ───────────────────────────────\n\nexport interface TransferMissingFiles {\n\titems: Array<{ path: string; bytes: number; sha256: string }>;\n\tnextCursor?: string;\n}\n\nasync function listMissing(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\toptions: { cursor?: string; limit?: number },\n): Promise<TransferMissingFiles> {\n\tconst limit = pageLimit(options.limit);\n\tconst after = options.cursor === undefined ? undefined : decodeCursor(options.cursor).orderValue;\n\tconst files = await new TransferStagedFileRepository(db).list(operationId, {\n\t\tstate: \"declared\",\n\t\tafter,\n\t\tlimit: limit + 1,\n\t});\n\tconst items = files\n\t\t.slice(0, limit)\n\t\t.map((file) => ({ path: file.path, bytes: file.bytes, sha256: file.sha256 }));\n\tconst last = items.at(-1);\n\treturn files.length > limit && last\n\t\t? { items, nextCursor: encodeCursor(last.path, last.path) }\n\t\t: { items };\n}\n\nasync function stageManifest(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperation: TransferOperation,\n\tmanifest: SitePackageManifest,\n\tbytes: Uint8Array,\n): Promise<void> {\n\tconst staged = new TransferStagedFileRepository(db);\n\tconst existing = await staged.get(operation.id, MANIFEST_PATH);\n\tif (existing?.state !== \"verified\") {\n\t\tconst sha256 = await sha256Hex(bytes);\n\t\tawait stageFor(storage, operation).putVerified(MANIFEST_PATH, bytes, bytes.byteLength, sha256, {\n\t\t\tcontentType: \"application/json\",\n\t\t\tkeepExistingOnFailure: () => staged.isVerified(operation.id, MANIFEST_PATH),\n\t\t});\n\t\tawait staged.declareMany(\n\t\t\toperation.id,\n\t\t\t[{ path: MANIFEST_PATH, bytes: bytes.byteLength, sha256 }],\n\t\t\t\"verified\",\n\t\t);\n\t}\n\tawait staged.declareMany(\n\t\toperation.id,\n\t\tmanifest.index.map((ref) => ({ path: ref.path, bytes: ref.bytes, sha256: ref.sha256 })),\n\t);\n}\n\nexport interface CreateImportInput {\n\tuserId: string;\n\t/** Raw `manifest.json` bytes (canonical JSON). */\n\tmanifest: Uint8Array;\n\tidempotencyKey?: string;\n}\n\n/**\n * Create an import from a manifest, stage the manifest, and return the first\n * page of files still to upload. The same idempotency key with the same\n * manifest returns the existing operation; with a different manifest it\n * fails with `TRANSFER_IDEMPOTENCY_CONFLICT`.\n */\nexport async function handleImportCreate(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: CreateImportInput,\n): Promise<\n\tApiResult<{ operation: PublicTransferOperation; created: boolean; missing: TransferMissingFiles }>\n> {\n\ttry {\n\t\tconst manifest = parseManifest(input.manifest);\n\t\tconst digest = await packageDigest(manifest);\n\t\tconst domain = await inspectPortableDomain(db);\n\t\tif (!domain.empty) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_TARGET_NOT_EMPTY\",\n\t\t\t\t\"This site already has content; import needs an empty site\",\n\t\t\t\t{ detail: { blockers: domain.blockers.length } },\n\t\t\t);\n\t\t}\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tconst { operation, created } = await operations.create({\n\t\t\tkind: \"import\",\n\t\t\tcreatedBy: input.userId,\n\t\t\tidempotencyKey: input.idempotencyKey,\n\t\t\tpackageDigest: digest,\n\t\t\toriginSiteId: manifest.originSiteId,\n\t\t});\n\t\tif (operation.kind !== \"import\") {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Operation is not an import\");\n\t\t}\n\t\tif (created) {\n\t\t\tawait recordTransferAudit(db, {\n\t\t\t\tactorId: input.userId,\n\t\t\t\taction: \"transfer_import_create\",\n\t\t\t\tresourceType: \"transfer_operation\",\n\t\t\t\tresourceId: operation.id,\n\t\t\t\tdetails: { packageDigest: digest },\n\t\t\t});\n\t\t}\n\t\tif (operation.state === \"uploading\") {\n\t\t\tawait stageManifest(db, storage, operation, manifest, input.manifest);\n\t\t}\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\toperation: toPublicOperation(operation),\n\t\t\t\tcreated,\n\t\t\t\tmissing: await listMissing(db, operation.id, {}),\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to create import\");\n\t}\n}\n\nexport async function handleImportMissing(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\toptions: { cursor?: string; limit?: number },\n): Promise<ApiResult<TransferMissingFiles>> {\n\ttry {\n\t\tawait requireImport(new TransferOperationRepository(db), operationId);\n\t\treturn { success: true, data: await listMissing(db, operationId, options) };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to list missing files\");\n\t}\n}\n\nexport interface UploadImportFileInput {\n\toperationId: string;\n\tpath: string;\n\t/** `Content-Length` of the request. */\n\tcontentLength: number;\n\tbody: ReadableStream<Uint8Array> | null;\n\t/** Largest media blob the site accepts (`maxUploadSize`). */\n\tmaxBlobBytes: number;\n}\n\nexport interface UploadImportFileResult {\n\tpath: string;\n\tbytes: number;\n\t/** True when the path was already verified and the body matched it. */\n\talreadyVerified: boolean;\n\t/** Declared files still to upload. */\n\tremaining: number;\n}\n\nfunction fileLimit(type: \"manifest\" | \"index\" | \"records\" | \"media\", maxBlobBytes: number): number {\n\tswitch (type) {\n\t\tcase \"manifest\":\n\t\t\treturn TRANSFER_LIMITS.manifestBytes;\n\t\tcase \"media\":\n\t\t\treturn maxBlobBytes;\n\t\tcase \"index\":\n\t\tcase \"records\":\n\t\t\treturn TRANSFER_LIMITS.chunkBytes;\n\t}\n}\n\nasync function digestOfBody(body: ReadableStream<Uint8Array> | null, bytes: number) {\n\tconst hasher = await createSha256();\n\tconst hashing = createHashingStream(hasher, {\n\t\tmaxBytes: bytes,\n\t\tonLimitExceeded: () =>\n\t\t\tnew TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"File is larger than declared\"),\n\t});\n\tif (body) await body.pipeThrough(hashing.stream).pipeTo(new WritableStream());\n\treturn { sha256: await hasher.digest(), bytes: hashing.bytes() };\n}\n\n/**\n * Whether the staged object at `path` exists and still holds exactly the\n * bytes it was verified with. A storage error other than a missing object\n * is thrown rather than read as a mismatch.\n */\nasync function stagedFileIntact(\n\tstage: TransferStage,\n\tpath: string,\n\tfile: { bytes: number; sha256: string },\n): Promise<boolean> {\n\tif (!(await stage.exists(path))) return false;\n\tlet download: DownloadResult;\n\ttry {\n\t\tdownload = await stage.storage.download(stage.keyFor(path));\n\t} catch (error) {\n\t\tthrow new TransferError(\"TRANSFER_STORAGE_ERROR\", \"Failed to read a staged file\", {\n\t\t\tcause: error,\n\t\t});\n\t}\n\ttry {\n\t\tconst stored = await digestOfBody(download.body, file.bytes);\n\t\treturn stored.bytes === file.bytes && stored.sha256 === file.sha256;\n\t} catch (error) {\n\t\tif (isTransferError(error) && error.code === \"TRANSFER_FILE_SIZE_MISMATCH\") return false;\n\t\tthrow error;\n\t}\n}\n\n/**\n * Stream one declared package file into staging, verifying its size and\n * digest. Uploading an index chunk declares the files it lists. A path that\n * is already verified is only compared, never written, while its staged\n * object still matches; once that object no longer matches (a failed\n * concurrent upload of the same path overwrote it), an upload replaces it.\n * An upload that is still streaming when analysis starts is refused.\n */\nexport async function handleImportFileUpload(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: UploadImportFileInput,\n): Promise<ApiResult<UploadImportFileResult>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tconst operation = await requireImport(operations, input.operationId);\n\t\tif (operation.state !== \"uploading\") {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\t\"Files can only be uploaded before analysis\",\n\t\t\t);\n\t\t}\n\t\tconst parsed = parsePackagePath(input.path);\n\t\tif (!parsed) {\n\t\t\tthrow new TransferError(\"TRANSFER_PATH_INVALID\", \"Invalid package path\");\n\t\t}\n\t\tconst staged = new TransferStagedFileRepository(db);\n\t\tconst file = await staged.get(operation.id, parsed.path);\n\t\tif (!file) {\n\t\t\tthrow new TransferError(\"TRANSFER_FILE_NOT_DECLARED\", \"File is not declared by the package\", {\n\t\t\t\tdetail: { path: parsed.path },\n\t\t\t});\n\t\t}\n\t\tconst limit = fileLimit(parsed.type, input.maxBlobBytes);\n\t\tif (file.bytes > limit) {\n\t\t\tthrow new TransferError(\"TRANSFER_LIMIT_EXCEEDED\", \"File is larger than this site accepts\", {\n\t\t\t\tdetail: { path: parsed.path, bytes: file.bytes, limit },\n\t\t\t});\n\t\t}\n\t\tif (input.contentLength !== file.bytes) {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_FILE_SIZE_MISMATCH\",\n\t\t\t\t\"Content-Length does not match the declared size\",\n\t\t\t\t{ detail: { path: parsed.path, expected: file.bytes } },\n\t\t\t);\n\t\t}\n\n\t\tconst stage = stageFor(storage, operation);\n\t\tif (file.state === \"verified\" && (await stagedFileIntact(stage, parsed.path, file))) {\n\t\t\tconst received = await digestOfBody(input.body, file.bytes);\n\t\t\tif (received.bytes !== file.bytes) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_SIZE_MISMATCH\", \"File size does not match\", {\n\t\t\t\t\tdetail: { path: parsed.path, expected: file.bytes },\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (received.sha256 !== file.sha256) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_DIGEST_MISMATCH\", \"File digest does not match\", {\n\t\t\t\t\tdetail: { path: parsed.path },\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn {\n\t\t\t\tsuccess: true,\n\t\t\t\tdata: {\n\t\t\t\t\tpath: parsed.path,\n\t\t\t\t\tbytes: file.bytes,\n\t\t\t\t\talreadyVerified: true,\n\t\t\t\t\tremaining: (await staged.countByState(operation.id)).declared,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\n\t\tawait stage.putVerified(parsed.path, input.body ?? new Uint8Array(0), file.bytes, file.sha256, {\n\t\t\tkeepExistingOnFailure: () => staged.isVerified(operation.id, parsed.path),\n\t\t});\n\t\tif ((await operations.require(operation.id)).state !== \"uploading\") {\n\t\t\tthrow new TransferError(\n\t\t\t\t\"TRANSFER_INVALID_STATE\",\n\t\t\t\t\"Files can only be uploaded before analysis\",\n\t\t\t);\n\t\t}\n\t\tif (parsed.type === \"index\") {\n\t\t\tconst entries = await new StagedPackageReader(stage).indexChunk(parsed.seq);\n\t\t\tawait staged.declareMany(\n\t\t\t\toperation.id,\n\t\t\t\tentries.map((entry) => ({ path: entry.path, bytes: entry.bytes, sha256: entry.sha256 })),\n\t\t\t);\n\t\t}\n\t\tawait staged.markVerified(operation.id, file);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\tpath: parsed.path,\n\t\t\t\tbytes: file.bytes,\n\t\t\t\talreadyVerified: false,\n\t\t\t\tremaining: (await staged.countByState(operation.id)).declared,\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_STORAGE_ERROR\", \"Failed to store the uploaded file\");\n\t}\n}\n\n// ── Imports: analysis and plan ──────────────────────────────────\n\nexport interface AnalyzeImportInput {\n\toperationId: string;\n\tdecisions?: SiteImportDecisionsInput;\n\ttarget: AnalysisTargetContext;\n\tbudget?: TransferStepBudget;\n}\n\nexport interface AnalyzeImportResult {\n\toperation: PublicTransferOperation;\n\tplan?: SiteImportPlan;\n\tplanDigest?: Sha256Digest;\n\t/** Milliseconds until the client should call again, or null when analysis has ended. */\n\tnextRequestInMs: number | null;\n}\n\n/**\n * Run one bounded analysis step. Once the import is planned, returns the plan\n * and, when `decisions` are given, applies them first. Decisions are refused\n * with `TRANSFER_INVALID_STATE` once execution has been requested.\n */\nexport async function handleImportAnalyze(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: AnalyzeImportInput,\n): Promise<ApiResult<AnalyzeImportResult>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tlet operation = await requireImport(operations, input.operationId);\n\t\tlet plan: SiteImportPlan | null = null;\n\t\tlet digest: Sha256Digest | null = null;\n\n\t\tif (operation.state === \"uploading\") {\n\t\t\tconst { declared } = await new TransferStagedFileRepository(db).countByState(operation.id);\n\t\t\tif (declared > 0) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_FILE_MISSING\", \"Some package files are not uploaded\", {\n\t\t\t\t\tdetail: { missing: declared },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\n\t\tif (operation.state === \"uploading\" || operation.state === \"analyzing\") {\n\t\t\tconst step = await analyzeImportStep({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: operation.id,\n\t\t\t\tbudget: input.budget ?? new TransferStepBudget(),\n\t\t\t\ttargetContext: input.target,\n\t\t\t}).catch((error: unknown) => {\n\t\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_LEASE_ACTIVE\") return null;\n\t\t\t\tthrow error;\n\t\t\t});\n\t\t\tif (!step) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: toPublicOperation(await operations.require(operation.id)),\n\t\t\t\t\t\tnextRequestInMs: LEASE_RETRY_MS,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\toperation = step.operation;\n\t\t\tif (!step.done) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: { operation: toPublicOperation(operation), nextRequestInMs: 0 },\n\t\t\t\t};\n\t\t\t}\n\t\t\tplan = step.plan;\n\t\t\tdigest = step.planDigest;\n\t\t} else if (operation.state === \"planned\") {\n\t\t\tplan = await loadImportPlan(storage, operation);\n\t\t\tdigest = operation.planDigest;\n\t\t} else {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import is past analysis\");\n\t\t}\n\n\t\tif (operation.state === \"planned\" && input.decisions !== undefined) {\n\t\t\tconst finalized = await finalizePlan({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: operation.id,\n\t\t\t\tdecisions: input.decisions,\n\t\t\t});\n\t\t\tplan = finalized.plan;\n\t\t\tdigest = finalized.planDigest;\n\t\t\toperation = await operations.require(operation.id);\n\t\t}\n\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: {\n\t\t\t\toperation: toPublicOperation(operation),\n\t\t\t\t...(plan ? { plan } : {}),\n\t\t\t\t...(plan && digest ? { planDigest: digest } : {}),\n\t\t\t\tnextRequestInMs: null,\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_ANALYZE_ERROR\", \"Failed to analyze import\");\n\t}\n}\n\nexport async function handleImportPlan(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperationId: string,\n): Promise<ApiResult<{ plan: SiteImportPlan; planDigest: Sha256Digest }>> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), operationId);\n\t\tconst plan = operation.planDigest ? await loadImportPlan(storage, operation) : null;\n\t\tif (!plan || !operation.planDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has not been analyzed\");\n\t\t}\n\t\treturn { success: true, data: { plan, planDigest: operation.planDigest } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_ANALYZE_ERROR\", \"Failed to read import plan\");\n\t}\n}\n\n// ── Imports: status and control ─────────────────────────────────\n\nexport async function handleImportGet(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<\n\tApiResult<{\n\t\toperation: PublicTransferOperation;\n\t\tfiles: { declared: number; verified: number };\n\t}>\n> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), operationId);\n\t\tconst files = await new TransferStagedFileRepository(db).countByState(operation.id);\n\t\treturn { success: true, data: { operation: toPublicOperation(operation), files } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to read import\");\n\t}\n}\n\nexport async function handleImportList(\n\tdb: Kysely<Database>,\n\toptions: { cursor?: string; limit?: number },\n): Promise<ApiResult<{ items: PublicTransferOperation[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst page = await new TransferOperationRepository(db).list({\n\t\t\tkind: \"import\",\n\t\t\tlimit: pageLimit(options.limit),\n\t\t\tcursor: decodeTimeCursor(options.cursor),\n\t\t});\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: page.next\n\t\t\t\t? { items: page.items, nextCursor: encodeCursor(page.next.createdAt, page.next.id) }\n\t\t\t\t: { items: page.items },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to list imports\");\n\t}\n}\n\n/** Cancel an import; a step in flight stops after its current batch. */\nexport async function handleImportCancel(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\tuserId: string,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireImport(operations, operationId);\n\t\tconst operation = await operations.requestCancel(operationId);\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_cancel\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operationId,\n\t\t});\n\t\treturn { success: true, data: { operation: toPublicOperation(operation) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to cancel import\");\n\t}\n}\n\n/**\n * Abandon a failed or cancelled import. Lifts the site write fence; imported\n * data stays in place.\n */\nexport async function handleImportAbandon(\n\tdb: Kysely<Database>,\n\toperationId: string,\n\tuserId: string,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireImport(operations, operationId);\n\t\tconst operation = await operations.abandon(operationId);\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_abandon\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operationId,\n\t\t});\n\t\treturn { success: true, data: { operation: toPublicOperation(operation) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to abandon import\");\n\t}\n}\n\n// ── Exports ─────────────────────────────────────────────────────\n\nasync function requireExport(\n\toperations: TransferOperationRepository,\n\toperationId: string,\n): Promise<TransferOperation> {\n\tconst operation = await operations.get(operationId);\n\tif (!operation || operation.kind !== \"export\") {\n\t\tthrow new TransferError(\"TRANSFER_OPERATION_NOT_FOUND\", \"Transfer operation not found\");\n\t}\n\treturn operation;\n}\n\nasync function requireCompleteExport(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<TransferOperation> {\n\tconst operation = await requireExport(new TransferOperationRepository(db), operationId);\n\tif (operation.state !== \"complete\") {\n\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Export is not complete\");\n\t}\n\tif (operation.stagingCollectedAt !== null) {\n\t\tthrow new TransferError(\"TRANSFER_EXPIRED\", \"Export files are no longer available\");\n\t}\n\treturn operation;\n}\n\n/**\n * Run `start` after a grant was consumed for it, handing the grant back when\n * the operation does not start so the caller can retry with it.\n */\nasync function withGrantRestoredOnFailure<T>(\n\tapprovals: TransferApprovalRepository,\n\tapproval: TransferApprovalGrant | undefined,\n\tstart: () => Promise<T>,\n): Promise<T> {\n\ttry {\n\t\treturn await start();\n\t} catch (error) {\n\t\tif (approval) {\n\t\t\tawait approvals.restore(approval.id).catch((restoreError: unknown) => {\n\t\t\t\tconsole.error(\"[transfer] Failed to restore an approval grant:\", restoreError);\n\t\t\t});\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Digest an export approval grant binds: the export options, normalized. */\nexport async function exportParamsDigest(options: ExportOptions): Promise<Sha256Digest> {\n\treturn canonicalDigest(exportOptionsSchema.parse(options));\n}\n\n/** A one-time approval grant a caller without the transfer scope presents. */\nexport interface TransferApprovalGrant {\n\tid: string;\n\t/** The API token the caller is authenticated with, if any. */\n\ttokenId?: string;\n}\n\nexport interface CreateExportInput {\n\tuserId: string;\n\toptions: ExportOptions;\n\tidempotencyKey?: string;\n\t/**\n\t * Consumed before the export is created, and restored if creation fails;\n\t * bound to the user and the options digest.\n\t */\n\tapproval?: TransferApprovalGrant;\n}\n\n/**\n * Create an export, or return the existing one for the same idempotency key.\n * With `approval`, the grant must be approved, unexpired, and bound to this\n * user, action `export`, these options, and the caller's token.\n */\nexport async function handleExportCreate(\n\tdb: Kysely<Database>,\n\tinput: CreateExportInput,\n): Promise<ApiResult<{ operation: PublicTransferOperation; created: boolean }>> {\n\ttry {\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tif (input.approval) {\n\t\t\tawait approvals.consume(input.approval.id, {\n\t\t\t\tuserId: input.userId,\n\t\t\t\taction: \"export\",\n\t\t\t\tparamsDigest: await exportParamsDigest(input.options),\n\t\t\t\ttokenId: input.approval.tokenId,\n\t\t\t});\n\t\t}\n\t\tconst { operation, created } = await withGrantRestoredOnFailure(approvals, input.approval, () =>\n\t\t\tcreateExport({\n\t\t\t\tdb,\n\t\t\t\tcreatedBy: input.userId,\n\t\t\t\toptions: input.options,\n\t\t\t\tidempotencyKey: input.idempotencyKey,\n\t\t\t}),\n\t\t);\n\t\tif (input.approval) await approvals.linkOperation(input.approval.id, operation.id);\n\t\tif (created) {\n\t\t\tawait recordTransferAudit(db, {\n\t\t\t\tactorId: input.userId,\n\t\t\t\taction: \"transfer_export_create\",\n\t\t\t\tresourceType: \"transfer_operation\",\n\t\t\t\tresourceId: operation.id,\n\t\t\t});\n\t\t}\n\t\treturn { success: true, data: { operation: toPublicOperation(operation), created } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to create export\");\n\t}\n}\n\nexport interface AdvanceExportRouteInput {\n\toperationId: string;\n\tdefaultLocale?: string;\n\tbudget?: TransferStepBudget;\n}\n\nconst validatePackage: ExportPackageValidator = (input) => validateStagedPackageStep(input);\n\n/** Run one bounded export step. */\nexport async function handleExportAdvance(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: AdvanceExportRouteInput,\n): Promise<ApiResult<{ operation: PublicTransferOperation; nextRequestInMs: number | null }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireExport(operations, input.operationId);\n\t\tlet step;\n\t\ttry {\n\t\t\tstep = await advanceExport({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tbudget: input.budget,\n\t\t\t\tdefaultLocale: input.defaultLocale,\n\t\t\t\tvalidatePackage,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (isTransferError(error) && error.code === \"TRANSFER_LEASE_LOST\") {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: toPublicOperation(await operations.require(input.operationId)),\n\t\t\t\t\t\tnextRequestInMs: LEASE_RETRY_MS,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tconst nextRequestInMs =\n\t\t\tstep.outcome === \"advanced\" ? 0 : step.outcome === \"busy\" ? LEASE_RETRY_MS : null;\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { operation: toPublicOperation(step.operation), nextRequestInMs },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to advance export\");\n\t}\n}\n\nexport async function handleExportGet(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operation = await requireExport(new TransferOperationRepository(db), operationId);\n\t\treturn { success: true, data: { operation: toPublicOperation(operation) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to read export\");\n\t}\n}\n\nexport async function handleExportList(\n\tdb: Kysely<Database>,\n\toptions: { cursor?: string; limit?: number },\n): Promise<ApiResult<{ items: PublicTransferOperation[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst page = await new TransferOperationRepository(db).list({\n\t\t\tkind: \"export\",\n\t\t\tlimit: pageLimit(options.limit),\n\t\t\tcursor: decodeTimeCursor(options.cursor),\n\t\t});\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: page.next\n\t\t\t\t? { items: page.items, nextCursor: encodeCursor(page.next.createdAt, page.next.id) }\n\t\t\t\t: { items: page.items },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to list exports\");\n\t}\n}\n\n/** A package file ready to stream: its size and a body verified as it streams. */\nexport interface ExportFileStream {\n\tpath: string;\n\tbytes: number;\n\tsha256: string;\n\tbody: ReadableStream<Uint8Array>;\n}\n\nfunction exportFileMismatch(): TransferError {\n\treturn new TransferError(\n\t\t\"TRANSFER_FILE_DIGEST_MISMATCH\",\n\t\t\"Stored file no longer matches the export\",\n\t);\n}\n\n/**\n * Pass `body` through, failing the stream if it does not carry exactly\n * `bytes` bytes hashing to `sha256`, so a changed source object never\n * reaches the client as a complete file.\n */\nfunction verifyingStream(\n\tbody: ReadableStream<Uint8Array>,\n\texpected: { bytes: number; sha256: string },\n): ReadableStream<Uint8Array> {\n\tlet hasher: Awaited<ReturnType<typeof createSha256>> | undefined;\n\tlet total = 0;\n\treturn body.pipeThrough(\n\t\tnew TransformStream<Uint8Array, Uint8Array>({\n\t\t\tasync start() {\n\t\t\t\thasher = await createSha256();\n\t\t\t},\n\t\t\ttransform(chunk, controller) {\n\t\t\t\ttotal += chunk.byteLength;\n\t\t\t\tif (total > expected.bytes) throw exportFileMismatch();\n\t\t\t\thasher?.update(chunk);\n\t\t\t\tcontroller.enqueue(chunk);\n\t\t\t},\n\t\t\tasync flush() {\n\t\t\t\tif (total !== expected.bytes || (await hasher?.digest()) !== expected.sha256) {\n\t\t\t\t\tthrow exportFileMismatch();\n\t\t\t\t}\n\t\t\t},\n\t\t}),\n\t);\n}\n\nasync function openExportFile(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperation: TransferOperation,\n\tpath: string,\n): Promise<ExportFileStream> {\n\tconst parsed = parsePackagePath(path);\n\tif (!parsed) throw new TransferError(\"TRANSFER_PATH_INVALID\", \"Invalid package path\");\n\tconst reader = openExportPackage({ db, storage, operation });\n\tif (parsed.type === \"manifest\") {\n\t\tconst bytes = await reader.stage.readBytes(MANIFEST_PATH, TRANSFER_LIMITS.manifestBytes);\n\t\treturn {\n\t\t\tpath: MANIFEST_PATH,\n\t\t\tbytes: bytes.byteLength,\n\t\t\tsha256: await sha256Hex(bytes),\n\t\t\tbody: new ReadableStream<Uint8Array>({\n\t\t\t\tstart(controller) {\n\t\t\t\t\tcontroller.enqueue(bytes);\n\t\t\t\t\tcontroller.close();\n\t\t\t\t},\n\t\t\t}),\n\t\t};\n\t}\n\tconst file = await new TransferStagedFileRepository(db).get(operation.id, parsed.path);\n\tif (!file || file.state !== \"verified\") {\n\t\tthrow new TransferError(\"TRANSFER_FILE_NOT_DECLARED\", \"File is not part of this export\", {\n\t\t\tdetail: { path: parsed.path },\n\t\t});\n\t}\n\tconst source =\n\t\tparsed.type === \"media\"\n\t\t\t? await reader.blob(parsed.sha256)\n\t\t\t: (await reader.stage.open(parsed.path)).body;\n\treturn {\n\t\tpath: file.path,\n\t\tbytes: file.bytes,\n\t\tsha256: file.sha256,\n\t\tbody: verifyingStream(source, file),\n\t};\n}\n\n/**\n * Open one file of a complete export: `manifest.json`, an index or record\n * chunk from staging, or a media blob streamed from the origin object. The\n * body errors if the bytes no longer match the export's digest.\n */\nexport async function handleExportFile(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperationId: string,\n\tpath: string,\n): Promise<ApiResult<ExportFileStream>> {\n\ttry {\n\t\tconst operation = await requireCompleteExport(db, operationId);\n\t\treturn { success: true, data: await openExportFile(db, storage, operation, path) };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to read export file\");\n\t}\n}\n\nasync function* exportArchiveFiles(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperation: TransferOperation,\n): AsyncGenerator<PackageFileSource> {\n\tconst manifest = await openExportFile(db, storage, operation, MANIFEST_PATH);\n\tyield { path: manifest.path, bytes: manifest.bytes, body: () => manifest.body };\n\tconst staged = new TransferStagedFileRepository(db);\n\tlet after: string | undefined;\n\tfor (;;) {\n\t\tconst page = await staged.list(operation.id, { state: \"verified\", after, limit: 500 });\n\t\tfor (const file of page) {\n\t\t\tif (file.path === MANIFEST_PATH) continue;\n\t\t\tyield {\n\t\t\t\tpath: file.path,\n\t\t\t\tbytes: file.bytes,\n\t\t\t\tbody: async () => (await openExportFile(db, storage, operation, file.path)).body,\n\t\t\t};\n\t\t}\n\t\tconst last = page.at(-1);\n\t\tif (!last || page.length < 500) return;\n\t\tafter = last.path;\n\t}\n}\n\n/**\n * Stream a complete export as one tar container: the manifest first, then\n * every index chunk, media blob, and record chunk in path order. Each file is\n * read and verified as it is written, so a failure mid-archive ends the\n * stream with an error rather than a short archive. On Workers the whole\n * archive must stream within one request's limits; large sites should\n * download files individually.\n */\nexport async function handleExportArchive(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\toperationId: string,\n): Promise<ApiResult<{ body: ReadableStream<Uint8Array> }>> {\n\ttry {\n\t\tconst operation = await requireCompleteExport(db, operationId);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { body: packSitePackage(exportArchiveFiles(db, storage, operation)) },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_EXPORT_ERROR\", \"Failed to read export archive\");\n\t}\n}\n\n// ── Imports: execution ──────────────────────────────────────────\n\nexport interface ExecuteImportInput {\n\toperationId: string;\n\tuserId: string;\n\tpackageDigest: Sha256Digest;\n\tplanDigest: Sha256Digest;\n\t/**\n\t * Consumed before execution starts, and restored if it cannot start;\n\t * bound to the user, action `import`, this operation, both digests, and\n\t * the caller's token.\n\t */\n\tapproval?: TransferApprovalGrant;\n}\n\n/**\n * Request execution of a planned import. The digests must match the staged\n * package and the current plan (`TRANSFER_PACKAGE_DIGEST_MISMATCH` /\n * `TRANSFER_PLAN_DIGEST_MISMATCH`), and the plan must have no blockers.\n * Repeating the request for an import already executing returns it.\n */\nexport async function handleImportExecute(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: ExecuteImportInput,\n): Promise<ApiResult<{ operation: PublicTransferOperation }>> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), input.operationId);\n\t\tif (operation.packageDigest !== input.packageDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_PACKAGE_DIGEST_MISMATCH\", \"Package digest does not match\");\n\t\t}\n\t\tif (operation.planDigest === null || operation.planDigest !== input.planDigest) {\n\t\t\tthrow new TransferError(\"TRANSFER_PLAN_DIGEST_MISMATCH\", \"Plan digest does not match\");\n\t\t}\n\t\tif (operation.state === \"planned\") {\n\t\t\tconst plan = await loadImportPlan(storage, operation);\n\t\t\tif (!plan || !isPlanExecutable(plan)) {\n\t\t\t\tthrow new TransferError(\"TRANSFER_PLAN_BLOCKED\", \"The import plan has blockers\", {\n\t\t\t\t\tdetail: { blockers: plan?.blockers.length ?? 0 },\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tif (input.approval) {\n\t\t\tawait approvals.consume(input.approval.id, {\n\t\t\t\tuserId: input.userId,\n\t\t\t\taction: \"import\",\n\t\t\t\toperationId: operation.id,\n\t\t\t\tpackageDigest: input.packageDigest,\n\t\t\t\tplanDigest: input.planDigest,\n\t\t\t\ttokenId: input.approval.tokenId,\n\t\t\t});\n\t\t}\n\t\tconst { operation: requested, requested: newlyRequested } = await withGrantRestoredOnFailure(\n\t\t\tapprovals,\n\t\t\tinput.approval,\n\t\t\t() =>\n\t\t\t\trequestImportExecution({\n\t\t\t\t\tdb,\n\t\t\t\t\toperationId: operation.id,\n\t\t\t\t\tpackageDigest: input.packageDigest,\n\t\t\t\t\tplanDigest: input.planDigest,\n\t\t\t\t}),\n\t\t);\n\t\tif (newlyRequested) {\n\t\t\tawait recordTransferAudit(db, {\n\t\t\t\tactorId: input.userId,\n\t\t\t\taction: \"transfer_import_execute\",\n\t\t\t\tresourceType: \"transfer_operation\",\n\t\t\t\tresourceId: operation.id,\n\t\t\t\tdetails: { packageDigest: input.packageDigest, planDigest: input.planDigest },\n\t\t\t});\n\t\t}\n\t\treturn { success: true, data: { operation: toPublicOperation(requested) } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to execute import\");\n\t}\n}\n\n/**\n * Run one bounded import step. Retryable failures are recorded on the\n * operation and reported through `nextRequestInMs`, as is a step that lost\n * its lease to another caller; it is null once the import has ended. The\n * step that completes or fails the import records it in the audit log as\n * `userId`'s.\n */\nexport async function handleImportAdvance(\n\tdb: Kysely<Database>,\n\tstorage: Storage,\n\tinput: { operationId: string; userId: string; budget?: TransferStepBudget },\n): Promise<ApiResult<{ operation: PublicTransferOperation; nextRequestInMs: number | null }>> {\n\ttry {\n\t\tconst operations = new TransferOperationRepository(db);\n\t\tawait requireImport(operations, input.operationId);\n\t\tlet step;\n\t\ttry {\n\t\t\tstep = await advanceImport({\n\t\t\t\tdb,\n\t\t\t\tstorage,\n\t\t\t\toperationId: input.operationId,\n\t\t\t\tverify: verifyImportStep,\n\t\t\t\tbudget: input.budget,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (isLeaseError(error)) {\n\t\t\t\treturn {\n\t\t\t\t\tsuccess: true,\n\t\t\t\t\tdata: {\n\t\t\t\t\t\toperation: toPublicOperation(await operations.require(input.operationId)),\n\t\t\t\t\t\tnextRequestInMs: LEASE_RETRY_MS,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t\tthrow error;\n\t\t}\n\t\tif (step.ended) await auditImportEnd(db, step.operation, input.userId);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: { operation: toPublicOperation(step.operation), nextRequestInMs: step.nextRequestInMs },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to advance import\");\n\t}\n}\n\nasync function auditImportEnd(\n\tdb: Kysely<Database>,\n\toperation: TransferOperation,\n\tuserId: string,\n): Promise<void> {\n\tif (operation.state === \"complete\") {\n\t\tconst counts = operation.receipt?.counts ?? {};\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_complete\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operation.id,\n\t\t\tdetails: {\n\t\t\t\tpackageDigest: operation.packageDigest,\n\t\t\t\tplanDigest: operation.planDigest,\n\t\t\t\trecords: Object.values(counts).reduce((sum, count) => sum + count, 0),\n\t\t\t},\n\t\t});\n\t} else if (operation.state === \"failed\") {\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: userId,\n\t\t\taction: \"transfer_import_fail\",\n\t\t\tresourceType: \"transfer_operation\",\n\t\t\tresourceId: operation.id,\n\t\t\tdetails: { errorCode: operation.errorCode },\n\t\t\tstatus: \"failure\",\n\t\t});\n\t}\n}\n\nexport async function handleImportReceipt(\n\tdb: Kysely<Database>,\n\toperationId: string,\n): Promise<ApiResult<{ receipt: SiteImportReceipt }>> {\n\ttry {\n\t\tconst operation = await requireImport(new TransferOperationRepository(db), operationId);\n\t\tif (operation.state !== \"complete\" || !operation.receipt) {\n\t\t\tthrow new TransferError(\"TRANSFER_INVALID_STATE\", \"Import has no receipt\");\n\t\t}\n\t\treturn { success: true, data: { receipt: operation.receipt } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to read import receipt\");\n\t}\n}\n\n// ── Approvals ───────────────────────────────────────────────────\n\nconst APPROVAL_PERMISSION: Readonly<Record<TransferApprovalAction, Permission>> = {\n\texport: \"transfer:export\",\n\timport: \"transfer:import\",\n};\n\nexport async function handleApprovalList(\n\tdb: Kysely<Database>,\n\toptions: { status?: ApprovalStatus; cursor?: string; limit?: number },\n): Promise<ApiResult<{ items: TransferApproval[]; nextCursor?: string }>> {\n\ttry {\n\t\tconst page = await new TransferApprovalRepository(db).list({\n\t\t\tstatus: options.status,\n\t\t\tlimit: pageLimit(options.limit),\n\t\t\tcursor: decodeTimeCursor(options.cursor),\n\t\t});\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t\tdata: page.next\n\t\t\t\t? { items: page.items, nextCursor: encodeCursor(page.next.createdAt, page.next.id) }\n\t\t\t\t: { items: page.items },\n\t\t};\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to list approvals\");\n\t}\n}\n\n/**\n * Approve or deny a pending grant. The deciding user needs the permission\n * for the grant's action. Callers must only reach this from a session, never\n * with a bearer token.\n */\nexport async function handleApprovalDecide(\n\tdb: Kysely<Database>,\n\tinput: {\n\t\tapprovalId: string;\n\t\tdecision: \"approve\" | \"deny\";\n\t\tuser: { id: string; role: RoleLevel };\n\t},\n): Promise<ApiResult<{ approval: TransferApproval }>> {\n\ttry {\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tconst approval = await approvals.get(input.approvalId);\n\t\tif (!approval) {\n\t\t\tthrow new TransferError(\"TRANSFER_APPROVAL_INVALID\", \"Approval not found\");\n\t\t}\n\t\tif (!hasPermission(input.user, APPROVAL_PERMISSION[approval.action])) {\n\t\t\treturn failure(\"FORBIDDEN\", \"Insufficient permissions\");\n\t\t}\n\t\tconst decided =\n\t\t\tinput.decision === \"approve\"\n\t\t\t\t? await approvals.approve(approval.id, input.user.id)\n\t\t\t\t: await approvals.deny(approval.id, input.user.id);\n\t\tawait recordTransferAudit(db, {\n\t\t\tactorId: input.user.id,\n\t\t\taction: input.decision === \"approve\" ? \"transfer_approval_approve\" : \"transfer_approval_deny\",\n\t\t\tresourceType: \"transfer_approval\",\n\t\t\tresourceId: approval.id,\n\t\t\tdetails: {\n\t\t\t\taction: approval.action,\n\t\t\t\tuserId: approval.userId,\n\t\t\t\t...(approval.operationId === null ? {} : { operationId: approval.operationId }),\n\t\t\t},\n\t\t});\n\t\treturn { success: true, data: { approval: decided } };\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to decide approval\");\n\t}\n}\n\nexport interface RequestTransferApprovalInput {\n\t/** The user the grant is for: the caller that will consume it. */\n\tuserId: string;\n\taction: TransferApprovalAction;\n\t/** The API token the caller is authenticated with, if any. */\n\trequestedByTokenId?: string;\n\toperationId?: string;\n\tparamsDigest?: Sha256Digest;\n\tpackageDigest?: Sha256Digest;\n\tplanDigest?: Sha256Digest;\n}\n\n/**\n * Create a pending approval grant for a caller that lacks the transfer scope\n * for `action`, and fail with `TRANSFER_APPROVAL_REQUIRED` carrying its id.\n * An unexpired pending grant with the same binding is returned instead of a\n * new one. An admin approves it in a session; the caller then retries with\n * the id and consumes the grant with `TransferApprovalRepository.consume`.\n */\nexport async function requestTransferApproval(\n\tdb: Kysely<Database>,\n\tinput: RequestTransferApprovalInput,\n): Promise<ErrorResult> {\n\ttry {\n\t\tconst approvals = new TransferApprovalRepository(db);\n\t\tconst approval =\n\t\t\t(await approvals.findPending({ ...input, tokenId: input.requestedByTokenId })) ??\n\t\t\t(await approvals.createPending(input));\n\t\treturn failure(\"TRANSFER_APPROVAL_REQUIRED\", \"An admin must approve this transfer\", {\n\t\t\tapprovalId: approval.id,\n\t\t\texpiresAt: approval.expiresAt,\n\t\t});\n\t} catch (error) {\n\t\treturn errorResult(error, \"TRANSFER_IMPORT_ERROR\", \"Failed to request approval\");\n\t}\n}\n"],"mappings":"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"}