@duplojs/agents-kit 0.0.0-stage → 0.1.0-beta.3
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 +73 -2
- package/dist/bin/index.d.ts +2 -0
- package/dist/bin/index.mjs +7 -0
- package/dist/bin/install/index.d.ts +2 -0
- package/dist/bin/install/index.mjs +25 -0
- package/dist/bin/install/skill.d.ts +28 -0
- package/dist/bin/install/skill.mjs +58 -0
- package/dist/bin/packagePath.d.ts +2 -0
- package/dist/bin/packagePath.mjs +12 -0
- package/dist/bin/setup/index.d.ts +12 -0
- package/dist/bin/setup/index.mjs +33 -0
- package/dist/bin/setup/instructions.d.ts +8 -0
- package/dist/bin/setup/instructions.mjs +27 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.mjs +0 -0
- package/docs/API/10-lang/10-array/10-at.ts +65 -0
- package/docs/API/10-lang/10-array/10-chunk.ts +42 -0
- package/docs/API/10-lang/10-array/10-coalescing.ts +19 -0
- package/docs/API/10-lang/10-array/10-concat.ts +34 -0
- package/docs/API/10-lang/10-array/10-copyWithin.ts +34 -0
- package/docs/API/10-lang/10-array/10-every.ts +25 -0
- package/docs/API/10-lang/10-array/10-fill.ts +34 -0
- package/docs/API/10-lang/10-array/10-fillAll.ts +34 -0
- package/docs/API/10-lang/10-array/10-filter.ts +43 -0
- package/docs/API/10-lang/10-array/10-find.ts +33 -0
- package/docs/API/10-lang/10-array/10-findAndReplace.ts +35 -0
- package/docs/API/10-lang/10-array/10-findAndSpliceDelete.ts +35 -0
- package/docs/API/10-lang/10-array/10-findAndSpliceInsert.ts +35 -0
- package/docs/API/10-lang/10-array/10-findAndSpliceReplace.ts +24 -0
- package/docs/API/10-lang/10-array/10-findDuplicates.ts +19 -0
- package/docs/API/10-lang/10-array/10-findIndex.ts +25 -0
- package/docs/API/10-lang/10-array/10-findLast.ts +33 -0
- package/docs/API/10-lang/10-array/10-findLastIndex.ts +25 -0
- package/docs/API/10-lang/10-array/10-first.ts +21 -0
- package/docs/API/10-lang/10-array/10-flat.ts +22 -0
- package/docs/API/10-lang/10-array/10-flatMap.ts +24 -0
- package/docs/API/10-lang/10-array/10-from.ts +25 -0
- package/docs/API/10-lang/10-array/10-group.ts +27 -0
- package/docs/API/10-lang/10-array/10-groupOutput.ts +30 -0
- package/docs/API/10-lang/10-array/10-includes.ts +24 -0
- package/docs/API/10-lang/10-array/10-indexOf.ts +24 -0
- package/docs/API/10-lang/10-array/10-insert.ts +34 -0
- package/docs/API/10-lang/10-array/10-is.ts +15 -0
- package/docs/API/10-lang/10-array/10-isLastIndex.ts +24 -0
- package/docs/API/10-lang/10-array/10-last.ts +21 -0
- package/docs/API/10-lang/10-array/10-lastIndexOf.ts +24 -0
- package/docs/API/10-lang/10-array/10-length.ts +28 -0
- package/docs/API/10-lang/10-array/10-lengthEqual.ts +39 -0
- package/docs/API/10-lang/10-array/10-map.ts +34 -0
- package/docs/API/10-lang/10-array/10-maxElements.ts +44 -0
- package/docs/API/10-lang/10-array/10-minElements.ts +44 -0
- package/docs/API/10-lang/10-array/10-notIncludes.ts +24 -0
- package/docs/API/10-lang/10-array/10-pop.ts +23 -0
- package/docs/API/10-lang/10-array/10-prepend.ts +34 -0
- package/docs/API/10-lang/10-array/10-push.ts +34 -0
- package/docs/API/10-lang/10-array/10-reduce.ts +28 -0
- package/docs/API/10-lang/10-array/10-reduceFrom.ts +16 -0
- package/docs/API/10-lang/10-array/10-reduceRight.ts +28 -0
- package/docs/API/10-lang/10-array/10-reverse.ts +25 -0
- package/docs/API/10-lang/10-array/10-select.ts +26 -0
- package/docs/API/10-lang/10-array/10-set.ts +24 -0
- package/docs/API/10-lang/10-array/10-shift.ts +23 -0
- package/docs/API/10-lang/10-array/10-slice.ts +24 -0
- package/docs/API/10-lang/10-array/10-some.ts +25 -0
- package/docs/API/10-lang/10-array/10-sort.ts +34 -0
- package/docs/API/10-lang/10-array/10-spliceDelete.ts +34 -0
- package/docs/API/10-lang/10-array/10-spliceInsert.ts +34 -0
- package/docs/API/10-lang/10-array/10-spliceReplace.ts +24 -0
- package/docs/API/10-lang/10-array/10-unshift.ts +34 -0
- package/docs/API/10-lang/10-array/index.llms.md +220 -0
- package/docs/API/10-lang/10-array/index.md +3 -0
- package/docs/API/10-lang/10-chrono/10-addDays.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addHours.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addMilliseconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addMinutes.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addMonths.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addSeconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addTime.ts +38 -0
- package/docs/API/10-lang/10-chrono/10-addWeeks.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-addYears.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-applyTimezone.ts +29 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanDate.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanOrEqualDate.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanOrEqualTime.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-betweenThanTime.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-closestTo.ts +48 -0
- package/docs/API/10-lang/10-chrono/10-computeTime.ts +35 -0
- package/docs/API/10-lang/10-chrono/10-createDate.ts +122 -0
- package/docs/API/10-lang/10-chrono/10-createDateOrThrow.ts +39 -0
- package/docs/API/10-lang/10-chrono/10-createTime.ts +86 -0
- package/docs/API/10-lang/10-chrono/10-createTimeOrThrow.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-eachDate.ts +67 -0
- package/docs/API/10-lang/10-chrono/10-equalDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-equalTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-formatDate.ts +43 -0
- package/docs/API/10-lang/10-chrono/10-formatTime.ts +37 -0
- package/docs/API/10-lang/10-chrono/10-getDayOfMonth.ts +37 -0
- package/docs/API/10-lang/10-chrono/10-getDayOfWeek.ts +30 -0
- package/docs/API/10-lang/10-chrono/10-getDayOfYear.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-getDifference.ts +29 -0
- package/docs/API/10-lang/10-chrono/10-getFirstDayOfMonth.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getFirstDayOfWeek.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getHour.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-getLastDayOfMonth.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getLastDayOfWeek.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getMilliseconds.ts +24 -0
- package/docs/API/10-lang/10-chrono/10-getMinute.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getMonth.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getSecond.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getTimezoneOffset.ts +28 -0
- package/docs/API/10-lang/10-chrono/10-getWeekOfYear.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-getYear.ts +27 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanOrEqualDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanOrEqualTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-greaterThanTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-isDate.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-isSafeTimeValue.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-isSafeTimestamp.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-isSerializedTheDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-isSerializedTheTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-isTime.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-lessThanDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-lessThanOrEqualDate.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-lessThanOrEqualTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-lessThanTime.ts +26 -0
- package/docs/API/10-lang/10-chrono/10-makeSafeTimeValue.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-makeSafeTimestamp.ts +19 -0
- package/docs/API/10-lang/10-chrono/10-maxDate.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-maxTime.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-minDate.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-minTime.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-now.ts +13 -0
- package/docs/API/10-lang/10-chrono/10-round.ts +41 -0
- package/docs/API/10-lang/10-chrono/10-serialize.ts +23 -0
- package/docs/API/10-lang/10-chrono/10-sortDates.ts +32 -0
- package/docs/API/10-lang/10-chrono/10-sortTimes.ts +31 -0
- package/docs/API/10-lang/10-chrono/10-subtractDays.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractHours.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractMilliseconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractMinutes.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractMonths.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractSeconds.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractTime.ts +38 -0
- package/docs/API/10-lang/10-chrono/10-subtractWeeks.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-subtractYears.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-toDateISOString.ts +17 -0
- package/docs/API/10-lang/10-chrono/10-toNative.ts +25 -0
- package/docs/API/10-lang/10-chrono/10-toTimeValue.ts +17 -0
- package/docs/API/10-lang/10-chrono/10-toTimestamp.ts +17 -0
- package/docs/API/10-lang/10-chrono/10-today.ts +13 -0
- package/docs/API/10-lang/10-chrono/10-tomorrow.ts +13 -0
- package/docs/API/10-lang/10-chrono/10-yesterday.ts +13 -0
- package/docs/API/10-lang/10-chrono/index.llms.md +332 -0
- package/docs/API/10-lang/10-chrono/index.md +3 -0
- package/docs/API/10-lang/10-common/10-and.ts +45 -0
- package/docs/API/10-lang/10-common/10-asserts.ts +13 -0
- package/docs/API/10-lang/10-common/10-asyncInnerPipe.ts +23 -0
- package/docs/API/10-lang/10-common/10-asyncLoop.ts +25 -0
- package/docs/API/10-lang/10-common/10-asyncPipe.ts +21 -0
- package/docs/API/10-lang/10-common/10-callThen.ts +22 -0
- package/docs/API/10-lang/10-common/10-cast.ts +16 -0
- package/docs/API/10-lang/10-common/10-clone.ts +12 -0
- package/docs/API/10-lang/10-common/10-createAsyncRetry.ts +34 -0
- package/docs/API/10-lang/10-common/10-createBuilder.ts +19 -0
- package/docs/API/10-lang/10-common/10-createEnum.ts +25 -0
- package/docs/API/10-lang/10-common/10-createExternalPromise.ts +13 -0
- package/docs/API/10-lang/10-common/10-createFormData.ts +16 -0
- package/docs/API/10-lang/10-common/10-createInterpolation.ts +12 -0
- package/docs/API/10-lang/10-common/10-createQueue.ts +16 -0
- package/docs/API/10-lang/10-common/10-createTransformer.ts +16 -0
- package/docs/API/10-lang/10-common/10-detachObjectMethod.ts +20 -0
- package/docs/API/10-lang/10-common/10-equal.ts +31 -0
- package/docs/API/10-lang/10-common/10-escapeRegExp.ts +11 -0
- package/docs/API/10-lang/10-common/10-falsy.ts +12 -0
- package/docs/API/10-lang/10-common/10-forward.ts +11 -0
- package/docs/API/10-lang/10-common/10-forwardAsserts.ts +17 -0
- package/docs/API/10-lang/10-common/10-forwardLog.ts +11 -0
- package/docs/API/10-lang/10-common/10-infer.ts +16 -0
- package/docs/API/10-lang/10-common/10-innerPipe.ts +23 -0
- package/docs/API/10-lang/10-common/10-instanceOf.ts +23 -0
- package/docs/API/10-lang/10-common/10-isType.ts +29 -0
- package/docs/API/10-lang/10-common/10-justExec.ts +28 -0
- package/docs/API/10-lang/10-common/10-justReturn.ts +19 -0
- package/docs/API/10-lang/10-common/10-loop.ts +20 -0
- package/docs/API/10-lang/10-common/10-memo.ts +12 -0
- package/docs/API/10-lang/10-common/10-memoObject.ts +11 -0
- package/docs/API/10-lang/10-common/10-memoPromise.ts +16 -0
- package/docs/API/10-lang/10-common/10-or.ts +29 -0
- package/docs/API/10-lang/10-common/10-pipe.ts +21 -0
- package/docs/API/10-lang/10-common/10-pipeCall.ts +20 -0
- package/docs/API/10-lang/10-common/10-prepareAsyncPipe.ts +20 -0
- package/docs/API/10-lang/10-common/10-preparePipe.ts +20 -0
- package/docs/API/10-lang/10-common/10-promiseAll.ts +16 -0
- package/docs/API/10-lang/10-common/10-promiseObject.ts +22 -0
- package/docs/API/10-lang/10-common/10-removeConstraint.ts +13 -0
- package/docs/API/10-lang/10-common/10-shameOnYou.ts +20 -0
- package/docs/API/10-lang/10-common/10-simpleClone.ts +12 -0
- package/docs/API/10-lang/10-common/10-stringToBytes.ts +16 -0
- package/docs/API/10-lang/10-common/10-stringToMillisecond.ts +17 -0
- package/docs/API/10-lang/10-common/10-timeout.ts +11 -0
- package/docs/API/10-lang/10-common/10-toCurriedPredicate.ts +28 -0
- package/docs/API/10-lang/10-common/10-toJSON.ts +15 -0
- package/docs/API/10-lang/10-common/10-toNative.ts +15 -0
- package/docs/API/10-lang/10-common/10-toRegExp.ts +17 -0
- package/docs/API/10-lang/10-common/10-transformer.ts +21 -0
- package/docs/API/10-lang/10-common/10-truthy.ts +12 -0
- package/docs/API/10-lang/10-common/10-useAsyncRetry.ts +31 -0
- package/docs/API/10-lang/10-common/10-when.ts +27 -0
- package/docs/API/10-lang/10-common/10-whenElse.ts +28 -0
- package/docs/API/10-lang/10-common/10-whenNot.ts +26 -0
- package/docs/API/10-lang/10-common/index.llms.md +228 -0
- package/docs/API/10-lang/10-common/index.md +3 -0
- package/docs/API/10-lang/10-dataStructure/10-absolutePath.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-allowedCharacters.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-array.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-arrayLengthEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-betweenThan.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-betweenThanOrEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-bigint.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-boolean.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-createCodec.ts +45 -0
- package/docs/API/10-lang/10-dataStructure/10-createCodecs.ts +134 -0
- package/docs/API/10-lang/10-dataStructure/10-createErrorInterpreter.ts +74 -0
- package/docs/API/10-lang/10-dataStructure/10-date.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-email.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-endsWith.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-even.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-extend.ts +27 -0
- package/docs/API/10-lang/10-dataStructure/10-greaterThan.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-greaterThanOrEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-include.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-integer.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-isNullStructure.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-isNullable.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-isOptional.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-isUndefinedStructure.ts +12 -0
- package/docs/API/10-lang/10-dataStructure/10-lazy.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-lessThan.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-lessThanOrEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-literal.ts +19 -0
- package/docs/API/10-lang/10-dataStructure/10-maxCharacters.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-maxElements.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-minCharacters.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-minElements.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-multipleOf.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-negative.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-notEmpty.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-notZero.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-null.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-nullable.ts +19 -0
- package/docs/API/10-lang/10-dataStructure/10-number.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-numberInString.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-object.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-odd.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-optional.ts +19 -0
- package/docs/API/10-lang/10-dataStructure/10-partial.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-path.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-positive.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-record.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-refine.ts +27 -0
- package/docs/API/10-lang/10-dataStructure/10-regex.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-required.ts +21 -0
- package/docs/API/10-lang/10-dataStructure/10-safe.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-segmentPath.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-startsWith.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-strictNegative.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-strictPositive.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-string.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-stringLengthEqual.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-time.ts +23 -0
- package/docs/API/10-lang/10-dataStructure/10-trimmed.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-typeStructureIdentifier.ts +33 -0
- package/docs/API/10-lang/10-dataStructure/10-undefined.ts +22 -0
- package/docs/API/10-lang/10-dataStructure/10-union.ts +24 -0
- package/docs/API/10-lang/10-dataStructure/10-unwrapLazy.ts +17 -0
- package/docs/API/10-lang/10-dataStructure/10-url.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/10-uuid.ts +25 -0
- package/docs/API/10-lang/10-dataStructure/index.llms.md +264 -0
- package/docs/API/10-lang/10-dataStructure/index.md +3 -0
- package/docs/API/10-lang/10-either/10-asyncGroup.ts +44 -0
- package/docs/API/10-lang/10-either/10-asyncSafeCallback.ts +23 -0
- package/docs/API/10-lang/10-either/10-error.ts +12 -0
- package/docs/API/10-lang/10-either/10-expect.ts +13 -0
- package/docs/API/10-lang/10-either/10-fail.ts +12 -0
- package/docs/API/10-lang/10-either/10-forwardAssertsSelection.ts +28 -0
- package/docs/API/10-lang/10-either/10-group.ts +58 -0
- package/docs/API/10-lang/10-either/10-hasInformation.ts +24 -0
- package/docs/API/10-lang/10-either/10-isLeft.ts +16 -0
- package/docs/API/10-lang/10-either/10-isRight.ts +16 -0
- package/docs/API/10-lang/10-either/10-isSelected.ts +29 -0
- package/docs/API/10-lang/10-either/10-keepAsRightByInformation.ts +29 -0
- package/docs/API/10-lang/10-either/10-keepAsRightSelection.ts +23 -0
- package/docs/API/10-lang/10-either/10-left.ts +13 -0
- package/docs/API/10-lang/10-either/10-matchInformation.ts +26 -0
- package/docs/API/10-lang/10-either/10-matchInformationOtherwise.ts +27 -0
- package/docs/API/10-lang/10-either/10-none.ts +12 -0
- package/docs/API/10-lang/10-either/10-ok.ts +12 -0
- package/docs/API/10-lang/10-either/10-result.ts +18 -0
- package/docs/API/10-lang/10-either/10-rewriteInformation.ts +24 -0
- package/docs/API/10-lang/10-either/10-right.ts +13 -0
- package/docs/API/10-lang/10-either/10-rightAsyncPipe.ts +69 -0
- package/docs/API/10-lang/10-either/10-rightPipe.ts +72 -0
- package/docs/API/10-lang/10-either/10-safeCallback.ts +29 -0
- package/docs/API/10-lang/10-either/10-some.ts +12 -0
- package/docs/API/10-lang/10-either/10-success.ts +12 -0
- package/docs/API/10-lang/10-either/10-toMaybe.ts +53 -0
- package/docs/API/10-lang/10-either/10-unwrapByInformation.ts +20 -0
- package/docs/API/10-lang/10-either/10-unwrapByInformationOrThrow.ts +19 -0
- package/docs/API/10-lang/10-either/10-unwrapLeft.ts +14 -0
- package/docs/API/10-lang/10-either/10-unwrapLeftOrThrow.ts +17 -0
- package/docs/API/10-lang/10-either/10-unwrapOr.ts +17 -0
- package/docs/API/10-lang/10-either/10-unwrapOtherwise.ts +20 -0
- package/docs/API/10-lang/10-either/10-unwrapRight.ts +14 -0
- package/docs/API/10-lang/10-either/10-unwrapRightOrThrow.ts +17 -0
- package/docs/API/10-lang/10-either/10-unwrapSelection.ts +26 -0
- package/docs/API/10-lang/10-either/10-unwrapSelectionOrThrow.ts +19 -0
- package/docs/API/10-lang/10-either/10-whenHasInformation.ts +35 -0
- package/docs/API/10-lang/10-either/10-whenHasInformationOtherwise.ts +29 -0
- package/docs/API/10-lang/10-either/10-whenIsLeft.ts +20 -0
- package/docs/API/10-lang/10-either/10-whenIsLeftOtherwise.ts +27 -0
- package/docs/API/10-lang/10-either/10-whenIsRight.ts +20 -0
- package/docs/API/10-lang/10-either/10-whenIsRightOtherwise.ts +26 -0
- package/docs/API/10-lang/10-either/10-whenIsSelected.ts +33 -0
- package/docs/API/10-lang/10-either/10-whenIsSelectedOtherwise.ts +35 -0
- package/docs/API/10-lang/10-either/index.llms.md +184 -0
- package/docs/API/10-lang/10-either/index.md +3 -0
- package/docs/API/10-lang/10-generator/10-asyncChunk.ts +55 -0
- package/docs/API/10-lang/10-generator/10-asyncConcat.ts +46 -0
- package/docs/API/10-lang/10-generator/10-asyncFilter.ts +41 -0
- package/docs/API/10-lang/10-generator/10-asyncFlat.ts +37 -0
- package/docs/API/10-lang/10-generator/10-asyncGroup.ts +65 -0
- package/docs/API/10-lang/10-generator/10-asyncLoop.ts +59 -0
- package/docs/API/10-lang/10-generator/10-asyncMap.ts +48 -0
- package/docs/API/10-lang/10-generator/10-asyncReduce.ts +63 -0
- package/docs/API/10-lang/10-generator/10-chunk.ts +44 -0
- package/docs/API/10-lang/10-generator/10-concat.ts +37 -0
- package/docs/API/10-lang/10-generator/10-createExternalAsyncGenerator.ts +29 -0
- package/docs/API/10-lang/10-generator/10-execute.ts +44 -0
- package/docs/API/10-lang/10-generator/10-filter.ts +35 -0
- package/docs/API/10-lang/10-generator/10-flat.ts +25 -0
- package/docs/API/10-lang/10-generator/10-group.ts +44 -0
- package/docs/API/10-lang/10-generator/10-groupOutput.ts +48 -0
- package/docs/API/10-lang/10-generator/10-loop.ts +55 -0
- package/docs/API/10-lang/10-generator/10-map.ts +35 -0
- package/docs/API/10-lang/10-generator/10-reduce.ts +51 -0
- package/docs/API/10-lang/10-generator/10-reduceFrom.ts +30 -0
- package/docs/API/10-lang/10-generator/index.llms.md +84 -0
- package/docs/API/10-lang/10-generator/index.md +3 -0
- package/docs/API/10-lang/index.md +3 -0
- package/docs/API/index.md +3 -0
- package/docs/API.llms.md +31 -0
- package/docs/concepts/01-fundamental/01-constraint/01-use.ts +22 -0
- package/docs/concepts/01-fundamental/01-constraint/10-built-in-constraint.ts +37 -0
- package/docs/concepts/01-fundamental/01-constraint/20-manipulation.ts +38 -0
- package/docs/concepts/01-fundamental/01-constraint/30-cast.ts +62 -0
- package/docs/concepts/01-fundamental/01-constraint/40-custom-constraint.ts +45 -0
- package/docs/concepts/01-fundamental/01-constraint/index.md +3 -0
- package/docs/concepts/01-fundamental/02-currying/01-use.ts +33 -0
- package/docs/concepts/01-fundamental/02-currying/10-built-in-function.ts +178 -0
- package/docs/concepts/01-fundamental/02-currying/20-inner-pipe.ts +39 -0
- package/docs/concepts/01-fundamental/02-currying/30-async-pipe.ts +42 -0
- package/docs/concepts/01-fundamental/02-currying/index.md +3 -0
- package/docs/concepts/01-fundamental/03-either/01-use.ts +21 -0
- package/docs/concepts/01-fundamental/03-either/10-discrimination.ts +79 -0
- package/docs/concepts/01-fundamental/03-either/20-exhaustive-handling.ts +73 -0
- package/docs/concepts/01-fundamental/03-either/30-composition.ts +72 -0
- package/docs/concepts/01-fundamental/03-either/40-result-adaptation.ts +40 -0
- package/docs/concepts/01-fundamental/03-either/50-external-results.ts +59 -0
- package/docs/concepts/01-fundamental/03-either/60-contextual-state.ts +40 -0
- package/docs/concepts/01-fundamental/03-either/index.md +3 -0
- package/docs/concepts/01-fundamental/04-data-structure/01-use.ts +22 -0
- package/docs/concepts/01-fundamental/04-data-structure/10-structure.ts +193 -0
- package/docs/concepts/01-fundamental/04-data-structure/20-constraint.ts +78 -0
- package/docs/concepts/01-fundamental/04-data-structure/30-validation.ts +100 -0
- package/docs/concepts/01-fundamental/04-data-structure/40-codecs.ts +151 -0
- package/docs/concepts/01-fundamental/04-data-structure/50-recursive.ts +48 -0
- package/docs/concepts/01-fundamental/04-data-structure/60-interpret-error.ts +123 -0
- package/docs/concepts/01-fundamental/04-data-structure/index.md +3 -0
- package/docs/concepts/01-fundamental/05-chrono/01-use.ts +14 -0
- package/docs/concepts/01-fundamental/05-chrono/10-creation.ts +59 -0
- package/docs/concepts/01-fundamental/05-chrono/20-manipulation.ts +94 -0
- package/docs/concepts/01-fundamental/05-chrono/30-serialized.ts +73 -0
- package/docs/concepts/01-fundamental/05-chrono/40-timezone.ts +81 -0
- package/docs/concepts/01-fundamental/05-chrono/index.md +3 -0
- package/docs/concepts/01-fundamental/06-modeling/10-new-type.ts +42 -0
- package/docs/concepts/01-fundamental/06-modeling/20-entity.ts +204 -0
- package/docs/concepts/01-fundamental/06-modeling/30-tagged-object.ts +181 -0
- package/docs/concepts/01-fundamental/06-modeling/40-entity-lifecycle.ts +275 -0
- package/docs/concepts/01-fundamental/06-modeling/50-evidence.ts +94 -0
- package/docs/concepts/01-fundamental/06-modeling/60-signed-function.ts +26 -0
- package/docs/concepts/01-fundamental/06-modeling/index.md +3 -0
- package/docs/concepts/01-fundamental/07-discrimination/10-entity.ts +104 -0
- package/docs/concepts/01-fundamental/07-discrimination/20-fact.ts +142 -0
- package/docs/concepts/01-fundamental/07-discrimination/30-tagged-object.ts +105 -0
- package/docs/concepts/01-fundamental/07-discrimination/40-error.ts +57 -0
- package/docs/concepts/01-fundamental/07-discrimination/50-literal.ts +87 -0
- package/docs/concepts/01-fundamental/07-discrimination/60-shape.ts +152 -0
- package/docs/concepts/01-fundamental/07-discrimination/70-predicate.ts +89 -0
- package/docs/concepts/01-fundamental/07-discrimination/index.md +3 -0
- package/docs/concepts/01-fundamental/index.md +1 -0
- package/docs/concepts/02-server/10-file/10-manipulation.ts +40 -0
- package/docs/concepts/02-server/10-file/20-path.ts +56 -0
- package/docs/concepts/02-server/10-file/index.md +3 -0
- package/docs/concepts/02-server/20-http/10-init.ts +31 -0
- package/docs/concepts/02-server/20-http/20-route.ts +174 -0
- package/docs/concepts/02-server/20-http/30-routine.ts +195 -0
- package/docs/concepts/02-server/20-http/40-jwt.ts +137 -0
- package/docs/concepts/02-server/20-http/50-codegen.ts +29 -0
- package/docs/concepts/02-server/20-http/index.md +3 -0
- package/docs/concepts/02-server/30-environment/10-platform.ts +38 -0
- package/docs/concepts/02-server/30-environment/20-variable.ts +41 -0
- package/docs/concepts/02-server/30-environment/index.md +3 -0
- package/docs/concepts/02-server/40-command/10-use.ts +112 -0
- package/docs/concepts/02-server/40-command/20-sub-command.ts +48 -0
- package/docs/concepts/02-server/40-command/index.md +3 -0
- package/docs/concepts/02-server/index.md +1 -0
- package/docs/concepts/03-client/10-http/10-init.ts +64 -0
- package/docs/concepts/03-client/10-http/20-request.ts +244 -0
- package/docs/concepts/03-client/10-http/30-hook.ts +139 -0
- package/docs/concepts/03-client/10-http/index.md +3 -0
- package/docs/concepts/03-client/20-form/10-init.ts +95 -0
- package/docs/concepts/03-client/20-form/20-input.ts +96 -0
- package/docs/concepts/03-client/20-form/30-layout.ts +160 -0
- package/docs/concepts/03-client/20-form/40-template.ts +89 -0
- package/docs/concepts/03-client/20-form/index.md +3 -0
- package/docs/concepts/03-client/index.md +1 -0
- package/docs/concepts/04-tests/01-unit/10-either.ts +136 -0
- package/docs/concepts/04-tests/01-unit/20-server-mocking.ts +53 -0
- package/docs/concepts/04-tests/01-unit/index.md +3 -0
- package/docs/concepts/04-tests/02-e2e/10-init.ts +80 -0
- package/docs/concepts/04-tests/02-e2e/20-architecture.ts +76 -0
- package/docs/concepts/04-tests/02-e2e/30-testing.ts +90 -0
- package/docs/concepts/04-tests/02-e2e/index.md +3 -0
- package/docs/concepts/04-tests/index.md +1 -0
- package/docs/concepts/05-type-driven-design/01-architecture/10-boundaries.md +41 -0
- package/docs/concepts/05-type-driven-design/01-architecture/index.md +3 -0
- package/docs/concepts/05-type-driven-design/02-domains/10-entities.md +58 -0
- package/docs/concepts/05-type-driven-design/02-domains/20-aggregates.md +49 -0
- package/docs/concepts/05-type-driven-design/02-domains/30-repositories.md +41 -0
- package/docs/concepts/05-type-driven-design/02-domains/index.md +3 -0
- package/docs/concepts/05-type-driven-design/03-applications/10-use-case.md +69 -0
- package/docs/concepts/05-type-driven-design/03-applications/index.md +3 -0
- package/docs/concepts/05-type-driven-design/04-infrastructure/10-implementation.md +56 -0
- package/docs/concepts/05-type-driven-design/04-infrastructure/index.md +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/book.ts +10 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/client.ts +10 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/email.ts +7 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/ports/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/clientGiveBackBook.ts +27 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/clientRentBook.ts +30 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/createBook.ts +32 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/clientGiveBackBook.ts +15 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/clientRentBook.ts +16 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/createBook.ts +21 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/create.ts +34 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/rental.ts +31 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/returnBook.ts +30 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/index.ts +87 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/facts/giveBackBook.ts +33 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/facts/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/facts/rentBook.ts +32 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/client/index.ts +82 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/book.ts +16 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/client.ts +7 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/email.ts +12 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/domains/repositories/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/business/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/command/clientRentBook.ts +62 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/command/index.ts +11 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/checkers/bookExist.ts +19 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/checkers/clientExist.ts +19 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/checkers/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/main.ts +19 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/routes/clientGiveBackBook.ts +37 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/routes/clientRentBook.ts +50 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/http/routes/index.ts +2 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/book.ts +25 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/client.ts +7 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/email.ts +10 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/ports/index.ts +3 -0
- package/docs/concepts/05-type-driven-design/fixtures/infrastructure/useCases/index.ts +12 -0
- package/docs/concepts/05-type-driven-design/index.md +3 -0
- package/docs/concepts.llms.md +475 -0
- package/instructions/coding-conventions.md +8 -0
- package/package.json +96 -3
- package/skills/command/SKILL.md +63 -0
- package/skills/command/references/examples/cli.ts +22 -0
- package/skills/command/references/examples/options-only.ts +27 -0
- package/skills/command/references/examples/preview-command.ts +57 -0
- package/skills/command/references/execution.md +31 -0
- package/skills/command/references/inputs.md +27 -0
- package/skills/fundamental/SKILL.md +80 -0
- package/skills/fundamental/references/composition.md +35 -0
- package/skills/fundamental/references/constraints-and-validation.md +61 -0
- package/skills/fundamental/references/examples/async-composition.ts +15 -0
- package/skills/fundamental/references/examples/cast.ts +18 -0
- package/skills/fundamental/references/examples/composition.ts +40 -0
- package/skills/fundamental/references/examples/environment-initialization.ts +19 -0
- package/skills/fundamental/references/examples/error-propagation.ts +24 -0
- package/skills/fundamental/references/examples/generic-inference.ts +31 -0
- package/skills/fundamental/references/examples/guaranteed-array-access.ts +31 -0
- package/skills/fundamental/references/examples/independent-inputs.ts +18 -0
- package/skills/fundamental/references/examples/infer.ts +21 -0
- package/skills/fundamental/references/examples/input-validation.ts +37 -0
- package/skills/fundamental/references/examples/safe-declarations.ts +25 -0
- package/skills/fundamental/references/results-and-errors.md +59 -0
- package/skills/http-client/SKILL.md +50 -0
- package/skills/http-client/references/configuration.md +9 -0
- package/skills/http-client/references/examples/client-expectations.ts +84 -0
- package/skills/http-client/references/examples/client-streams.ts +74 -0
- package/skills/http-client/references/examples/external-client.ts +78 -0
- package/skills/http-client/references/hooks.md +7 -0
- package/skills/http-client/references/responses.md +39 -0
- package/skills/http-client/references/streams.md +10 -0
- package/skills/http-server/SKILL.md +66 -0
- package/skills/http-server/references/code-generation.md +31 -0
- package/skills/http-server/references/examples/authentication.ts +42 -0
- package/skills/http-server/references/examples/contracts.ts +19 -0
- package/skills/http-server/references/examples/generate-sdk.ts +36 -0
- package/skills/http-server/references/examples/initialize.ts +29 -0
- package/skills/http-server/references/examples/minimal-route.ts +18 -0
- package/skills/http-server/references/examples/protected-route.ts +31 -0
- package/skills/http-server/references/examples/rename-user-route.ts +54 -0
- package/skills/http-server/references/examples/user-checker.ts +26 -0
- package/skills/http-server/references/examples/user-route.ts +38 -0
- package/skills/http-server/references/initialization.md +33 -0
- package/skills/http-server/references/reusable-flows.md +40 -0
- package/skills/http-server/references/routes-and-floor.md +38 -0
- package/skills/modeling/SKILL.md +76 -0
- package/skills/modeling/references/domain.md +33 -0
- package/skills/modeling/references/orchestration.md +36 -0
- package/skills/server/SKILL.md +55 -0
- package/skills/server/references/environment.md +30 -0
- package/skills/server/references/examples/environment.ts +41 -0
- package/skills/server/references/examples/file-structure.ts +26 -0
- package/skills/server/references/examples/files.ts +52 -0
- package/skills/server/references/files.md +38 -0
- package/skills/server/references/structures.md +15 -0
- package/skills/test/SKILL.md +70 -0
- package/skills/test/references/examples/results.ts +95 -0
- package/skills/test/references/examples/server.ts +59 -0
- package/skills/test/references/results.md +21 -0
- package/skills/test/references/server.md +17 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Tests
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
### Frontières entre domaine, application et infrastructure
|
|
2
|
+
|
|
3
|
+
Déterminer les dépendances autorisées, les opérations utilisables depuis chaque couche et le traitement des données et erreurs aux frontières du système.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Sens des dépendances
|
|
7
|
+
|
|
8
|
+
Les couches suivent cette direction :
|
|
9
|
+
|
|
10
|
+
```text
|
|
11
|
+
Infrastructure → Application → Domaine
|
|
12
|
+
Infrastructure → Domaine
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Le domaine ne dépend ni de l'application ni de l'infrastructure. L'application orchestre les opérations du domaine et définit les ports dont elle a besoin. L'infrastructure fournit les implémentations concrètes et adapte les systèmes externes à ces contrats.
|
|
16
|
+
|
|
17
|
+
Une dépendance vers le domaine depuis l'infrastructure est donc autorisée lorsqu'elle sert à consommer un contrat ou une capacité du logiciel. Elle ne permet pas à l'infrastructure de déplacer une règle métier dans sa propre couche.
|
|
18
|
+
|
|
19
|
+
### Respecter les responsabilités aux frontières
|
|
20
|
+
|
|
21
|
+
Une couche extérieure peut consommer le domaine et l'application, mais ne réalise pas leurs transitions à leur place. L'infrastructure peut :
|
|
22
|
+
|
|
23
|
+
- lire des données à travers un repository, dont l'implémentation les hydrate avec `map` ou `decodeMap` ;
|
|
24
|
+
- appeler une fonction pure de qualification pour établir une condition attendue par l'application ;
|
|
25
|
+
- appeler un use case et adapter son résultat au point d'entrée consommé.
|
|
26
|
+
|
|
27
|
+
Les lectures seules, comme `findById` ou `findMany`, peuvent servir une consultation ou préparer les entrées d'un use case sans imposer un use case de relais. Lorsqu'une opération comporte des règles métier, le domaine les exprime et l'application orchestre leur exécution, les effets et la persistance.
|
|
28
|
+
|
|
29
|
+
L'infrastructure passe alors par le use case : elle n'appelle directement ni `Fact` ni agrégat et ne modifie pas une entité pour réaliser une transition. Elle n'utilise pas non plus `Flag.append` ; la qualification du domaine établit le flag après avoir constaté la condition.
|
|
30
|
+
|
|
31
|
+
### Faire entrer les données dans le modèle
|
|
32
|
+
|
|
33
|
+
L'implémentation qui lit une base, une API ou un fichier hydrate la donnée avant de la retourner avec le contrat prévu. Les structures du domaine servent aussi à valider les entrées externes, afin de transmettre les types métier jusqu'aux use cases.
|
|
34
|
+
|
|
35
|
+
La couche qui possède la donnée établit les préconditions demandées : qualification du domaine pour un flag, opération prévue par le contrat pour une évidence de contexte. Un simple filtre technique ne suffit pas à produire ces preuves.
|
|
36
|
+
|
|
37
|
+
### Adapter les résultats
|
|
38
|
+
|
|
39
|
+
Un résultat métier attendu reste discriminé par son contrat, souvent avec `Either` et une `information`. La frontière le traduit ensuite vers le besoin du consommateur : réponse HTTP, sortie de commande ou autre protocole. Le code de transport ne remplace pas la règle qui a produit le résultat.
|
|
40
|
+
|
|
41
|
+
Les refus prévisibles restent des résultats à traiter, qu'ils concernent le métier, la vérification d'une donnée externe ou une manipulation technique. Les exceptions de défaillance imprévue déjà émises par les dépendances ou le runtime remontent implicitement, sans ajouter de `throw` dans les fonctions réutilisables. Le code applicatif réserve ses `throw` explicites à la consommation finale du résultat par la frontière, qui décide de sa conséquence. La distinction et l'adaptation des API qui lèvent sont détaillées dans les [résultats et exceptions](../../01-fundamental/03-either/50-external-results.ts).
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
### Conception des entités en Type-Driven Design
|
|
2
|
+
|
|
3
|
+
Organisation des modèles métier, de leurs invariants, qualifications et transitions dans le domaine.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Placer les règles métier
|
|
7
|
+
|
|
8
|
+
Concevoir une entité consiste à définir ses données, les conditions nécessaires aux opérations métier et les garanties obtenues après chaque transition. Les primitives sont documentées dans les fondamentaux : [NewType](../../01-fundamental/06-modeling/10-new-type.ts), [Entity](../../01-fundamental/06-modeling/20-entity.ts), [TaggedObject](../../01-fundamental/06-modeling/30-tagged-object.ts) et [cycle de vie avec Flag et Fact](../../01-fundamental/06-modeling/40-entity-lifecycle.ts).
|
|
9
|
+
|
|
10
|
+
Les règles suivantes sont des **conventions d'architecture du domaine** :
|
|
11
|
+
|
|
12
|
+
| Responsabilité | Placement et règle |
|
|
13
|
+
| --- | --- |
|
|
14
|
+
| Définir le modèle | Regrouper dans le namespace TypeScript de l'entité son `createEntityNamespace`, ses `NewType`, sa définition commune, ses états, ses flags et l'union de ses `Facts`. Représenter les propriétés pouvant changer de forme par des unions, notamment de `TaggedObject`. |
|
|
15
|
+
| Qualifier une condition | Une fonction du namespace inspecte les données sans modifier les propriétés métier et ajoute le flag correspondant uniquement après vérification. La condition peut porter sur un état, une capacité ou une relation avec une autre entité. |
|
|
16
|
+
| Créer ou modifier l'entité | Une `Fact` de son dossier `facts/` porte chaque création ou modification métier, même un simple changement de propriété. Elle peut lire plusieurs entités, mais ne modifie que sa cible. `Entity.update` est réservé aux faits ; ils ajoutent les flags dont leur transition établit les conditions. |
|
|
17
|
+
| Hydrater des données existantes | Utiliser les API de mapping décrites dans [Entity](../../01-fundamental/06-modeling/20-entity.ts). Cette entrée dans le modèle ne constitue pas une création métier. |
|
|
18
|
+
| Coordonner plusieurs cibles | Prévoir un fait par entité modifiée et confier leur orchestration à un [agrégat](./20-aggregates.md). |
|
|
19
|
+
|
|
20
|
+
`Flag.append` est réservé aux qualifications et aux faits décrits ci-dessus. Le placement de l'appel et la vérification de sa condition relèvent de ces conventions ; la présence d'un flag dans le type ne dispense pas son producteur d'établir la garantie annoncée.
|
|
21
|
+
|
|
22
|
+
### Choisir la primitive de modélisation
|
|
23
|
+
|
|
24
|
+
Les propriétés d'une entité portent des types métier explicites, généralement des `NewType`, des structures ou des `TaggedObject` adaptés à leur rôle. Utiliser la primitive correspondant à l'intention évite de confondre identité, forme, état et ordre d'exécution.
|
|
25
|
+
|
|
26
|
+
| Intention | Primitive | Règle |
|
|
27
|
+
| --- | --- | --- |
|
|
28
|
+
| Donner une identité métier à une valeur | `NewType` | Deux valeurs de même représentation mais de sens différent ne sont pas interchangeables. Les contraintes de forme sont vérifiées lors du mapping. |
|
|
29
|
+
| Décrire une forme identifiée | `TaggedObject` | Son tag permet le pattern matching et le transport entre frontières. Il décrit une shape, pas un cycle de vie ; une union de tags modélise les formes possibles d'une propriété. |
|
|
30
|
+
| Certifier une condition sur l'entité actuelle | `Flag` | Une qualification inspecte la valeur puis ajoute le flag correspondant. Le flag peut porter la payload de la vérification ; plusieurs flags peuvent coexister. |
|
|
31
|
+
| Représenter une création ou modification métier | `Fact` | Toute transition est un événement, même si l'état final ressemble à l'état initial. Une fact peut lire plusieurs entités, mais ne modifie que sa cible. |
|
|
32
|
+
| Imposer une provenance ou un ordre d'exécution | `Evidence` | La preuve identifie l'opération qui doit avoir précédé, indépendamment de la forme de la valeur. Ses contrats sont détaillés dans les [agrégats](./20-aggregates.md) et les [repositories](./30-repositories.md). |
|
|
33
|
+
|
|
34
|
+
Un `Flag` et une `Evidence` peuvent sembler proches, mais leur centre de gravité diffère : le flag certifie une caractéristique ou une qualification de l'état courant d'une entité ; l'évidence certifie un passage requis par le parcours d'exécution, indépendamment de la nature de la valeur. Une condition d'état se modélise donc par un flag ; une dépendance d'ordre ou de provenance se modélise par une evidence.
|
|
35
|
+
|
|
36
|
+
Une fonction de qualification peut être utilisée après l'hydratation d'une entité, y compris par l'infrastructure. Elle ne modifie pas les propriétés métier et ne réalise aucune transition ; `Flag.append` est utilisé seulement après la vérification de la condition, dans une qualification ou une `Fact`.
|
|
37
|
+
|
|
38
|
+
### Distinguer invariant et précondition
|
|
39
|
+
|
|
40
|
+
Un invariant doit rester vrai pour toute valeur de l'entité. Une précondition détermine si une opération particulière est possible et devient une preuve exigée par sa signature.
|
|
41
|
+
|
|
42
|
+
Dans la fixture [`Client`](../fixtures/business/domains/entities/client/index.ts), `borrowedBooks` contient au maximum **cinq** identifiants. `Client.canRentBook` vérifie une limite de **quatre** avant une nouvelle location et produit un résultat `CanRentBook` portant `CanRentBookFlag`, ou `NoBookRentalSlotsAvailable`. Le fait peut ainsi ajouter un livre en préservant l'invariant. Une capacité à agir mérite une qualification même si elle ne constitue pas un état du cycle de vie.
|
|
43
|
+
|
|
44
|
+
### Définir le contrat d'une transition
|
|
45
|
+
|
|
46
|
+
Exiger les preuves en entrée, construire des propriétés portant les contraintes attendues, créer ou mettre à jour la cible, puis ajouter les garanties de sortie et appliquer le fait. Le [cycle de vie](../../01-fundamental/06-modeling/40-entity-lifecycle.ts) détaille les API et la reconstruction des preuves après `update`.
|
|
47
|
+
|
|
48
|
+
La fixture [`BookRentalFact`](../fixtures/business/domains/entities/book/facts/rental.ts) illustre ce contrat :
|
|
49
|
+
|
|
50
|
+
| Étape | Contrat |
|
|
51
|
+
| --- | --- |
|
|
52
|
+
| Entrée | Un `Client.Entity & Client.CanRentBookFlag` et un `Book.Entity & Book.AvailableFlag`. Pour le livre, qualifier avec [`Book.refineState`](../fixtures/business/domains/entities/book/index.ts) puis sélectionner la branche disponible. |
|
|
53
|
+
| Transformation | Construire un `BorrowedState` avec l'identifiant du client et mettre à jour le livre. Le client est lu, sans être modifié par ce fait. |
|
|
54
|
+
| Sortie | Ajouter `BorrowedFlag` et appliquer `BookRentalFact` avec le nouvel état comme payload. `run` enveloppe la valeur `Book.Entity & Book.BorrowedFlag & BookRentalFact` dans un `Either` droit. |
|
|
55
|
+
|
|
56
|
+
Après une transition, poursuivre avec **l'entité retournée**. Les preuves d'une ancienne valeur décrivent la situation antérieure et ne doivent pas être transférées sans vérification. Les valeurs fournies à `update` doivent déjà porter le typage métier attendu : cette opération ne valide pas les nouvelles propriétés au runtime, comme précisé dans [Entity](../../01-fundamental/06-modeling/20-entity.ts).
|
|
57
|
+
|
|
58
|
+
La fact portée par l'entité représente le fait courant ; conserver un historique persistant des transitions demande un mécanisme dédié. Les entités, flags et évidences sont immuables : après `update`, poursuivre avec la nouvelle valeur et ne pas transférer automatiquement les preuves de l'ancienne. Une preuve devenue fausse entre la qualification et la persistance révèle une contrainte de concurrence ou de transaction à traiter dans le contrat d'orchestration, pas une raison de rendre les preuves mutables.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
### Conception des agrégats en Type-Driven Design
|
|
2
|
+
|
|
3
|
+
Contrats des transactions métier, préconditions et orchestration de faits réutilisables.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Délimiter une transaction métier
|
|
7
|
+
|
|
8
|
+
Dans ce Type-Driven Design, un **agrégat est une fonction pure de transaction métier**. Son nom exprime l'opération prise en charge. Il exige ses préconditions dans sa signature, choisit les faits nécessaires, relie leurs entrées et leurs sorties et rassemble les résultats métier.
|
|
9
|
+
|
|
10
|
+
Les [faits](./10-entities.md) portent les transitions de chaque cible et restent réutilisables dans plusieurs agrégats. Un agrégat peut appeler un seul fait : ses exigences peuvent déjà différer de celles de cette transition.
|
|
11
|
+
|
|
12
|
+
Pour concevoir l'opération, déterminer ses entrées et leurs preuves, choisir les faits, organiser leur enchaînement selon leurs dépendances, puis restituer les entités produites et les éventuels besoins d'effets. Les couches appelantes fournissent les entrées qualifiées et gèrent les situations où les préconditions ne peuvent pas être établies. La décision de créer un agrégat vient du besoin métier ; elle ne se déduit pas seulement du nombre d'entités dans les paramètres.
|
|
13
|
+
|
|
14
|
+
Un agrégat n'appelle jamais un repository et n'exécute jamais une dépendance fournie par l'extérieur. Il reste pur : pour les mêmes entrées, il produit le même résultat métier et les mêmes besoins déclarés. L'application appelle les repositories, prépare les entrées puis appelle l'agrégat.
|
|
15
|
+
|
|
16
|
+
### Coordonner plusieurs entités
|
|
17
|
+
|
|
18
|
+
La fixture [`clientRentBook`](../fixtures/business/domains/aggregates/clientRentBook.ts) exige un `Client.Entity & Client.CanRentBookFlag` et un `Book.Entity & Book.AvailableFlag`.
|
|
19
|
+
|
|
20
|
+
Elle appelle [`ClientRentBookFact`](../fixtures/business/domains/entities/client/facts/rentBook.ts) pour ajouter le livre aux emprunts du client et [`BookRentalFact`](../fixtures/business/domains/entities/book/facts/rental.ts) pour passer le livre à l'état emprunté. Les deux faits reçoivent ici les mêmes entrées qualifiées et produisent chacun la nouvelle valeur de leur cible.
|
|
21
|
+
|
|
22
|
+
Si plusieurs faits modifient successivement **la même entité**, transmettre à chaque étape la valeur retournée par la précédente, avec les preuves exigées. Réutiliser l'entrée initiale ferait perdre les modifications intermédiaires.
|
|
23
|
+
|
|
24
|
+
Une `Fact` représente l'événement du cycle de vie d'une seule entité. Lorsque le métier coordonne plusieurs entités dans la même opération, l'agrégat orchestre les faits correspondants. Si cette coordination n'est pas une exigence du métier, les transitions peuvent rester dans des opérations distinctes.
|
|
25
|
+
|
|
26
|
+
### Ajouter les exigences propres à la transaction
|
|
27
|
+
|
|
28
|
+
La fixture [`createBook`](../fixtures/business/domains/aggregates/createBook.ts) distingue le contrat de création de l'entité et celui de la transaction :
|
|
29
|
+
|
|
30
|
+
| Contrat | Préconditions |
|
|
31
|
+
| --- | --- |
|
|
32
|
+
| [`CreateBookFact`](../fixtures/business/domains/entities/book/facts/create.ts) | Un `Book.Id` et un `Book.Title`. |
|
|
33
|
+
| Agrégat `createBook` | Un identifiant portant la preuve `generated` et un titre portant la preuve `title-not-registered`, exigés avec `GetEvidenceResult`. |
|
|
34
|
+
|
|
35
|
+
Ces garanties proviennent du contrat de [`BookRepository`](../fixtures/business/domains/repositories/book.ts). Les contraintes de `Book.Title` décrivent sa forme ; l'absence du titre dans le catalogue dépend d'une vérification extérieure. Un titre seul ne satisfait donc pas le contrat de l'agrégat. Voir [les preuves de passage](../../01-fundamental/06-modeling/50-evidence.ts) pour le mécanisme `Evidence` et [les repositories](./30-repositories.md) pour les opérations qui les produisent.
|
|
36
|
+
|
|
37
|
+
Un autre agrégat peut réutiliser le même fait avec d'autres préconditions. **Les exigences de la transaction appartiennent à l'agrégat ; la création ou modification de l'entité appartient au fait.**
|
|
38
|
+
|
|
39
|
+
Le niveau d'exigence dépend de l'orchestration choisie. Une `Fact` peut exiger directement une évidence lorsqu'une transition impose une provenance, tandis que l'agrégat ou une étape intermédiaire peut l'exiger lorsque la contrainte concerne le parcours complet. Ne pas ajouter cette exigence à une transition qui autorise volontairement plusieurs provenances.
|
|
40
|
+
|
|
41
|
+
### Déclarer les effets attendus
|
|
42
|
+
|
|
43
|
+
Lorsqu'une transaction nécessite des effets, retourner un `Resolver` contenant les résultats métier et le contrat des opérations attendues. Sa construction déclare ces besoins sans les exécuter : l'agrégat reste pur.
|
|
44
|
+
|
|
45
|
+
Le `Resolver` est optionnel. Un agrégat sans effet peut retourner directement sa valeur ou son `Either`; l'utiliser sert à rassembler plusieurs résultats et à déclarer les effets nécessaires, sans les exécuter.
|
|
46
|
+
|
|
47
|
+
Dans `clientRentBook`, le résolveur rassemble `client` et `book` et exige `sendInformationalEmail`, typé par `EmailRepository["sendRentInformationalEmail"]`. L'[application](../03-applications/10-use-case.md) fournit les implémentations, exécute le résolveur et décide de l'ordre des effets et de la persistance.
|
|
48
|
+
|
|
49
|
+
Le résolveur décrit les conséquences attendues de l'événement métier ; l'application décide de leur ordre, de leur criticité et de leur stratégie d'exécution. Si un effet doit réussir avant de poursuivre, la composition du use case doit arrêter les étapes suivantes lorsqu'il renvoie un `Left`.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
### Conception des repositories en Type-Driven Design
|
|
2
|
+
|
|
3
|
+
Contrats des opérations nécessaires au métier dont l'implémentation technique reste extérieure au domaine.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Déclarer une capacité à partir du besoin métier
|
|
7
|
+
|
|
8
|
+
Dans ce Type-Driven Design, un **repository est, conceptuellement, un agrégat dont l'implémentation ne concerne pas le domaine**. Il est déclaré dans le domaine sous forme de contrat : ses entrées, ses résultats possibles et ses garanties utilisent les types métier ; sa réalisation technique reste extérieure.
|
|
9
|
+
|
|
10
|
+
Son périmètre suit les capacités que le métier doit nommer : récupération de données, génération de valeurs, vérifications préalables, calculs précis ou envoi de courriels. Le domaine décrit ce qu'il attend sans exposer de requête SQL, de client de base de données ou de configuration de transport.
|
|
11
|
+
|
|
12
|
+
Les fixtures donnent des contrats adaptés à plusieurs besoins :
|
|
13
|
+
|
|
14
|
+
| Besoin | Contrat |
|
|
15
|
+
| --- | --- |
|
|
16
|
+
| Obtenir un identifiant issu de la génération prévue | [`BookRepository.generateId`](../fixtures/business/domains/repositories/book.ts) retourne un `Book.Id` portant l'évidence `generated`. |
|
|
17
|
+
| Vérifier une condition du catalogue | `BookRepository.titleIsAlreadyRegistered` retourne une promesse de résultat portant `title-already-registered` ou `title-not-registered`, avec le titre concerné. |
|
|
18
|
+
| Retrouver une entité | `BookRepository.findById` et [`ClientRepository.findById`](../fixtures/business/domains/repositories/client.ts) retournent une promesse de `Maybe` contenant l'entité ou représentant son absence. |
|
|
19
|
+
| Demander un traitement de disponibilité | `BookRepository.rankAvailability` décrit une fonction signée recevant le livre. |
|
|
20
|
+
| Envoyer un courriel de location | [`EmailRepository.sendRentInformationalEmail`](../fixtures/business/domains/repositories/email.ts) décrit une fonction signée recevant le client et le livre. |
|
|
21
|
+
|
|
22
|
+
Voir [les preuves de passage](../../01-fundamental/06-modeling/50-evidence.ts) et [l'identité des fonctions dans les dépendances](../../01-fundamental/06-modeling/60-signed-function.ts) pour les mécanismes de typage utilisés par ces contrats.
|
|
23
|
+
|
|
24
|
+
### Relier le contrat aux transactions
|
|
25
|
+
|
|
26
|
+
Un repository intervient de deux façons auprès des [agrégats](./20-aggregates.md) :
|
|
27
|
+
|
|
28
|
+
- **Avant la transaction**, son opération fournit des données ou établit une précondition extérieure que l'agrégat exige en entrée. `createBook` utilise ainsi les garanties de génération d'identifiant et de vérification du titre. Pour une recherche, la couche appelante gère l'absence de l'entité et la qualifie selon les besoins de l'opération.
|
|
29
|
+
- **Pour les effets attendus**, son contrat définit une dépendance du résolveur retourné par l'agrégat. `clientRentBook` utilise ainsi la signature de `EmailRepository.sendRentInformationalEmail`.
|
|
30
|
+
|
|
31
|
+
L'application orchestre les appels techniques et la résolution des effets. L'agrégat exploite les résultats préparés ou déclare les effets attendus, sans exécuter l'implémentation du repository.
|
|
32
|
+
|
|
33
|
+
Lorsqu'une recherche retourne une entité, le repository l'hydrate avant de la transmettre. Une requête peut filtrer sur un état, mais elle ne suffit pas à ajouter le flag : appeler ensuite la qualification du domaine. Si elle révèle un autre état, le repository doit signaler l'incohérence comme une erreur technique.
|
|
34
|
+
|
|
35
|
+
Une opération de repository peut établir un contexte transactionnel ou une autre garantie d'exécution. Si elle reçoit une callback, son contrat doit préciser que celle-ci est exécutée dans le contexte requis ; l'implémentation ne produit l'évidence associée qu'après avoir réellement établi et exécuté ce contexte. Le domaine peut exiger cette preuve dans une `Fact`, un agrégat ou une étape intermédiaire.
|
|
36
|
+
|
|
37
|
+
### Respecter les garanties annoncées
|
|
38
|
+
|
|
39
|
+
**L'implémentation doit réellement établir une condition avant de produire sa preuve.** Le contrat exige la garantie dans le typage ; ajouter une évidence ne réalise pas la vérification technique.
|
|
40
|
+
|
|
41
|
+
Changer de base de données, de générateur ou de service de courriel préserve les transactions métier tant que les opérations conservent leurs entrées, leurs résultats et le sens des garanties annoncées. La seule compatibilité TypeScript ne suffit pas à respecter ce contrat.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
### Conception des use cases en Type-Driven Design
|
|
2
|
+
|
|
3
|
+
Orchestration applicative des agrégats, sélection et propagation des résultats Either, ports et injection avec Reader, résolution des effets et persistance.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Rôle de la couche applicative
|
|
7
|
+
|
|
8
|
+
La couche applicative se situe sous le domaine et au-dessus de l'infrastructure. Un **use case orchestre techniquement les agrégats** : préparer leurs entrées et leurs preuves, sélectionner les résultats permettant de poursuivre, appeler les agrégats, traiter leurs sorties, exécuter les résolveurs et sauvegarder les données.
|
|
9
|
+
|
|
10
|
+
Les règles et les transitions métier restent dans le [domaine](../02-domains/20-aggregates.md). L'application décide de l'enchaînement des opérations et de la persistance à travers des ports abstraits ; l'infrastructure implémente ces ports avec les outils concrets. Les use cases peuvent être transportés avec le domaine dans une autre application si les implémentations respectent ces contrats.
|
|
11
|
+
|
|
12
|
+
Un agrégat reste une fonction pure : les mêmes entrées produisent le même résultat métier et les mêmes besoins d'effets. Un use case équipé de ports impurs dépend aussi de l'état extérieur ; les mêmes paramètres ne garantissent donc pas le même résultat. Les frontières et les opérations autorisées entre les couches sont décrites dans [l'architecture](../01-architecture/10-boundaries.md).
|
|
13
|
+
|
|
14
|
+
### Composer les résultats avec Either
|
|
15
|
+
|
|
16
|
+
Les opérations utilisées par les use cases renvoient souvent des monades `Either`. Leur statut et leur information permettent de sélectionner les résultats souhaités, de poursuivre le cas positif et de propager les échecs.
|
|
17
|
+
|
|
18
|
+
| Besoin | Outil |
|
|
19
|
+
| --- | --- |
|
|
20
|
+
| Enchaîner les étapes du cas positif | `DEither.rightPipe` transmet la valeur des `Right` aux étapes suivantes ; dès qu'un `Left` apparaît, il le retourne sans exécuter la suite. `rightAsyncPipe` attend également les étapes asynchrones. |
|
|
21
|
+
| Choisir quels résultats autorisent la poursuite | `keepAsRightByInformation` ou `keepAsRightSelection` classe les variantes souhaitées à droite et les autres à gauche. |
|
|
22
|
+
| Réunir plusieurs résultats nécessaires à une étape | `group` ou `asyncGroup` rassemble les valeurs des `Right` dans un `Success`, ou retourne le premier `Left`. Fournir des getters permet de ne pas exécuter les opérations suivantes après un échec. |
|
|
23
|
+
| Traiter un résultat précis | Les fonctions de discrimination, comme `whenHasInformation` et `matchInformation`, permettent de définir la suite selon l'information du résultat. |
|
|
24
|
+
|
|
25
|
+
Un refus prévisible reste un résultat à gérer par les couches appelantes, y compris lorsqu'il provient d'une opération technique. Les exceptions techniques déjà émises par les dépendances ou le runtime remontent implicitement ; le use case n'ajoute pas ses propres `throw`, conformément aux [résultats et exceptions](../../01-fundamental/03-either/50-external-results.ts). `unwrapRight` intervient seulement après la discrimination, lorsqu'une seule branche pertinente reste à poursuivre.
|
|
26
|
+
|
|
27
|
+
Voir les fondamentaux : [composition et propagation des échecs](../../01-fundamental/03-either/30-composition.ts), [adaptation des résultats](../../01-fundamental/03-either/40-result-adaptation.ts), [discrimination](../../01-fundamental/03-either/10-discrimination.ts) et [traitement exhaustif](../../01-fundamental/03-either/20-exhaustive-handling.ts).
|
|
28
|
+
|
|
29
|
+
### Préparer les préconditions de l'agrégat
|
|
30
|
+
|
|
31
|
+
Dans [`CreateBookUseCase`](../fixtures/business/applications/useCases/createBook.ts), `bookRepository.titleIsAlreadyRegistered` retourne le résultat de la vérification du titre. `keepAsRightByInformation("title-not-registered")` conserve le cas souhaité à droite et classe `title-already-registered` à gauche.
|
|
32
|
+
|
|
33
|
+
Le `rightAsyncPipe` fournit alors à l'[agrégat `createBook`](../fixtures/business/domains/aggregates/createBook.ts) le titre portant la preuve `title-not-registered` et l'identifiant généré portant `generated`, puis sauvegarde le livre produit. Si le titre est déjà enregistré, le résultat à gauche est retourné sans génération d'identifiant, appel d'agrégat ni sauvegarde.
|
|
34
|
+
|
|
35
|
+
La sélection conserve les preuves et rend l'appel type-safe. L'implémentation du repository doit réellement établir les garanties qu'elle annonce. Voir [les repositories](../02-domains/30-repositories.md) et [les évidences](../../01-fundamental/06-modeling/50-evidence.ts).
|
|
36
|
+
|
|
37
|
+
Les garanties peuvent aussi être exigées de l'appelant : [`ClientRentBookUseCase`](../fixtures/business/applications/useCases/clientRentBook.ts) reçoit déjà un client portant `CanRentBookFlag` et un livre portant `AvailableFlag`, qualifiés dans la [route de location](../fixtures/infrastructure/http/routes/clientRentBook.ts).
|
|
38
|
+
|
|
39
|
+
### Déclarer les ports et construire le Reader
|
|
40
|
+
|
|
41
|
+
Un **port décrit une capacité nécessaire à l'application**. Il peut reprendre un contrat de repository du domaine et le compléter : [`BookRepositoryPort`](../fixtures/business/applications/ports/book.ts) étend `BookRepository` avec `save`, car la décision de sauvegarder appartient à l'application.
|
|
42
|
+
|
|
43
|
+
`save` n'est pas une obligation générale des repositories. Cette méthode appartient au port applicatif lorsque le domaine ne fixe pas lui-même le moment, le contexte ou les garanties de la sauvegarde. Si le métier exige une sauvegarde particulière, la dépendance doit être exprimée dans le contrat et, si nécessaire, par une `Evidence`.
|
|
44
|
+
|
|
45
|
+
Le port associe une interface TypeScript à une constante créée avec `DInvocation.createPort<Interface>()`. L'interface décrit les signatures ; la constante représente la dépendance au runtime. Dans l'infrastructure, la constante du port, par exemple `BookRepositoryPort`, expose `createImplementation` et reçoit une implémentation compatible avec ce contrat.
|
|
46
|
+
|
|
47
|
+
Le use case utilise la monade **Reader** de `@duplojs/lang/invocation`. `DInvocation.createReader` reçoit les ports nécessaires et une fonction qui reçoit leurs implémentations, puis retourne la fonction du cas d'utilisation. Les dépendances sont injectées lors de la résolution du Reader ; les paramètres métier sont fournis ensuite à la fonction obtenue.
|
|
48
|
+
|
|
49
|
+
Pour un port, Reader met la première lettre de la clé de dépendance en minuscule et retire le suffixe final `Port` : `BookRepositoryPort` correspond à `bookRepository`. **L'injection doit respecter ce nom et la signature du port.** Un Reader peut aussi dépendre d'autres Readers, résolus à partir des ports fournis.
|
|
50
|
+
|
|
51
|
+
Dans l'infrastructure, `Reader.run` résout un use case isolé ; `DInvocation.resolveReaders` résout un ensemble avec tous les ports nécessaires. La [fixture de résolution](../fixtures/infrastructure/useCases/index.ts) produit ainsi `useCases.clientRentBookUseCase`, appelable depuis n'importe quel point d'entrée respectant sa signature.
|
|
52
|
+
|
|
53
|
+
Un use case peut dépendre d'un autre `Reader` ; ses dépendances sont alors incluses dans celles du reader courant. Le même port peut être partagé par plusieurs readers.
|
|
54
|
+
|
|
55
|
+
### Résoudre les effets et décider de la persistance
|
|
56
|
+
|
|
57
|
+
**Reader fournit les dépendances du use case ; Resolver exécute les effets déclarés par l'agrégat.** L'[agrégat `clientRentBook`](../fixtures/business/domains/aggregates/clientRentBook.ts) retourne les nouvelles entités et le besoin `sendInformationalEmail`, sans envoyer lui-même de courriel.
|
|
58
|
+
|
|
59
|
+
Le [use case de location](../fixtures/business/applications/useCases/clientRentBook.ts) fournit `emailRepository.sendRentInformationalEmail` à `resolver.resolve`, puis sauvegarde le client et le livre. Le [use case de retour](../fixtures/business/applications/useCases/clientGiveBackBook.ts) résout de même `rankBookAvailability` avant de sauvegarder.
|
|
60
|
+
|
|
61
|
+
L'ordre appartient au use case selon le besoin de l'opération. Si la sauvegarde doit précéder les effets, `Resolver.runAndResolve` permet d'attendre cette étape avant de les déclencher. Si un effet doit réussir avant la sauvegarde, arrêter la composition lorsqu'il renvoie un `Left`. Une transaction peut être coordonnée par un port ; l'application en définit le périmètre et l'infrastructure fournit le mécanisme. `promiseObject` exécute plusieurs sauvegardes en parallèle, sans fournir d'atomicité par lui-même.
|
|
62
|
+
|
|
63
|
+
### Démarche d'implémentation
|
|
64
|
+
|
|
65
|
+
1. Lire les contrats des agrégats : entrées, preuves, résultats et effets attendus.
|
|
66
|
+
2. Définir les paramètres du use case et les ports nécessaires, puis créer le Reader.
|
|
67
|
+
3. Préparer les entrées et composer les résultats Either pour poursuivre les branches souhaitées et propager ou traiter les autres.
|
|
68
|
+
4. Appeler les agrégats, résoudre leurs effets et sauvegarder leurs résultats dans l'ordre requis.
|
|
69
|
+
5. Fournir les implémentations de ports et résoudre les use cases dans l'infrastructure.
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
### Assembler l'application dans l'infrastructure
|
|
2
|
+
|
|
3
|
+
Fournir les dépendances concrètes de l'application et raccorder ses capacités aux points d'entrée du système.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
### Rôle de l'infrastructure
|
|
7
|
+
|
|
8
|
+
L'infrastructure assemble l'application dans un contexte concret : base de données, services externes, génération d'identifiants, envoi de messages ou point d'entrée. Elle dépend des contrats exposés par le domaine et l'application ; le domaine et les use cases ne dépendent pas d'une technologie d'infrastructure.
|
|
9
|
+
|
|
10
|
+
Le sens des dépendances et les responsabilités aux frontières sont définis dans [les frontières de l'architecture](../01-architecture/10-boundaries.md). Ce chapitre se concentre sur leur mise en œuvre : fournir les ports demandés par l'application, résoudre les use cases et les rendre accessibles aux consommateurs.
|
|
11
|
+
|
|
12
|
+
### Implémenter les ports applicatifs
|
|
13
|
+
|
|
14
|
+
Un port applicatif exprime une capacité dont un use case a besoin. Son implémentation appartient à l'infrastructure, qui choisit la technologie concrète tout en préservant le contrat du port : signatures, résultats, preuves et autres garanties annoncées.
|
|
15
|
+
|
|
16
|
+
La déclaration des capacités et l'extension d'un contrat de domaine par un port applicatif sont expliquées dans [les repositories](../02-domains/30-repositories.md) et [les use cases](../03-applications/10-use-case.md). L'infrastructure fournit ensuite une implémentation compatible avec ce contrat ; elle ne déduit pas une garantie du seul typage et ne remplace pas une transition métier par un traitement technique.
|
|
17
|
+
|
|
18
|
+
Les [implémentations des ports de la fixture](../fixtures/infrastructure/ports/index.ts) construisent ainsi `bookRepository`, `clientRepository` et `emailRepository` depuis les ports applicatifs. Un même port peut être partagé par plusieurs use cases ; il n'est pas nécessaire de créer une implémentation différente pour chaque scénario.
|
|
19
|
+
|
|
20
|
+
### Résoudre les use cases
|
|
21
|
+
|
|
22
|
+
Les use cases décrivent leurs dépendances avec `Reader`, puis reçoivent leurs implémentations au moment de la résolution. Le fonctionnement de l'injection, des ports et des `Reader` est documenté dans [la couche applicative](../03-applications/10-use-case.md) ; l'infrastructure en réalise l'assemblage.
|
|
23
|
+
|
|
24
|
+
`DInvocation.resolveReaders` associe un ensemble de use cases à un même jeu d'implémentations. Dans la [fixture de résolution](../fixtures/infrastructure/useCases/index.ts), l'infrastructure injecte les repositories concrets et expose notamment `useCases.clientRentBookUseCase`.
|
|
25
|
+
|
|
26
|
+
La résolution ne réimplémente pas l'orchestration métier et ne reconstruit pas les dépendances dans chaque point d'entrée. Elle produit des fonctions prêtes à être consommées avec leurs paramètres métier.
|
|
27
|
+
|
|
28
|
+
### Raccorder les points d'entrée
|
|
29
|
+
|
|
30
|
+
Un point d'entrée adapte un moyen de consommation aux capacités de l'application : valider les données externes avec les structures du domaine, préparer les paramètres exigés par le use case résolu, l'appeler puis traduire son résultat pour le consommateur. Les opérations autorisées pour cette préparation sont définies dans [les frontières de l'architecture](../01-architecture/10-boundaries.md#respecter-les-responsabilités-aux-frontières).
|
|
31
|
+
|
|
32
|
+
La nature du protocole ne change pas cette responsabilité. Une route HTTP, une commande ou un autre client peuvent consommer le même use case résolu ; chacun possède sa propre documentation de protocole et son propre contrat de sortie.
|
|
33
|
+
|
|
34
|
+
La [fixture HTTP de location](../fixtures/infrastructure/http/routes/clientRentBook.ts) et la [fixture de commande de location](../fixtures/infrastructure/command/clientRentBook.ts) utilisent ainsi `Client.Id` et `Book.Id` pour valider les entrées, récupèrent les entités puis les qualifient pour satisfaire la signature du même use case. Le [checker de livre](../fixtures/infrastructure/http/checkers/bookExist.ts) illustre l'étape de lecture et le traitement de l'absence du livre.
|
|
35
|
+
|
|
36
|
+
Les détails de construction d'une route sont documentés dans [les routes HTTP](../../02-server/20-http/20-route.ts), ceux des vérifications réutilisables dans [les routines HTTP](../../02-server/20-http/30-routine.ts), et ceux des commandes dans [la définition d'une commande](../../02-server/40-command/10-use.ts). La composition des résultats est documentée dans [les fondamentaux `Either`](../../01-fundamental/03-either/30-composition.ts) ; l'adaptation au protocole reste documentée par chaque moyen de consommation.
|
|
37
|
+
|
|
38
|
+
L'assemblage suit donc ce parcours :
|
|
39
|
+
|
|
40
|
+
```text
|
|
41
|
+
Port applicatif
|
|
42
|
+
↓ implémentation concrète
|
|
43
|
+
Use case résolu par Reader
|
|
44
|
+
↓ consommation par un point d'entrée
|
|
45
|
+
Point d'entrée
|
|
46
|
+
↓ adaptation au protocole
|
|
47
|
+
Contrat du consommateur
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Démarche d'implémentation
|
|
51
|
+
|
|
52
|
+
1. Lire les contrats des [ports applicatifs](../03-applications/10-use-case.md#déclarer-les-ports-et-construire-le-reader) et identifier les systèmes capables de les implémenter.
|
|
53
|
+
2. Fournir une implémentation par port en conservant les signatures et les garanties du contrat.
|
|
54
|
+
3. Résoudre les Readers avec `DInvocation.resolveReaders`.
|
|
55
|
+
4. Raccorder chaque point d'entrée au use case résolu et à son contrat de consommation.
|
|
56
|
+
5. Consulter la documentation du protocole concerné pour implémenter ses mécanismes propres.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { type Book, type BookRepository } from "../../domains";
|
|
3
|
+
|
|
4
|
+
export interface BookRepositoryPort extends BookRepository {
|
|
5
|
+
save<
|
|
6
|
+
GenericEntity extends Book.Entity & Book.Facts,
|
|
7
|
+
>(entity: GenericEntity): Promise<GenericEntity>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const BookRepositoryPort = DInvocation.createPort<BookRepositoryPort>();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { type Client, type ClientRepository } from "../../domains";
|
|
3
|
+
|
|
4
|
+
export interface ClientRepositoryPort extends ClientRepository {
|
|
5
|
+
save<
|
|
6
|
+
GenericEntity extends Client.Entity & Client.Facts,
|
|
7
|
+
>(entity: GenericEntity): Promise<GenericEntity>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const ClientRepositoryPort = DInvocation.createPort<ClientRepositoryPort>();
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { type EmailRepository } from "../../domains";
|
|
3
|
+
|
|
4
|
+
export interface EmailRepositoryPort extends EmailRepository {
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const EmailRepositoryPort = DInvocation.createPort<EmailRepositoryPort>();
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { type Client, clientGiveBackBook } from "../../domains";
|
|
3
|
+
import * as DEither from "@duplojs/lang/either";
|
|
4
|
+
import { BookRepositoryPort, ClientRepositoryPort } from "../ports";
|
|
5
|
+
import * as DCommon from "@duplojs/lang/common";
|
|
6
|
+
|
|
7
|
+
export const ClientGiveBackBookUseCase = DInvocation.createReader(
|
|
8
|
+
{
|
|
9
|
+
BookRepositoryPort,
|
|
10
|
+
ClientRepositoryPort,
|
|
11
|
+
},
|
|
12
|
+
({
|
|
13
|
+
bookRepository,
|
|
14
|
+
clientRepository,
|
|
15
|
+
}) => (
|
|
16
|
+
params: {
|
|
17
|
+
client: Client.Entity & Client.HaveBookFlag;
|
|
18
|
+
},
|
|
19
|
+
) => DEither.rightAsyncPipe(
|
|
20
|
+
clientGiveBackBook(params.client),
|
|
21
|
+
(resolver) => resolver.resolve({ rankBookAvailability: bookRepository.rankAvailability }),
|
|
22
|
+
({ client, book }) => DCommon.promiseObject({
|
|
23
|
+
client: clientRepository.save(client),
|
|
24
|
+
book: bookRepository.save(book),
|
|
25
|
+
}),
|
|
26
|
+
),
|
|
27
|
+
);
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { type Book, type Client, clientRentBook } from "../../domains";
|
|
3
|
+
import * as DEither from "@duplojs/lang/either";
|
|
4
|
+
import { BookRepositoryPort, ClientRepositoryPort, EmailRepositoryPort } from "../ports";
|
|
5
|
+
import * as DCommon from "@duplojs/lang/common";
|
|
6
|
+
|
|
7
|
+
export const ClientRentBookUseCase = DInvocation.createReader(
|
|
8
|
+
{
|
|
9
|
+
BookRepositoryPort,
|
|
10
|
+
ClientRepositoryPort,
|
|
11
|
+
EmailRepositoryPort,
|
|
12
|
+
},
|
|
13
|
+
({
|
|
14
|
+
bookRepository,
|
|
15
|
+
clientRepository,
|
|
16
|
+
emailRepository,
|
|
17
|
+
}) => (
|
|
18
|
+
params: {
|
|
19
|
+
client: Client.Entity & Client.CanRentBookFlag;
|
|
20
|
+
book: Book.Entity & Book.AvailableFlag;
|
|
21
|
+
},
|
|
22
|
+
) => DEither.rightAsyncPipe(
|
|
23
|
+
clientRentBook(params.client, params.book),
|
|
24
|
+
(resolver) => resolver.resolve({ sendInformationalEmail: emailRepository.sendRentInformationalEmail }),
|
|
25
|
+
({ client, book }) => DCommon.promiseObject({
|
|
26
|
+
client: clientRepository.save(client),
|
|
27
|
+
book: bookRepository.save(book),
|
|
28
|
+
}),
|
|
29
|
+
),
|
|
30
|
+
);
|
package/docs/concepts/05-type-driven-design/fixtures/business/applications/useCases/createBook.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { createBook, type Book } from "../../domains";
|
|
3
|
+
import * as DEither from "@duplojs/lang/either";
|
|
4
|
+
import { BookRepositoryPort } from "../ports";
|
|
5
|
+
import * as DCommon from "@duplojs/lang/common";
|
|
6
|
+
|
|
7
|
+
export const CreateBookUseCase = DInvocation.createReader(
|
|
8
|
+
{
|
|
9
|
+
BookRepositoryPort,
|
|
10
|
+
},
|
|
11
|
+
({
|
|
12
|
+
bookRepository,
|
|
13
|
+
}) => (
|
|
14
|
+
params: {
|
|
15
|
+
title: Book.Title;
|
|
16
|
+
},
|
|
17
|
+
) => DEither.rightAsyncPipe(
|
|
18
|
+
DCommon.asyncPipe(
|
|
19
|
+
bookRepository.titleIsAlreadyRegistered(params.title),
|
|
20
|
+
DEither.keepAsRightByInformation(
|
|
21
|
+
"title-not-registered",
|
|
22
|
+
),
|
|
23
|
+
),
|
|
24
|
+
(title) => createBook({
|
|
25
|
+
id: bookRepository.generateId(),
|
|
26
|
+
title,
|
|
27
|
+
}),
|
|
28
|
+
(book) => DCommon.promiseObject({
|
|
29
|
+
book: bookRepository.save(book),
|
|
30
|
+
}),
|
|
31
|
+
),
|
|
32
|
+
);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { ClientGiveBackBook, ReturnBookFact, type Client } from "../entities";
|
|
3
|
+
import * as DEither from "@duplojs/lang/either";
|
|
4
|
+
import { type BookRepository } from "../repositories";
|
|
5
|
+
|
|
6
|
+
export function clientGiveBackBook(
|
|
7
|
+
client: Client.Entity & Client.HaveBookFlag,
|
|
8
|
+
) {
|
|
9
|
+
return DInvocation.createResolver({
|
|
10
|
+
client: DEither.unwrapRight(ClientGiveBackBook.run(client)),
|
|
11
|
+
book: DEither.unwrapRight(ReturnBookFact.run(client)),
|
|
12
|
+
})<{
|
|
13
|
+
rankBookAvailability: BookRepository["rankAvailability"];
|
|
14
|
+
}>();
|
|
15
|
+
}
|
package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/clientRentBook.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { BookRentalFact, ClientRentBookFact, type Book, type Client } from "../entities";
|
|
3
|
+
import * as DEither from "@duplojs/lang/either";
|
|
4
|
+
import { type EmailRepository } from "../repositories/email";
|
|
5
|
+
|
|
6
|
+
export function clientRentBook(
|
|
7
|
+
client: Client.Entity & Client.CanRentBookFlag,
|
|
8
|
+
book: Book.Entity & Book.AvailableFlag,
|
|
9
|
+
) {
|
|
10
|
+
return DInvocation.createResolver({
|
|
11
|
+
client: DEither.unwrapRight(ClientRentBookFact.run(client, book)),
|
|
12
|
+
book: DEither.unwrapRight(BookRentalFact.run(client, book)),
|
|
13
|
+
})<{
|
|
14
|
+
sendInformationalEmail: EmailRepository["sendRentInformationalEmail"];
|
|
15
|
+
}>();
|
|
16
|
+
}
|
package/docs/concepts/05-type-driven-design/fixtures/business/domains/aggregates/createBook.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type * as DInvocation from "@duplojs/lang/invocation";
|
|
2
|
+
import { type BookRepository } from "../repositories";
|
|
3
|
+
import { CreateBookFact } from "../entities";
|
|
4
|
+
|
|
5
|
+
export function createBook(
|
|
6
|
+
params: {
|
|
7
|
+
id: DInvocation.GetEvidenceResult<
|
|
8
|
+
BookRepository["generateId"],
|
|
9
|
+
"generated"
|
|
10
|
+
>;
|
|
11
|
+
title: DInvocation.GetEvidenceResult<
|
|
12
|
+
BookRepository["titleIsAlreadyRegistered"],
|
|
13
|
+
"title-not-registered"
|
|
14
|
+
>;
|
|
15
|
+
},
|
|
16
|
+
) {
|
|
17
|
+
return CreateBookFact.run({
|
|
18
|
+
id: params.id,
|
|
19
|
+
title: params.title,
|
|
20
|
+
});
|
|
21
|
+
}
|
package/docs/concepts/05-type-driven-design/fixtures/business/domains/entities/book/facts/create.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as DModeling from "@duplojs/lang/modeling";
|
|
2
|
+
import { Book } from "..";
|
|
3
|
+
import * as DCommon from "@duplojs/lang/common";
|
|
4
|
+
|
|
5
|
+
export type CreateBookFact = DModeling.Fact<
|
|
6
|
+
"CreateBook",
|
|
7
|
+
{
|
|
8
|
+
id: Book.Id;
|
|
9
|
+
state: Book.AvailableState;
|
|
10
|
+
}
|
|
11
|
+
>;
|
|
12
|
+
export const CreateBookFact = DModeling.createFact<
|
|
13
|
+
CreateBookFact,
|
|
14
|
+
typeof Book.Entity
|
|
15
|
+
>("CreateBook")(
|
|
16
|
+
({ applyFact }) => (
|
|
17
|
+
params: {
|
|
18
|
+
id: Book.Id;
|
|
19
|
+
title: Book.Title;
|
|
20
|
+
},
|
|
21
|
+
) => {
|
|
22
|
+
const payload = {
|
|
23
|
+
id: params.id,
|
|
24
|
+
title: params.title,
|
|
25
|
+
state: Book.AvailableState.new({}),
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
return DCommon.pipe(
|
|
29
|
+
Book.Entity.new(payload),
|
|
30
|
+
Book.AvailableFlag.append(payload.state),
|
|
31
|
+
applyFact(payload),
|
|
32
|
+
);
|
|
33
|
+
},
|
|
34
|
+
);
|