@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.
- package/LICENSE +185 -0
- package/README.md +73 -0
- package/dist/artifact/integrity.d.ts +29 -0
- package/dist/artifact/integrity.js +54 -0
- package/dist/artifact/limits.d.ts +26 -0
- package/dist/artifact/limits.js +46 -0
- package/dist/artifact/source.d.ts +21 -0
- package/dist/artifact/source.js +24 -0
- package/dist/artifact/spec.d.ts +148 -0
- package/dist/artifact/spec.js +92 -0
- package/dist/artifact/verify.d.ts +26 -0
- package/dist/artifact/verify.js +18 -0
- package/dist/cache/content.d.ts +52 -0
- package/dist/cache/content.js +80 -0
- package/dist/content.d.ts +168 -0
- package/dist/content.js +107 -0
- package/dist/country.d.ts +4 -0
- package/dist/country.js +8 -0
- package/dist/date.d.ts +24 -0
- package/dist/date.js +44 -0
- package/dist/decode.d.ts +4 -0
- package/dist/decode.js +8 -0
- package/dist/delivery.d.ts +4 -0
- package/dist/delivery.js +7 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.js +8 -0
- package/dist/graph/family.d.ts +45 -0
- package/dist/graph/family.js +85 -0
- package/dist/graph/identity.d.ts +19 -0
- package/dist/graph/identity.js +39 -0
- package/dist/graph/spec.d.ts +20 -0
- package/dist/graph/spec.js +26 -0
- package/dist/hash/text.d.ts +10 -0
- package/dist/hash/text.js +20 -0
- package/dist/ids.d.ts +27 -0
- package/dist/ids.js +63 -0
- package/dist/limits.d.ts +10 -0
- package/dist/limits.js +10 -0
- package/dist/locale.d.ts +37 -0
- package/dist/locale.js +53 -0
- package/dist/material/domain.d.ts +4 -0
- package/dist/material/domain.js +8 -0
- package/dist/preview/artifact.d.ts +198 -0
- package/dist/preview/artifact.js +20 -0
- package/dist/preview/auth.d.ts +71 -0
- package/dist/preview/auth.js +49 -0
- package/dist/preview/document.d.ts +692 -0
- package/dist/preview/document.js +90 -0
- package/dist/preview/spec.d.ts +2517 -0
- package/dist/preview/spec.js +142 -0
- package/dist/preview/target.d.ts +172 -0
- package/dist/preview/target.js +70 -0
- package/dist/program/curriculum.d.ts +69 -0
- package/dist/program/curriculum.js +181 -0
- package/dist/program/snapshot/digest.d.ts +26 -0
- package/dist/program/snapshot/digest.js +220 -0
- package/dist/program/snapshot/hash.d.ts +31 -0
- package/dist/program/snapshot/hash.js +40 -0
- package/dist/program/snapshot/row-hash.d.ts +155 -0
- package/dist/program/snapshot/row-hash.js +34 -0
- package/dist/program/snapshot/row.d.ts +139 -0
- package/dist/program/snapshot/row.js +28 -0
- package/dist/program/snapshot/spec.d.ts +36 -0
- package/dist/program/snapshot/spec.js +39 -0
- package/dist/program/spec.d.ts +85 -0
- package/dist/program/spec.js +197 -0
- package/dist/projection/article.d.ts +145 -0
- package/dist/projection/article.js +150 -0
- package/dist/projection/digest.d.ts +261 -0
- package/dist/projection/digest.js +59 -0
- package/dist/projection/hash.d.ts +3 -0
- package/dist/projection/hash.js +10 -0
- package/dist/projection/material.d.ts +109 -0
- package/dist/projection/material.js +160 -0
- package/dist/projection/page.d.ts +112 -0
- package/dist/projection/page.js +106 -0
- package/dist/projection/question.d.ts +520 -0
- package/dist/projection/question.js +109 -0
- package/dist/projection/spec.d.ts +503 -0
- package/dist/projection/spec.js +56 -0
- package/dist/projection/verify.d.ts +281 -0
- package/dist/projection/verify.js +86 -0
- package/dist/question/identity.d.ts +175 -0
- package/dist/question/identity.js +205 -0
- package/dist/question/item.d.ts +453 -0
- package/dist/question/item.js +146 -0
- package/dist/question/response.d.ts +175 -0
- package/dist/question/response.js +150 -0
- package/dist/quran/attribution.d.ts +48 -0
- package/dist/quran/attribution.js +44 -0
- package/dist/quran/identity.d.ts +105 -0
- package/dist/quran/identity.js +100 -0
- package/dist/quran/notes.d.ts +56 -0
- package/dist/quran/notes.js +142 -0
- package/dist/quran/provenance.d.ts +257 -0
- package/dist/quran/provenance.js +144 -0
- package/dist/quran/snapshot/digest.d.ts +33 -0
- package/dist/quran/snapshot/digest.js +232 -0
- package/dist/quran/snapshot/hash.d.ts +51 -0
- package/dist/quran/snapshot/hash.js +50 -0
- package/dist/quran/snapshot/row/hash.d.ts +748 -0
- package/dist/quran/snapshot/row/hash.js +115 -0
- package/dist/quran/snapshot/row.d.ts +354 -0
- package/dist/quran/snapshot/row.js +91 -0
- package/dist/quran/snapshot/spec.d.ts +50 -0
- package/dist/quran/snapshot/spec.js +66 -0
- package/dist/quran/source.d.ts +206 -0
- package/dist/quran/source.js +153 -0
- package/dist/quran/spec.d.ts +47 -0
- package/dist/quran/spec.js +41 -0
- package/dist/quran/text.d.ts +7 -0
- package/dist/quran/text.js +11 -0
- package/dist/release/canonical.d.ts +23 -0
- package/dist/release/canonical.js +29 -0
- package/dist/release/current/evidence.d.ts +424 -0
- package/dist/release/current/evidence.js +41 -0
- package/dist/release/current/runtime.d.ts +4 -0
- package/dist/release/current/runtime.js +15 -0
- package/dist/release/current/state.d.ts +567 -0
- package/dist/release/current/state.js +91 -0
- package/dist/release/digest.d.ts +54 -0
- package/dist/release/digest.js +71 -0
- package/dist/release/hash.d.ts +72 -0
- package/dist/release/hash.js +14 -0
- package/dist/release/head.d.ts +206 -0
- package/dist/release/head.js +131 -0
- package/dist/release/items.d.ts +98 -0
- package/dist/release/items.js +114 -0
- package/dist/release/lifecycle.d.ts +297 -0
- package/dist/release/lifecycle.js +97 -0
- package/dist/release/origin.d.ts +30 -0
- package/dist/release/origin.js +24 -0
- package/dist/release/policy.d.ts +45 -0
- package/dist/release/policy.js +124 -0
- package/dist/release/result/digest.d.ts +127 -0
- package/dist/release/result/digest.js +140 -0
- package/dist/release/result/spec.d.ts +4 -0
- package/dist/release/result/spec.js +5 -0
- package/dist/release/rollback/digest.d.ts +126 -0
- package/dist/release/rollback/digest.js +92 -0
- package/dist/release/rollback/spec.d.ts +1729 -0
- package/dist/release/rollback/spec.js +156 -0
- package/dist/release/route/digest.d.ts +45 -0
- package/dist/release/route/digest.js +59 -0
- package/dist/release/route/page.d.ts +56 -0
- package/dist/release/route/page.js +46 -0
- package/dist/release/route/spec.d.ts +49 -0
- package/dist/release/route/spec.js +40 -0
- package/dist/release/route/verify.d.ts +66 -0
- package/dist/release/route/verify.js +67 -0
- package/dist/release/signing.d.ts +6 -0
- package/dist/release/signing.js +38 -0
- package/dist/release/snapshot/data.d.ts +475 -0
- package/dist/release/snapshot/data.js +74 -0
- package/dist/release/snapshot/evidence-requirement.d.ts +22 -0
- package/dist/release/snapshot/evidence-requirement.js +21 -0
- package/dist/release/snapshot/evidence.d.ts +58 -0
- package/dist/release/snapshot/evidence.js +14 -0
- package/dist/release/snapshot/program-evidence.d.ts +17 -0
- package/dist/release/snapshot/program-evidence.js +39 -0
- package/dist/release/snapshot/quran-evidence.d.ts +27 -0
- package/dist/release/snapshot/quran-evidence.js +43 -0
- package/dist/release/snapshot/scope.d.ts +60 -0
- package/dist/release/snapshot/scope.js +102 -0
- package/dist/release/snapshot/spec.d.ts +193 -0
- package/dist/release/snapshot/spec.js +139 -0
- package/dist/release/snapshot/tryout-evidence.d.ts +22 -0
- package/dist/release/snapshot/tryout-evidence.js +86 -0
- package/dist/release/snapshot/verify.d.ts +710 -0
- package/dist/release/snapshot/verify.js +147 -0
- package/dist/release/spec.d.ts +491 -0
- package/dist/release/spec.js +200 -0
- package/dist/release/verify.d.ts +98 -0
- package/dist/release/verify.js +70 -0
- package/dist/renderer/compatibility.d.ts +35 -0
- package/dist/renderer/compatibility.js +48 -0
- package/dist/renderer/component.d.ts +99 -0
- package/dist/renderer/component.js +102 -0
- package/dist/renderer/contract.d.ts +144 -0
- package/dist/renderer/contract.js +122 -0
- package/dist/renderer/domain.d.ts +6 -0
- package/dist/renderer/domain.js +18 -0
- package/dist/renderer/manifest.d.ts +86 -0
- package/dist/renderer/manifest.js +49 -0
- package/dist/renderer/selection.d.ts +39 -0
- package/dist/renderer/selection.js +87 -0
- package/dist/runtime/error.d.ts +8 -0
- package/dist/runtime/error.js +20 -0
- package/dist/runtime/protected/limits.d.ts +10 -0
- package/dist/runtime/protected/limits.js +15 -0
- package/dist/runtime/protected/spec.d.ts +328 -0
- package/dist/runtime/protected/spec.js +79 -0
- package/dist/runtime/protected/verify.d.ts +97 -0
- package/dist/runtime/protected/verify.js +72 -0
- package/dist/runtime/result.d.ts +12 -0
- package/dist/runtime/result.js +17 -0
- package/dist/runtime/spec.d.ts +705 -0
- package/dist/runtime/spec.js +61 -0
- package/dist/runtime/verify.d.ts +479 -0
- package/dist/runtime/verify.js +123 -0
- package/dist/signature/spec.d.ts +53 -0
- package/dist/signature/spec.js +29 -0
- package/dist/signature/trusted.d.ts +19 -0
- package/dist/signature/trusted.js +32 -0
- package/dist/signature/verify.d.ts +10 -0
- package/dist/signature/verify.js +82 -0
- package/dist/text/order.d.ts +2 -0
- package/dist/text/order.js +10 -0
- package/dist/text/syntax.d.ts +6 -0
- package/dist/text/syntax.js +15 -0
- package/dist/transport/batch.d.ts +971 -0
- package/dist/transport/batch.js +101 -0
- package/dist/transport/failure.d.ts +168 -0
- package/dist/transport/failure.js +194 -0
- package/dist/transport/group.d.ts +2946 -0
- package/dist/transport/group.js +47 -0
- package/dist/transport/limits.d.ts +30 -0
- package/dist/transport/limits.js +30 -0
- package/dist/transport/request.d.ts +9333 -0
- package/dist/transport/request.js +121 -0
- package/dist/transport/response.d.ts +6247 -0
- package/dist/transport/response.js +181 -0
- package/dist/transport/runtime.d.ts +77 -0
- package/dist/transport/runtime.js +33 -0
- package/dist/transport/snapshot.d.ts +978 -0
- package/dist/transport/snapshot.js +70 -0
- package/dist/tryout/canonical.d.ts +2 -0
- package/dist/tryout/canonical.js +11 -0
- package/dist/tryout/catalog-hash.d.ts +134 -0
- package/dist/tryout/catalog-hash.js +203 -0
- package/dist/tryout/catalog.d.ts +376 -0
- package/dist/tryout/catalog.js +147 -0
- package/dist/tryout/content-hash.d.ts +89 -0
- package/dist/tryout/content-hash.js +72 -0
- package/dist/tryout/identity.d.ts +12 -0
- package/dist/tryout/identity.js +46 -0
- package/dist/tryout/key.d.ts +4 -0
- package/dist/tryout/key.js +8 -0
- package/dist/tryout/language.d.ts +24 -0
- package/dist/tryout/language.js +32 -0
- package/dist/tryout/locale-closure.d.ts +20 -0
- package/dist/tryout/locale-closure.js +164 -0
- package/dist/tryout/placement-closure.d.ts +5 -0
- package/dist/tryout/placement-closure.js +30 -0
- package/dist/tryout/placement-hash.d.ts +11 -0
- package/dist/tryout/placement-hash.js +55 -0
- package/dist/tryout/placement.d.ts +280 -0
- package/dist/tryout/placement.js +82 -0
- package/dist/tryout/row-hash.d.ts +28 -0
- package/dist/tryout/row-hash.js +50 -0
- package/dist/tryout/runtime/canonical.d.ts +8 -0
- package/dist/tryout/runtime/canonical.js +33 -0
- package/dist/tryout/runtime/hash.d.ts +32 -0
- package/dist/tryout/runtime/hash.js +11 -0
- package/dist/tryout/runtime/source.d.ts +42 -0
- package/dist/tryout/runtime/source.js +47 -0
- package/dist/tryout/runtime/spec.d.ts +58 -0
- package/dist/tryout/runtime/spec.js +21 -0
- package/dist/tryout/runtime/verify.d.ts +61 -0
- package/dist/tryout/runtime/verify.js +69 -0
- package/dist/tryout/snapshot/canonical.d.ts +7 -0
- package/dist/tryout/snapshot/canonical.js +17 -0
- package/dist/tryout/snapshot/hash.d.ts +8 -0
- package/dist/tryout/snapshot/hash.js +19 -0
- package/dist/tryout/snapshot/spec.d.ts +46 -0
- package/dist/tryout/snapshot/spec.js +30 -0
- package/dist/tryout/spec.d.ts +13 -0
- package/dist/tryout/spec.js +15 -0
- package/package.json +506 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { Sha256HashSchema } from "#contracts/ids";
|
|
3
|
+
import { ActiveAppLocaleListSchema, AppLocaleSchema, } from "#contracts/locale";
|
|
4
|
+
import { quranSourceFileCount } from "#contracts/quran/source";
|
|
5
|
+
import { QURAN_ATTRIBUTION_COUNT, QURAN_SURAH_COUNT, QURAN_VERSE_COUNT, } from "#contracts/quran/spec";
|
|
6
|
+
/** Semantic wire identity of the current localized Quran snapshot. */
|
|
7
|
+
export const QURAN_SNAPSHOT_FORMAT = "localized-quran-snapshot";
|
|
8
|
+
const CountSchema = Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0)));
|
|
9
|
+
const SourceBytesSchema = Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0)));
|
|
10
|
+
/** Production publication status derived from reviewed provenance records. */
|
|
11
|
+
export const QuranProvenanceStatusSchema = Schema.Literals([
|
|
12
|
+
"approved",
|
|
13
|
+
"blocked",
|
|
14
|
+
]);
|
|
15
|
+
const QuranSnapshotFactFields = {
|
|
16
|
+
activeAppLocales: ActiveAppLocaleListSchema,
|
|
17
|
+
attributionCount: CountSchema,
|
|
18
|
+
chunkCount: CountSchema,
|
|
19
|
+
projectionCount: CountSchema,
|
|
20
|
+
projectionDigest: Sha256HashSchema,
|
|
21
|
+
provenanceDigest: Sha256HashSchema,
|
|
22
|
+
provenanceStatus: QuranProvenanceStatusSchema,
|
|
23
|
+
runtimeCount: CountSchema,
|
|
24
|
+
runtimeDigest: Sha256HashSchema,
|
|
25
|
+
searchCount: CountSchema,
|
|
26
|
+
searchDigest: Sha256HashSchema,
|
|
27
|
+
sourceBytes: SourceBytesSchema,
|
|
28
|
+
sourceDigest: Sha256HashSchema,
|
|
29
|
+
sourceFileCount: CountSchema,
|
|
30
|
+
surahCount: CountSchema,
|
|
31
|
+
tafsirLocales: Schema.Array(Schema.Literal("id")).pipe(Schema.check(Schema.isMaxLength(1))),
|
|
32
|
+
verseCount: CountSchema,
|
|
33
|
+
};
|
|
34
|
+
/** Checks source, translation, and Tafsir counts against active locales. */
|
|
35
|
+
function hasCompleteSnapshotCounts(input) {
|
|
36
|
+
const hasIndonesian = input.activeAppLocales.includes(AppLocaleSchema.make("id"));
|
|
37
|
+
return (input.attributionCount === QURAN_ATTRIBUTION_COUNT &&
|
|
38
|
+
input.surahCount === QURAN_SURAH_COUNT &&
|
|
39
|
+
input.verseCount === QURAN_VERSE_COUNT &&
|
|
40
|
+
input.searchCount === QURAN_SURAH_COUNT * input.activeAppLocales.length &&
|
|
41
|
+
input.sourceFileCount === quranSourceFileCount(input.activeAppLocales) &&
|
|
42
|
+
JSON.stringify(input.tafsirLocales) ===
|
|
43
|
+
JSON.stringify(hasIndonesian ? ["id"] : []));
|
|
44
|
+
}
|
|
45
|
+
/** Checks runtime and search arithmetic for complete projection inventory. */
|
|
46
|
+
function hasCoherentProjectionCounts(input) {
|
|
47
|
+
return (input.runtimeCount ===
|
|
48
|
+
input.attributionCount + input.surahCount + input.chunkCount &&
|
|
49
|
+
input.projectionCount === input.runtimeCount + input.searchCount);
|
|
50
|
+
}
|
|
51
|
+
/** Immutable current Quran facts before content-addressed identity. */
|
|
52
|
+
export const QuranSnapshotFactsSchema = Schema.Struct(QuranSnapshotFactFields).pipe(Schema.check(Schema.makeFilter(hasCompleteSnapshotCounts, {
|
|
53
|
+
message: "Expected complete active-locale Quran source counts.",
|
|
54
|
+
})), Schema.check(Schema.makeFilter(hasCoherentProjectionCounts, {
|
|
55
|
+
message: "Expected Quran runtime and search counts to cover every projection.",
|
|
56
|
+
})));
|
|
57
|
+
/** Immutable identity and completeness proof for one Quran snapshot. */
|
|
58
|
+
export const QuranSnapshotSchema = Schema.Struct({
|
|
59
|
+
...QuranSnapshotFactFields,
|
|
60
|
+
format: Schema.Literal(QURAN_SNAPSHOT_FORMAT),
|
|
61
|
+
snapshotId: Sha256HashSchema,
|
|
62
|
+
}).pipe(Schema.check(Schema.makeFilter(hasCompleteSnapshotCounts, {
|
|
63
|
+
message: "Expected complete active-locale Quran source counts.",
|
|
64
|
+
})), Schema.check(Schema.makeFilter(hasCoherentProjectionCounts, {
|
|
65
|
+
message: "Expected Quran runtime and search counts to cover every projection.",
|
|
66
|
+
})));
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { type ActiveAppLocaleList } from "#contracts/locale";
|
|
3
|
+
import { type QuranSourceId } from "#contracts/quran/identity";
|
|
4
|
+
/** Derives the exact source identities required by one active locale set. */
|
|
5
|
+
export declare function quranSourceIds(activeAppLocales: ActiveAppLocaleList): readonly [QuranSourceId, QuranSourceId, ...QuranSourceId[]];
|
|
6
|
+
/** Counts exact source files required by one active locale set. */
|
|
7
|
+
export declare function quranSourceFileCount(activeAppLocales: ActiveAppLocaleList): number;
|
|
8
|
+
/** Content identity of one pinned official source or legal evidence artifact. */
|
|
9
|
+
export declare const QuranSourceArtifactSchema: Schema.Struct<{
|
|
10
|
+
readonly byteCount: Schema.Int;
|
|
11
|
+
readonly digest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
|
|
12
|
+
readonly fileCount: Schema.Int;
|
|
13
|
+
}>;
|
|
14
|
+
export type QuranSourceArtifact = typeof QuranSourceArtifactSchema.Type;
|
|
15
|
+
/** Nakafa-owned source label and notice for one application locale. */
|
|
16
|
+
export declare const QuranSourceCopySchema: Schema.Struct<{
|
|
17
|
+
readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
|
|
18
|
+
readonly notice: Schema.Trimmed;
|
|
19
|
+
readonly title: Schema.Trimmed;
|
|
20
|
+
}>;
|
|
21
|
+
export type QuranSourceCopy = typeof QuranSourceCopySchema.Type;
|
|
22
|
+
/** Attribution for source bytes embedded and authenticated by Aksara. */
|
|
23
|
+
export declare const QuranEmbeddedSourceAttributionSchema: Schema.Struct<{
|
|
24
|
+
readonly copy: Schema.NonEmptyArray<Schema.Struct<{
|
|
25
|
+
readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
|
|
26
|
+
readonly notice: Schema.Trimmed;
|
|
27
|
+
readonly title: Schema.Trimmed;
|
|
28
|
+
}>>;
|
|
29
|
+
readonly publisher: Schema.Trimmed;
|
|
30
|
+
readonly retrievedAt: Schema.String;
|
|
31
|
+
readonly sourceUrl: Schema.String;
|
|
32
|
+
readonly updateUrl: Schema.String;
|
|
33
|
+
readonly version: Schema.Trimmed;
|
|
34
|
+
readonly artifact: Schema.Struct<{
|
|
35
|
+
readonly byteCount: Schema.Int;
|
|
36
|
+
readonly digest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
|
|
37
|
+
readonly fileCount: Schema.Int;
|
|
38
|
+
}>;
|
|
39
|
+
readonly id: Schema.Literals<readonly ["tanzil-text", "tanzil-metadata", "kemenag-names", "bubenheim-names", "quranenc-english", "quranenc-indonesian", "quranenc-german", "quranenc-tafsir"]>;
|
|
40
|
+
readonly kind: Schema.Literal<"embedded">;
|
|
41
|
+
readonly terms: Schema.Struct<{
|
|
42
|
+
readonly artifact: Schema.Struct<{
|
|
43
|
+
readonly byteCount: Schema.Int;
|
|
44
|
+
readonly digest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
|
|
45
|
+
readonly fileCount: Schema.Int;
|
|
46
|
+
}>;
|
|
47
|
+
readonly url: Schema.String;
|
|
48
|
+
}>;
|
|
49
|
+
}>;
|
|
50
|
+
export type QuranEmbeddedSourceAttribution = typeof QuranEmbeddedSourceAttributionSchema.Type;
|
|
51
|
+
/** Attribution for an official edition that Aksara may only link to. */
|
|
52
|
+
export declare const QuranExternalSourceAttributionSchema: Schema.Struct<{
|
|
53
|
+
readonly copy: Schema.NonEmptyArray<Schema.Struct<{
|
|
54
|
+
readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
|
|
55
|
+
readonly notice: Schema.Trimmed;
|
|
56
|
+
readonly title: Schema.Trimmed;
|
|
57
|
+
}>>;
|
|
58
|
+
readonly publisher: Schema.Trimmed;
|
|
59
|
+
readonly retrievedAt: Schema.String;
|
|
60
|
+
readonly sourceUrl: Schema.String;
|
|
61
|
+
readonly updateUrl: Schema.String;
|
|
62
|
+
readonly version: Schema.Trimmed;
|
|
63
|
+
readonly id: Schema.Literals<readonly ["mokhtasar-english", "mokhtasar-german"]>;
|
|
64
|
+
readonly kind: Schema.Literal<"external">;
|
|
65
|
+
readonly terms: Schema.Struct<{
|
|
66
|
+
readonly access: Schema.Literal<"link-only">;
|
|
67
|
+
readonly url: Schema.String;
|
|
68
|
+
}>;
|
|
69
|
+
}>;
|
|
70
|
+
export type QuranExternalSourceAttribution = typeof QuranExternalSourceAttributionSchema.Type;
|
|
71
|
+
/** Public attribution that distinguishes embedded bytes from external links. */
|
|
72
|
+
export declare const QuranSourceAttributionSchema: Schema.Union<readonly [Schema.Struct<{
|
|
73
|
+
readonly copy: Schema.NonEmptyArray<Schema.Struct<{
|
|
74
|
+
readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
|
|
75
|
+
readonly notice: Schema.Trimmed;
|
|
76
|
+
readonly title: Schema.Trimmed;
|
|
77
|
+
}>>;
|
|
78
|
+
readonly publisher: Schema.Trimmed;
|
|
79
|
+
readonly retrievedAt: Schema.String;
|
|
80
|
+
readonly sourceUrl: Schema.String;
|
|
81
|
+
readonly updateUrl: Schema.String;
|
|
82
|
+
readonly version: Schema.Trimmed;
|
|
83
|
+
readonly artifact: Schema.Struct<{
|
|
84
|
+
readonly byteCount: Schema.Int;
|
|
85
|
+
readonly digest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
|
|
86
|
+
readonly fileCount: Schema.Int;
|
|
87
|
+
}>;
|
|
88
|
+
readonly id: Schema.Literals<readonly ["tanzil-text", "tanzil-metadata", "kemenag-names", "bubenheim-names", "quranenc-english", "quranenc-indonesian", "quranenc-german", "quranenc-tafsir"]>;
|
|
89
|
+
readonly kind: Schema.Literal<"embedded">;
|
|
90
|
+
readonly terms: Schema.Struct<{
|
|
91
|
+
readonly artifact: Schema.Struct<{
|
|
92
|
+
readonly byteCount: Schema.Int;
|
|
93
|
+
readonly digest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
|
|
94
|
+
readonly fileCount: Schema.Int;
|
|
95
|
+
}>;
|
|
96
|
+
readonly url: Schema.String;
|
|
97
|
+
}>;
|
|
98
|
+
}>, Schema.Struct<{
|
|
99
|
+
readonly copy: Schema.NonEmptyArray<Schema.Struct<{
|
|
100
|
+
readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
|
|
101
|
+
readonly notice: Schema.Trimmed;
|
|
102
|
+
readonly title: Schema.Trimmed;
|
|
103
|
+
}>>;
|
|
104
|
+
readonly publisher: Schema.Trimmed;
|
|
105
|
+
readonly retrievedAt: Schema.String;
|
|
106
|
+
readonly sourceUrl: Schema.String;
|
|
107
|
+
readonly updateUrl: Schema.String;
|
|
108
|
+
readonly version: Schema.Trimmed;
|
|
109
|
+
readonly id: Schema.Literals<readonly ["mokhtasar-english", "mokhtasar-german"]>;
|
|
110
|
+
readonly kind: Schema.Literal<"external">;
|
|
111
|
+
readonly terms: Schema.Struct<{
|
|
112
|
+
readonly access: Schema.Literal<"link-only">;
|
|
113
|
+
readonly url: Schema.String;
|
|
114
|
+
}>;
|
|
115
|
+
}>]>;
|
|
116
|
+
export type QuranSourceAttribution = typeof QuranSourceAttributionSchema.Type;
|
|
117
|
+
/** Signed locale-specific access to embedded or official external Tafsir. */
|
|
118
|
+
export declare const QuranTafsirAccessSchema: Schema.Union<readonly [Schema.Struct<{
|
|
119
|
+
readonly appLocale: Schema.brand<Schema.Literal<"en">, "@NakafaAI/AksaraAppLocale">;
|
|
120
|
+
readonly kind: Schema.Literal<"external">;
|
|
121
|
+
readonly notice: Schema.Trimmed;
|
|
122
|
+
readonly sourceId: Schema.Literal<"mokhtasar-english">;
|
|
123
|
+
}>, Schema.Struct<{
|
|
124
|
+
readonly appLocale: Schema.brand<Schema.Literal<"id">, "@NakafaAI/AksaraAppLocale">;
|
|
125
|
+
readonly kind: Schema.Literal<"embedded">;
|
|
126
|
+
readonly notice: Schema.Trimmed;
|
|
127
|
+
readonly sourceId: Schema.Literal<"quranenc-tafsir">;
|
|
128
|
+
}>, Schema.Struct<{
|
|
129
|
+
readonly appLocale: Schema.brand<Schema.Literal<"de">, "@NakafaAI/AksaraAppLocale">;
|
|
130
|
+
readonly kind: Schema.Literal<"external">;
|
|
131
|
+
readonly notice: Schema.Trimmed;
|
|
132
|
+
readonly sourceId: Schema.Literal<"mokhtasar-german">;
|
|
133
|
+
}>]>;
|
|
134
|
+
export type QuranTafsirAccess = typeof QuranTafsirAccessSchema.Type;
|
|
135
|
+
/** Checks every source copy against the exact active locale set and order. */
|
|
136
|
+
export declare function hasCompleteQuranSourceCopy(source: QuranSourceAttribution, activeAppLocales: ActiveAppLocaleList): boolean;
|
|
137
|
+
/** Checks exact Tafsir access coverage against one active locale set. */
|
|
138
|
+
export declare function hasCompleteQuranTafsirAccess(access: readonly QuranTafsirAccess[], activeAppLocales: ActiveAppLocaleList): boolean;
|
|
139
|
+
/** Visible attribution row carrying the active official source subset. */
|
|
140
|
+
export declare const QuranAttributionRowSchema: Schema.Struct<{
|
|
141
|
+
readonly activeAppLocales: Schema.NonEmptyArray<Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">>;
|
|
142
|
+
readonly kind: Schema.Literal<"quran-attribution">;
|
|
143
|
+
readonly sources: Schema.NonEmptyArray<Schema.Union<readonly [Schema.Struct<{
|
|
144
|
+
readonly copy: Schema.NonEmptyArray<Schema.Struct<{
|
|
145
|
+
readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
|
|
146
|
+
readonly notice: Schema.Trimmed;
|
|
147
|
+
readonly title: Schema.Trimmed;
|
|
148
|
+
}>>;
|
|
149
|
+
readonly publisher: Schema.Trimmed;
|
|
150
|
+
readonly retrievedAt: Schema.String;
|
|
151
|
+
readonly sourceUrl: Schema.String;
|
|
152
|
+
readonly updateUrl: Schema.String;
|
|
153
|
+
readonly version: Schema.Trimmed;
|
|
154
|
+
readonly artifact: Schema.Struct<{
|
|
155
|
+
readonly byteCount: Schema.Int;
|
|
156
|
+
readonly digest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
|
|
157
|
+
readonly fileCount: Schema.Int;
|
|
158
|
+
}>;
|
|
159
|
+
readonly id: Schema.Literals<readonly ["tanzil-text", "tanzil-metadata", "kemenag-names", "bubenheim-names", "quranenc-english", "quranenc-indonesian", "quranenc-german", "quranenc-tafsir"]>;
|
|
160
|
+
readonly kind: Schema.Literal<"embedded">;
|
|
161
|
+
readonly terms: Schema.Struct<{
|
|
162
|
+
readonly artifact: Schema.Struct<{
|
|
163
|
+
readonly byteCount: Schema.Int;
|
|
164
|
+
readonly digest: Schema.brand<Schema.String, "@NakafaAI/AksaraSha256Hash">;
|
|
165
|
+
readonly fileCount: Schema.Int;
|
|
166
|
+
}>;
|
|
167
|
+
readonly url: Schema.String;
|
|
168
|
+
}>;
|
|
169
|
+
}>, Schema.Struct<{
|
|
170
|
+
readonly copy: Schema.NonEmptyArray<Schema.Struct<{
|
|
171
|
+
readonly appLocale: Schema.brand<Schema.Literals<readonly ["en", "id", "de"]>, "@NakafaAI/AksaraAppLocale">;
|
|
172
|
+
readonly notice: Schema.Trimmed;
|
|
173
|
+
readonly title: Schema.Trimmed;
|
|
174
|
+
}>>;
|
|
175
|
+
readonly publisher: Schema.Trimmed;
|
|
176
|
+
readonly retrievedAt: Schema.String;
|
|
177
|
+
readonly sourceUrl: Schema.String;
|
|
178
|
+
readonly updateUrl: Schema.String;
|
|
179
|
+
readonly version: Schema.Trimmed;
|
|
180
|
+
readonly id: Schema.Literals<readonly ["mokhtasar-english", "mokhtasar-german"]>;
|
|
181
|
+
readonly kind: Schema.Literal<"external">;
|
|
182
|
+
readonly terms: Schema.Struct<{
|
|
183
|
+
readonly access: Schema.Literal<"link-only">;
|
|
184
|
+
readonly url: Schema.String;
|
|
185
|
+
}>;
|
|
186
|
+
}>]>>;
|
|
187
|
+
readonly tafsirAccess: Schema.NonEmptyArray<Schema.Union<readonly [Schema.Struct<{
|
|
188
|
+
readonly appLocale: Schema.brand<Schema.Literal<"en">, "@NakafaAI/AksaraAppLocale">;
|
|
189
|
+
readonly kind: Schema.Literal<"external">;
|
|
190
|
+
readonly notice: Schema.Trimmed;
|
|
191
|
+
readonly sourceId: Schema.Literal<"mokhtasar-english">;
|
|
192
|
+
}>, Schema.Struct<{
|
|
193
|
+
readonly appLocale: Schema.brand<Schema.Literal<"id">, "@NakafaAI/AksaraAppLocale">;
|
|
194
|
+
readonly kind: Schema.Literal<"embedded">;
|
|
195
|
+
readonly notice: Schema.Trimmed;
|
|
196
|
+
readonly sourceId: Schema.Literal<"quranenc-tafsir">;
|
|
197
|
+
}>, Schema.Struct<{
|
|
198
|
+
readonly appLocale: Schema.brand<Schema.Literal<"de">, "@NakafaAI/AksaraAppLocale">;
|
|
199
|
+
readonly kind: Schema.Literal<"external">;
|
|
200
|
+
readonly notice: Schema.Trimmed;
|
|
201
|
+
readonly sourceId: Schema.Literal<"mokhtasar-german">;
|
|
202
|
+
}>]>>;
|
|
203
|
+
}>;
|
|
204
|
+
export type QuranAttributionRow = typeof QuranAttributionRowSchema.Type;
|
|
205
|
+
/** Checks exact source coverage against one active application-locale set. */
|
|
206
|
+
export declare function hasRequiredQuranSources(sources: readonly QuranSourceAttribution[], activeAppLocales: ActiveAppLocaleList): boolean;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { Sha256HashSchema } from "#contracts/ids";
|
|
3
|
+
import { ActiveAppLocaleListSchema, AppLocaleSchema, appLocaleLiteral, } from "#contracts/locale";
|
|
4
|
+
import { QURAN_SOURCE_IDS, QuranEmbeddedSourceIdSchema, QuranExternalSourceIdSchema, quranNameSourceId, quranTafsirSourceId, quranTranslationSourceId, } from "#contracts/quran/identity";
|
|
5
|
+
import { QURAN_SURAH_COUNT, QuranExternalTafsirLocaleSchema, QuranTafsirLocaleSchema, } from "#contracts/quran/spec";
|
|
6
|
+
import { isHttpsUrl } from "#contracts/text/syntax";
|
|
7
|
+
/** Derives the exact source identities required by one active locale set. */
|
|
8
|
+
export function quranSourceIds(activeAppLocales) {
|
|
9
|
+
const sourceIds = activeAppLocales.flatMap((appLocale) => [
|
|
10
|
+
quranNameSourceId(appLocale),
|
|
11
|
+
quranTranslationSourceId(appLocale),
|
|
12
|
+
quranTafsirSourceId(appLocale),
|
|
13
|
+
]);
|
|
14
|
+
return [
|
|
15
|
+
"tanzil-text",
|
|
16
|
+
"tanzil-metadata",
|
|
17
|
+
...QURAN_SOURCE_IDS.slice(2).filter((sourceId) => sourceIds.includes(sourceId)),
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
/** Counts exact source files required by one active locale set. */
|
|
21
|
+
export function quranSourceFileCount(activeAppLocales) {
|
|
22
|
+
const supplementalNameFileCount = activeAppLocales.filter((appLocale) => quranNameSourceId(appLocale) !== "tanzil-metadata").length;
|
|
23
|
+
const tafsirFileCount = activeAppLocales.includes(AppLocaleSchema.make("id"))
|
|
24
|
+
? QURAN_SURAH_COUNT
|
|
25
|
+
: 0;
|
|
26
|
+
return (2 + activeAppLocales.length + supplementalNameFileCount + tafsirFileCount);
|
|
27
|
+
}
|
|
28
|
+
const HttpsUrlSchema = Schema.String.pipe(Schema.check(Schema.makeFilter(isHttpsUrl, {
|
|
29
|
+
message: "Quran source links must use HTTPS.",
|
|
30
|
+
})));
|
|
31
|
+
const RetrievedAtSchema = Schema.String.pipe(Schema.check(Schema.isPattern(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/u, {
|
|
32
|
+
message: "Expected an exact UTC Quran source retrieval time.",
|
|
33
|
+
})));
|
|
34
|
+
/** Content identity of one pinned official source or legal evidence artifact. */
|
|
35
|
+
export const QuranSourceArtifactSchema = Schema.Struct({
|
|
36
|
+
byteCount: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
|
|
37
|
+
digest: Sha256HashSchema,
|
|
38
|
+
fileCount: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
|
|
39
|
+
});
|
|
40
|
+
/** Nakafa-owned source label and notice for one application locale. */
|
|
41
|
+
export const QuranSourceCopySchema = Schema.Struct({
|
|
42
|
+
appLocale: AppLocaleSchema,
|
|
43
|
+
notice: Schema.Trimmed.check(Schema.isNonEmpty()),
|
|
44
|
+
title: Schema.Trimmed.check(Schema.isNonEmpty()),
|
|
45
|
+
});
|
|
46
|
+
const QuranSourceAttributionFields = {
|
|
47
|
+
copy: Schema.NonEmptyArray(QuranSourceCopySchema),
|
|
48
|
+
publisher: Schema.Trimmed.check(Schema.isNonEmpty()),
|
|
49
|
+
retrievedAt: RetrievedAtSchema,
|
|
50
|
+
sourceUrl: HttpsUrlSchema,
|
|
51
|
+
updateUrl: HttpsUrlSchema,
|
|
52
|
+
version: Schema.Trimmed.check(Schema.isNonEmpty()),
|
|
53
|
+
};
|
|
54
|
+
/** Attribution for source bytes embedded and authenticated by Aksara. */
|
|
55
|
+
export const QuranEmbeddedSourceAttributionSchema = Schema.Struct({
|
|
56
|
+
...QuranSourceAttributionFields,
|
|
57
|
+
artifact: QuranSourceArtifactSchema,
|
|
58
|
+
id: QuranEmbeddedSourceIdSchema,
|
|
59
|
+
kind: Schema.Literal("embedded"),
|
|
60
|
+
terms: Schema.Struct({
|
|
61
|
+
artifact: QuranSourceArtifactSchema,
|
|
62
|
+
url: HttpsUrlSchema,
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
/** Attribution for an official edition that Aksara may only link to. */
|
|
66
|
+
export const QuranExternalSourceAttributionSchema = Schema.Struct({
|
|
67
|
+
...QuranSourceAttributionFields,
|
|
68
|
+
id: QuranExternalSourceIdSchema,
|
|
69
|
+
kind: Schema.Literal("external"),
|
|
70
|
+
terms: Schema.Struct({
|
|
71
|
+
access: Schema.Literal("link-only"),
|
|
72
|
+
url: HttpsUrlSchema,
|
|
73
|
+
}),
|
|
74
|
+
});
|
|
75
|
+
/** Public attribution that distinguishes embedded bytes from external links. */
|
|
76
|
+
export const QuranSourceAttributionSchema = Schema.Union([
|
|
77
|
+
QuranEmbeddedSourceAttributionSchema,
|
|
78
|
+
QuranExternalSourceAttributionSchema,
|
|
79
|
+
]);
|
|
80
|
+
const QuranIndonesianTafsirAccessSchema = Schema.Struct({
|
|
81
|
+
appLocale: appLocaleLiteral(QuranTafsirLocaleSchema.literal),
|
|
82
|
+
kind: Schema.Literal("embedded"),
|
|
83
|
+
notice: Schema.Trimmed.check(Schema.isNonEmpty()),
|
|
84
|
+
sourceId: Schema.Literal(quranTafsirSourceId(QuranTafsirLocaleSchema.literal)),
|
|
85
|
+
});
|
|
86
|
+
const QuranEnglishTafsirAccessSchema = Schema.Struct({
|
|
87
|
+
appLocale: appLocaleLiteral(QuranExternalTafsirLocaleSchema.literals[0]),
|
|
88
|
+
kind: Schema.Literal("external"),
|
|
89
|
+
notice: Schema.Trimmed.check(Schema.isNonEmpty()),
|
|
90
|
+
sourceId: Schema.Literal(quranTafsirSourceId(QuranExternalTafsirLocaleSchema.literals[0])),
|
|
91
|
+
});
|
|
92
|
+
const QuranGermanTafsirAccessSchema = Schema.Struct({
|
|
93
|
+
appLocale: appLocaleLiteral(QuranExternalTafsirLocaleSchema.literals[1]),
|
|
94
|
+
kind: Schema.Literal("external"),
|
|
95
|
+
notice: Schema.Trimmed.check(Schema.isNonEmpty()),
|
|
96
|
+
sourceId: Schema.Literal(quranTafsirSourceId(QuranExternalTafsirLocaleSchema.literals[1])),
|
|
97
|
+
});
|
|
98
|
+
/** Signed locale-specific access to embedded or official external Tafsir. */
|
|
99
|
+
export const QuranTafsirAccessSchema = Schema.Union([
|
|
100
|
+
QuranEnglishTafsirAccessSchema,
|
|
101
|
+
QuranIndonesianTafsirAccessSchema,
|
|
102
|
+
QuranGermanTafsirAccessSchema,
|
|
103
|
+
]);
|
|
104
|
+
/** Checks source identities for uniqueness and canonical contract order. */
|
|
105
|
+
function hasCanonicalSources(sources) {
|
|
106
|
+
return sources.every((source, index) => {
|
|
107
|
+
const previous = sources[index - 1];
|
|
108
|
+
return (previous === undefined ||
|
|
109
|
+
QURAN_SOURCE_IDS.indexOf(previous.id) <
|
|
110
|
+
QURAN_SOURCE_IDS.indexOf(source.id));
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/** Checks every source copy against the exact active locale set and order. */
|
|
114
|
+
export function hasCompleteQuranSourceCopy(source, activeAppLocales) {
|
|
115
|
+
return (source.copy.length === activeAppLocales.length &&
|
|
116
|
+
source.copy.every(({ appLocale }, index) => appLocale === activeAppLocales[index]));
|
|
117
|
+
}
|
|
118
|
+
/** Checks localized copy closure across every selected official source. */
|
|
119
|
+
function hasCompleteLocalizedCopy(input) {
|
|
120
|
+
return input.sources.every((source) => hasCompleteQuranSourceCopy(source, input.activeAppLocales));
|
|
121
|
+
}
|
|
122
|
+
/** Checks every signed Tafsir access record against one attributed source. */
|
|
123
|
+
function hasAttributedTafsirSources(input) {
|
|
124
|
+
return input.tafsirAccess.every((access) => input.sources.some((source) => source.id === access.sourceId));
|
|
125
|
+
}
|
|
126
|
+
/** Checks exact Tafsir access coverage against one active locale set. */
|
|
127
|
+
export function hasCompleteQuranTafsirAccess(access, activeAppLocales) {
|
|
128
|
+
return (access.length === activeAppLocales.length &&
|
|
129
|
+
access.every(({ appLocale }, index) => appLocale === activeAppLocales[index]));
|
|
130
|
+
}
|
|
131
|
+
/** Visible attribution row carrying the active official source subset. */
|
|
132
|
+
export const QuranAttributionRowSchema = Schema.Struct({
|
|
133
|
+
activeAppLocales: ActiveAppLocaleListSchema,
|
|
134
|
+
kind: Schema.Literal("quran-attribution"),
|
|
135
|
+
sources: Schema.NonEmptyArray(QuranSourceAttributionSchema),
|
|
136
|
+
tafsirAccess: Schema.NonEmptyArray(QuranTafsirAccessSchema),
|
|
137
|
+
}).pipe(Schema.check(Schema.makeFilter(({ sources }) => hasCanonicalSources(sources), {
|
|
138
|
+
message: "Expected unique Quran sources in canonical order.",
|
|
139
|
+
})), Schema.check(Schema.makeFilter(({ activeAppLocales, sources }) => hasRequiredQuranSources(sources, activeAppLocales), {
|
|
140
|
+
message: "Expected exact Quran source coverage for the active locale set.",
|
|
141
|
+
})), Schema.check(Schema.makeFilter(hasCompleteLocalizedCopy, {
|
|
142
|
+
message: "Expected localized Quran attribution copy for every active locale.",
|
|
143
|
+
})), Schema.check(Schema.makeFilter(({ activeAppLocales, tafsirAccess }) => hasCompleteQuranTafsirAccess(tafsirAccess, activeAppLocales), {
|
|
144
|
+
message: "Expected exact Tafsir access for every active locale.",
|
|
145
|
+
})), Schema.check(Schema.makeFilter(hasAttributedTafsirSources, {
|
|
146
|
+
message: "Expected every Tafsir access record to bind an attribution.",
|
|
147
|
+
})));
|
|
148
|
+
/** Checks exact source coverage against one active application-locale set. */
|
|
149
|
+
export function hasRequiredQuranSources(sources, activeAppLocales) {
|
|
150
|
+
const expected = quranSourceIds(activeAppLocales);
|
|
151
|
+
return (sources.length === expected.length &&
|
|
152
|
+
sources.every(({ id }, index) => id === expected[index]));
|
|
153
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** Tafsir locale whose complete reviewed source may enter runtime rows. */
|
|
3
|
+
export declare const QuranTafsirLocaleSchema: Schema.Literal<"id">;
|
|
4
|
+
/** App locales whose official Tafsir edition remains an external link. */
|
|
5
|
+
export declare const QuranExternalTafsirLocaleSchema: Schema.Literals<readonly ["en", "de"]>;
|
|
6
|
+
/** Exact number of reviewed surahs in the authored Quran source. */
|
|
7
|
+
export declare const QURAN_SURAH_COUNT = 114;
|
|
8
|
+
/** Exact number of reviewed verses in the authored Quran source. */
|
|
9
|
+
export declare const QURAN_VERSE_COUNT = 6236;
|
|
10
|
+
/** One visible source-attribution row required before Quran runtime content. */
|
|
11
|
+
export declare const QURAN_ATTRIBUTION_COUNT = 1;
|
|
12
|
+
/** Maximum verses stored in one independently verifiable runtime chunk. */
|
|
13
|
+
export declare const QURAN_CHUNK_SIZE = 6;
|
|
14
|
+
/** Valid Quran surah number in canonical order. */
|
|
15
|
+
export declare const QuranSurahNumberSchema: Schema.Int;
|
|
16
|
+
/** Complete reviewed surah-name meaning map in canonical app-locale keys. */
|
|
17
|
+
export declare const QuranSurahNameMeaningSchema: Schema.$Record<Schema.Literals<readonly ["en", "id", "de"]>, Schema.String>;
|
|
18
|
+
/** Shared authored and published metadata for one reviewed Quran surah. */
|
|
19
|
+
export declare const QuranSurahMetadataSchema: Schema.Struct<{
|
|
20
|
+
readonly name: Schema.Struct<{
|
|
21
|
+
readonly arabic: Schema.String;
|
|
22
|
+
readonly meaning: Schema.$Record<Schema.Literals<readonly ["en", "id", "de"]>, Schema.String>;
|
|
23
|
+
readonly transliteration: Schema.String;
|
|
24
|
+
}>;
|
|
25
|
+
readonly number: Schema.Int;
|
|
26
|
+
readonly numberOfVerses: Schema.Int;
|
|
27
|
+
readonly revelation: Schema.Struct<{
|
|
28
|
+
readonly order: Schema.Int;
|
|
29
|
+
readonly place: Schema.Literals<readonly ["Meccan", "Medinan"]>;
|
|
30
|
+
}>;
|
|
31
|
+
}>;
|
|
32
|
+
/** Immutable metadata row for one reviewed Quran surah. */
|
|
33
|
+
export declare const QuranSurahRowSchema: Schema.Struct<{
|
|
34
|
+
readonly name: Schema.Struct<{
|
|
35
|
+
readonly arabic: Schema.String;
|
|
36
|
+
readonly meaning: Schema.$Record<Schema.Literals<readonly ["en", "id", "de"]>, Schema.String>;
|
|
37
|
+
readonly transliteration: Schema.String;
|
|
38
|
+
}>;
|
|
39
|
+
readonly number: Schema.Int;
|
|
40
|
+
readonly numberOfVerses: Schema.Int;
|
|
41
|
+
readonly revelation: Schema.Struct<{
|
|
42
|
+
readonly order: Schema.Int;
|
|
43
|
+
readonly place: Schema.Literals<readonly ["Meccan", "Medinan"]>;
|
|
44
|
+
}>;
|
|
45
|
+
readonly kind: Schema.Literal<"quran-surah">;
|
|
46
|
+
}>;
|
|
47
|
+
export type QuranSurahRow = typeof QuranSurahRowSchema.Type;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
import { AppLocaleCodeSchema, ENGLISH_APP_LOCALE_CODE, GERMAN_APP_LOCALE_CODE, INDONESIAN_APP_LOCALE_CODE, } from "#contracts/locale";
|
|
3
|
+
import { QuranMeaningfulTextSchema } from "#contracts/quran/text";
|
|
4
|
+
/** Tafsir locale whose complete reviewed source may enter runtime rows. */
|
|
5
|
+
export const QuranTafsirLocaleSchema = Schema.Literal(INDONESIAN_APP_LOCALE_CODE);
|
|
6
|
+
/** App locales whose official Tafsir edition remains an external link. */
|
|
7
|
+
export const QuranExternalTafsirLocaleSchema = Schema.Literals([
|
|
8
|
+
ENGLISH_APP_LOCALE_CODE,
|
|
9
|
+
GERMAN_APP_LOCALE_CODE,
|
|
10
|
+
]);
|
|
11
|
+
/** Exact number of reviewed surahs in the authored Quran source. */
|
|
12
|
+
export const QURAN_SURAH_COUNT = 114;
|
|
13
|
+
/** Exact number of reviewed verses in the authored Quran source. */
|
|
14
|
+
export const QURAN_VERSE_COUNT = 6236;
|
|
15
|
+
/** One visible source-attribution row required before Quran runtime content. */
|
|
16
|
+
export const QURAN_ATTRIBUTION_COUNT = 1;
|
|
17
|
+
/** Maximum verses stored in one independently verifiable runtime chunk. */
|
|
18
|
+
export const QURAN_CHUNK_SIZE = 6;
|
|
19
|
+
/** Valid Quran surah number in canonical order. */
|
|
20
|
+
export const QuranSurahNumberSchema = Schema.Int.pipe(Schema.check(Schema.isBetween({ maximum: QURAN_SURAH_COUNT, minimum: 1 })));
|
|
21
|
+
/** Complete reviewed surah-name meaning map in canonical app-locale keys. */
|
|
22
|
+
export const QuranSurahNameMeaningSchema = Schema.Record(AppLocaleCodeSchema, QuranMeaningfulTextSchema);
|
|
23
|
+
/** Shared authored and published metadata for one reviewed Quran surah. */
|
|
24
|
+
export const QuranSurahMetadataSchema = Schema.Struct({
|
|
25
|
+
name: Schema.Struct({
|
|
26
|
+
arabic: QuranMeaningfulTextSchema,
|
|
27
|
+
meaning: QuranSurahNameMeaningSchema,
|
|
28
|
+
transliteration: QuranMeaningfulTextSchema,
|
|
29
|
+
}),
|
|
30
|
+
number: QuranSurahNumberSchema,
|
|
31
|
+
numberOfVerses: Schema.Int.pipe(Schema.check(Schema.isGreaterThan(0))),
|
|
32
|
+
revelation: Schema.Struct({
|
|
33
|
+
order: QuranSurahNumberSchema,
|
|
34
|
+
place: Schema.Literals(["Meccan", "Medinan"]),
|
|
35
|
+
}),
|
|
36
|
+
});
|
|
37
|
+
/** Immutable metadata row for one reviewed Quran surah. */
|
|
38
|
+
export const QuranSurahRowSchema = Schema.Struct({
|
|
39
|
+
kind: Schema.Literal("quran-surah"),
|
|
40
|
+
...QuranSurahMetadataSchema.fields,
|
|
41
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** Non-empty Quran text shared by authored and published row contracts. */
|
|
3
|
+
export declare const QuranMeaningfulTextSchema: Schema.String;
|
|
4
|
+
/** Verbatim Tanzil Arabic text without compatibility fields. */
|
|
5
|
+
export declare const QuranTextSchema: Schema.Struct<{
|
|
6
|
+
readonly arabic: Schema.String;
|
|
7
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Schema } from "effect";
|
|
2
|
+
/** Non-empty Quran text shared by authored and published row contracts. */
|
|
3
|
+
export const QuranMeaningfulTextSchema = Schema.String.pipe(Schema.check(Schema.isPattern(/\S/u, {
|
|
4
|
+
description: "Authored Quran text containing at least one visible character.",
|
|
5
|
+
identifier: "QuranText",
|
|
6
|
+
message: "Quran text cannot be empty.",
|
|
7
|
+
})));
|
|
8
|
+
/** Verbatim Tanzil Arabic text without compatibility fields. */
|
|
9
|
+
export const QuranTextSchema = Schema.Struct({
|
|
10
|
+
arabic: QuranMeaningfulTextSchema,
|
|
11
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ContentChange, ContentReleaseItem } from "#contracts/release/spec";
|
|
2
|
+
/** Serializes one change with stable fields for item digest computation. */
|
|
3
|
+
export declare function canonicalizeContentChange(change: ContentChange): {
|
|
4
|
+
artifactHash: string & import("effect/Brand").Brand<"@NakafaAI/AksaraSha256Hash">;
|
|
5
|
+
artifactLocale: ("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraArtifactLocale">;
|
|
6
|
+
contentKey: string & import("effect/Brand").Brand<"@NakafaAI/AksaraContentKey">;
|
|
7
|
+
delivery: "authenticated" | "entitled" | "public";
|
|
8
|
+
family: "article" | "material" | "page" | "question";
|
|
9
|
+
operation: "upsert";
|
|
10
|
+
rendererDomain: "ai-ds" | "biology" | "chemistry" | "mathematics" | "physics" | "politics" | "site" | "snbt-general" | "snbt-math" | "snbt-plain" | "snbt-quant" | "tka-math";
|
|
11
|
+
sourcePath: string & import("effect/Brand").Brand<"@NakafaAI/AksaraCorpusSourcePath">;
|
|
12
|
+
} | {
|
|
13
|
+
artifactHash?: never;
|
|
14
|
+
delivery?: never;
|
|
15
|
+
rendererDomain?: never;
|
|
16
|
+
sourcePath?: never;
|
|
17
|
+
artifactLocale: ("de" | "en" | "id") & import("effect/Brand").Brand<"@NakafaAI/AksaraArtifactLocale">;
|
|
18
|
+
contentKey: string & import("effect/Brand").Brand<"@NakafaAI/AksaraContentKey">;
|
|
19
|
+
family: "article" | "material" | "page" | "question";
|
|
20
|
+
operation: "delete";
|
|
21
|
+
};
|
|
22
|
+
/** Serializes one release item with stable identity, order, and content. */
|
|
23
|
+
export declare function canonicalizeContentReleaseItem(item: ContentReleaseItem): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/** Serializes one change with stable fields for item digest computation. */
|
|
2
|
+
export function canonicalizeContentChange(change) {
|
|
3
|
+
if (change.operation === "upsert") {
|
|
4
|
+
return {
|
|
5
|
+
artifactHash: change.artifactHash,
|
|
6
|
+
artifactLocale: change.artifactLocale,
|
|
7
|
+
contentKey: change.contentKey,
|
|
8
|
+
delivery: change.delivery,
|
|
9
|
+
family: change.family,
|
|
10
|
+
operation: change.operation,
|
|
11
|
+
rendererDomain: change.rendererDomain,
|
|
12
|
+
sourcePath: change.sourcePath,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
artifactLocale: change.artifactLocale,
|
|
17
|
+
contentKey: change.contentKey,
|
|
18
|
+
family: change.family,
|
|
19
|
+
operation: change.operation,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
/** Serializes one release item with stable identity, order, and content. */
|
|
23
|
+
export function canonicalizeContentReleaseItem(item) {
|
|
24
|
+
return JSON.stringify({
|
|
25
|
+
change: canonicalizeContentChange(item.change),
|
|
26
|
+
index: item.index,
|
|
27
|
+
releaseId: item.releaseId,
|
|
28
|
+
});
|
|
29
|
+
}
|