@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,139 @@
1
+ import { Schema } from "effect";
2
+ /** Hashed current learning-program catalog record. */
3
+ export declare const LearningProgramRecordSchema: Schema.Struct<{
4
+ readonly kind: Schema.Literal<"program">;
5
+ readonly row: Schema.Struct<{
6
+ readonly defaultCoverageStatus: Schema.Literals<readonly ["archived", "available", "hidden", "partial", "planned"]>;
7
+ readonly displayOrder: Schema.Int;
8
+ readonly iconKey: Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>;
9
+ readonly key: Schema.brand<Schema.String, "@NakafaAI/AksaraLearningProgramKey">;
10
+ readonly kind: Schema.Literals<readonly ["admission-exam", "assessment", "custom-program", "institution-program", "school-curriculum"]>;
11
+ readonly navigation: Schema.Struct<{
12
+ readonly levels: Schema.NonEmptyArray<Schema.Literals<readonly ["class", "course", "domain", "lesson", "phase", "section", "set", "stage", "subject", "topic", "track", "unit"]>>;
13
+ readonly model: Schema.Literals<readonly ["course-unit-lesson", "curriculum-tree", "exam-domain-set", "track-topic"]>;
14
+ }>;
15
+ readonly provider: Schema.Struct<{
16
+ readonly homeCountry: Schema.optional<Schema.String>;
17
+ readonly kind: Schema.Literals<readonly ["institution", "learner", "nakafa", "official"]>;
18
+ readonly name: Schema.Trimmed;
19
+ }>;
20
+ readonly recommendedCountry: Schema.optional<Schema.String>;
21
+ readonly sources: Schema.NonEmptyArray<Schema.Struct<{
22
+ readonly label: Schema.Trimmed;
23
+ readonly retrievedAt: Schema.String;
24
+ readonly reviewAfter: Schema.optional<Schema.String>;
25
+ readonly type: Schema.Literals<readonly ["institution-document", "nakafa-editorial", "official-blueprint", "official-policy", "official-portal"]>;
26
+ readonly url: Schema.String;
27
+ }>>;
28
+ readonly translations: Schema.NonEmptyArray<Schema.Struct<{
29
+ readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
30
+ readonly publicSlug: Schema.String;
31
+ readonly title: Schema.Trimmed;
32
+ }>>;
33
+ readonly version: Schema.Struct<{
34
+ readonly endsAt: Schema.optional<Schema.String>;
35
+ readonly label: Schema.Trimmed;
36
+ readonly startsAt: Schema.optional<Schema.String>;
37
+ }>;
38
+ }>;
39
+ readonly rowHash: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
40
+ }>;
41
+ /** Hashed current localized curriculum-route record. */
42
+ export declare const CurriculumRouteRecordSchema: Schema.Struct<{
43
+ readonly kind: Schema.Literal<"curriculum">;
44
+ readonly row: Schema.Struct<{
45
+ appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
46
+ canonicalPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
47
+ displayGroupIconKey: Schema.optional<Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>>;
48
+ displayGroupTitle: Schema.optional<Schema.String>;
49
+ iconKey: Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>;
50
+ kind: Schema.Literal<"curriculum-context">;
51
+ level: Schema.Literals<readonly ["class", "course", "domain", "lesson", "phase", "section", "set", "stage", "subject", "topic", "track", "unit"]>;
52
+ materialCardDescription: Schema.optional<Schema.String>;
53
+ materialCardTitle: Schema.optional<Schema.String>;
54
+ materialContextNodeKey: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraCurriculumNodeKey">>;
55
+ materialContextParentPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
56
+ materialContextPublicPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
57
+ materialDomain: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraMaterialDomain">>;
58
+ materialKey: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraMaterialKey">>;
59
+ nodeKey: Schema.String;
60
+ order: Schema.Int;
61
+ parentPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
62
+ programKey: Schema.brand<Schema.String, "@NakafaAI/AksaraLearningProgramKey">;
63
+ publicPath: Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">;
64
+ sitemap: Schema.Boolean;
65
+ sourcePath: Schema.brand<Schema.String, "@NakafaAI/AksaraCorpusSourcePath">;
66
+ title: Schema.String;
67
+ }>;
68
+ readonly rowHash: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
69
+ }>;
70
+ /** Complete row vocabulary owned by the current program snapshot. */
71
+ export declare const ProgramSnapshotRowSchema: Schema.Union<readonly [Schema.Struct<{
72
+ readonly kind: Schema.Literal<"program">;
73
+ readonly row: Schema.Struct<{
74
+ readonly defaultCoverageStatus: Schema.Literals<readonly ["archived", "available", "hidden", "partial", "planned"]>;
75
+ readonly displayOrder: Schema.Int;
76
+ readonly iconKey: Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>;
77
+ readonly key: Schema.brand<Schema.String, "@NakafaAI/AksaraLearningProgramKey">;
78
+ readonly kind: Schema.Literals<readonly ["admission-exam", "assessment", "custom-program", "institution-program", "school-curriculum"]>;
79
+ readonly navigation: Schema.Struct<{
80
+ readonly levels: Schema.NonEmptyArray<Schema.Literals<readonly ["class", "course", "domain", "lesson", "phase", "section", "set", "stage", "subject", "topic", "track", "unit"]>>;
81
+ readonly model: Schema.Literals<readonly ["course-unit-lesson", "curriculum-tree", "exam-domain-set", "track-topic"]>;
82
+ }>;
83
+ readonly provider: Schema.Struct<{
84
+ readonly homeCountry: Schema.optional<Schema.String>;
85
+ readonly kind: Schema.Literals<readonly ["institution", "learner", "nakafa", "official"]>;
86
+ readonly name: Schema.Trimmed;
87
+ }>;
88
+ readonly recommendedCountry: Schema.optional<Schema.String>;
89
+ readonly sources: Schema.NonEmptyArray<Schema.Struct<{
90
+ readonly label: Schema.Trimmed;
91
+ readonly retrievedAt: Schema.String;
92
+ readonly reviewAfter: Schema.optional<Schema.String>;
93
+ readonly type: Schema.Literals<readonly ["institution-document", "nakafa-editorial", "official-blueprint", "official-policy", "official-portal"]>;
94
+ readonly url: Schema.String;
95
+ }>>;
96
+ readonly translations: Schema.NonEmptyArray<Schema.Struct<{
97
+ readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
98
+ readonly publicSlug: Schema.String;
99
+ readonly title: Schema.Trimmed;
100
+ }>>;
101
+ readonly version: Schema.Struct<{
102
+ readonly endsAt: Schema.optional<Schema.String>;
103
+ readonly label: Schema.Trimmed;
104
+ readonly startsAt: Schema.optional<Schema.String>;
105
+ }>;
106
+ }>;
107
+ readonly rowHash: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
108
+ }>, Schema.Struct<{
109
+ readonly kind: Schema.Literal<"curriculum">;
110
+ readonly row: Schema.Struct<{
111
+ appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
112
+ canonicalPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
113
+ displayGroupIconKey: Schema.optional<Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>>;
114
+ displayGroupTitle: Schema.optional<Schema.String>;
115
+ iconKey: Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>;
116
+ kind: Schema.Literal<"curriculum-context">;
117
+ level: Schema.Literals<readonly ["class", "course", "domain", "lesson", "phase", "section", "set", "stage", "subject", "topic", "track", "unit"]>;
118
+ materialCardDescription: Schema.optional<Schema.String>;
119
+ materialCardTitle: Schema.optional<Schema.String>;
120
+ materialContextNodeKey: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraCurriculumNodeKey">>;
121
+ materialContextParentPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
122
+ materialContextPublicPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
123
+ materialDomain: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraMaterialDomain">>;
124
+ materialKey: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraMaterialKey">>;
125
+ nodeKey: Schema.String;
126
+ order: Schema.Int;
127
+ parentPath: Schema.optional<Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">>;
128
+ programKey: Schema.brand<Schema.String, "@NakafaAI/AksaraLearningProgramKey">;
129
+ publicPath: Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">;
130
+ sitemap: Schema.Boolean;
131
+ sourcePath: Schema.brand<Schema.String, "@NakafaAI/AksaraCorpusSourcePath">;
132
+ title: Schema.String;
133
+ }>;
134
+ readonly rowHash: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
135
+ }>]>;
136
+ export type ProgramSnapshotRow = typeof ProgramSnapshotRowSchema.Type;
137
+ export type ProgramSnapshotRowInput = Pick<typeof LearningProgramRecordSchema.Type, "kind" | "row"> | Pick<typeof CurriculumRouteRecordSchema.Type, "kind" | "row">;
138
+ /** Serializes one current program snapshot row without its derived hash. */
139
+ export declare function canonicalizeProgramSnapshotRow(record: ProgramSnapshotRowInput): string;
@@ -0,0 +1,28 @@
1
+ import { Schema } from "effect";
2
+ import { Sha256HashSchema } from "#contracts/ids";
3
+ import { CurriculumRouteSchema, canonicalizeCurriculumRoute, } from "#contracts/program/curriculum";
4
+ import { canonicalizeLearningProgram, LearningProgramSchema, } from "#contracts/program/spec";
5
+ /** Hashed current learning-program catalog record. */
6
+ export const LearningProgramRecordSchema = Schema.Struct({
7
+ kind: Schema.Literal("program"),
8
+ row: LearningProgramSchema,
9
+ rowHash: Sha256HashSchema,
10
+ });
11
+ /** Hashed current localized curriculum-route record. */
12
+ export const CurriculumRouteRecordSchema = Schema.Struct({
13
+ kind: Schema.Literal("curriculum"),
14
+ row: CurriculumRouteSchema,
15
+ rowHash: Sha256HashSchema,
16
+ });
17
+ /** Complete row vocabulary owned by the current program snapshot. */
18
+ export const ProgramSnapshotRowSchema = Schema.Union([
19
+ LearningProgramRecordSchema,
20
+ CurriculumRouteRecordSchema,
21
+ ]);
22
+ /** Serializes one current program snapshot row without its derived hash. */
23
+ export function canonicalizeProgramSnapshotRow(record) {
24
+ if (record.kind === "program") {
25
+ return `{"kind":"program","row":${canonicalizeLearningProgram(record.row)}}`;
26
+ }
27
+ return `{"kind":"curriculum","row":${canonicalizeCurriculumRoute(record.row)}}`;
28
+ }
@@ -0,0 +1,36 @@
1
+ import { Schema } from "effect";
2
+ /** Semantic wire identity of the current localized program snapshot. */
3
+ export declare const PROGRAM_SNAPSHOT_FORMAT = "localized-program-snapshot";
4
+ /** Source-derived row counts checked against each complete program replay. */
5
+ export declare const ProgramCountsSchema: Schema.Struct<{
6
+ curriculumRowCount: Schema.Int;
7
+ programRowCount: Schema.Int;
8
+ rowCount: Schema.Int;
9
+ sitemapCount: Schema.Int;
10
+ slugCount: Schema.Int;
11
+ }>;
12
+ export type ProgramCounts = typeof ProgramCountsSchema.Type;
13
+ /** Canonical current program facts before content-addressed identity. */
14
+ export declare const ProgramSnapshotFactsSchema: Schema.Struct<{
15
+ curriculumRowCount: Schema.Int;
16
+ programRowCount: Schema.Int;
17
+ rowCount: Schema.Int;
18
+ sitemapCount: Schema.Int;
19
+ slugCount: Schema.Int;
20
+ activeAppLocales: Schema.NonEmptyArray<Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">>;
21
+ rowDigest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
22
+ }>;
23
+ export type ProgramSnapshotFacts = typeof ProgramSnapshotFactsSchema.Type;
24
+ /** Content-addressed current program snapshot selected by one release. */
25
+ export declare const ProgramSnapshotSchema: Schema.Struct<{
26
+ readonly curriculumRowCount: Schema.Int;
27
+ readonly programRowCount: Schema.Int;
28
+ readonly rowCount: Schema.Int;
29
+ readonly sitemapCount: Schema.Int;
30
+ readonly slugCount: Schema.Int;
31
+ readonly activeAppLocales: Schema.NonEmptyArray<Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">>;
32
+ readonly rowDigest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
33
+ readonly format: Schema.Literal<"localized-program-snapshot">;
34
+ readonly snapshotId: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
35
+ }>;
36
+ export type ProgramSnapshot = typeof ProgramSnapshotSchema.Type;
@@ -0,0 +1,39 @@
1
+ import { Schema } from "effect";
2
+ import { Sha256HashSchema } from "#contracts/ids";
3
+ import { ActiveAppLocaleListSchema } from "#contracts/locale";
4
+ /** Semantic wire identity of the current localized program snapshot. */
5
+ export const PROGRAM_SNAPSHOT_FORMAT = "localized-program-snapshot";
6
+ const CountSchema = Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0)));
7
+ const ProgramCountFields = {
8
+ curriculumRowCount: CountSchema,
9
+ programRowCount: CountSchema,
10
+ rowCount: CountSchema,
11
+ sitemapCount: CountSchema,
12
+ slugCount: CountSchema,
13
+ };
14
+ /** Source-derived row counts checked against each complete program replay. */
15
+ export const ProgramCountsSchema = Schema.Struct(ProgramCountFields);
16
+ /** Checks aggregate arithmetic without coupling it to one corpus size. */
17
+ function hasCompleteProgramSnapshot(input) {
18
+ return (input.programRowCount > 0 &&
19
+ input.slugCount === input.programRowCount * input.activeAppLocales.length &&
20
+ input.rowCount === input.programRowCount + input.curriculumRowCount &&
21
+ input.sitemapCount <= input.curriculumRowCount);
22
+ }
23
+ const ProgramSnapshotFactFields = {
24
+ activeAppLocales: ActiveAppLocaleListSchema,
25
+ ...ProgramCountFields,
26
+ rowDigest: Sha256HashSchema,
27
+ };
28
+ /** Canonical current program facts before content-addressed identity. */
29
+ export const ProgramSnapshotFactsSchema = Schema.Struct(ProgramSnapshotFactFields).pipe(Schema.check(Schema.makeFilter(hasCompleteProgramSnapshot, {
30
+ message: "Expected self-consistent program and curriculum snapshot counts.",
31
+ })));
32
+ /** Content-addressed current program snapshot selected by one release. */
33
+ export const ProgramSnapshotSchema = Schema.Struct({
34
+ ...ProgramSnapshotFactFields,
35
+ format: Schema.Literal(PROGRAM_SNAPSHOT_FORMAT),
36
+ snapshotId: Sha256HashSchema,
37
+ }).pipe(Schema.check(Schema.makeFilter(hasCompleteProgramSnapshot, {
38
+ message: "Expected self-consistent program and curriculum snapshot counts.",
39
+ })));
@@ -0,0 +1,85 @@
1
+ import { Schema } from "effect";
2
+ /** Canonical language-neutral identity for one learning program. */
3
+ export declare const LearningProgramKeySchema: Schema.brand<Schema.String, "@NakafaAI/AksaraLearningProgramKey">;
4
+ export type LearningProgramKey = typeof LearningProgramKeySchema.Type;
5
+ /** Product role of one reviewed learning program. */
6
+ export declare const LearningProgramKindSchema: Schema.Literals<readonly ["admission-exam", "assessment", "custom-program", "institution-program", "school-curriculum"]>;
7
+ /** Navigation model rendered by one learning program surface. */
8
+ export declare const ProgramNavigationModelSchema: Schema.Literals<readonly ["course-unit-lesson", "curriculum-tree", "exam-domain-set", "track-topic"]>;
9
+ /** Complete level vocabulary used by reviewed curriculum and exam sources. */
10
+ export declare const ProgramNavigationLevelSchema: Schema.Literals<readonly ["class", "course", "domain", "lesson", "phase", "section", "set", "stage", "subject", "topic", "track", "unit"]>;
11
+ export type ProgramNavigationLevel = typeof ProgramNavigationLevelSchema.Type;
12
+ /** Complete icon vocabulary referenced by learning program sources. */
13
+ export declare const ProgramNavigationIconKeySchema: Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>;
14
+ export type ProgramNavigationIconKey = typeof ProgramNavigationIconKeySchema.Type;
15
+ /** Publication state derived from reviewed source coverage. */
16
+ export declare const ProgramCoverageSchema: Schema.Literals<readonly ["archived", "available", "hidden", "partial", "planned"]>;
17
+ /** Reviewed organization class behind one program. */
18
+ export declare const ProgramProviderKindSchema: Schema.Literals<readonly ["institution", "learner", "nakafa", "official"]>;
19
+ /** Provenance role of one cited program source. */
20
+ export declare const ProgramSourceKindSchema: Schema.Literals<readonly ["institution-document", "nakafa-editorial", "official-blueprint", "official-policy", "official-portal"]>;
21
+ /** One localized title and public slug owned by a learning program. */
22
+ export declare const ProgramTranslationSchema: Schema.Struct<{
23
+ readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
24
+ readonly publicSlug: Schema.String;
25
+ readonly title: Schema.Trimmed;
26
+ }>;
27
+ export type ProgramTranslation = typeof ProgramTranslationSchema.Type;
28
+ /** Reviewed provider identity attached to one learning program. */
29
+ export declare const ProgramProviderSchema: Schema.Struct<{
30
+ readonly homeCountry: Schema.optional<Schema.String>;
31
+ readonly kind: Schema.Literals<readonly ["institution", "learner", "nakafa", "official"]>;
32
+ readonly name: Schema.Trimmed;
33
+ }>;
34
+ /** Exact official or editorial source used by one program registry row. */
35
+ export declare const ProgramSourceSchema: Schema.Struct<{
36
+ readonly label: Schema.Trimmed;
37
+ readonly retrievedAt: Schema.String;
38
+ readonly reviewAfter: Schema.optional<Schema.String>;
39
+ readonly type: Schema.Literals<readonly ["institution-document", "nakafa-editorial", "official-blueprint", "official-policy", "official-portal"]>;
40
+ readonly url: Schema.String;
41
+ }>;
42
+ /** Version label and optional inclusive availability window. */
43
+ export declare const ProgramVersionSchema: Schema.Struct<{
44
+ readonly endsAt: Schema.optional<Schema.String>;
45
+ readonly label: Schema.Trimmed;
46
+ readonly startsAt: Schema.optional<Schema.String>;
47
+ }>;
48
+ /** Complete source-controlled wire contract for one learning program. */
49
+ export declare const LearningProgramSchema: Schema.Struct<{
50
+ readonly defaultCoverageStatus: Schema.Literals<readonly ["archived", "available", "hidden", "partial", "planned"]>;
51
+ readonly displayOrder: Schema.Int;
52
+ readonly iconKey: Schema.Literals<readonly ["advanced", "assessment", "certificate", "course", "diploma", "early-years", "global-education", "grade-1", "grade-10", "grade-11", "grade-12", "grade-2", "grade-3", "grade-4", "grade-5", "grade-6", "grade-7", "grade-8", "grade-9", "high-school", "mathematics", "middle-school", "primary-school", "science", "school", "standards", "state"]>;
53
+ readonly key: Schema.brand<Schema.String, "@NakafaAI/AksaraLearningProgramKey">;
54
+ readonly kind: Schema.Literals<readonly ["admission-exam", "assessment", "custom-program", "institution-program", "school-curriculum"]>;
55
+ readonly navigation: Schema.Struct<{
56
+ readonly levels: Schema.NonEmptyArray<Schema.Literals<readonly ["class", "course", "domain", "lesson", "phase", "section", "set", "stage", "subject", "topic", "track", "unit"]>>;
57
+ readonly model: Schema.Literals<readonly ["course-unit-lesson", "curriculum-tree", "exam-domain-set", "track-topic"]>;
58
+ }>;
59
+ readonly provider: Schema.Struct<{
60
+ readonly homeCountry: Schema.optional<Schema.String>;
61
+ readonly kind: Schema.Literals<readonly ["institution", "learner", "nakafa", "official"]>;
62
+ readonly name: Schema.Trimmed;
63
+ }>;
64
+ readonly recommendedCountry: Schema.optional<Schema.String>;
65
+ readonly sources: Schema.NonEmptyArray<Schema.Struct<{
66
+ readonly label: Schema.Trimmed;
67
+ readonly retrievedAt: Schema.String;
68
+ readonly reviewAfter: Schema.optional<Schema.String>;
69
+ readonly type: Schema.Literals<readonly ["institution-document", "nakafa-editorial", "official-blueprint", "official-policy", "official-portal"]>;
70
+ readonly url: Schema.String;
71
+ }>>;
72
+ readonly translations: Schema.NonEmptyArray<Schema.Struct<{
73
+ readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
74
+ readonly publicSlug: Schema.String;
75
+ readonly title: Schema.Trimmed;
76
+ }>>;
77
+ readonly version: Schema.Struct<{
78
+ readonly endsAt: Schema.optional<Schema.String>;
79
+ readonly label: Schema.Trimmed;
80
+ readonly startsAt: Schema.optional<Schema.String>;
81
+ }>;
82
+ }>;
83
+ export type LearningProgram = typeof LearningProgramSchema.Type;
84
+ /** Serializes one program in stable signed field order. */
85
+ export declare function canonicalizeLearningProgram(program: LearningProgram): string;
@@ -0,0 +1,197 @@
1
+ import { Schema } from "effect";
2
+ import { CountryCodeSchema } from "#contracts/country";
3
+ import { DateOnlySchema } from "#contracts/date";
4
+ import { APP_LOCALE_CODES, AppLocaleSchema } from "#contracts/locale";
5
+ import { isHttpsUrl, isLowerKebab } from "#contracts/text/syntax";
6
+ /** Canonical language-neutral identity for one learning program. */
7
+ export const LearningProgramKeySchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isLowerKebab, {
8
+ description: "Lowercase kebab-case canonical learning program key.",
9
+ identifier: "LearningProgramKey",
10
+ message: "Invalid learning program key. Expected lowercase kebab-case.",
11
+ })), Schema.brand("@NakafaAI/AksaraLearningProgramKey"));
12
+ /** Product role of one reviewed learning program. */
13
+ export const LearningProgramKindSchema = Schema.Literals([
14
+ "admission-exam",
15
+ "assessment",
16
+ "custom-program",
17
+ "institution-program",
18
+ "school-curriculum",
19
+ ]);
20
+ /** Navigation model rendered by one learning program surface. */
21
+ export const ProgramNavigationModelSchema = Schema.Literals([
22
+ "course-unit-lesson",
23
+ "curriculum-tree",
24
+ "exam-domain-set",
25
+ "track-topic",
26
+ ]);
27
+ /** Complete level vocabulary used by reviewed curriculum and exam sources. */
28
+ export const ProgramNavigationLevelSchema = Schema.Literals([
29
+ "class",
30
+ "course",
31
+ "domain",
32
+ "lesson",
33
+ "phase",
34
+ "section",
35
+ "set",
36
+ "stage",
37
+ "subject",
38
+ "topic",
39
+ "track",
40
+ "unit",
41
+ ]);
42
+ /** Complete icon vocabulary referenced by learning program sources. */
43
+ export const ProgramNavigationIconKeySchema = Schema.Literals([
44
+ "advanced",
45
+ "assessment",
46
+ "certificate",
47
+ "course",
48
+ "diploma",
49
+ "early-years",
50
+ "global-education",
51
+ "grade-1",
52
+ "grade-10",
53
+ "grade-11",
54
+ "grade-12",
55
+ "grade-2",
56
+ "grade-3",
57
+ "grade-4",
58
+ "grade-5",
59
+ "grade-6",
60
+ "grade-7",
61
+ "grade-8",
62
+ "grade-9",
63
+ "high-school",
64
+ "mathematics",
65
+ "middle-school",
66
+ "primary-school",
67
+ "science",
68
+ "school",
69
+ "standards",
70
+ "state",
71
+ ]);
72
+ /** Publication state derived from reviewed source coverage. */
73
+ export const ProgramCoverageSchema = Schema.Literals([
74
+ "archived",
75
+ "available",
76
+ "hidden",
77
+ "partial",
78
+ "planned",
79
+ ]);
80
+ /** Reviewed organization class behind one program. */
81
+ export const ProgramProviderKindSchema = Schema.Literals([
82
+ "institution",
83
+ "learner",
84
+ "nakafa",
85
+ "official",
86
+ ]);
87
+ /** Provenance role of one cited program source. */
88
+ export const ProgramSourceKindSchema = Schema.Literals([
89
+ "institution-document",
90
+ "nakafa-editorial",
91
+ "official-blueprint",
92
+ "official-policy",
93
+ "official-portal",
94
+ ]);
95
+ const ProgramSlugSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isLowerKebab)));
96
+ /** One localized title and public slug owned by a learning program. */
97
+ export const ProgramTranslationSchema = Schema.Struct({
98
+ appLocale: AppLocaleSchema,
99
+ publicSlug: ProgramSlugSchema,
100
+ title: Schema.Trimmed.check(Schema.isNonEmpty()),
101
+ });
102
+ /** Checks translations for unique canonical application-locale order. */
103
+ function hasCanonicalTranslations(translations) {
104
+ return translations.every((translation, index) => {
105
+ const previous = translations[index - 1];
106
+ return (previous === undefined ||
107
+ APP_LOCALE_CODES.indexOf(previous.appLocale) <
108
+ APP_LOCALE_CODES.indexOf(translation.appLocale));
109
+ });
110
+ }
111
+ const ProgramTranslationListSchema = Schema.NonEmptyArray(ProgramTranslationSchema).pipe(Schema.check(Schema.makeFilter(hasCanonicalTranslations, {
112
+ message: "Program translations must use unique canonical app-locale order.",
113
+ })));
114
+ /** Reviewed provider identity attached to one learning program. */
115
+ export const ProgramProviderSchema = Schema.Struct({
116
+ homeCountry: Schema.optional(CountryCodeSchema),
117
+ kind: ProgramProviderKindSchema,
118
+ name: Schema.Trimmed.check(Schema.isNonEmpty()),
119
+ });
120
+ /** Exact official or editorial source used by one program registry row. */
121
+ export const ProgramSourceSchema = Schema.Struct({
122
+ label: Schema.Trimmed.check(Schema.isNonEmpty()),
123
+ retrievedAt: DateOnlySchema,
124
+ reviewAfter: Schema.optional(DateOnlySchema),
125
+ type: ProgramSourceKindSchema,
126
+ url: Schema.String.pipe(Schema.check(Schema.makeFilter(isHttpsUrl))),
127
+ });
128
+ /** Version label and optional inclusive availability window. */
129
+ export const ProgramVersionSchema = Schema.Struct({
130
+ endsAt: Schema.optional(DateOnlySchema),
131
+ label: Schema.Trimmed.check(Schema.isNonEmpty()),
132
+ startsAt: Schema.optional(DateOnlySchema),
133
+ }).pipe(Schema.check(Schema.makeFilter(({ endsAt, startsAt }) => endsAt === undefined || startsAt === undefined || startsAt <= endsAt, { message: "Expected a coherent learning program date window." })));
134
+ /** Complete source-controlled wire contract for one learning program. */
135
+ export const LearningProgramSchema = Schema.Struct({
136
+ defaultCoverageStatus: ProgramCoverageSchema,
137
+ displayOrder: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
138
+ iconKey: ProgramNavigationIconKeySchema,
139
+ key: LearningProgramKeySchema,
140
+ kind: LearningProgramKindSchema,
141
+ navigation: Schema.Struct({
142
+ levels: Schema.NonEmptyArray(ProgramNavigationLevelSchema),
143
+ model: ProgramNavigationModelSchema,
144
+ }),
145
+ provider: ProgramProviderSchema,
146
+ recommendedCountry: Schema.optional(CountryCodeSchema),
147
+ sources: Schema.NonEmptyArray(ProgramSourceSchema),
148
+ translations: ProgramTranslationListSchema,
149
+ version: ProgramVersionSchema,
150
+ });
151
+ /** Serializes one program in stable signed field order. */
152
+ export function canonicalizeLearningProgram(program) {
153
+ return JSON.stringify({
154
+ defaultCoverageStatus: program.defaultCoverageStatus,
155
+ displayOrder: program.displayOrder,
156
+ iconKey: program.iconKey,
157
+ key: program.key,
158
+ kind: program.kind,
159
+ navigation: {
160
+ levels: program.navigation.levels,
161
+ model: program.navigation.model,
162
+ },
163
+ provider: {
164
+ ...(program.provider.homeCountry === undefined
165
+ ? {}
166
+ : { homeCountry: program.provider.homeCountry }),
167
+ kind: program.provider.kind,
168
+ name: program.provider.name,
169
+ },
170
+ ...(program.recommendedCountry === undefined
171
+ ? {}
172
+ : { recommendedCountry: program.recommendedCountry }),
173
+ sources: program.sources.map((source) => ({
174
+ label: source.label,
175
+ retrievedAt: source.retrievedAt,
176
+ ...(source.reviewAfter === undefined
177
+ ? {}
178
+ : { reviewAfter: source.reviewAfter }),
179
+ type: source.type,
180
+ url: source.url,
181
+ })),
182
+ translations: program.translations.map((translation) => ({
183
+ appLocale: translation.appLocale,
184
+ publicSlug: translation.publicSlug,
185
+ title: translation.title,
186
+ })),
187
+ version: {
188
+ ...(program.version.endsAt === undefined
189
+ ? {}
190
+ : { endsAt: program.version.endsAt }),
191
+ label: program.version.label,
192
+ ...(program.version.startsAt === undefined
193
+ ? {}
194
+ : { startsAt: program.version.startsAt }),
195
+ },
196
+ });
197
+ }