@nakafa/aksara-contracts 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/LICENSE +185 -0
  2. package/README.md +73 -0
  3. package/dist/artifact/integrity.d.ts +29 -0
  4. package/dist/artifact/integrity.js +54 -0
  5. package/dist/artifact/limits.d.ts +26 -0
  6. package/dist/artifact/limits.js +46 -0
  7. package/dist/artifact/source.d.ts +21 -0
  8. package/dist/artifact/source.js +24 -0
  9. package/dist/artifact/spec.d.ts +148 -0
  10. package/dist/artifact/spec.js +92 -0
  11. package/dist/artifact/verify.d.ts +26 -0
  12. package/dist/artifact/verify.js +18 -0
  13. package/dist/cache/content.d.ts +52 -0
  14. package/dist/cache/content.js +80 -0
  15. package/dist/content.d.ts +168 -0
  16. package/dist/content.js +107 -0
  17. package/dist/country.d.ts +4 -0
  18. package/dist/country.js +8 -0
  19. package/dist/date.d.ts +24 -0
  20. package/dist/date.js +44 -0
  21. package/dist/decode.d.ts +4 -0
  22. package/dist/decode.js +8 -0
  23. package/dist/delivery.d.ts +4 -0
  24. package/dist/delivery.js +7 -0
  25. package/dist/errors.d.ts +10 -0
  26. package/dist/errors.js +8 -0
  27. package/dist/graph/family.d.ts +45 -0
  28. package/dist/graph/family.js +85 -0
  29. package/dist/graph/identity.d.ts +19 -0
  30. package/dist/graph/identity.js +39 -0
  31. package/dist/graph/spec.d.ts +20 -0
  32. package/dist/graph/spec.js +26 -0
  33. package/dist/hash/text.d.ts +10 -0
  34. package/dist/hash/text.js +20 -0
  35. package/dist/ids.d.ts +27 -0
  36. package/dist/ids.js +63 -0
  37. package/dist/limits.d.ts +10 -0
  38. package/dist/limits.js +10 -0
  39. package/dist/locale.d.ts +37 -0
  40. package/dist/locale.js +53 -0
  41. package/dist/material/domain.d.ts +4 -0
  42. package/dist/material/domain.js +8 -0
  43. package/dist/preview/artifact.d.ts +198 -0
  44. package/dist/preview/artifact.js +20 -0
  45. package/dist/preview/auth.d.ts +71 -0
  46. package/dist/preview/auth.js +49 -0
  47. package/dist/preview/document.d.ts +692 -0
  48. package/dist/preview/document.js +90 -0
  49. package/dist/preview/spec.d.ts +2517 -0
  50. package/dist/preview/spec.js +142 -0
  51. package/dist/preview/target.d.ts +172 -0
  52. package/dist/preview/target.js +70 -0
  53. package/dist/program/curriculum.d.ts +69 -0
  54. package/dist/program/curriculum.js +181 -0
  55. package/dist/program/snapshot/digest.d.ts +26 -0
  56. package/dist/program/snapshot/digest.js +220 -0
  57. package/dist/program/snapshot/hash.d.ts +31 -0
  58. package/dist/program/snapshot/hash.js +40 -0
  59. package/dist/program/snapshot/row-hash.d.ts +155 -0
  60. package/dist/program/snapshot/row-hash.js +34 -0
  61. package/dist/program/snapshot/row.d.ts +139 -0
  62. package/dist/program/snapshot/row.js +28 -0
  63. package/dist/program/snapshot/spec.d.ts +36 -0
  64. package/dist/program/snapshot/spec.js +39 -0
  65. package/dist/program/spec.d.ts +85 -0
  66. package/dist/program/spec.js +197 -0
  67. package/dist/projection/article.d.ts +145 -0
  68. package/dist/projection/article.js +150 -0
  69. package/dist/projection/digest.d.ts +261 -0
  70. package/dist/projection/digest.js +59 -0
  71. package/dist/projection/hash.d.ts +3 -0
  72. package/dist/projection/hash.js +10 -0
  73. package/dist/projection/material.d.ts +109 -0
  74. package/dist/projection/material.js +160 -0
  75. package/dist/projection/page.d.ts +112 -0
  76. package/dist/projection/page.js +106 -0
  77. package/dist/projection/question.d.ts +520 -0
  78. package/dist/projection/question.js +109 -0
  79. package/dist/projection/spec.d.ts +503 -0
  80. package/dist/projection/spec.js +56 -0
  81. package/dist/projection/verify.d.ts +281 -0
  82. package/dist/projection/verify.js +86 -0
  83. package/dist/question/identity.d.ts +175 -0
  84. package/dist/question/identity.js +205 -0
  85. package/dist/question/item.d.ts +453 -0
  86. package/dist/question/item.js +146 -0
  87. package/dist/question/response.d.ts +175 -0
  88. package/dist/question/response.js +150 -0
  89. package/dist/quran/attribution.d.ts +48 -0
  90. package/dist/quran/attribution.js +44 -0
  91. package/dist/quran/identity.d.ts +105 -0
  92. package/dist/quran/identity.js +100 -0
  93. package/dist/quran/notes.d.ts +56 -0
  94. package/dist/quran/notes.js +142 -0
  95. package/dist/quran/provenance.d.ts +257 -0
  96. package/dist/quran/provenance.js +144 -0
  97. package/dist/quran/snapshot/digest.d.ts +33 -0
  98. package/dist/quran/snapshot/digest.js +232 -0
  99. package/dist/quran/snapshot/hash.d.ts +51 -0
  100. package/dist/quran/snapshot/hash.js +50 -0
  101. package/dist/quran/snapshot/row/hash.d.ts +748 -0
  102. package/dist/quran/snapshot/row/hash.js +115 -0
  103. package/dist/quran/snapshot/row.d.ts +354 -0
  104. package/dist/quran/snapshot/row.js +91 -0
  105. package/dist/quran/snapshot/spec.d.ts +50 -0
  106. package/dist/quran/snapshot/spec.js +66 -0
  107. package/dist/quran/source.d.ts +206 -0
  108. package/dist/quran/source.js +153 -0
  109. package/dist/quran/spec.d.ts +47 -0
  110. package/dist/quran/spec.js +41 -0
  111. package/dist/quran/text.d.ts +7 -0
  112. package/dist/quran/text.js +11 -0
  113. package/dist/release/canonical.d.ts +23 -0
  114. package/dist/release/canonical.js +29 -0
  115. package/dist/release/current/evidence.d.ts +424 -0
  116. package/dist/release/current/evidence.js +41 -0
  117. package/dist/release/current/runtime.d.ts +4 -0
  118. package/dist/release/current/runtime.js +15 -0
  119. package/dist/release/current/state.d.ts +567 -0
  120. package/dist/release/current/state.js +91 -0
  121. package/dist/release/digest.d.ts +54 -0
  122. package/dist/release/digest.js +71 -0
  123. package/dist/release/hash.d.ts +72 -0
  124. package/dist/release/hash.js +14 -0
  125. package/dist/release/head.d.ts +206 -0
  126. package/dist/release/head.js +131 -0
  127. package/dist/release/items.d.ts +98 -0
  128. package/dist/release/items.js +114 -0
  129. package/dist/release/lifecycle.d.ts +297 -0
  130. package/dist/release/lifecycle.js +97 -0
  131. package/dist/release/origin.d.ts +30 -0
  132. package/dist/release/origin.js +24 -0
  133. package/dist/release/policy.d.ts +45 -0
  134. package/dist/release/policy.js +124 -0
  135. package/dist/release/result/digest.d.ts +127 -0
  136. package/dist/release/result/digest.js +140 -0
  137. package/dist/release/result/spec.d.ts +4 -0
  138. package/dist/release/result/spec.js +5 -0
  139. package/dist/release/rollback/digest.d.ts +126 -0
  140. package/dist/release/rollback/digest.js +92 -0
  141. package/dist/release/rollback/spec.d.ts +1729 -0
  142. package/dist/release/rollback/spec.js +156 -0
  143. package/dist/release/route/digest.d.ts +45 -0
  144. package/dist/release/route/digest.js +59 -0
  145. package/dist/release/route/page.d.ts +56 -0
  146. package/dist/release/route/page.js +46 -0
  147. package/dist/release/route/spec.d.ts +49 -0
  148. package/dist/release/route/spec.js +40 -0
  149. package/dist/release/route/verify.d.ts +66 -0
  150. package/dist/release/route/verify.js +67 -0
  151. package/dist/release/signing.d.ts +6 -0
  152. package/dist/release/signing.js +38 -0
  153. package/dist/release/snapshot/data.d.ts +475 -0
  154. package/dist/release/snapshot/data.js +74 -0
  155. package/dist/release/snapshot/evidence-requirement.d.ts +22 -0
  156. package/dist/release/snapshot/evidence-requirement.js +21 -0
  157. package/dist/release/snapshot/evidence.d.ts +58 -0
  158. package/dist/release/snapshot/evidence.js +14 -0
  159. package/dist/release/snapshot/program-evidence.d.ts +17 -0
  160. package/dist/release/snapshot/program-evidence.js +39 -0
  161. package/dist/release/snapshot/quran-evidence.d.ts +27 -0
  162. package/dist/release/snapshot/quran-evidence.js +43 -0
  163. package/dist/release/snapshot/scope.d.ts +60 -0
  164. package/dist/release/snapshot/scope.js +102 -0
  165. package/dist/release/snapshot/spec.d.ts +193 -0
  166. package/dist/release/snapshot/spec.js +139 -0
  167. package/dist/release/snapshot/tryout-evidence.d.ts +22 -0
  168. package/dist/release/snapshot/tryout-evidence.js +86 -0
  169. package/dist/release/snapshot/verify.d.ts +710 -0
  170. package/dist/release/snapshot/verify.js +147 -0
  171. package/dist/release/spec.d.ts +491 -0
  172. package/dist/release/spec.js +200 -0
  173. package/dist/release/verify.d.ts +98 -0
  174. package/dist/release/verify.js +70 -0
  175. package/dist/renderer/compatibility.d.ts +35 -0
  176. package/dist/renderer/compatibility.js +48 -0
  177. package/dist/renderer/component.d.ts +99 -0
  178. package/dist/renderer/component.js +102 -0
  179. package/dist/renderer/contract.d.ts +144 -0
  180. package/dist/renderer/contract.js +122 -0
  181. package/dist/renderer/domain.d.ts +6 -0
  182. package/dist/renderer/domain.js +18 -0
  183. package/dist/renderer/manifest.d.ts +86 -0
  184. package/dist/renderer/manifest.js +49 -0
  185. package/dist/renderer/selection.d.ts +39 -0
  186. package/dist/renderer/selection.js +87 -0
  187. package/dist/runtime/error.d.ts +8 -0
  188. package/dist/runtime/error.js +20 -0
  189. package/dist/runtime/protected/limits.d.ts +10 -0
  190. package/dist/runtime/protected/limits.js +15 -0
  191. package/dist/runtime/protected/spec.d.ts +328 -0
  192. package/dist/runtime/protected/spec.js +79 -0
  193. package/dist/runtime/protected/verify.d.ts +97 -0
  194. package/dist/runtime/protected/verify.js +72 -0
  195. package/dist/runtime/result.d.ts +12 -0
  196. package/dist/runtime/result.js +17 -0
  197. package/dist/runtime/spec.d.ts +705 -0
  198. package/dist/runtime/spec.js +61 -0
  199. package/dist/runtime/verify.d.ts +479 -0
  200. package/dist/runtime/verify.js +123 -0
  201. package/dist/signature/spec.d.ts +53 -0
  202. package/dist/signature/spec.js +29 -0
  203. package/dist/signature/trusted.d.ts +19 -0
  204. package/dist/signature/trusted.js +32 -0
  205. package/dist/signature/verify.d.ts +10 -0
  206. package/dist/signature/verify.js +82 -0
  207. package/dist/text/order.d.ts +2 -0
  208. package/dist/text/order.js +10 -0
  209. package/dist/text/syntax.d.ts +6 -0
  210. package/dist/text/syntax.js +15 -0
  211. package/dist/transport/batch.d.ts +971 -0
  212. package/dist/transport/batch.js +101 -0
  213. package/dist/transport/failure.d.ts +168 -0
  214. package/dist/transport/failure.js +194 -0
  215. package/dist/transport/group.d.ts +2946 -0
  216. package/dist/transport/group.js +47 -0
  217. package/dist/transport/limits.d.ts +30 -0
  218. package/dist/transport/limits.js +30 -0
  219. package/dist/transport/request.d.ts +9333 -0
  220. package/dist/transport/request.js +121 -0
  221. package/dist/transport/response.d.ts +6247 -0
  222. package/dist/transport/response.js +181 -0
  223. package/dist/transport/runtime.d.ts +77 -0
  224. package/dist/transport/runtime.js +33 -0
  225. package/dist/transport/snapshot.d.ts +978 -0
  226. package/dist/transport/snapshot.js +70 -0
  227. package/dist/tryout/canonical.d.ts +2 -0
  228. package/dist/tryout/canonical.js +11 -0
  229. package/dist/tryout/catalog-hash.d.ts +134 -0
  230. package/dist/tryout/catalog-hash.js +203 -0
  231. package/dist/tryout/catalog.d.ts +376 -0
  232. package/dist/tryout/catalog.js +147 -0
  233. package/dist/tryout/content-hash.d.ts +89 -0
  234. package/dist/tryout/content-hash.js +72 -0
  235. package/dist/tryout/identity.d.ts +12 -0
  236. package/dist/tryout/identity.js +46 -0
  237. package/dist/tryout/key.d.ts +4 -0
  238. package/dist/tryout/key.js +8 -0
  239. package/dist/tryout/language.d.ts +24 -0
  240. package/dist/tryout/language.js +32 -0
  241. package/dist/tryout/locale-closure.d.ts +20 -0
  242. package/dist/tryout/locale-closure.js +164 -0
  243. package/dist/tryout/placement-closure.d.ts +5 -0
  244. package/dist/tryout/placement-closure.js +30 -0
  245. package/dist/tryout/placement-hash.d.ts +11 -0
  246. package/dist/tryout/placement-hash.js +55 -0
  247. package/dist/tryout/placement.d.ts +280 -0
  248. package/dist/tryout/placement.js +82 -0
  249. package/dist/tryout/row-hash.d.ts +28 -0
  250. package/dist/tryout/row-hash.js +50 -0
  251. package/dist/tryout/runtime/canonical.d.ts +8 -0
  252. package/dist/tryout/runtime/canonical.js +33 -0
  253. package/dist/tryout/runtime/hash.d.ts +32 -0
  254. package/dist/tryout/runtime/hash.js +11 -0
  255. package/dist/tryout/runtime/source.d.ts +42 -0
  256. package/dist/tryout/runtime/source.js +47 -0
  257. package/dist/tryout/runtime/spec.d.ts +58 -0
  258. package/dist/tryout/runtime/spec.js +21 -0
  259. package/dist/tryout/runtime/verify.d.ts +61 -0
  260. package/dist/tryout/runtime/verify.js +69 -0
  261. package/dist/tryout/snapshot/canonical.d.ts +7 -0
  262. package/dist/tryout/snapshot/canonical.js +17 -0
  263. package/dist/tryout/snapshot/hash.d.ts +8 -0
  264. package/dist/tryout/snapshot/hash.js +19 -0
  265. package/dist/tryout/snapshot/spec.d.ts +46 -0
  266. package/dist/tryout/snapshot/spec.js +30 -0
  267. package/dist/tryout/spec.d.ts +13 -0
  268. package/dist/tryout/spec.js +15 -0
  269. package/package.json +506 -0
