@plasius/learning 0.2.19 → 0.2.20
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/README.md +24 -0
- package/dist/index.cjs +155 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -1
- package/dist/index.d.ts +106 -1
- package/dist/index.js +142 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -54,6 +54,30 @@ const result = calculateAssessment(rubric, [
|
|
|
54
54
|
console.log(result.score, result.completed);
|
|
55
55
|
```
|
|
56
56
|
|
|
57
|
+
## Validate a Guardian-approved static project
|
|
58
|
+
|
|
59
|
+
The publishing contracts cover only immutable evidence and safe render models.
|
|
60
|
+
HTTP, persistence, identity checks, scanning implementations and hosting remain
|
|
61
|
+
consumer responsibilities. A public renderer must consume the allow-listed
|
|
62
|
+
`renderModel`; it must never execute learner source.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import {
|
|
66
|
+
assertValidStaticProjectGuardianApproval,
|
|
67
|
+
assertValidStaticProjectPublication,
|
|
68
|
+
assertValidStaticProjectSnapshot,
|
|
69
|
+
} from "@plasius/learning";
|
|
70
|
+
|
|
71
|
+
assertValidStaticProjectSnapshot(snapshot);
|
|
72
|
+
assertValidStaticProjectGuardianApproval(approval);
|
|
73
|
+
assertValidStaticProjectPublication(publication);
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The version-one contract supports the three launch web projects, requires a
|
|
77
|
+
score of at least 80 plus mandatory safety evidence, records all eight scanner
|
|
78
|
+
checks, binds adult approval to the exact snapshot digest, and requires an
|
|
79
|
+
unlisted HTTPS URL with a random slug and explicit expiry.
|
|
80
|
+
|
|
57
81
|
## Validate mission authoring
|
|
58
82
|
|
|
59
83
|
Mission authoring is additive to the immutable catalog. A bundle contains
|
package/dist/index.cjs
CHANGED
|
@@ -42,15 +42,27 @@ __export(index_exports, {
|
|
|
42
42
|
SERVO_CREATURE_MISSION_ONE_AUTHORING_V1: () => SERVO_CREATURE_MISSION_ONE_AUTHORING_V1,
|
|
43
43
|
SKYWING_SPRINT_MISSION_ONE_AUTHORING_V1: () => SKYWING_SPRINT_MISSION_ONE_AUTHORING_V1,
|
|
44
44
|
STAR_DEFENDER_SQUADRON_MISSION_ONE_AUTHORING_V1: () => STAR_DEFENDER_SQUADRON_MISSION_ONE_AUTHORING_V1,
|
|
45
|
+
STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1: () => STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1,
|
|
46
|
+
STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1: () => STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1,
|
|
47
|
+
STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1: () => STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1,
|
|
48
|
+
STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1: () => STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1,
|
|
49
|
+
STATIC_PROJECT_SAFETY_CHECK_IDS_V1: () => STATIC_PROJECT_SAFETY_CHECK_IDS_V1,
|
|
50
|
+
STATIC_PROJECT_SCANNER_VERSION_V1: () => STATIC_PROJECT_SCANNER_VERSION_V1,
|
|
45
51
|
VIBE_BUG_DETECTIVE_MISSION_ONE_AUTHORING_V1: () => VIBE_BUG_DETECTIVE_MISSION_ONE_AUTHORING_V1,
|
|
46
52
|
VIBE_GAME_REMIX_LAB_MISSION_ONE_AUTHORING_V1: () => VIBE_GAME_REMIX_LAB_MISSION_ONE_AUTHORING_V1,
|
|
47
53
|
VIBE_IDEA_STUDIO_MISSION_ONE_AUTHORING_V1: () => VIBE_IDEA_STUDIO_MISSION_ONE_AUTHORING_V1,
|
|
48
54
|
assertValidLearningPath: () => assertValidLearningPath,
|
|
49
55
|
assertValidMissionAuthoringBundle: () => assertValidMissionAuthoringBundle,
|
|
56
|
+
assertValidStaticProjectGuardianApproval: () => assertValidStaticProjectGuardianApproval,
|
|
57
|
+
assertValidStaticProjectPublication: () => assertValidStaticProjectPublication,
|
|
58
|
+
assertValidStaticProjectSnapshot: () => assertValidStaticProjectSnapshot,
|
|
50
59
|
calculateAssessment: () => calculateAssessment,
|
|
51
60
|
validateAssessmentRubric: () => validateAssessmentRubric,
|
|
52
61
|
validateLearningPath: () => validateLearningPath,
|
|
53
|
-
validateMissionAuthoringBundle: () => validateMissionAuthoringBundle
|
|
62
|
+
validateMissionAuthoringBundle: () => validateMissionAuthoringBundle,
|
|
63
|
+
validateStaticProjectGuardianApproval: () => validateStaticProjectGuardianApproval,
|
|
64
|
+
validateStaticProjectPublication: () => validateStaticProjectPublication,
|
|
65
|
+
validateStaticProjectSnapshot: () => validateStaticProjectSnapshot
|
|
54
66
|
});
|
|
55
67
|
module.exports = __toCommonJS(index_exports);
|
|
56
68
|
|
|
@@ -627,6 +639,135 @@ var JUNIOR_CODER_ROBOT_RESCUE_PATH_CURRENT = JUNIOR_CODER_ROBOT_RESCUE_PATH_V1_1
|
|
|
627
639
|
// src/contracts.ts
|
|
628
640
|
var MISSION_AUTHORING_CONTRACT_VERSION_V1 = "1.0.0";
|
|
629
641
|
|
|
642
|
+
// src/publishing.ts
|
|
643
|
+
var STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1 = "1.0.0";
|
|
644
|
+
var STATIC_PROJECT_SCANNER_VERSION_V1 = "junior-coder-static-scan-v1";
|
|
645
|
+
var STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1 = "guardian-static-publication-v1";
|
|
646
|
+
var STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1 = 90;
|
|
647
|
+
var STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1 = 8e3;
|
|
648
|
+
var STATIC_PROJECT_SAFETY_CHECK_IDS_V1 = [
|
|
649
|
+
"allow-listed-source",
|
|
650
|
+
"no-personal-details",
|
|
651
|
+
"no-external-network",
|
|
652
|
+
"no-executable-markup",
|
|
653
|
+
"no-transmitting-forms",
|
|
654
|
+
"no-uploads-or-embeds",
|
|
655
|
+
"no-trackers-or-advertising",
|
|
656
|
+
"no-account-identifiers"
|
|
657
|
+
];
|
|
658
|
+
var DIGEST_PATTERN = /^sha256:[a-f0-9]{64}$/u;
|
|
659
|
+
var IDENTIFIER_PATTERN = /^(?:account|approval|publication|snapshot)_[A-Za-z0-9_-]{20,128}$/u;
|
|
660
|
+
var VERSION_PATTERN = /^[0-9]+\.[0-9]+\.[0-9]+(?:[-+][A-Za-z0-9.-]+)?$/u;
|
|
661
|
+
var RANDOM_SLUG_PATTERN = /^[A-Za-z0-9_-]{40,128}$/u;
|
|
662
|
+
function validDate(value) {
|
|
663
|
+
return typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
664
|
+
}
|
|
665
|
+
function allSafetyChecksPresent(scan) {
|
|
666
|
+
if (!Array.isArray(scan.checks) || scan.checks.length !== STATIC_PROJECT_SAFETY_CHECK_IDS_V1.length) {
|
|
667
|
+
return false;
|
|
668
|
+
}
|
|
669
|
+
const supplied = new Set(scan.checks.map((check) => check.id));
|
|
670
|
+
return STATIC_PROJECT_SAFETY_CHECK_IDS_V1.every((id) => supplied.has(id)) && scan.checks.every((check) => check.passed === true);
|
|
671
|
+
}
|
|
672
|
+
function safeAdventureRender(value) {
|
|
673
|
+
const headings = ["Moonbase Missions", "Forest Rescue Plans", "Ocean Quest Board"];
|
|
674
|
+
const titles = ["Find the moon crystal", "Guide the lost firefly", "Map the coral garden"];
|
|
675
|
+
const days = ["Saturday", "Sunday", "School holiday"];
|
|
676
|
+
const messages = ["Choose a day", "Add a mission title", "Mission ready!"];
|
|
677
|
+
return headings.includes(value.heading) && Array.isArray(value.missions) && value.missions.length >= 1 && value.missions.length <= 3 && value.missions.every((mission2) => titles.includes(mission2.title) && days.includes(mission2.day)) && messages.includes(value.validationMessage) && value.savedAcrossRestart === true && value.accessibleSummaryEnabled === true;
|
|
678
|
+
}
|
|
679
|
+
function safeCreatureRender(value) {
|
|
680
|
+
return ["Moon Moth", "Cloud Cat", "Pebble Dragon"].includes(value.creature) && ["Resting", "Ready to play", "Snack time"].includes(value.status) && [5, 10, 15].includes(value.timerSeconds) && ["single", "cosy-grid", "wide-grid"].includes(value.layout) && value.reducedMotion === true;
|
|
681
|
+
}
|
|
682
|
+
function safeRobotRender(value) {
|
|
683
|
+
return ["scan", "hold-position", "return-to-base"].includes(value.command) && value.safetyConfirmed === true && [1, 2, 4].includes(value.telemetryRate) && ["line", "bars", "text-only"].includes(value.chartMode) && value.serialSimulation === true && ["SCANNING", "HOLDING", "RETURNING"].includes(value.state);
|
|
684
|
+
}
|
|
685
|
+
function validateStaticProjectSnapshot(value) {
|
|
686
|
+
const issues = [];
|
|
687
|
+
if (value.schemaVersion !== "1") issues.push("invalid-schema-version");
|
|
688
|
+
if (value.contractVersion !== STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1) {
|
|
689
|
+
issues.push("invalid-contract-version");
|
|
690
|
+
}
|
|
691
|
+
if (!IDENTIFIER_PATTERN.test(value.snapshotId) || !IDENTIFIER_PATTERN.test(value.subjectAccountId)) {
|
|
692
|
+
issues.push("invalid-identifier");
|
|
693
|
+
}
|
|
694
|
+
if (!value.moduleId.startsWith("junior-coder.") || value.moduleId !== `junior-coder.${value.moduleSlug}`) {
|
|
695
|
+
issues.push("invalid-module");
|
|
696
|
+
}
|
|
697
|
+
if (!VERSION_PATTERN.test(value.moduleVersion)) issues.push("invalid-version");
|
|
698
|
+
if (!DIGEST_PATTERN.test(value.sourceDigest)) issues.push("invalid-source-digest");
|
|
699
|
+
if (!DIGEST_PATTERN.test(value.snapshotDigest)) issues.push("invalid-snapshot-digest");
|
|
700
|
+
if (!Number.isInteger(value.sourceCharacterCount) || value.sourceCharacterCount < 1 || value.sourceCharacterCount > STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1) {
|
|
701
|
+
issues.push("invalid-source-size");
|
|
702
|
+
}
|
|
703
|
+
if (!Number.isInteger(value.assessmentScore) || value.assessmentScore < 80 || value.assessmentScore > 100) {
|
|
704
|
+
issues.push("assessment-score-incomplete");
|
|
705
|
+
}
|
|
706
|
+
if (value.mandatorySafetyPassed !== true) issues.push("mandatory-safety-missing");
|
|
707
|
+
if (value.scan?.passed !== true || value.scan?.scannerVersion !== STATIC_PROJECT_SCANNER_VERSION_V1) {
|
|
708
|
+
issues.push("scan-not-passed");
|
|
709
|
+
}
|
|
710
|
+
if (!value.scan || !allSafetyChecksPresent(value.scan)) issues.push("scan-checks-incomplete");
|
|
711
|
+
if (value.moduleSlug !== value.renderModel?.kind) issues.push("module-render-model-mismatch");
|
|
712
|
+
const renderSafe = value.renderModel?.kind === "adventure-mission-planner" ? safeAdventureRender(value.renderModel) : value.renderModel?.kind === "creature-care-dashboard" ? safeCreatureRender(value.renderModel) : value.renderModel?.kind === "robot-mission-control" ? safeRobotRender(value.renderModel) : false;
|
|
713
|
+
if (!renderSafe) issues.push("unsafe-render-model");
|
|
714
|
+
if (value.state !== "pending-review" || !validDate(value.createdAt)) issues.push("invalid-created-at");
|
|
715
|
+
return [...new Set(issues)];
|
|
716
|
+
}
|
|
717
|
+
function assertValidStaticProjectSnapshot(value) {
|
|
718
|
+
const issues = validateStaticProjectSnapshot(value);
|
|
719
|
+
if (issues.length > 0) throw new Error(`Invalid static project snapshot: ${issues.join(", ")}`);
|
|
720
|
+
}
|
|
721
|
+
function validateStaticProjectGuardianApproval(value) {
|
|
722
|
+
const issues = [];
|
|
723
|
+
if (value.schemaVersion !== "1") issues.push("invalid-schema-version");
|
|
724
|
+
if (!IDENTIFIER_PATTERN.test(value.approvalId) || !IDENTIFIER_PATTERN.test(value.snapshotId) || !IDENTIFIER_PATTERN.test(value.guardianActorAccountId)) {
|
|
725
|
+
issues.push("invalid-identifier");
|
|
726
|
+
}
|
|
727
|
+
if (!DIGEST_PATTERN.test(value.snapshotDigest)) issues.push("invalid-snapshot-digest");
|
|
728
|
+
if (value.statementVersion !== STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1) {
|
|
729
|
+
issues.push("invalid-approval-statement");
|
|
730
|
+
}
|
|
731
|
+
if (!validDate(value.approvedAt)) issues.push("invalid-approved-at");
|
|
732
|
+
return [...new Set(issues)];
|
|
733
|
+
}
|
|
734
|
+
function assertValidStaticProjectGuardianApproval(value) {
|
|
735
|
+
const issues = validateStaticProjectGuardianApproval(value);
|
|
736
|
+
if (issues.length > 0) throw new Error(`Invalid static project approval: ${issues.join(", ")}`);
|
|
737
|
+
}
|
|
738
|
+
function validateStaticProjectPublication(value) {
|
|
739
|
+
const issues = [];
|
|
740
|
+
if (value.schemaVersion !== "1") issues.push("invalid-schema-version");
|
|
741
|
+
if (!IDENTIFIER_PATTERN.test(value.publicationId) || !IDENTIFIER_PATTERN.test(value.snapshotId) || !IDENTIFIER_PATTERN.test(value.approvalId)) {
|
|
742
|
+
issues.push("invalid-identifier");
|
|
743
|
+
}
|
|
744
|
+
if (!DIGEST_PATTERN.test(value.snapshotDigest)) issues.push("invalid-snapshot-digest");
|
|
745
|
+
if (!RANDOM_SLUG_PATTERN.test(value.randomSlug)) issues.push("invalid-random-slug");
|
|
746
|
+
let parsedUrl;
|
|
747
|
+
try {
|
|
748
|
+
parsedUrl = new URL(value.publicUrl);
|
|
749
|
+
} catch {
|
|
750
|
+
parsedUrl = void 0;
|
|
751
|
+
}
|
|
752
|
+
if (!parsedUrl || parsedUrl.protocol !== "https:" || parsedUrl.username || parsedUrl.password) {
|
|
753
|
+
issues.push("invalid-public-url");
|
|
754
|
+
}
|
|
755
|
+
if (!parsedUrl?.pathname.endsWith(`/${value.randomSlug}`)) issues.push("public-url-slug-mismatch");
|
|
756
|
+
if (value.state !== "published") issues.push("published-state-required");
|
|
757
|
+
if (!validDate(value.publishedAt)) issues.push("invalid-published-at");
|
|
758
|
+
if (!validDate(value.expiresAt) || validDate(value.publishedAt) && Date.parse(value.expiresAt) <= Date.parse(value.publishedAt)) {
|
|
759
|
+
issues.push("invalid-publication-expiry");
|
|
760
|
+
}
|
|
761
|
+
if (value.renewedAt !== void 0 && !validDate(value.renewedAt) || value.unpublishedAt !== void 0 && !validDate(value.unpublishedAt)) {
|
|
762
|
+
issues.push("invalid-lifecycle-timestamp");
|
|
763
|
+
}
|
|
764
|
+
return [...new Set(issues)];
|
|
765
|
+
}
|
|
766
|
+
function assertValidStaticProjectPublication(value) {
|
|
767
|
+
const issues = validateStaticProjectPublication(value);
|
|
768
|
+
if (issues.length > 0) throw new Error(`Invalid static project publication: ${issues.join(", ")}`);
|
|
769
|
+
}
|
|
770
|
+
|
|
630
771
|
// src/rubric-validation.ts
|
|
631
772
|
var DIMENSION_TOTALS = {
|
|
632
773
|
structure: 20,
|
|
@@ -6707,14 +6848,26 @@ ${summary}`);
|
|
|
6707
6848
|
SERVO_CREATURE_MISSION_ONE_AUTHORING_V1,
|
|
6708
6849
|
SKYWING_SPRINT_MISSION_ONE_AUTHORING_V1,
|
|
6709
6850
|
STAR_DEFENDER_SQUADRON_MISSION_ONE_AUTHORING_V1,
|
|
6851
|
+
STATIC_PROJECT_APPROVAL_STATEMENT_VERSION_V1,
|
|
6852
|
+
STATIC_PROJECT_DEFAULT_LIFETIME_DAYS_V1,
|
|
6853
|
+
STATIC_PROJECT_MAX_SOURCE_CHARACTERS_V1,
|
|
6854
|
+
STATIC_PROJECT_PUBLISHING_CONTRACT_VERSION_V1,
|
|
6855
|
+
STATIC_PROJECT_SAFETY_CHECK_IDS_V1,
|
|
6856
|
+
STATIC_PROJECT_SCANNER_VERSION_V1,
|
|
6710
6857
|
VIBE_BUG_DETECTIVE_MISSION_ONE_AUTHORING_V1,
|
|
6711
6858
|
VIBE_GAME_REMIX_LAB_MISSION_ONE_AUTHORING_V1,
|
|
6712
6859
|
VIBE_IDEA_STUDIO_MISSION_ONE_AUTHORING_V1,
|
|
6713
6860
|
assertValidLearningPath,
|
|
6714
6861
|
assertValidMissionAuthoringBundle,
|
|
6862
|
+
assertValidStaticProjectGuardianApproval,
|
|
6863
|
+
assertValidStaticProjectPublication,
|
|
6864
|
+
assertValidStaticProjectSnapshot,
|
|
6715
6865
|
calculateAssessment,
|
|
6716
6866
|
validateAssessmentRubric,
|
|
6717
6867
|
validateLearningPath,
|
|
6718
|
-
validateMissionAuthoringBundle
|
|
6868
|
+
validateMissionAuthoringBundle,
|
|
6869
|
+
validateStaticProjectGuardianApproval,
|
|
6870
|
+
validateStaticProjectPublication,
|
|
6871
|
+
validateStaticProjectSnapshot
|
|
6719
6872
|
});
|
|
6720
6873
|
//# sourceMappingURL=index.cjs.map
|