@roster-lock/shared 0.1.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.md +11 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/match-lock-file/config-types.js +3 -0
- package/dist/match-lock-file/config-types.js.map +1 -0
- package/dist/match-lock-file/index.js +19 -0
- package/dist/match-lock-file/index.js.map +1 -0
- package/dist/match-lock-file/match-config/index.js +18 -0
- package/dist/match-lock-file/match-config/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/draft/index.js +44 -0
- package/dist/match-lock-file/match-config/version-1/draft/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/draft/roster-piece-info.js +32 -0
- package/dist/match-lock-file/match-config/version-1/draft/roster-piece-info.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/draft/selection-script-info.js +13 -0
- package/dist/match-lock-file/match-config/version-1/draft/selection-script-info.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/index.js +22 -0
- package/dist/match-lock-file/match-config/version-1/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/index.js +37 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/keywords.js +43 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/keywords.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/index.js +7 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/officialSelections.js +41 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/officialSelections.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/index.js +20 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/keywords.js +31 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/keywords.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/schema.js +40 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/schema.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/index.js +17 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/keywords.js +16 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/keywords.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/index.js +19 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/error.js +25 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/error.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/index.js +33 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath-component.js +31 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath-component.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath.js +37 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/index.js +22 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/pathvariables.js +24 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/pathvariables.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/index.js +39 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/index.js +46 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/path-variables.js +23 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/path-variables.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/requirements.js +99 -0
- package/dist/match-lock-file/match-config/version-1/lock/engine/validate/piece/requirements.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/index.js +56 -0
- package/dist/match-lock-file/match-config/version-1/lock/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/piece-meta/caster-json-schema/index.js +87 -0
- package/dist/match-lock-file/match-config/version-1/lock/piece-meta/caster-json-schema/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/piece-meta/index.js +19 -0
- package/dist/match-lock-file/match-config/version-1/lock/piece-meta/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/piece-meta/validate/index.js +94 -0
- package/dist/match-lock-file/match-config/version-1/lock/piece-meta/validate/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/downloadableSources.js +18 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/downloadableSources.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.js +28 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/id.js +31 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/id.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.js +68 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/pathVariables.js +49 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/pathVariables.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/requiresPieces.js +62 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/requiresPieces.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/version.js +21 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/version.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/index.js +19 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/downloadable-source.js +10 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/downloadable-source.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/human.js +27 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/human.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/id.js +27 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/id.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/index.js +74 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/path-variables.js +31 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/path-variables.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/required-pieces.js +25 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/required-pieces.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/utils.js +23 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/utils.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/version.js +19 -0
- package/dist/match-lock-file/match-config/version-1/lock/rosters/validate/version.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/index.js +42 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/script.js +46 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/script.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/game-controlled.js +12 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/game-controlled.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/normal.js +49 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/normal.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/preselected.js +32 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/preselected.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/unselectable.js +12 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/unselectable.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/index.js +19 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/index.js +33 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/script.js +23 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/script.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/normal.js +49 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/normal.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/preselected.js +14 -0
- package/dist/match-lock-file/match-config/version-1/lock/selection/validate/selections/preselected.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/file-paths.js +5 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/file-paths.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/index.js +23 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/keywords.js +29 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/keywords.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/schema.js +19 -0
- package/dist/match-lock-file/match-config/version-1/piece-info/schema.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/shared/Identity.js +15 -0
- package/dist/match-lock-file/match-config/version-1/shared/Identity.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/shared/SelectedPiece.js +38 -0
- package/dist/match-lock-file/match-config/version-1/shared/SelectedPiece.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/shared/count.js +48 -0
- package/dist/match-lock-file/match-config/version-1/shared/count.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/shared/index.js +25 -0
- package/dist/match-lock-file/match-config/version-1/shared/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/calculatePieceVersion.js +70 -0
- package/dist/match-lock-file/match-config/version-1/usage/calculatePieceVersion.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/empty-configs.js +49 -0
- package/dist/match-lock-file/match-config/version-1/usage/empty-configs.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/constants.js +8 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/constants.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getAssetsOfFiles.js +75 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getAssetsOfFiles.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getMatchingAsset.js +28 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/getMatchingAsset.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/index.js +20 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/types.js +3 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/types.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/validateAssetFileCount.js +33 -0
- package/dist/match-lock-file/match-config/version-1/usage/files-and-assets/validateAssetFileCount.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/index.js +22 -0
- package/dist/match-lock-file/match-config/version-1/usage/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/publish/SemVer.js +63 -0
- package/dist/match-lock-file/match-config/version-1/usage/publish/SemVer.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/publish/diffLocks.js +51 -0
- package/dist/match-lock-file/match-config/version-1/usage/publish/diffLocks.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/publish/index.js +19 -0
- package/dist/match-lock-file/match-config/version-1/usage/publish/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/constants.js +14 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/constants.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/ensure-pieces-are-in-roster.js +53 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/ensure-pieces-are-in-roster.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/handle-validation.js +49 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/handle-validation.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/index.js +68 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/game-controlled.js +38 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/game-controlled.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/cast-result.js +40 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/cast-result.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/index.js +78 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/index.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/validate-user-selection.js +43 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/validate-user-selection.js.map +1 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/preselected.js +26 -0
- package/dist/match-lock-file/match-config/version-1/usage/validate-select/selection-types/preselected.js.map +1 -0
- package/dist/match-lock-file/util-types/json-schema/JSONSchemaCaster.js +45 -0
- package/dist/match-lock-file/util-types/json-schema/JSONSchemaCaster.js.map +1 -0
- package/dist/match-lock-file/util-types/json-schema/defineKeyword.js +30 -0
- package/dist/match-lock-file/util-types/json-schema/defineKeyword.js.map +1 -0
- package/dist/match-lock-file/util-types/json-schema/index.js +21 -0
- package/dist/match-lock-file/util-types/json-schema/index.js.map +1 -0
- package/dist/match-lock-file/util-types/json-schema/safe-keyword.js +3 -0
- package/dist/match-lock-file/util-types/json-schema/safe-keyword.js.map +1 -0
- package/dist/match-lock-file/util-types/json-schema/schema-types.js +3 -0
- package/dist/match-lock-file/util-types/json-schema/schema-types.js.map +1 -0
- package/package.json +49 -0
- package/src/index.ts +3 -0
- package/src/match-lock-file/config-types.ts +10 -0
- package/src/match-lock-file/index.ts +4 -0
- package/src/match-lock-file/match-config/index.ts +2 -0
- package/src/match-lock-file/match-config/version-0/pieces/caster-runtypes/index.ts +99 -0
- package/src/match-lock-file/match-config/version-0/pieces/caster-runtypes/util-casters.ts +155 -0
- package/src/match-lock-file/match-config/version-0/pieces/index.ts +3 -0
- package/src/match-lock-file/match-config/version-0/pieces/types.ts +49 -0
- package/src/match-lock-file/match-config/version-0/pieces/validate/definition/assetCount.ts +33 -0
- package/src/match-lock-file/match-config/version-0/pieces/validate/definition/assetType.ts +22 -0
- package/src/match-lock-file/match-config/version-0/pieces/validate/definition/index.ts +30 -0
- package/src/match-lock-file/match-config/version-0/pieces/validate/definition/pathVariables.ts +39 -0
- package/src/match-lock-file/match-config/version-0/pieces/validate/index.ts +4 -0
- package/src/match-lock-file/match-config/version-0/pieces/validate/sha.ts +23 -0
- package/src/match-lock-file/match-config/version-0/pieces/validate/version.ts +66 -0
- package/src/match-lock-file/match-config/version-0/restriction/casters.ts +52 -0
- package/src/match-lock-file/match-config/version-0/restriction/index.ts +4 -0
- package/src/match-lock-file/match-config/version-0/restriction/types.ts +42 -0
- package/src/match-lock-file/match-config/version-0/restriction/validate/index.ts +15 -0
- package/src/match-lock-file/match-config/version-0/restriction/validate/piece/index.ts +46 -0
- package/src/match-lock-file/match-config/version-0/restriction/validate/sha.ts +19 -0
- package/src/match-lock-file/match-config/version-0/selection/casters.ts +105 -0
- package/src/match-lock-file/match-config/version-0/selection/validate/count.ts +16 -0
- package/src/match-lock-file/match-config/version-0/selection/validate/index.ts +40 -0
- package/src/match-lock-file/match-config/version-0/selection/validate/scriptMeta.ts +26 -0
- package/src/match-lock-file/match-config/version-1/draft/index.ts +52 -0
- package/src/match-lock-file/match-config/version-1/draft/roster-piece-info.ts +33 -0
- package/src/match-lock-file/match-config/version-1/draft/selection-script-info.ts +16 -0
- package/src/match-lock-file/match-config/version-1/index.ts +7 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/index.ts +46 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/asset/keywords.ts +48 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/index.ts +6 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/officialSelections.ts +42 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/index.ts +26 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/requirements/keywords.ts +34 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/schema.ts +47 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/index.ts +22 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/caster-json-schema/variables/keywords.ts +14 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/index.ts +3 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/constants.ts +7 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/error.ts +21 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/index.ts +18 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath-component.ts +41 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/filepath.ts +55 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/index.ts +21 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/glob/pathvariables.ts +28 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/assets/index.ts +46 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/index.ts +37 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/path-variables.ts +21 -0
- package/src/match-lock-file/match-config/version-1/lock/engine/validate/piece/requirements.ts +117 -0
- package/src/match-lock-file/match-config/version-1/lock/index.ts +51 -0
- package/src/match-lock-file/match-config/version-1/lock/piece-meta/caster-json-schema/index.ts +97 -0
- package/src/match-lock-file/match-config/version-1/lock/piece-meta/index.ts +3 -0
- package/src/match-lock-file/match-config/version-1/lock/piece-meta/validate/index.ts +114 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/downloadableSources.ts +25 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.ts +33 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/id.ts +33 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.ts +103 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/pathVariables.ts +59 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/requiresPieces.ts +71 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/version.ts +22 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/index.ts +3 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/downloadable-source.ts +9 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/human.ts +22 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/id.ts +20 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/index.ts +83 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/path-variables.ts +40 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/required-pieces.ts +30 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/utils.ts +17 -0
- package/src/match-lock-file/match-config/version-1/lock/rosters/validate/version.ts +22 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/index.ts +53 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/script.ts +54 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/game-controlled.ts +11 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/normal.ts +58 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/preselected.ts +37 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/caster-json-schema/selection-types/unselectable.ts +11 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/index.ts +3 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/validate/index.ts +37 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/validate/script.ts +28 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/validate/selections/normal.ts +69 -0
- package/src/match-lock-file/match-config/version-1/lock/selection/validate/selections/preselected.ts +18 -0
- package/src/match-lock-file/match-config/version-1/piece-info/file-paths.ts +2 -0
- package/src/match-lock-file/match-config/version-1/piece-info/index.ts +14 -0
- package/src/match-lock-file/match-config/version-1/piece-info/keywords.ts +39 -0
- package/src/match-lock-file/match-config/version-1/piece-info/schema.ts +29 -0
- package/src/match-lock-file/match-config/version-1/shared/Identity.ts +14 -0
- package/src/match-lock-file/match-config/version-1/shared/SelectedPiece.ts +49 -0
- package/src/match-lock-file/match-config/version-1/shared/count.ts +47 -0
- package/src/match-lock-file/match-config/version-1/shared/index.ts +9 -0
- package/src/match-lock-file/match-config/version-1/usage/calculatePieceVersion.ts +85 -0
- package/src/match-lock-file/match-config/version-1/usage/empty-configs.ts +61 -0
- package/src/match-lock-file/match-config/version-1/usage/files-and-assets/constants.ts +6 -0
- package/src/match-lock-file/match-config/version-1/usage/files-and-assets/getAssetsOfFiles.ts +88 -0
- package/src/match-lock-file/match-config/version-1/usage/files-and-assets/getMatchingAsset.ts +42 -0
- package/src/match-lock-file/match-config/version-1/usage/files-and-assets/index.ts +4 -0
- package/src/match-lock-file/match-config/version-1/usage/files-and-assets/types.ts +5 -0
- package/src/match-lock-file/match-config/version-1/usage/files-and-assets/validateAssetFileCount.ts +34 -0
- package/src/match-lock-file/match-config/version-1/usage/index.ts +6 -0
- package/src/match-lock-file/match-config/version-1/usage/publish/SemVer.ts +67 -0
- package/src/match-lock-file/match-config/version-1/usage/publish/diffLocks.ts +66 -0
- package/src/match-lock-file/match-config/version-1/usage/publish/index.ts +2 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/constants.ts +9 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/ensure-pieces-are-in-roster.ts +61 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/handle-validation.ts +54 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/index.ts +98 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/game-controlled.ts +49 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/cast-result.ts +39 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/include-mandatory-require.ts +44 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/index.ts +101 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/normal/validate-user-selection.ts +51 -0
- package/src/match-lock-file/match-config/version-1/usage/validate-select/selection-types/preselected.ts +36 -0
- package/src/match-lock-file/util-types/json-schema/JSONSchemaCaster.ts +52 -0
- package/src/match-lock-file/util-types/json-schema/checkVersion.ts +9 -0
- package/src/match-lock-file/util-types/json-schema/defineKeyword.ts +50 -0
- package/src/match-lock-file/util-types/json-schema/index.ts +4 -0
- package/src/match-lock-file/util-types/json-schema/safe-keyword.ts +27 -0
- package/src/match-lock-file/util-types/json-schema/schema-types.ts +5 -0
- package/tests/engine/assets.spec.ts +147 -0
- package/tests/engine/official-selections.spec.ts +67 -0
- package/tests/engine/requirements.spec.ts +43 -0
- package/tests/piece-info/cast.spec.ts +20 -0
- package/tests/piece-info/rosterlock.piece-info.json +15 -0
- package/tests/piece-meta/cast.spec.ts +60 -0
- package/tests/rosters/path-variables.spec.ts +52 -0
- package/tests/selection/cast-result.spec.ts +72 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RosterLockV1Config, PlayerId, PieceType, SelectedPiece, FinalSelection, UserInput
|
|
3
|
+
} from "@roster-lock/types";
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import { handleGameControlledSelection } from "./selection-types/game-controlled";
|
|
7
|
+
import { handlePreselectedSelection } from "./selection-types/preselected";
|
|
8
|
+
import { handleNormalSelection } from "./selection-types/normal";
|
|
9
|
+
import { ScriptStarter } from "@roster-lock/types";
|
|
10
|
+
|
|
11
|
+
import { RunUntrustedError } from "./constants";
|
|
12
|
+
import { handleValidationResult } from "./handle-validation";
|
|
13
|
+
|
|
14
|
+
export async function runSelection(
|
|
15
|
+
config: RosterLockV1Config,
|
|
16
|
+
gameControlledSelections: Record<PieceType, Array<SelectedPiece> | Record<PlayerId, Array<SelectedPiece>>>,
|
|
17
|
+
userInputs: Record<PlayerId, UserInput>,
|
|
18
|
+
runScript: (input: ScriptStarter)=>Promise<any>
|
|
19
|
+
){
|
|
20
|
+
const users: Array<string> = [];
|
|
21
|
+
const seeds: Array<string> = [];
|
|
22
|
+
const allSelections: Record<PlayerId, Record<PieceType, Array<SelectedPiece>>> = {};
|
|
23
|
+
// userInputs is built by each party independently (e.g. from concurrent
|
|
24
|
+
// per-player decryption), so its key-insertion order isn't guaranteed to
|
|
25
|
+
// match across parties. Sort by playerId so the merge script's RNG seed
|
|
26
|
+
// (derived from `seeds`) is deterministic regardless of insertion order -
|
|
27
|
+
// otherwise two parties can compute different "random" tie-breaks for the
|
|
28
|
+
// same selection and disagree on the final result.
|
|
29
|
+
const sortedPlayerIds = Object.keys(userInputs).sort();
|
|
30
|
+
for(const playerId of sortedPlayerIds){
|
|
31
|
+
const { randomSeed, userSelection } = userInputs[playerId];
|
|
32
|
+
users.push(playerId);
|
|
33
|
+
seeds.push(randomSeed);
|
|
34
|
+
allSelections[playerId] = userSelection;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const finalSelection: FinalSelection = {};
|
|
38
|
+
await Promise.all(Object.entries(config.engine.pieceDefinitions).map(async ([
|
|
39
|
+
pieceType, pieceConfig
|
|
40
|
+
])=>{
|
|
41
|
+
// Skip on demand pieces
|
|
42
|
+
if(pieceConfig.selectionStrategy === "on demand") return;
|
|
43
|
+
if(pieceConfig.selectionStrategy === "mandatory"){
|
|
44
|
+
if(!config.rosters[pieceType]){
|
|
45
|
+
throw new Error(`Missing roster for mandatory piece ${pieceType}`);
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const selectionConfig = config.selection.piece[pieceType];
|
|
51
|
+
if(!selectionConfig){
|
|
52
|
+
throw new Error(`Missing selection config for ${pieceType}`);
|
|
53
|
+
}
|
|
54
|
+
if(selectionConfig.type === "game-controlled"){
|
|
55
|
+
finalSelection[pieceType] = await handleGameControlledSelection(
|
|
56
|
+
config, users, pieceType, gameControlledSelections
|
|
57
|
+
);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if(selectionConfig.type === "preselected"){
|
|
61
|
+
finalSelection[pieceType] = await handlePreselectedSelection(
|
|
62
|
+
config, users, pieceType, selectionConfig
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if(selectionConfig.type === "normal"){
|
|
67
|
+
finalSelection[pieceType] = await handleNormalSelection(
|
|
68
|
+
config, seeds, users, pieceType, selectionConfig, allSelections, runScript
|
|
69
|
+
);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Unknown Selection Type ${(selectionConfig as any).type}`);
|
|
73
|
+
}));
|
|
74
|
+
|
|
75
|
+
if(!config.selection.globalValidation) return finalSelection;
|
|
76
|
+
|
|
77
|
+
const strippedSelection: Record<PieceType, Array<SelectedPiece> | Record<PlayerId, Array<SelectedPiece>>> = {};
|
|
78
|
+
for(const [k,v] of Object.entries(finalSelection)){
|
|
79
|
+
strippedSelection[k] = v.value;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
await Promise.all(config.selection.globalValidation.map(async (script)=>{
|
|
83
|
+
return handleValidationResult(script, runScript({
|
|
84
|
+
config,
|
|
85
|
+
randomSeeds: seeds,
|
|
86
|
+
purpose: {
|
|
87
|
+
type: "global-validation",
|
|
88
|
+
users,
|
|
89
|
+
pieceTypes: Object.keys(config.engine.pieceDefinitions),
|
|
90
|
+
input: strippedSelection,
|
|
91
|
+
},
|
|
92
|
+
entryScript: script,
|
|
93
|
+
}));
|
|
94
|
+
}));
|
|
95
|
+
|
|
96
|
+
return finalSelection;
|
|
97
|
+
}
|
|
98
|
+
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RosterLockV1Config, FinalSelection, PieceType, SelectedPiece, PlayerId
|
|
3
|
+
} from "@roster-lock/types";
|
|
4
|
+
import { ensurePiecesAreInRoster } from "../ensure-pieces-are-in-roster";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
export async function handleGameControlledSelection(
|
|
8
|
+
config: RosterLockV1Config,
|
|
9
|
+
users: Array<PlayerId>,
|
|
10
|
+
pieceType: PieceType,
|
|
11
|
+
gameControlledSelections: Record<PieceType, Array<SelectedPiece> | Record<PlayerId, Array<SelectedPiece>>>,
|
|
12
|
+
): Promise<FinalSelection[PieceType]>{
|
|
13
|
+
const pieceDefinition = config.engine.pieceDefinitions[pieceType];
|
|
14
|
+
if(!pieceDefinition){
|
|
15
|
+
throw new Error(`Missing piece config for ${pieceType}`);
|
|
16
|
+
}
|
|
17
|
+
if(pieceDefinition.selectionStrategy === "mandatory"){
|
|
18
|
+
throw new Error(`Mandatory piece ${pieceType} cannot be game controlled`);
|
|
19
|
+
}
|
|
20
|
+
if(pieceDefinition.selectionStrategy === "on demand"){
|
|
21
|
+
throw new Error(`On demand piece ${pieceType} cannot be game controlled`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const pieceSelections = gameControlledSelections[pieceType];
|
|
25
|
+
if(!pieceSelections){
|
|
26
|
+
throw new Error(`Missing selections for ${pieceType}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if(pieceDefinition.selectionStrategy === "shared"){
|
|
30
|
+
if(!Array.isArray(pieceSelections)){
|
|
31
|
+
throw new Error(`Expected Array for Shared Selection`);
|
|
32
|
+
}
|
|
33
|
+
ensurePiecesAreInRoster(config, pieceType, pieceSelections);
|
|
34
|
+
return { type: "shared", value: pieceSelections };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
if(Array.isArray(pieceSelections) || pieceSelections === null){
|
|
39
|
+
throw new Error(`Expected Record for Personal Selection`);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for(const userId of users){
|
|
43
|
+
if(!pieceSelections[userId]){
|
|
44
|
+
throw new Error(`Missing selection for ${userId}`);
|
|
45
|
+
}
|
|
46
|
+
ensurePiecesAreInRoster(config, pieceType, pieceSelections[userId]);
|
|
47
|
+
}
|
|
48
|
+
return { type: "personal", value: pieceSelections };
|
|
49
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SelectedPiece, PlayerId } from "@roster-lock/types";
|
|
2
|
+
import Ajv from "ajv";
|
|
3
|
+
import { SelectedPieceSchema, SelectedPieceSchemaDef } from "../../../../shared/SelectedPiece";
|
|
4
|
+
|
|
5
|
+
const ajv = new Ajv({ allErrors: true, strict: true, allowUnionTypes: true });
|
|
6
|
+
|
|
7
|
+
ajv.addSchema({
|
|
8
|
+
$id: "SelectedPiece",
|
|
9
|
+
...SelectedPieceSchemaDef,
|
|
10
|
+
...SelectedPieceSchema,
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
const validateShared = ajv.compile<Array<SelectedPiece>>({
|
|
14
|
+
type: "array",
|
|
15
|
+
items: { $ref: "SelectedPiece" },
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
const validatePersonal = ajv.compile<Record<PlayerId, Array<SelectedPiece>>>({
|
|
19
|
+
type: "object",
|
|
20
|
+
required: [],
|
|
21
|
+
additionalProperties: {
|
|
22
|
+
type: "array",
|
|
23
|
+
items: { $ref: "SelectedPiece" },
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
export function castSharedResult(value: unknown): Array<SelectedPiece> {
|
|
28
|
+
if (!validateShared(value)) {
|
|
29
|
+
throw validateShared.errors;
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function castPersonalResult(value: unknown): Record<PlayerId, Array<SelectedPiece>> {
|
|
35
|
+
if (!validatePersonal(value)) {
|
|
36
|
+
throw validatePersonal.errors;
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { RosterLockV1Config, PieceType, SelectedPiece } from "@roster-lock/types";
|
|
2
|
+
|
|
3
|
+
export function includeMandatoryRequire(
|
|
4
|
+
config: RosterLockV1Config,
|
|
5
|
+
pieceType: PieceType,
|
|
6
|
+
selection: SelectedPiece
|
|
7
|
+
){
|
|
8
|
+
const pieceDef = config.engine.pieceDefinitions[pieceType];
|
|
9
|
+
const piece = config.rosters[pieceType].find(p=>p.id === selection.id);
|
|
10
|
+
if(!piece){
|
|
11
|
+
throw new Error(`Piece ${selection.id} does not exist`);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
for(const requirePieceType of pieceDef.requires){
|
|
15
|
+
const requiredPieceConfig = piece.requiredPieces[requirePieceType];
|
|
16
|
+
if(!requiredPieceConfig){
|
|
17
|
+
throw new Error(`Piece ${selection.id} is missing required piece type ${requirePieceType}`);
|
|
18
|
+
}
|
|
19
|
+
const requiredSelection = (()=>{
|
|
20
|
+
const found = selection.required[requirePieceType];
|
|
21
|
+
if(found) return found;
|
|
22
|
+
const newSelection: Array<SelectedPiece> = [];
|
|
23
|
+
selection.required[requirePieceType] = newSelection;
|
|
24
|
+
return newSelection;
|
|
25
|
+
})();
|
|
26
|
+
if(!requiredPieceConfig.selectable){
|
|
27
|
+
for(const selected of requiredSelection){
|
|
28
|
+
if(!requiredPieceConfig.expected.includes(selected.id)){
|
|
29
|
+
throw new Error(`Piece ${selection.id} requires ${selected.id} but it is not selectable`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
for(const requiredPieceId of requiredPieceConfig.expected){
|
|
34
|
+
const piece = requiredSelection.find(p=>p.id === requiredPieceId);
|
|
35
|
+
if(piece){
|
|
36
|
+
includeMandatoryRequire(config, requirePieceType, piece);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const newPiece = { id: requiredPieceId, required: {} };
|
|
40
|
+
includeMandatoryRequire(config, requirePieceType, newPiece);
|
|
41
|
+
requiredSelection.push(newPiece);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RosterLockV1Config, SelectionNormalConfig, PieceType, SelectedPiece, PlayerId, FinalSelection
|
|
3
|
+
} from "@roster-lock/types";
|
|
4
|
+
import { ensurePiecesAreInRoster } from "../../ensure-pieces-are-in-roster";
|
|
5
|
+
import { ScriptStarter } from "@roster-lock/types";
|
|
6
|
+
|
|
7
|
+
import { validateUserSelection } from "./validate-user-selection";
|
|
8
|
+
import { handleValidationResult } from "../../handle-validation";
|
|
9
|
+
|
|
10
|
+
import { castSharedResult, castPersonalResult } from "./cast-result";
|
|
11
|
+
|
|
12
|
+
export async function handleNormalSelection(
|
|
13
|
+
config: RosterLockV1Config,
|
|
14
|
+
randomSeeds: string[],
|
|
15
|
+
users: Array<PlayerId>,
|
|
16
|
+
pieceType: PieceType,
|
|
17
|
+
selectionConfig: SelectionNormalConfig,
|
|
18
|
+
allSelections: Record<PlayerId, Record<PieceType, Array<SelectedPiece>>>,
|
|
19
|
+
runScript: (input: ScriptStarter)=>Promise<any>
|
|
20
|
+
): Promise<FinalSelection[PieceType]>{
|
|
21
|
+
const pieceConfig = config.engine.pieceDefinitions[pieceType];
|
|
22
|
+
if(!pieceConfig){
|
|
23
|
+
throw new Error(`Missing piece config for ${pieceType}`);
|
|
24
|
+
}
|
|
25
|
+
if(pieceConfig.selectionStrategy === "mandatory"){
|
|
26
|
+
throw new Error(`Mandatory piece ${pieceType} cannot be normal`);
|
|
27
|
+
}
|
|
28
|
+
if(pieceConfig.selectionStrategy === "on demand"){
|
|
29
|
+
throw new Error(`On demand piece ${pieceType} cannot be normal`);
|
|
30
|
+
}
|
|
31
|
+
await Promise.all(users.map(async (userId)=>{
|
|
32
|
+
const userSelections = allSelections[userId][pieceType];
|
|
33
|
+
if(!userSelections){
|
|
34
|
+
throw new Error(`Missing selections for ${pieceType}`);
|
|
35
|
+
}
|
|
36
|
+
await validateUserSelection(
|
|
37
|
+
config, pieceType, userSelections, selectionConfig,
|
|
38
|
+
);
|
|
39
|
+
if(!selectionConfig.validation?.customValidation.length){
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
await Promise.all(selectionConfig.validation.customValidation.map(async (script)=>(
|
|
44
|
+
handleValidationResult(script, runScript({
|
|
45
|
+
config,
|
|
46
|
+
randomSeeds,
|
|
47
|
+
purpose: {
|
|
48
|
+
type: "piece-user-validation",
|
|
49
|
+
pieceType,
|
|
50
|
+
userId,
|
|
51
|
+
input: userSelections,
|
|
52
|
+
},
|
|
53
|
+
entryScript: script
|
|
54
|
+
}))
|
|
55
|
+
)));
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
if(pieceConfig.selectionStrategy === "shared" && !selectionConfig.mergeAlgorithm){
|
|
59
|
+
throw new Error(`Shared piece ${pieceType} is missing merge algorithm`);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const usersSelections: Record<PlayerId, Array<SelectedPiece>> = {};
|
|
63
|
+
for(const userId of users){
|
|
64
|
+
usersSelections[userId] = allSelections[userId][pieceType];
|
|
65
|
+
}
|
|
66
|
+
// If there is no merge algorithm, we just use the users selections which have been validated
|
|
67
|
+
if(!selectionConfig.mergeAlgorithm){
|
|
68
|
+
return { type: "personal", value: usersSelections };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const rawResult = await runScript({
|
|
72
|
+
config,
|
|
73
|
+
randomSeeds,
|
|
74
|
+
purpose: {
|
|
75
|
+
type: "piece-merge",
|
|
76
|
+
pieceType,
|
|
77
|
+
users,
|
|
78
|
+
input: usersSelections,
|
|
79
|
+
},
|
|
80
|
+
entryScript: selectionConfig.mergeAlgorithm
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
if(pieceConfig.selectionStrategy === "shared"){
|
|
84
|
+
const mergedSelection = castSharedResult(rawResult);
|
|
85
|
+
ensurePiecesAreInRoster(config, pieceType, mergedSelection);
|
|
86
|
+
return { type: "shared", value: mergedSelection };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if(pieceConfig.selectionStrategy === "personal"){
|
|
90
|
+
const mergedSelection = castPersonalResult(rawResult);
|
|
91
|
+
for(const userId of users){
|
|
92
|
+
if(!mergedSelection[userId]){
|
|
93
|
+
throw new Error(`Missing selection for ${userId}`);
|
|
94
|
+
}
|
|
95
|
+
ensurePiecesAreInRoster(config, pieceType, mergedSelection[userId]);
|
|
96
|
+
}
|
|
97
|
+
return { type: "personal", value: mergedSelection };
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
throw new Error("Invalid Selection Strategy: " + pieceConfig.selectionStrategy);
|
|
101
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { RosterLockV1Config, SelectionNormalConfig, PieceType, PieceId, SelectedPiece } from "@roster-lock/types";
|
|
2
|
+
import { ensurePiecesAreInRoster } from "../../ensure-pieces-are-in-roster";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export async function validateUserSelection(
|
|
6
|
+
config: RosterLockV1Config,
|
|
7
|
+
pieceType: PieceType,
|
|
8
|
+
userSelections: Array<SelectedPiece>,
|
|
9
|
+
selectionConfig: SelectionNormalConfig,
|
|
10
|
+
){
|
|
11
|
+
|
|
12
|
+
ensurePiecesAreInRoster(config, pieceType, userSelections);
|
|
13
|
+
|
|
14
|
+
if(!selectionConfig.validation) return;
|
|
15
|
+
|
|
16
|
+
validateCount(selectionConfig.validation.count, userSelections);
|
|
17
|
+
const banList = selectionConfig.validation.banList || [];
|
|
18
|
+
const viewed = new Set<PieceId>();
|
|
19
|
+
for(const piece of userSelections){
|
|
20
|
+
if(banList.includes(piece.id)){
|
|
21
|
+
throw new Error(`Banned piece ${piece.id} selected for ${pieceType}`);
|
|
22
|
+
}
|
|
23
|
+
if(selectionConfig.validation.unique){
|
|
24
|
+
if(viewed.has(piece.id)){
|
|
25
|
+
throw new Error(`Duplicate piece ${piece.id} selected for ${pieceType}`);
|
|
26
|
+
}
|
|
27
|
+
viewed.add(piece.id);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateCount(
|
|
33
|
+
countConfig: NonNullable<SelectionNormalConfig["validation"]>["count"],
|
|
34
|
+
userSelections: Array<SelectedPiece>
|
|
35
|
+
){
|
|
36
|
+
if(!Array.isArray(countConfig)){
|
|
37
|
+
if(countConfig === "*") return;
|
|
38
|
+
if(userSelections.length !== countConfig){
|
|
39
|
+
throw new Error(`Expected ${countConfig} pieces, got ${userSelections.length}`);
|
|
40
|
+
}
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const [min, max] = countConfig;
|
|
44
|
+
if(userSelections.length < min){
|
|
45
|
+
throw new Error(`Expected at least ${min} pieces, got ${userSelections.length}`);
|
|
46
|
+
}
|
|
47
|
+
if(max === "*") return;
|
|
48
|
+
if(userSelections.length > max){
|
|
49
|
+
throw new Error(`Expected at most ${max} pieces, got ${userSelections.length}`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import {
|
|
2
|
+
RosterLockV1Config, SelectionPreselectedConfig,
|
|
3
|
+
FinalSelection, PieceType, SelectedPiece, PlayerId
|
|
4
|
+
} from "@roster-lock/types";
|
|
5
|
+
import { ensurePiecesAreInRoster } from "../ensure-pieces-are-in-roster";
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export async function handlePreselectedSelection(
|
|
9
|
+
config: RosterLockV1Config,
|
|
10
|
+
users: Array<PlayerId>,
|
|
11
|
+
pieceType: PieceType,
|
|
12
|
+
selectionConfig: SelectionPreselectedConfig,
|
|
13
|
+
): Promise<FinalSelection[PieceType]>{
|
|
14
|
+
const pieceDefinition = config.engine.pieceDefinitions[pieceType];
|
|
15
|
+
if(!pieceDefinition){
|
|
16
|
+
throw new Error(`Missing piece config for ${pieceType}`);
|
|
17
|
+
}
|
|
18
|
+
if(pieceDefinition.selectionStrategy === "mandatory"){
|
|
19
|
+
throw new Error(`Mandatory piece ${pieceType} cannot be game controlled`);
|
|
20
|
+
}
|
|
21
|
+
if(pieceDefinition.selectionStrategy === "on demand"){
|
|
22
|
+
throw new Error(`On demand piece ${pieceType} cannot be game controlled`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
ensurePiecesAreInRoster(config, pieceType, selectionConfig.pieces);
|
|
26
|
+
|
|
27
|
+
if(pieceDefinition.selectionStrategy === "shared"){
|
|
28
|
+
return { type: "shared", value: selectionConfig.pieces };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const userSelections: Record<PlayerId, Array<SelectedPiece>> = {};
|
|
32
|
+
for(const userId of users){
|
|
33
|
+
userSelections[userId] = selectionConfig.pieces;
|
|
34
|
+
}
|
|
35
|
+
return { type: "personal", value: userSelections };
|
|
36
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
import { Ajv, ErrorObject, JSONSchemaType } from "ajv";
|
|
4
|
+
import { AJVKeywordDefinition } from "./defineKeyword";
|
|
5
|
+
|
|
6
|
+
function returnTrue(){ return true; }
|
|
7
|
+
function createAJVInstance<T>(
|
|
8
|
+
engineSchema: JSONSchemaType<T>,
|
|
9
|
+
engineKeywords: Array<AJVKeywordDefinition>,
|
|
10
|
+
validate: boolean = true
|
|
11
|
+
){
|
|
12
|
+
const ajv = new Ajv({ allErrors: true, strict: true, allowUnionTypes: true });
|
|
13
|
+
for(const keyword of engineKeywords){
|
|
14
|
+
ajv.addKeyword({
|
|
15
|
+
keyword: keyword.keyword,
|
|
16
|
+
errors: true,
|
|
17
|
+
schema: true,
|
|
18
|
+
type: keyword.type,
|
|
19
|
+
validate: !validate ? returnTrue : keyword.validate,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
return ajv.compile(engineSchema);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type SafeValue<T> = (
|
|
26
|
+
| { valid: true, value: T }
|
|
27
|
+
| { valid: false, error: Array<ErrorObject> }
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export class JSONSchemaCaster<T> {
|
|
31
|
+
constructor(
|
|
32
|
+
private schema: JSONSchemaType<T>,
|
|
33
|
+
private keywords: Array<AJVKeywordDefinition>,
|
|
34
|
+
){}
|
|
35
|
+
|
|
36
|
+
safeCast(input: unknown, validate: boolean = true): SafeValue<T> {
|
|
37
|
+
try {
|
|
38
|
+
return { valid: true, value: this.cast(input, validate) };
|
|
39
|
+
}catch(e){
|
|
40
|
+
return { valid: false, error: e as Array<ErrorObject> };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
cast(input: unknown, validate: boolean = true) {
|
|
45
|
+
const schemaValidator = createAJVInstance(this.schema, this.keywords, validate);
|
|
46
|
+
if(!schemaValidator(input)){
|
|
47
|
+
if(!schemaValidator.errors) throw new Error("Validation failed with no information");
|
|
48
|
+
throw schemaValidator.errors;
|
|
49
|
+
}
|
|
50
|
+
return input as T;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
|
|
2
|
+
export function checkConfigVersion(value: unknown){
|
|
3
|
+
if(typeof value !== "object") return null;
|
|
4
|
+
if(value === null) return null;
|
|
5
|
+
if(Array.isArray(value)) return null;
|
|
6
|
+
if(!("rosterlockVersion" in value)) return null;
|
|
7
|
+
if(typeof value.rosterlockVersion !== "number") return null;
|
|
8
|
+
return value.rosterlockVersion;
|
|
9
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SchemaValidateFunction } from "ajv";
|
|
2
|
+
import { SafeKeyword } from "./safe-keyword";
|
|
3
|
+
import { JSONSchemaType } from "./schema-types";
|
|
4
|
+
|
|
5
|
+
export type AJVKeywordDefinition<K extends string = string> = {
|
|
6
|
+
keyword: SafeKeyword<K>,
|
|
7
|
+
type: JSONSchemaType,
|
|
8
|
+
validate: SchemaValidateFunction
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export function defineKeyword<T, K extends string>(
|
|
12
|
+
definition: {
|
|
13
|
+
keyword: SafeKeyword<K>,
|
|
14
|
+
type: JSONSchemaType,
|
|
15
|
+
validate: (v: any, engine: T, path: string)=>unknown
|
|
16
|
+
}
|
|
17
|
+
): AJVKeywordDefinition<K>{
|
|
18
|
+
return {
|
|
19
|
+
...definition, validate: wrapValidator<T>(definition.keyword, definition.validate)
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function wrapValidator<T>(
|
|
24
|
+
keyword: string,
|
|
25
|
+
validator: (v: any, engine: T, path: string)=>unknown
|
|
26
|
+
): SchemaValidateFunction {
|
|
27
|
+
const wrapped: SchemaValidateFunction = function(
|
|
28
|
+
_schema,
|
|
29
|
+
value: any,
|
|
30
|
+
_parentSchema,
|
|
31
|
+
dataCxt,
|
|
32
|
+
){
|
|
33
|
+
if(!dataCxt) return true;
|
|
34
|
+
try {
|
|
35
|
+
validator(value, dataCxt.rootData as T, dataCxt.instancePath);
|
|
36
|
+
return true;
|
|
37
|
+
}catch(e: any){
|
|
38
|
+
wrapped.errors = [{
|
|
39
|
+
instancePath: dataCxt.instancePath,
|
|
40
|
+
schemaPath: "",
|
|
41
|
+
keyword: keyword,
|
|
42
|
+
message: e.message,
|
|
43
|
+
params: {}
|
|
44
|
+
}];
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return wrapped;
|
|
49
|
+
}
|
|
50
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// List of JSON Schema reserved keywords
|
|
2
|
+
type JSONSchemaReservedKeywords =
|
|
3
|
+
| "type" | "properties" | "required" | "additionalProperties"
|
|
4
|
+
| "items" | "prefixItems" | "contains" | "minItems" | "maxItems"
|
|
5
|
+
| "uniqueItems" | "minContains" | "maxContains"
|
|
6
|
+
| "minimum" | "maximum" | "exclusiveMinimum" | "exclusiveMaximum"
|
|
7
|
+
| "multipleOf"
|
|
8
|
+
| "minLength" | "maxLength" | "pattern" | "format"
|
|
9
|
+
| "minProperties" | "maxProperties" | "patternProperties"
|
|
10
|
+
| "dependentRequired" | "dependentSchemas"
|
|
11
|
+
| "enum" | "const"
|
|
12
|
+
| "allOf" | "anyOf" | "oneOf" | "not"
|
|
13
|
+
| "if" | "then" | "else"
|
|
14
|
+
| "$ref" | "$defs" | "$id" | "$schema" | "$comment"
|
|
15
|
+
| "$anchor" | "$dynamicRef" | "$dynamicAnchor" | "$vocabulary"
|
|
16
|
+
| "title" | "description" | "default" | "deprecated"
|
|
17
|
+
| "readOnly" | "writeOnly" | "examples"
|
|
18
|
+
| "contentMediaType" | "contentEncoding" | "contentSchema";
|
|
19
|
+
|
|
20
|
+
// Combine all checks
|
|
21
|
+
export type SafeKeyword<T extends string> = (
|
|
22
|
+
T extends "" ? "❌ Keyword cannot be an empty string" :
|
|
23
|
+
T extends `${string} ${string}` ? "❌ Keyword cannot contain whitespace" :
|
|
24
|
+
T extends JSONSchemaReservedKeywords ? `❌ Cannot use reserved JSON Schema keyword "${T}". Use a custom prefix like "_${T}" instead.` :
|
|
25
|
+
T
|
|
26
|
+
);
|
|
27
|
+
|