@@ -0,0 +1,58 @@
1
+ import { Effect } from "effect";
2
+ import type { SnapshotRowSource } from "#contracts/release/snapshot/evidence-requirement";
3
+ /** Authenticates one replacement manifest through fresh structured-row replays. */
4
+ export declare const verifySnapshotRows: <E, R>(snapshot: {
5
+ readonly family: "program";
6
+ readonly manifest: {
7
+ readonly curriculumRowCount: number;
8
+ readonly programRowCount: number;
9
+ readonly rowCount: number;
10
+ readonly sitemapCount: number;
11
+ readonly slugCount: number;
12
+ readonly activeAppLocales: readonly [("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">, ...(("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">)[]];
13
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
14
+ readonly format: "localized-program-snapshot";
15
+ readonly snapshotId: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
16
+ };
17
+ } | {
18
+ readonly family: "quran";
19
+ readonly manifest: {
20
+ readonly activeAppLocales: readonly [("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">, ...(("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">)[]];
21
+ readonly attributionCount: number;
22
+ readonly chunkCount: number;
23
+ readonly projectionCount: number;
24
+ readonly projectionDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
25
+ readonly provenanceDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
26
+ readonly provenanceStatus: "approved" | "blocked";
27
+ readonly runtimeCount: number;
28
+ readonly runtimeDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
29
+ readonly searchCount: number;
30
+ readonly searchDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
31
+ readonly sourceBytes: number;
32
+ readonly sourceDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
33
+ readonly sourceFileCount: number;
34
+ readonly surahCount: number;
35
+ readonly tafsirLocales: readonly "id"[];
36
+ readonly verseCount: number;
37
+ readonly format: "localized-quran-snapshot";
38
+ readonly snapshotId: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
39
+ };
40
+ } | {
41
+ readonly family: "tryout";
42
+ readonly manifest: {
43
+ readonly activeAppLocales: readonly [("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">, ...(("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">)[]];
44
+ readonly catalogDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
45
+ readonly counts: {
46
+ readonly country: number;
47
+ readonly exam: number;
48
+ readonly section: number;
49
+ readonly set: number;
50
+ readonly track: number;
51
+ };
52
+ readonly placementCount: number;
53
+ readonly placementDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
54
+ readonly routeCount: number;
55
+ readonly format: "localized-tryout-snapshot";
56
+ readonly snapshotId: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
57
+ };
58
+ }, rows: SnapshotRowSource<E, R>) => Effect.Effect<number, E | import("../../program/snapshot/digest.js").ProgramDigestError | import("../../program/snapshot/row-hash.js").ProgramRowHashError | import("../../program/snapshot/hash.js").ProgramSnapshotHashError | import("../../quran/snapshot/row/hash.js").QuranRowHashError | import("../../quran/snapshot/digest.js").QuranRowIntegrityError | import("../../quran/snapshot/digest.js").QuranRowOrderError | import("../../quran/snapshot/hash.js").QuranSnapshotHashError | import("#contracts/release/snapshot/evidence-requirement").SnapshotEvidenceError | import("../../tryout/locale-closure.js").TryoutClosureError | import("../../tryout/row-hash.js").TryoutDigestError, R>;
@@ -0,0 +1,14 @@
1
+ import { Effect } from "effect";
2
+ import { verifyProgramSnapshotRows } from "#contracts/release/snapshot/program-evidence";
3
+ import { verifyQuranSnapshotRows } from "#contracts/release/snapshot/quran-evidence";
4
+ import { verifyTryoutSnapshotRows } from "#contracts/release/snapshot/tryout-evidence";
5
+ /** Authenticates one replacement manifest through fresh structured-row replays. */
6
+ export const verifySnapshotRows = Effect.fn("AksaraContracts.verifySnapshotRows")(function* (snapshot, rows) {
7
+ if (snapshot.family === "program") {
8
+ return yield* verifyProgramSnapshotRows(snapshot, rows);
9
+ }
10
+ if (snapshot.family === "quran") {
11
+ return yield* verifyQuranSnapshotRows(snapshot, rows);
12
+ }
13
+ return yield* verifyTryoutSnapshotRows(snapshot, rows);
14
+ });
@@ -0,0 +1,17 @@
1
+ import { Effect } from "effect";
2
+ import { type SnapshotRowSource } from "#contracts/release/snapshot/evidence-requirement";
3
+ /** Verifies all program row and snapshot identity evidence. */
4
+ export declare const verifyProgramSnapshotRows: <E, R>(snapshot: {
5
+ readonly family: "program";
6
+ readonly manifest: {
7
+ readonly curriculumRowCount: number;
8
+ readonly programRowCount: number;
9
+ readonly rowCount: number;
10
+ readonly sitemapCount: number;
11
+ readonly slugCount: number;
12
+ readonly activeAppLocales: readonly [("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">, ...(("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">)[]];
13
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
14
+ readonly format: "localized-program-snapshot";
15
+ readonly snapshotId: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
16
+ };
17
+ }, rows: SnapshotRowSource<E, R>) => Effect.Effect<number, E | import("#contracts/program/snapshot/digest").ProgramDigestError | import("../../program/snapshot/row-hash.js").ProgramRowHashError | import("#contracts/program/snapshot/hash").ProgramSnapshotHashError | import("#contracts/release/snapshot/evidence-requirement").SnapshotEvidenceError, R>;
@@ -0,0 +1,39 @@
1
+ import { Effect, Result, Stream } from "effect";
2
+ import { digestProgramRows } from "#contracts/program/snapshot/digest";
3
+ import { verifyProgramSnapshotHash } from "#contracts/program/snapshot/hash";
4
+ import { requireSnapshotEvidence, } from "#contracts/release/snapshot/evidence-requirement";
5
+ /** Selects current program rows while preserving source failures. */
6
+ function programRows(rows) {
7
+ return rows.pipe(Stream.filterMap((row) => row.family === "program" ? Result.succeed(row.record) : Result.failVoid));
8
+ }
9
+ /** Verifies all program row and snapshot identity evidence. */
10
+ export const verifyProgramSnapshotRows = Effect.fn("AksaraContracts.verifyProgramSnapshotRows")(function* (snapshot, rows) {
11
+ const summary = yield* digestProgramRows({
12
+ activeAppLocales: snapshot.manifest.activeAppLocales,
13
+ expected: snapshot.manifest,
14
+ rows: programRows(rows),
15
+ });
16
+ for (const field of [
17
+ "curriculumRowCount",
18
+ "programRowCount",
19
+ "rowCount",
20
+ "rowDigest",
21
+ "sitemapCount",
22
+ "slugCount",
23
+ ]) {
24
+ yield* requireSnapshotEvidence({
25
+ actual: summary[field],
26
+ expected: snapshot.manifest[field],
27
+ family: "program",
28
+ field,
29
+ });
30
+ }
31
+ const actualId = yield* verifyProgramSnapshotHash(snapshot.manifest);
32
+ yield* requireSnapshotEvidence({
33
+ actual: actualId,
34
+ expected: snapshot.manifest.snapshotId,
35
+ family: "program",
36
+ field: "snapshotId",
37
+ });
38
+ return summary.rowCount;
39
+ });
@@ -0,0 +1,27 @@
1
+ import { Effect } from "effect";
2
+ import { type SnapshotRowSource } from "#contracts/release/snapshot/evidence-requirement";
3
+ /** Verifies all Quran row, digest, binding, and snapshot evidence. */
4
+ export declare const verifyQuranSnapshotRows: <E, R>(snapshot: {
5
+ readonly family: "quran";
6
+ readonly manifest: {
7
+ readonly activeAppLocales: readonly [("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">, ...(("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">)[]];
8
+ readonly attributionCount: number;
9
+ readonly chunkCount: number;
10
+ readonly projectionCount: number;
11
+ readonly projectionDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
12
+ readonly provenanceDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
13
+ readonly provenanceStatus: "approved" | "blocked";
14
+ readonly runtimeCount: number;
15
+ readonly runtimeDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
16
+ readonly searchCount: number;
17
+ readonly searchDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
18
+ readonly sourceBytes: number;
19
+ readonly sourceDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
20
+ readonly sourceFileCount: number;
21
+ readonly surahCount: number;
22
+ readonly tafsirLocales: readonly "id"[];
23
+ readonly verseCount: number;
24
+ readonly format: "localized-quran-snapshot";
25
+ readonly snapshotId: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
26
+ };
27
+ }, rows: SnapshotRowSource<E, R>) => Effect.Effect<number, E | import("../../quran/snapshot/row/hash.js").QuranRowHashError | import("#contracts/quran/snapshot/digest").QuranRowIntegrityError | import("#contracts/quran/snapshot/digest").QuranRowOrderError | import("#contracts/quran/snapshot/hash").QuranSnapshotHashError | import("#contracts/release/snapshot/evidence-requirement").SnapshotEvidenceError, R>;
@@ -0,0 +1,43 @@
1
+ import { Effect, Result, Stream } from "effect";
2
+ import { digestQuranRows } from "#contracts/quran/snapshot/digest";
3
+ import { verifyQuranSnapshotHash } from "#contracts/quran/snapshot/hash";
4
+ import { requireSnapshotEvidence, } from "#contracts/release/snapshot/evidence-requirement";
5
+ /** Selects and binds current Quran rows to the manifest identity. */
6
+ function quranRows(rows, snapshotId) {
7
+ return rows.pipe(Stream.filterMap((row) => row.family === "quran" ? Result.succeed(row.record) : Result.failVoid), Stream.mapEffect((record) => requireSnapshotEvidence({
8
+ actual: record.snapshotId,
9
+ expected: snapshotId,
10
+ family: "quran",
11
+ field: "snapshotId",
12
+ }).pipe(Effect.as(record))));
13
+ }
14
+ /** Verifies all Quran row, digest, binding, and snapshot evidence. */
15
+ export const verifyQuranSnapshotRows = Effect.fn("AksaraContracts.verifyQuranSnapshotRows")(function* (snapshot, rows) {
16
+ const summary = yield* digestQuranRows({
17
+ activeAppLocales: snapshot.manifest.activeAppLocales,
18
+ rows: quranRows(rows, snapshot.manifest.snapshotId),
19
+ });
20
+ for (const field of [
21
+ "projectionCount",
22
+ "projectionDigest",
23
+ "runtimeCount",
24
+ "runtimeDigest",
25
+ "searchCount",
26
+ "searchDigest",
27
+ ]) {
28
+ yield* requireSnapshotEvidence({
29
+ actual: summary[field],
30
+ expected: snapshot.manifest[field],
31
+ family: "quran",
32
+ field,
33
+ });
34
+ }
35
+ const actualId = yield* verifyQuranSnapshotHash(snapshot.manifest);
36
+ yield* requireSnapshotEvidence({
37
+ actual: actualId,
38
+ expected: snapshot.manifest.snapshotId,
39
+ family: "quran",
40
+ field: "snapshotId",
41
+ });
42
+ return summary.projectionCount;
43
+ });
@@ -0,0 +1,60 @@
1
+ import { Effect, Schema } from "effect";
2
+ /** Fixed structured families selected by the one global release pointer. */
3
+ export declare const ContentSnapshotKindSchema: Schema.Literals<readonly ["program", "quran", "tryout"]>;
4
+ export type ContentSnapshotKind = typeof ContentSnapshotKindSchema.Type;
5
+ /** Authenticates exact content selection retained by predecessor releases. */
6
+ export declare const PredecessorContentPublicationIdentitySchema: Schema.Struct<{
7
+ readonly artifactLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraArtifactLocale">;
8
+ readonly contentKey: Schema.brand<Schema.String, "@NakafaAI/AksaraContentKey">;
9
+ readonly family: Schema.Literals<readonly ["article", "material", "page", "question"]>;
10
+ }>;
11
+ export type PredecessorContentPublicationIdentity = typeof PredecessorContentPublicationIdentitySchema.Type;
12
+ /** Content and structured families authenticated from any signed release. */
13
+ export declare const PublicationScopeSchema: Schema.Struct<{
14
+ content: Schema.optional<Schema.$Array<Schema.Struct<{
15
+ readonly artifactLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraArtifactLocale">;
16
+ readonly contentKey: Schema.brand<Schema.String, "@NakafaAI/AksaraContentKey">;
17
+ readonly family: Schema.Literals<readonly ["article", "material", "page", "question"]>;
18
+ }>>>;
19
+ families: Schema.$Array<Schema.Literals<readonly ["article", "material", "page", "question"]>>;
20
+ snapshots: Schema.$Array<Schema.Literals<readonly ["program", "quran", "tryout"]>>;
21
+ }>;
22
+ export type PublicationScope = typeof PublicationScopeSchema.Type;
23
+ /** Whole-family scope accepted when preparing a new Git release. */
24
+ export declare const GitPublicationScopeSchema: Schema.Struct<{
25
+ readonly families: Schema.$Array<Schema.Literals<readonly ["article", "material", "page", "question"]>>;
26
+ readonly snapshots: Schema.$Array<Schema.Literals<readonly ["program", "quran", "tryout"]>>;
27
+ }>;
28
+ export type GitPublicationScope = typeof GitPublicationScopeSchema.Type;
29
+ declare const GitPublicationScopeError_base: Schema.Class<GitPublicationScopeError, Schema.TaggedStruct<"GitPublicationScopeError", {}>, import("effect/Cause").YieldableError>;
30
+ /** New Git release preparation received predecessor-only exact selection. */
31
+ export declare class GitPublicationScopeError extends GitPublicationScopeError_base {
32
+ }
33
+ /** Rejects predecessor-only fields before any new release work begins. */
34
+ export declare const verifyGitPublicationScope: (scope: {
35
+ readonly content?: readonly {
36
+ readonly artifactLocale: ("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraArtifactLocale">;
37
+ readonly contentKey: string & import("effect/Brand").Brand<"@NakafaAI/AksaraContentKey">;
38
+ readonly family: "article" | "material" | "page" | "question";
39
+ }[] | undefined;
40
+ readonly families: readonly ("article" | "material" | "page" | "question")[];
41
+ readonly snapshots: readonly ("program" | "quran" | "tryout")[];
42
+ }) => Effect.Effect<{
43
+ readonly families: readonly ("article" | "material" | "page" | "question")[];
44
+ readonly snapshots: readonly ("program" | "quran" | "tryout")[];
45
+ }, GitPublicationScopeError, never>;
46
+ /** Checks whether one body transition is authorized by the signed scope. */
47
+ export declare function publicationScopeSelectsContent(scope: PublicationScope, identity: PredecessorContentPublicationIdentity): boolean;
48
+ /** Checks whether one structured family may be replaced by this release. */
49
+ export declare function publicationScopeSelectsSnapshot(scope: PublicationScope, family: ContentSnapshotKind): boolean;
50
+ /** Serializes one publication scope with stable signed field order. */
51
+ export declare function canonicalizePublicationScope(scope: PublicationScope): {
52
+ content?: {
53
+ artifactLocale: ("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraArtifactLocale">;
54
+ contentKey: string & import("effect/Brand").Brand<"@NakafaAI/AksaraContentKey">;
55
+ family: "article" | "material" | "page" | "question";
56
+ }[];
57
+ families: ("article" | "material" | "page" | "question")[];
58
+ snapshots: ("program" | "quran" | "tryout")[];
59
+ };
60
+ export {};
@@ -0,0 +1,102 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { ContentFamilySchema, compareContentHeads, } from "#contracts/content";
3
+ import { ContentKeySchema } from "#contracts/ids";
4
+ import { ArtifactLocaleSchema } from "#contracts/locale";
5
+ import { compareCodeUnits } from "#contracts/text/order";
6
+ /** Fixed structured families selected by the one global release pointer. */
7
+ export const ContentSnapshotKindSchema = Schema.Literals([
8
+ "program",
9
+ "quran",
10
+ "tryout",
11
+ ]);
12
+ /** Authenticates exact content selection retained by predecessor releases. */
13
+ export const PredecessorContentPublicationIdentitySchema = Schema.Struct({
14
+ artifactLocale: ArtifactLocaleSchema,
15
+ contentKey: ContentKeySchema,
16
+ family: ContentFamilySchema,
17
+ });
18
+ /** Orders predecessor scope identities exactly as their signed release did. */
19
+ function comparePredecessorPublicationIdentities(left, right) {
20
+ const familyOrder = compareCodeUnits(left.family, right.family);
21
+ return familyOrder || compareContentHeads(left, right);
22
+ }
23
+ /** Accepts only canonical predecessor identities outside selected families. */
24
+ function hasCanonicalPredecessorContent(content, families) {
25
+ const ordered = content.every((identity, index) => {
26
+ const previous = content[index - 1];
27
+ return (previous === undefined ||
28
+ comparePredecessorPublicationIdentities(previous, identity) < 0);
29
+ });
30
+ return ordered && content.every(({ family }) => !families.includes(family));
31
+ }
32
+ /** Checks strict canonical ordering for selected content and snapshot families. */
33
+ function hasCanonicalPublicationScope(input) {
34
+ const content = input.content ?? [];
35
+ const contentIsCanonical = hasCanonicalPredecessorContent(content, input.families);
36
+ const snapshotsAreCanonical = input.snapshots.every((family, index) => {
37
+ const previous = input.snapshots[index - 1];
38
+ return (previous === undefined ||
39
+ ContentSnapshotKindSchema.literals.indexOf(previous) <
40
+ ContentSnapshotKindSchema.literals.indexOf(family));
41
+ });
42
+ const familiesAreCanonical = input.families.every((family, index) => {
43
+ const previous = input.families[index - 1];
44
+ return (previous === undefined ||
45
+ ContentFamilySchema.literals.indexOf(previous) <
46
+ ContentFamilySchema.literals.indexOf(family));
47
+ });
48
+ return (contentIsCanonical &&
49
+ familiesAreCanonical &&
50
+ snapshotsAreCanonical &&
51
+ content.length + input.families.length + input.snapshots.length > 0);
52
+ }
53
+ const PublicationScopeFields = {
54
+ content: Schema.optional(Schema.Array(PredecessorContentPublicationIdentitySchema)),
55
+ families: Schema.Array(ContentFamilySchema),
56
+ snapshots: Schema.Array(ContentSnapshotKindSchema),
57
+ };
58
+ /** Content and structured families authenticated from any signed release. */
59
+ export const PublicationScopeSchema = Schema.Struct(PublicationScopeFields).pipe(Schema.check(Schema.makeFilter(hasCanonicalPublicationScope, {
60
+ message: "Expected a non-empty publication scope in canonical unique order.",
61
+ })));
62
+ /** Whole-family scope accepted when preparing a new Git release. */
63
+ export const GitPublicationScopeSchema = Schema.Struct({
64
+ families: PublicationScopeFields.families,
65
+ snapshots: PublicationScopeFields.snapshots,
66
+ }).pipe(Schema.check(Schema.makeFilter(hasCanonicalPublicationScope, {
67
+ message: "Expected a non-empty Git publication scope in canonical unique order.",
68
+ })));
69
+ /** New Git release preparation received predecessor-only exact selection. */
70
+ export class GitPublicationScopeError extends Schema.TaggedError()("GitPublicationScopeError", {}) {
71
+ }
72
+ /** Rejects predecessor-only fields before any new release work begins. */
73
+ export const verifyGitPublicationScope = Effect.fn("AksaraContracts.verifyGitPublicationScope")((scope) => Schema.decodeEffect(GitPublicationScopeSchema)(scope, {
74
+ onExcessProperty: "error",
75
+ }).pipe(Effect.mapError(() => new GitPublicationScopeError())));
76
+ /** Checks whether one body transition is authorized by the signed scope. */
77
+ export function publicationScopeSelectsContent(scope, identity) {
78
+ return (scope.families.includes(identity.family) ||
79
+ scope.content?.some((selected) => selected.artifactLocale === identity.artifactLocale &&
80
+ selected.contentKey === identity.contentKey &&
81
+ selected.family === identity.family) === true);
82
+ }
83
+ /** Checks whether one structured family may be replaced by this release. */
84
+ export function publicationScopeSelectsSnapshot(scope, family) {
85
+ return scope.snapshots.includes(family);
86
+ }
87
+ /** Serializes one publication scope with stable signed field order. */
88
+ export function canonicalizePublicationScope(scope) {
89
+ return {
90
+ ...(scope.content === undefined
91
+ ? {}
92
+ : {
93
+ content: scope.content.map(({ artifactLocale, contentKey, family }) => ({
94
+ artifactLocale,
95
+ contentKey,
96
+ family,
97
+ })),
98
+ }),
99
+ families: [...scope.families],
100
+ snapshots: [...scope.snapshots],
101
+ };
102
+ }
@@ -0,0 +1,193 @@
1
+ /** Signed structured snapshot transition contracts. */
2
+ import { Schema } from "effect";
3
+ import { type Sha256Hash } from "#contracts/ids";
4
+ import { type PublicationScope } from "#contracts/release/snapshot/scope";
5
+ /** Canonical digest for a release that stages no structured snapshot rows. */
6
+ export declare const EMPTY_SNAPSHOT_ROW_DIGEST: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
7
+ /** One family's immutable snapshot transition authenticated by a release. */
8
+ export declare const ContentSnapshotStateSchema: Schema.Struct<{
9
+ readonly baseSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
10
+ readonly mode: Schema.Literals<readonly ["inherit", "replace", "restore"]>;
11
+ readonly resultSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
12
+ readonly rowCount: Schema.Int;
13
+ readonly rowDigest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
14
+ }>;
15
+ export type ContentSnapshotState = typeof ContentSnapshotStateSchema.Type;
16
+ /** Fixed snapshot states prevent a release from omitting one owned family. */
17
+ export declare const ContentSnapshotSetSchema: Schema.Struct<{
18
+ readonly program: Schema.Struct<{
19
+ readonly baseSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
20
+ readonly mode: Schema.Literals<readonly ["inherit", "replace", "restore"]>;
21
+ readonly resultSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
22
+ readonly rowCount: Schema.Int;
23
+ readonly rowDigest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
24
+ }>;
25
+ readonly quran: Schema.Struct<{
26
+ readonly baseSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
27
+ readonly mode: Schema.Literals<readonly ["inherit", "replace", "restore"]>;
28
+ readonly resultSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
29
+ readonly rowCount: Schema.Int;
30
+ readonly rowDigest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
31
+ }>;
32
+ readonly tryout: Schema.Struct<{
33
+ readonly baseSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
34
+ readonly mode: Schema.Literals<readonly ["inherit", "replace", "restore"]>;
35
+ readonly resultSnapshotId: Schema.NullOr<Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">>;
36
+ readonly rowCount: Schema.Int;
37
+ readonly rowDigest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
38
+ }>;
39
+ }>;
40
+ export type ContentSnapshotSet = typeof ContentSnapshotSetSchema.Type;
41
+ /** Requires every unselected structured family to remain inherited. */
42
+ export declare function hasScopedSnapshotTransitions(scope: PublicationScope, snapshots: ContentSnapshotSet): boolean;
43
+ /** Checks inheritance, replacement, and forward restore row semantics. */
44
+ export declare function hasCoherentSnapshotState(state: {
45
+ readonly baseSnapshotId: Sha256Hash | null;
46
+ readonly mode: "inherit" | "replace" | "restore";
47
+ readonly resultSnapshotId: Sha256Hash | null;
48
+ readonly rowCount: number;
49
+ readonly rowDigest: Sha256Hash;
50
+ }): boolean;
51
+ /** Builds a zero-row transition that preserves one immutable snapshot. */
52
+ export declare function inheritContentSnapshot(snapshotId: ContentSnapshotState["resultSnapshotId"]): {
53
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
54
+ readonly mode: "inherit" | "replace" | "restore";
55
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
56
+ readonly rowCount: number;
57
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
58
+ };
59
+ /** Builds fixed inherited states from the prior release's result identities. */
60
+ export declare function inheritContentSnapshots(previous: ContentSnapshotSet | null): {
61
+ readonly program: {
62
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
63
+ readonly mode: "inherit" | "replace" | "restore";
64
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
65
+ readonly rowCount: number;
66
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
67
+ };
68
+ readonly quran: {
69
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
70
+ readonly mode: "inherit" | "replace" | "restore";
71
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
72
+ readonly rowCount: number;
73
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
74
+ };
75
+ readonly tryout: {
76
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
77
+ readonly mode: "inherit" | "replace" | "restore";
78
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
79
+ readonly rowCount: number;
80
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
81
+ };
82
+ };
83
+ /** Reconstructs inherited prior state from one signed transition's base IDs. */
84
+ export declare function baseContentSnapshots(snapshots: ContentSnapshotSet): {
85
+ readonly program: {
86
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
87
+ readonly mode: "inherit" | "replace" | "restore";
88
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
89
+ readonly rowCount: number;
90
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
91
+ };
92
+ readonly quran: {
93
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
94
+ readonly mode: "inherit" | "replace" | "restore";
95
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
96
+ readonly rowCount: number;
97
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
98
+ };
99
+ readonly tryout: {
100
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
101
+ readonly mode: "inherit" | "replace" | "restore";
102
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
103
+ readonly rowCount: number;
104
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
105
+ };
106
+ };
107
+ /** Builds a full replacement transition for one prepared snapshot. */
108
+ export declare function replaceContentSnapshot(input: {
109
+ readonly baseSnapshotId: ContentSnapshotState["baseSnapshotId"];
110
+ readonly resultSnapshotId: Exclude<ContentSnapshotState["resultSnapshotId"], null>;
111
+ readonly rowCount: number;
112
+ readonly rowDigest: Sha256Hash;
113
+ }): {
114
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
115
+ readonly mode: "inherit" | "replace" | "restore";
116
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
117
+ readonly rowCount: number;
118
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
119
+ };
120
+ /** Builds a row-free forward restore to an existing or absent snapshot. */
121
+ export declare function restoreContentSnapshot(baseSnapshotId: ContentSnapshotState["baseSnapshotId"], resultSnapshotId: ContentSnapshotState["resultSnapshotId"]): {
122
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
123
+ readonly mode: "inherit" | "replace" | "restore";
124
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
125
+ readonly rowCount: number;
126
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
127
+ };
128
+ /** Builds the retained inverse without copying immutable snapshot rows. */
129
+ export declare function invertContentSnapshots(snapshots: ContentSnapshotSet): {
130
+ readonly program: {
131
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
132
+ readonly mode: "inherit" | "replace" | "restore";
133
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
134
+ readonly rowCount: number;
135
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
136
+ };
137
+ readonly quran: {
138
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
139
+ readonly mode: "inherit" | "replace" | "restore";
140
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
141
+ readonly rowCount: number;
142
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
143
+ };
144
+ readonly tryout: {
145
+ readonly baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
146
+ readonly mode: "inherit" | "replace" | "restore";
147
+ readonly resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
148
+ readonly rowCount: number;
149
+ readonly rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
150
+ };
151
+ };
152
+ /** Checks that an initial release does not claim an unstated snapshot base. */
153
+ export declare function hasEmptySnapshotBases(snapshots: ContentSnapshotSet): boolean;
154
+ /** Checks that a rollback only inherits or restores immutable snapshots. */
155
+ export declare function hasRollbackSnapshotModes(snapshots: ContentSnapshotSet): boolean;
156
+ /** Checks that reviewed Git sources only inherit or replace snapshots. */
157
+ export declare function hasGitSnapshotModes(snapshots: ContentSnapshotSet): boolean;
158
+ /** Returns the number of rows that must be staged for this release. */
159
+ export declare function snapshotRowCount(snapshots: ContentSnapshotSet): number;
160
+ /** Serializes one snapshot transition with stable signed field order. */
161
+ export declare function canonicalizeContentSnapshotState(state: ContentSnapshotState): {
162
+ baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
163
+ mode: "inherit" | "replace" | "restore";
164
+ resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
165
+ rowCount: number;
166
+ rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
167
+ };
168
+ /** Serializes all fixed snapshot families with stable signed field order. */
169
+ export declare function canonicalizeContentSnapshotSet(snapshots: ContentSnapshotSet): {
170
+ program: {
171
+ baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
172
+ mode: "inherit" | "replace" | "restore";
173
+ resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
174
+ rowCount: number;
175
+ rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
176
+ };
177
+ quran: {
178
+ baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
179
+ mode: "inherit" | "replace" | "restore";
180
+ resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
181
+ rowCount: number;
182
+ rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
183
+ };
184
+ tryout: {
185
+ baseSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
186
+ mode: "inherit" | "replace" | "restore";
187
+ resultSnapshotId: (string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">) | null;
188
+ rowCount: number;
189
+ rowDigest: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
190
+ };
191
+ };
192
+ /** Compares two fixed snapshot sets through their stable signed form. */
193
+ export declare function hasSameContentSnapshots(left: ContentSnapshotSet, right: ContentSnapshotSet): boolean;