@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,4 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { ContractDecodeError } from "#contracts/errors";
3
+ /** Strictly decodes one named wire contract into the shared typed failure. */
4
+ export declare function decodeContract<A, I>(schema: Schema.Codec<A, I>, contract: string, input: unknown): Effect.Effect<A, ContractDecodeError, never>;
package/dist/decode.js ADDED
@@ -0,0 +1,8 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { ContractDecodeError } from "#contracts/errors";
3
+ /** Strictly decodes one named wire contract into the shared typed failure. */
4
+ export function decodeContract(schema, contract, input) {
5
+ return Schema.decodeUnknownEffect(schema)(input, {
6
+ onExcessProperty: "error",
7
+ }).pipe(Effect.mapError((cause) => new ContractDecodeError({ cause, contract, message: String(cause) })));
8
+ }
@@ -0,0 +1,4 @@
1
+ import { Schema } from "effect";
2
+ /** Access boundary enforced before any published artifact body is returned. */
3
+ export declare const ContentDeliveryClassSchema: Schema.Literals<readonly ["public", "authenticated", "entitled"]>;
4
+ export type ContentDeliveryClass = typeof ContentDeliveryClassSchema.Type;
@@ -0,0 +1,7 @@
1
+ import { Schema } from "effect";
2
+ /** Access boundary enforced before any published artifact body is returned. */
3
+ export const ContentDeliveryClassSchema = Schema.Literals([
4
+ "public",
5
+ "authenticated",
6
+ "entitled",
7
+ ]);
@@ -0,0 +1,10 @@
1
+ import { Schema } from "effect";
2
+ declare const ContractDecodeError_base: Schema.Class<ContractDecodeError, Schema.TaggedStruct<"ContractDecodeError", {
3
+ readonly cause: Schema.Unknown;
4
+ readonly contract: Schema.Trimmed;
5
+ readonly message: Schema.Trimmed;
6
+ }>, import("effect/Cause").YieldableError>;
7
+ /** Describes a wire value that failed its named Effect Schema contract. */
8
+ export declare class ContractDecodeError extends ContractDecodeError_base {
9
+ }
10
+ export {};
package/dist/errors.js ADDED
@@ -0,0 +1,8 @@
1
+ import { Schema } from "effect";
2
+ /** Describes a wire value that failed its named Effect Schema contract. */
3
+ export class ContractDecodeError extends Schema.TaggedError()("ContractDecodeError", {
4
+ cause: Schema.Unknown,
5
+ contract: Schema.Trimmed.check(Schema.isNonEmpty()),
6
+ message: Schema.Trimmed.check(Schema.isNonEmpty()),
7
+ }) {
8
+ }
@@ -0,0 +1,45 @@
1
+ import { Effect, Schema } from "effect";
2
+ /** Current semantic families addressable through learning-graph identities. */
3
+ export declare const LearningGraphFamilySchema: Schema.Literals<readonly ["article", "material", "quran", "tryout"]>;
4
+ export type LearningGraphFamily = typeof LearningGraphFamilySchema.Type;
5
+ /** Current asset identity accepted by route and graph read-model dispatch. */
6
+ export declare const LearningGraphAssetIdSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraLearningGraphAssetId">;
7
+ export type LearningGraphAssetId = typeof LearningGraphAssetIdSchema.Type;
8
+ /** Semantic owner extracted from one exact current learning-graph asset ID. */
9
+ export declare const LearningGraphAssetOwnerSchema: Schema.Struct<{
10
+ readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
11
+ readonly family: Schema.Literals<readonly ["article", "material", "quran", "tryout"]>;
12
+ }>;
13
+ export type LearningGraphAssetOwner = typeof LearningGraphAssetOwnerSchema.Type;
14
+ declare const LearningGraphAssetFamilyError_base: Schema.Class<LearningGraphAssetFamilyError, Schema.TaggedStruct<"LearningGraphAssetFamilyError", {
15
+ readonly assetId: Schema.String;
16
+ }>, import("effect/Cause").YieldableError>;
17
+ /** One asset ID cannot address a supported current semantic content family. */
18
+ export declare class LearningGraphAssetFamilyError extends LearningGraphAssetFamilyError_base {
19
+ }
20
+ declare const LearningGraphFamilyError_base: Schema.Class<LearningGraphFamilyError, Schema.TaggedStruct<"LearningGraphFamilyError", {
21
+ readonly identity: Schema.Struct<{
22
+ readonly alignmentId: Schema.String;
23
+ readonly assetId: Schema.String;
24
+ readonly conceptId: Schema.String;
25
+ readonly learningObjectId: Schema.String;
26
+ readonly lensId: Schema.String;
27
+ }>;
28
+ }>, import("effect/Cause").YieldableError>;
29
+ /** One graph identity does not coherently belong to a current semantic family. */
30
+ export declare class LearningGraphFamilyError extends LearningGraphFamilyError_base {
31
+ }
32
+ /** Classifies one assetId-only reference without fabricating a full identity. */
33
+ export declare const classifyLearningGraphAssetId: (input: string) => Effect.Effect<{
34
+ readonly appLocale: ("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">;
35
+ readonly family: "article" | "material" | "quran" | "tryout";
36
+ }, LearningGraphAssetFamilyError, never>;
37
+ /** Classifies one coherent current learning-graph identity for direct dispatch. */
38
+ export declare const classifyLearningGraphIdentity: (identity: {
39
+ readonly alignmentId: string;
40
+ readonly assetId: string;
41
+ readonly conceptId: string;
42
+ readonly learningObjectId: string;
43
+ readonly lensId: string;
44
+ }) => Effect.Effect<"article" | "material" | "quran" | "tryout", LearningGraphFamilyError, never>;
45
+ export {};
@@ -0,0 +1,85 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { LearningGraphIdentitySchema, LearningGraphIdSchema, } from "#contracts/graph/spec";
3
+ import { AppLocaleCodeSchema, AppLocaleSchema } from "#contracts/locale";
4
+ /** Current semantic families addressable through learning-graph identities. */
5
+ export const LearningGraphFamilySchema = Schema.Literals([
6
+ "article",
7
+ "material",
8
+ "quran",
9
+ "tryout",
10
+ ]);
11
+ /** Checks one graph ID has the exact current asset dispatch prefix and shape. */
12
+ function hasAssetIdentityShape(assetId) {
13
+ const [prefix, appLocale, family, ...identity] = assetId.split(":");
14
+ return (prefix === "asset" &&
15
+ Schema.is(AppLocaleCodeSchema)(appLocale) &&
16
+ Schema.is(LearningGraphFamilySchema)(family) &&
17
+ identity.length > 0);
18
+ }
19
+ /** Current asset identity accepted by route and graph read-model dispatch. */
20
+ export const LearningGraphAssetIdSchema = LearningGraphIdSchema.pipe(Schema.check(Schema.makeFilter(hasAssetIdentityShape, {
21
+ message: "Expected asset:<appLocale>:<family>:<identity> graph identity.",
22
+ })), Schema.brand("@NakafaAI/AksaraLearningGraphAssetId"));
23
+ /** Semantic owner extracted from one exact current learning-graph asset ID. */
24
+ export const LearningGraphAssetOwnerSchema = Schema.Struct({
25
+ appLocale: AppLocaleSchema,
26
+ family: LearningGraphFamilySchema,
27
+ });
28
+ /** One asset ID cannot address a supported current semantic content family. */
29
+ export class LearningGraphAssetFamilyError extends Schema.TaggedError()("LearningGraphAssetFamilyError", { assetId: Schema.String }) {
30
+ }
31
+ /** One graph identity does not coherently belong to a current semantic family. */
32
+ export class LearningGraphFamilyError extends Schema.TaggedError()("LearningGraphFamilyError", { identity: LearningGraphIdentitySchema }) {
33
+ }
34
+ /** Returns whether an identity body belongs to one exact domain token. */
35
+ function hasOwner(body, owner) {
36
+ return body === owner || body.startsWith(`${owner}:`);
37
+ }
38
+ /** Returns the unprefixed body of one schema-validated graph identity. */
39
+ function identityBody(identity) {
40
+ const separator = identity.indexOf(":");
41
+ return identity.slice(separator + 1);
42
+ }
43
+ /** Returns whether a learning object uses its current family-owned identity. */
44
+ function hasLearningObjectOwner(identity, family) {
45
+ const body = identityBody(identity.learningObjectId);
46
+ if (family === "article") {
47
+ return hasOwner(body, "article");
48
+ }
49
+ if (family === "material") {
50
+ return hasOwner(body, "material-section");
51
+ }
52
+ if (family === "quran") {
53
+ return hasOwner(body, "quran-surah");
54
+ }
55
+ return (body === "tryout" ||
56
+ body.startsWith("tryout-") ||
57
+ body.startsWith("tryout:"));
58
+ }
59
+ /** Verifies every graph identity field against one semantic family. */
60
+ function hasCoherentFamily(identity, family) {
61
+ return (hasOwner(identityBody(identity.alignmentId), family) &&
62
+ hasOwner(identityBody(identity.conceptId), family) &&
63
+ hasLearningObjectOwner(identity, family) &&
64
+ hasOwner(identityBody(identity.lensId), family));
65
+ }
66
+ /** Classifies one assetId-only reference without fabricating a full identity. */
67
+ export const classifyLearningGraphAssetId = Effect.fn("AksaraContracts.classifyLearningGraphAssetId")(function* (input) {
68
+ const [, appLocale, family] = input.split(":");
69
+ const owner = yield* Schema.decodeUnknownEffect(LearningGraphAssetOwnerSchema)({
70
+ appLocale,
71
+ family,
72
+ }).pipe(Effect.mapError(() => new LearningGraphAssetFamilyError({ assetId: input })));
73
+ if (!Schema.is(LearningGraphAssetIdSchema)(input)) {
74
+ return yield* new LearningGraphAssetFamilyError({ assetId: input });
75
+ }
76
+ return owner;
77
+ });
78
+ /** Classifies one coherent current learning-graph identity for direct dispatch. */
79
+ export const classifyLearningGraphIdentity = Effect.fn("AksaraContracts.classifyLearningGraphIdentity")(function* (identity) {
80
+ const owner = yield* classifyLearningGraphAssetId(identity.assetId).pipe(Effect.mapError(() => new LearningGraphFamilyError({ identity })));
81
+ if (!hasCoherentFamily(identity, owner.family)) {
82
+ return yield* new LearningGraphFamilyError({ identity });
83
+ }
84
+ return owner.family;
85
+ });
@@ -0,0 +1,19 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { type LearningGraphIdentity } from "#contracts/graph/spec";
3
+ /** Validated hierarchy segments required to derive one graph identity. */
4
+ export declare const LearningGraphSegmentsSchema: Schema.Struct<{
5
+ readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
6
+ readonly concept: Schema.NonEmptyArray<Schema.String>;
7
+ readonly learningObject: Schema.NonEmptyArray<Schema.String>;
8
+ readonly lens: Schema.NonEmptyArray<Schema.String>;
9
+ }>;
10
+ export type LearningGraphSegments = typeof LearningGraphSegmentsSchema.Type;
11
+ declare const LearningGraphIdentityError_base: Schema.Class<LearningGraphIdentityError, Schema.TaggedStruct<"LearningGraphIdentityError", {
12
+ readonly cause: Schema.Unknown;
13
+ }>, import("effect/Cause").YieldableError>;
14
+ /** Source segments could not produce valid stable graph identities. */
15
+ export declare class LearningGraphIdentityError extends LearningGraphIdentityError_base {
16
+ }
17
+ /** Derives all product identities from one signed route projection source. */
18
+ export declare const makeLearningGraphIdentity: (source: LearningGraphSegments) => Effect.Effect<LearningGraphIdentity, LearningGraphIdentityError>;
19
+ export {};
@@ -0,0 +1,39 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { LearningGraphIdentitySchema, } from "#contracts/graph/spec";
3
+ import { AppLocaleSchema } from "#contracts/locale";
4
+ import { isLowerKebab } from "#contracts/text/syntax";
5
+ const LearningGraphSegmentSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isLowerKebab)));
6
+ /** Validated hierarchy segments required to derive one graph identity. */
7
+ export const LearningGraphSegmentsSchema = Schema.Struct({
8
+ appLocale: AppLocaleSchema,
9
+ concept: Schema.NonEmptyArray(LearningGraphSegmentSchema),
10
+ learningObject: Schema.NonEmptyArray(LearningGraphSegmentSchema),
11
+ lens: Schema.NonEmptyArray(LearningGraphSegmentSchema),
12
+ });
13
+ /** Builds one graph ID from already validated source-owned segments. */
14
+ function graphId(prefix, segments) {
15
+ return `${prefix}:${segments.join(":")}`;
16
+ }
17
+ /** Source segments could not produce valid stable graph identities. */
18
+ export class LearningGraphIdentityError extends Schema.TaggedError()("LearningGraphIdentityError", { cause: Schema.Unknown }) {
19
+ }
20
+ /** Derives all product identities from one signed route projection source. */
21
+ export const makeLearningGraphIdentity = Effect.fn("AksaraContracts.makeLearningGraphIdentity")(function* (source) {
22
+ const segments = yield* Schema.decodeEffect(LearningGraphSegmentsSchema)(source, { onExcessProperty: "error" }).pipe(Effect.mapError((cause) => new LearningGraphIdentityError({
23
+ cause,
24
+ })));
25
+ return LearningGraphIdentitySchema.make({
26
+ alignmentId: graphId("alignment", [
27
+ ...segments.lens,
28
+ ...segments.learningObject,
29
+ ]),
30
+ assetId: graphId("asset", [
31
+ segments.appLocale,
32
+ ...segments.lens,
33
+ ...segments.learningObject,
34
+ ]),
35
+ conceptId: graphId("concept", segments.concept),
36
+ learningObjectId: graphId("lo", segments.learningObject),
37
+ lensId: graphId("lens", segments.lens),
38
+ });
39
+ });
@@ -0,0 +1,20 @@
1
+ import { Schema } from "effect";
2
+ /** Canonical colon-separated identity in Nakafa's learning graph. */
3
+ export declare const LearningGraphIdSchema: Schema.String;
4
+ /** Stable graph identities persisted with every route-bearing projection. */
5
+ export declare const LearningGraphIdentitySchema: Schema.Struct<{
6
+ readonly alignmentId: Schema.String;
7
+ readonly assetId: Schema.String;
8
+ readonly conceptId: Schema.String;
9
+ readonly learningObjectId: Schema.String;
10
+ readonly lensId: Schema.String;
11
+ }>;
12
+ export type LearningGraphIdentity = typeof LearningGraphIdentitySchema.Type;
13
+ /** Serializes graph identity fields in stable signed order. */
14
+ export declare function canonicalizeLearningGraphIdentity(identity: LearningGraphIdentity): {
15
+ alignmentId: string;
16
+ assetId: string;
17
+ conceptId: string;
18
+ learningObjectId: string;
19
+ lensId: string;
20
+ };
@@ -0,0 +1,26 @@
1
+ import { Schema } from "effect";
2
+ const GRAPH_ID_PATTERN = /^(?:alignment|asset|concept|lens|lo):[a-z0-9]+(?:-[a-z0-9]+)*(?::[a-z0-9]+(?:-[a-z0-9]+)*)*$/u;
3
+ /** Canonical colon-separated identity in Nakafa's learning graph. */
4
+ export const LearningGraphIdSchema = Schema.String.pipe(Schema.check(Schema.isPattern(GRAPH_ID_PATTERN)));
5
+ /** Stable graph identities persisted with every route-bearing projection. */
6
+ export const LearningGraphIdentitySchema = Schema.Struct({
7
+ alignmentId: LearningGraphIdSchema,
8
+ assetId: LearningGraphIdSchema,
9
+ conceptId: LearningGraphIdSchema,
10
+ learningObjectId: LearningGraphIdSchema,
11
+ lensId: LearningGraphIdSchema,
12
+ }).pipe(Schema.check(Schema.makeFilter(({ alignmentId, assetId, conceptId, learningObjectId, lensId }) => alignmentId.startsWith("alignment:") &&
13
+ assetId.startsWith("asset:") &&
14
+ conceptId.startsWith("concept:") &&
15
+ learningObjectId.startsWith("lo:") &&
16
+ lensId.startsWith("lens:"), { message: "Expected each graph identity to use its owned prefix." })));
17
+ /** Serializes graph identity fields in stable signed order. */
18
+ export function canonicalizeLearningGraphIdentity(identity) {
19
+ return {
20
+ alignmentId: identity.alignmentId,
21
+ assetId: identity.assetId,
22
+ conceptId: identity.conceptId,
23
+ learningObjectId: identity.learningObjectId,
24
+ lensId: identity.lensId,
25
+ };
26
+ }
@@ -0,0 +1,10 @@
1
+ import { Effect, Schema } from "effect";
2
+ declare const TextHashError_base: Schema.Class<TextHashError, Schema.TaggedStruct<"TextHashError", {
3
+ readonly cause: Schema.Unknown;
4
+ }>, import("effect/Cause").YieldableError>;
5
+ /** Web Crypto could not hash one UTF-8 contract value. */
6
+ export declare class TextHashError extends TextHashError_base {
7
+ }
8
+ /** Hashes exact UTF-8 text through the Web Crypto contract. */
9
+ export declare const hashText: (value: string) => Effect.Effect<string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">, TextHashError, never>;
10
+ export {};
@@ -0,0 +1,20 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { Sha256HashSchema } from "#contracts/ids";
3
+ /** Web Crypto could not hash one UTF-8 contract value. */
4
+ export class TextHashError extends Schema.TaggedError()("TextHashError", { cause: Schema.Unknown }) {
5
+ }
6
+ /** Encodes one SHA-256 digest without depending on a Node runtime. */
7
+ function encodeDigest(value) {
8
+ let hex = "";
9
+ for (const byte of new Uint8Array(value)) {
10
+ hex += byte.toString(16).padStart(2, "0");
11
+ }
12
+ return Sha256HashSchema.make(`sha256:${hex}`);
13
+ }
14
+ /** Hashes exact UTF-8 text through the Web Crypto contract. */
15
+ export const hashText = Effect.fn("AksaraContracts.hashText")((value) => Effect.tryPromise({
16
+ catch: (cause) => new TextHashError({ cause }),
17
+ try: () => crypto.subtle
18
+ .digest("SHA-256", new TextEncoder().encode(value))
19
+ .then(encodeDigest),
20
+ }));
package/dist/ids.d.ts ADDED
@@ -0,0 +1,27 @@
1
+ import { Schema } from "effect";
2
+ /** Maximum wire length shared by every published content identity. */
3
+ export declare const CONTENT_KEY_MAX_LENGTH = 512;
4
+ /** Stable content identity shared across locales and immutable releases. */
5
+ export declare const ContentKeySchema: Schema.brand<Schema.String, "@NakafaAI/AksaraContentKey">;
6
+ export type ContentKey = typeof ContentKeySchema.Type;
7
+ /** Immutable publication generation identity. */
8
+ export declare const ReleaseIdSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraReleaseId">;
9
+ export type ReleaseId = typeof ReleaseIdSchema.Type;
10
+ /** Canonical stored public route without a locale or leading slash. */
11
+ export declare const PublicPathSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraPublicPath">;
12
+ export type PublicPath = typeof PublicPathSchema.Type;
13
+ /** Reviewed Git path used to reproduce one exact authored source revision. */
14
+ export declare const CorpusSourcePathSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraCorpusSourcePath">;
15
+ export type CorpusSourcePath = typeof CorpusSourcePathSchema.Type;
16
+ /** Full lowercase Git commit SHA recorded in a release manifest. */
17
+ export declare const GitCommitShaSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraGitCommitSha">;
18
+ export type GitCommitSha = typeof GitCommitShaSchema.Type;
19
+ /** Canonical SHA-256 value with an explicit algorithm prefix. */
20
+ export declare const Sha256HashSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
21
+ export type Sha256Hash = typeof Sha256HashSchema.Type;
22
+ /** Stable identifier selecting one trusted Ed25519 verification key. */
23
+ export declare const SigningKeyIdSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraSigningKeyId">;
24
+ export type SigningKeyId = typeof SigningKeyIdSchema.Type;
25
+ /** Unpadded base64url encoding of one 64-byte Ed25519 signature. */
26
+ export declare const Ed25519SignatureSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraEd25519Signature">;
27
+ export type Ed25519Signature = typeof Ed25519SignatureSchema.Type;
package/dist/ids.js ADDED
@@ -0,0 +1,63 @@
1
+ import { Schema } from "effect";
2
+ const HEX_40_PATTERN = /^[a-f\d]{40}$/;
3
+ const SHA256_PATTERN = /^sha256:[a-f\d]{64}$/;
4
+ const ED25519_SIGNATURE_PATTERN = /^[A-Za-z0-9_-]{85}[AQgw]$/;
5
+ const SIGNING_KEY_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
6
+ /** Maximum wire length shared by every published content identity. */
7
+ export const CONTENT_KEY_MAX_LENGTH = 512;
8
+ const CONTENT_KEY_PATTERN = /^[a-z0-9][a-z0-9._:/-]*$/;
9
+ const RELEASE_ID_PATTERN = /^[a-z0-9][a-z0-9._-]{0,127}$/;
10
+ const PUBLIC_PATH_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*(?:\/[a-z0-9]+(?:-[a-z0-9]+)*)*$/;
11
+ const CORPUS_SOURCE_PATH_PATTERN = /^packages\/corpus\/[a-z0-9][a-z0-9._-]*(?:\/[a-z0-9][a-z0-9._-]*)+$/;
12
+ /** Checks whether a value is a complete lowercase Git commit SHA. */
13
+ function isGitCommitSha(value) {
14
+ return HEX_40_PATTERN.test(value);
15
+ }
16
+ /** Checks whether a value uses Aksara's canonical SHA-256 wire format. */
17
+ function isSha256Hash(value) {
18
+ return SHA256_PATTERN.test(value);
19
+ }
20
+ /** Checks whether a value is a canonical unpadded Ed25519 signature. */
21
+ function isEd25519Signature(value) {
22
+ return ED25519_SIGNATURE_PATTERN.test(value);
23
+ }
24
+ /** Checks whether a value is a wire-safe signing key identifier. */
25
+ function isSigningKeyId(value) {
26
+ return SIGNING_KEY_ID_PATTERN.test(value);
27
+ }
28
+ /** Checks whether a value is a bounded canonical public route. */
29
+ function isPublicPath(value) {
30
+ return value.length <= 2048 && PUBLIC_PATH_PATTERN.test(value);
31
+ }
32
+ /** Checks whether a Git path stays inside the authored corpus workspace. */
33
+ function isCorpusSourcePath(value) {
34
+ return value.length <= 2048 && CORPUS_SOURCE_PATH_PATTERN.test(value);
35
+ }
36
+ /** Stable content identity shared across locales and immutable releases. */
37
+ export const ContentKeySchema = Schema.String.pipe(Schema.check(Schema.isPattern(CONTENT_KEY_PATTERN)), Schema.check(Schema.isMaxLength(CONTENT_KEY_MAX_LENGTH)), Schema.brand("@NakafaAI/AksaraContentKey"));
38
+ /** Immutable publication generation identity. */
39
+ export const ReleaseIdSchema = Schema.String.pipe(Schema.check(Schema.isPattern(RELEASE_ID_PATTERN)), Schema.brand("@NakafaAI/AksaraReleaseId"));
40
+ /** Canonical stored public route without a locale or leading slash. */
41
+ export const PublicPathSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isPublicPath, {
42
+ message: "Expected a canonical slashless public path.",
43
+ })), Schema.brand("@NakafaAI/AksaraPublicPath"));
44
+ /** Reviewed Git path used to reproduce one exact authored source revision. */
45
+ export const CorpusSourcePathSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isCorpusSourcePath, {
46
+ message: "Expected a safe relative source path below packages/corpus.",
47
+ })), Schema.brand("@NakafaAI/AksaraCorpusSourcePath"));
48
+ /** Full lowercase Git commit SHA recorded in a release manifest. */
49
+ export const GitCommitShaSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isGitCommitSha, {
50
+ message: "Expected a 40-character lowercase Git commit SHA.",
51
+ })), Schema.brand("@NakafaAI/AksaraGitCommitSha"));
52
+ /** Canonical SHA-256 value with an explicit algorithm prefix. */
53
+ export const Sha256HashSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isSha256Hash, {
54
+ message: "Expected sha256 followed by 64 lowercase hexadecimal characters.",
55
+ })), Schema.brand("@NakafaAI/AksaraSha256Hash"));
56
+ /** Stable identifier selecting one trusted Ed25519 verification key. */
57
+ export const SigningKeyIdSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isSigningKeyId, {
58
+ message: "Expected a lowercase wire-safe signing key identifier up to 64 characters.",
59
+ })), Schema.brand("@NakafaAI/AksaraSigningKeyId"));
60
+ /** Unpadded base64url encoding of one 64-byte Ed25519 signature. */
61
+ export const Ed25519SignatureSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isEd25519Signature, {
62
+ message: "Expected a canonical unpadded base64url 64-byte Ed25519 signature.",
63
+ })), Schema.brand("@NakafaAI/AksaraEd25519Signature"));
@@ -0,0 +1,10 @@
1
+ /** Maximum UTF-8 bytes accepted for one authored MDX source. */
2
+ export declare const MAX_RAW_MDX_BYTES: number;
3
+ /** Maximum UTF-8 bytes accepted for one emitted MDX function body. */
4
+ export declare const MAX_COMPILED_CODE_BYTES: number;
5
+ /** Maximum UTF-8 bytes accepted for one extracted plain-text projection. */
6
+ export declare const MAX_PLAIN_TEXT_BYTES: number;
7
+ /** Maximum UTF-8 bytes for all canonical compiled payload fields. */
8
+ export declare const MAX_CANONICAL_PAYLOAD_BYTES: number;
9
+ /** Maximum UTF-8 bytes for a complete signed artifact wire value. */
10
+ export declare const MAX_SIGNED_ARTIFACT_BYTES: number;
package/dist/limits.js ADDED
@@ -0,0 +1,10 @@
1
+ /** Maximum UTF-8 bytes accepted for one authored MDX source. */
2
+ export const MAX_RAW_MDX_BYTES = 128 * 1024;
3
+ /** Maximum UTF-8 bytes accepted for one emitted MDX function body. */
4
+ export const MAX_COMPILED_CODE_BYTES = 256 * 1024;
5
+ /** Maximum UTF-8 bytes accepted for one extracted plain-text projection. */
6
+ export const MAX_PLAIN_TEXT_BYTES = 128 * 1024;
7
+ /** Maximum UTF-8 bytes for all canonical compiled payload fields. */
8
+ export const MAX_CANONICAL_PAYLOAD_BYTES = 448 * 1024;
9
+ /** Maximum UTF-8 bytes for a complete signed artifact wire value. */
10
+ export const MAX_SIGNED_ARTIFACT_BYTES = 480 * 1024;
@@ -0,0 +1,37 @@
1
+ import { Schema } from "effect";
2
+ /** Stable locale codes supported by the current Aksara contract. */
3
+ export declare const AppLocaleCodeSchema: Schema.Literals<readonly ["en", "id", "de"]>;
4
+ export type AppLocaleCode = typeof AppLocaleCodeSchema.Type;
5
+ export declare const ENGLISH_APP_LOCALE_CODE: "en", INDONESIAN_APP_LOCALE_CODE: "id", GERMAN_APP_LOCALE_CODE: "de";
6
+ /** Application locale used for Nakafa-owned interface and explanation copy. */
7
+ export declare const AppLocaleSchema: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
8
+ export type AppLocale = typeof AppLocaleSchema.Type;
9
+ /** Narrows one canonical locale code while preserving application identity. */
10
+ export declare function appLocaleLiteral<const Code extends AppLocaleCode>(code: Code): Schema.brand<Schema.Literal<Code>, "@NakafaAI/AksaraAppLocale">;
11
+ /** Constructs one application locale without widening its literal identity. */
12
+ export declare function makeAppLocale<const Code extends AppLocaleCode>(code: Code): Code & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">;
13
+ /** Language delivered by content whose language may differ from the app shell. */
14
+ export declare const DeliveryLanguageSchema: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraDeliveryLanguage">;
15
+ export type DeliveryLanguage = typeof DeliveryLanguageSchema.Type;
16
+ /** Locale identity of one immutable compiled content artifact. */
17
+ export declare const ArtifactLocaleSchema: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraArtifactLocale">;
18
+ export type ArtifactLocale = typeof ArtifactLocaleSchema.Type;
19
+ /** Canonical locale order used by every active-locale subset. */
20
+ export declare const APP_LOCALE_CODES: readonly ["en", "id", "de"];
21
+ /** Source-controlled application locale codes included by this corpus. */
22
+ export declare const ActiveAppLocaleCodeSchema: Schema.Literals<readonly ["en", "id", "de"]>;
23
+ export type ActiveAppLocaleCode = typeof ActiveAppLocaleCodeSchema.Type;
24
+ /** Source-controlled codes used to index the currently complete corpus. */
25
+ export declare const ACTIVE_APP_LOCALE_CODES: readonly ["en", "id", "de"];
26
+ /** Application locale currently required from every authored scope. */
27
+ export declare const ActiveAppLocaleSchema: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
28
+ export type ActiveAppLocale = typeof ActiveAppLocaleSchema.Type;
29
+ /** Returns the plain source-map key for one validated active app locale. */
30
+ export declare function activeAppLocaleCode(appLocale: ActiveAppLocale): "de" | "en" | "id";
31
+ /** Returns the plain source-map key for one validated artifact locale. */
32
+ export declare function artifactLocaleCode(artifactLocale: ArtifactLocale): "de" | "en" | "id";
33
+ /** Nonempty unique active locale subset in canonical contract order. */
34
+ export declare const ActiveAppLocaleListSchema: Schema.NonEmptyArray<Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">>;
35
+ export type ActiveAppLocaleList = typeof ActiveAppLocaleListSchema.Type;
36
+ /** Source-controlled application locales included by the current corpus. */
37
+ export declare const ACTIVE_APP_LOCALES: readonly [("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">, ...(("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraAppLocale">)[]];
package/dist/locale.js ADDED
@@ -0,0 +1,53 @@
1
+ import { Schema } from "effect";
2
+ /** Stable locale codes supported by the current Aksara contract. */
3
+ export const AppLocaleCodeSchema = Schema.Literals(["en", "id", "de"]);
4
+ export const [ENGLISH_APP_LOCALE_CODE, INDONESIAN_APP_LOCALE_CODE, GERMAN_APP_LOCALE_CODE,] = AppLocaleCodeSchema.literals;
5
+ const APP_LOCALE_BRAND = "@NakafaAI/AksaraAppLocale";
6
+ /** Application locale used for Nakafa-owned interface and explanation copy. */
7
+ export const AppLocaleSchema = AppLocaleCodeSchema.pipe(Schema.brand(APP_LOCALE_BRAND));
8
+ /** Narrows one canonical locale code while preserving application identity. */
9
+ export function appLocaleLiteral(code) {
10
+ return Schema.Literal(code).pipe(Schema.brand(APP_LOCALE_BRAND));
11
+ }
12
+ /** Constructs one application locale without widening its literal identity. */
13
+ export function makeAppLocale(code) {
14
+ return appLocaleLiteral(code).make(code);
15
+ }
16
+ /** Language delivered by content whose language may differ from the app shell. */
17
+ export const DeliveryLanguageSchema = AppLocaleCodeSchema.pipe(Schema.brand("@NakafaAI/AksaraDeliveryLanguage"));
18
+ /** Locale identity of one immutable compiled content artifact. */
19
+ export const ArtifactLocaleSchema = AppLocaleCodeSchema.pipe(Schema.brand("@NakafaAI/AksaraArtifactLocale"));
20
+ /** Canonical locale order used by every active-locale subset. */
21
+ export const APP_LOCALE_CODES = AppLocaleCodeSchema.literals;
22
+ /** Source-controlled application locale codes included by this corpus. */
23
+ export const ActiveAppLocaleCodeSchema = AppLocaleCodeSchema;
24
+ /** Source-controlled codes used to index the currently complete corpus. */
25
+ export const ACTIVE_APP_LOCALE_CODES = ActiveAppLocaleCodeSchema.literals;
26
+ /** Application locale currently required from every authored scope. */
27
+ export const ActiveAppLocaleSchema = ActiveAppLocaleCodeSchema.pipe(Schema.brand(APP_LOCALE_BRAND));
28
+ /** Returns the plain source-map key for one validated active app locale. */
29
+ export function activeAppLocaleCode(appLocale) {
30
+ return Schema.encodeSync(ActiveAppLocaleSchema)(appLocale);
31
+ }
32
+ /** Returns the plain source-map key for one validated artifact locale. */
33
+ export function artifactLocaleCode(artifactLocale) {
34
+ return Schema.encodeSync(ArtifactLocaleSchema)(artifactLocale);
35
+ }
36
+ /** Checks a nonempty locale subset for uniqueness and canonical order. */
37
+ function hasCanonicalActiveAppLocales(locales) {
38
+ let previousIndex = -1;
39
+ for (const locale of locales) {
40
+ const index = APP_LOCALE_CODES.indexOf(locale);
41
+ if (index <= previousIndex) {
42
+ return false;
43
+ }
44
+ previousIndex = index;
45
+ }
46
+ return true;
47
+ }
48
+ /** Nonempty unique active locale subset in canonical contract order. */
49
+ export const ActiveAppLocaleListSchema = Schema.NonEmptyArray(AppLocaleSchema).pipe(Schema.check(Schema.makeFilter(hasCanonicalActiveAppLocales, {
50
+ message: "Active app locales must be unique and follow en, id, de order.",
51
+ })));
52
+ /** Source-controlled application locales included by the current corpus. */
53
+ export const ACTIVE_APP_LOCALES = Schema.decodeSync(Schema.NonEmptyArray(ActiveAppLocaleSchema))(ACTIVE_APP_LOCALE_CODES);
@@ -0,0 +1,4 @@
1
+ import { Schema } from "effect";
2
+ /** Stable language-neutral identity for one authored material domain. */
3
+ export declare const MaterialDomainSchema: Schema.brand<Schema.String, "@NakafaAI/AksaraMaterialDomain">;
4
+ export type MaterialDomain = typeof MaterialDomainSchema.Type;
@@ -0,0 +1,8 @@
1
+ import { Schema } from "effect";
2
+ import { isLowerKebab } from "#contracts/text/syntax";
3
+ /** Stable language-neutral identity for one authored material domain. */
4
+ export const MaterialDomainSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isLowerKebab, {
5
+ description: "Lowercase kebab-case material domain key.",
6
+ identifier: "MaterialDomain",
7
+ message: "Invalid material domain. Expected lowercase kebab-case.",
8
+ })), Schema.check(Schema.isMaxLength(128)), Schema.brand("@NakafaAI/AksaraMaterialDomain"));