@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,59 @@
|
|
|
1
|
+
# Résultats typés et exceptions
|
|
2
|
+
|
|
3
|
+
## Choisir selon la place de l'échec dans le traitement
|
|
4
|
+
|
|
5
|
+
Identifier les issues prévisibles que l'appelant doit pouvoir exploiter, puis les exprimer dans le contrat `Either`. Un refus peut concerner une règle métier, une vérification ou une manipulation technique. Une opération sur l'environnement ne justifie donc pas à elle seule une exception. Pour la distinction conceptuelle avec une défaillance de l'environnement, lire « Conversion des absences et exceptions en résultats » depuis le routeur du package installé.
|
|
6
|
+
|
|
7
|
+
Lorsqu'une fonction renvoie un `Either` dans une branche, toutes ses branches renvoient un `Either` : `DEither.Right` pour la réussite et `DEither.Left` pour le refus. Envelopper aussi une réussite sans valeur avec `DEither.ok()`, plutôt que retourner `undefined` à côté d'un `Left`. L'information identifie le cas ; la valeur associée transporte les détails utiles. Voir [une fonction qui propage les échecs de lecture](examples/error-propagation.ts).
|
|
8
|
+
|
|
9
|
+
Le `Left` de lecture reste visible dans le type de retour. Une autre fonction peut le propager, l'adapter ou tenter une récupération. Une absence de ressource exploitable par l'algorithme ne devient pas une panne d'environnement parce qu'elle provient d'une I/O. Ne pas la masquer par un `throw` ou un unwrap qui lève.
|
|
10
|
+
|
|
11
|
+
`DEither.rightPipe` et `DEither.rightAsyncPipe` composent les étapes sur les valeurs de réussite et arrêtent au premier `Left`. `DEither.isRight` et `DEither.isLeft` permettent une discrimination explicite avant `unwrapRight` ou `unwrapLeft`.
|
|
12
|
+
|
|
13
|
+
Pour une API qui lève sur un refus prévisible, adapter ses erreurs documentées en résultats. `DEither.safeCallback` et `DEither.asyncSafeCallback` capturent les exceptions ; examiner ensuite la cause pour distinguer le refus attendu d'une défaillance imprévue. Conserver une cause technique capturée dans le résultat jusqu'à sa consommation finale, sans la requalifier en refus métier ni la relancer depuis l'adaptation réutilisable. Préférer d'abord l'API DuploJS sûre si elle existe ; ne pas capturer systématiquement les exceptions des dépendances.
|
|
14
|
+
|
|
15
|
+
## Le consommateur final décide de l'effet
|
|
16
|
+
|
|
17
|
+
La frontière d'exécution consomme le résultat après le retour des fonctions appelées et décide de sa conséquence finale. C'est à ce stade que le code applicatif peut écrire un `throw` ou utiliser `OrThrow` pour interrompre l'exécution. Déclarer une fonction au niveau d'un module ou l'appeler depuis un point d'entrée ne lui donne pas cette responsabilité.
|
|
18
|
+
|
|
19
|
+
Exemples : initialisation du programme, callback d'une commande ou handler d'une route.
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
entrée externe
|
|
23
|
+
→ validation par les schémas du module
|
|
24
|
+
→ point d'entrée du traitement
|
|
25
|
+
→ fonction applicative
|
|
26
|
+
→ sous-fonction : renvoie les issues prévues en Right ou Left
|
|
27
|
+
← résultat typé
|
|
28
|
+
← résultat typé
|
|
29
|
+
→ le point d'entrée décide de l'effet final
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Les fonctions applicatives et leurs sous-fonctions renvoient les refus prévisibles dans leur contrat de retour, sans créer leurs propres `throw`. Les exceptions déjà émises par les dépendances ou le runtime remontent implicitement à travers ces appels ; cette propagation ne demande pas d'ajouter un `throw`.
|
|
33
|
+
|
|
34
|
+
À cette frontière, interpréter le `Left` selon le contrat d'exécution : par exemple produire une réponse HTTP, un diagnostic de commande ou une exception adaptée. Le fait qu'un appelant ignore le retour d'une fonction ne suffit pas à autoriser cette fonction à lever une exception.
|
|
35
|
+
|
|
36
|
+
## Choisir entre version sûre et `OrThrow`
|
|
37
|
+
|
|
38
|
+
Préférer une déclaration sûre pour une valeur connue. Pour une opération qui peut échouer, examiner les branches que `OrThrow` convertirait en exceptions avant de choisir cette variante.
|
|
39
|
+
|
|
40
|
+
| Situation | Choix |
|
|
41
|
+
| --- | --- |
|
|
42
|
+
| Constante dont la validité est prouvable | `cast`, `infer`, helper de déclaration ou surcharge littérale sûre |
|
|
43
|
+
| Vérification d'une donnée externe ou valeur runtime sans preuve | Validation ou fabrique sûre, puis traitement du `Either` |
|
|
44
|
+
| Refus prévisible d'une fonction réutilisable, métier ou technique | Renvoyer, propager ou adapter le `Left` |
|
|
45
|
+
| Exception de défaillance imprévue émise par une dépendance ou le runtime | La laisser remonter implicitement ; propager le résultat si elle a été capturée |
|
|
46
|
+
| Point d'entrée décidant de l'effet final d'un résultat | Interpréter le `Left`, puis produire la réponse, la fin d'exécution ou l'exception adaptée |
|
|
47
|
+
| Test affirmant un résultat attendu | `OrThrow` permet de faire échouer le test si le résultat diffère |
|
|
48
|
+
|
|
49
|
+
La commodité de l'extraction, la rareté supposée d'un refus ou la complexité de propagation ne changent pas sa nature. Une variante qui lève sur une absence exploitable ne convient pas à une fonction réutilisable qui doit transmettre ce cas.
|
|
50
|
+
|
|
51
|
+
## Démarrage et tests : interpréter le résultat
|
|
52
|
+
|
|
53
|
+
Au démarrage, l'initialisation peut décider qu'une configuration invalide empêche l'exécution. `environmentVariableOrThrow` valide d'abord par la version sûre, puis traduit son `Left` en exception. Cet usage exprime la décision finale du point d'entrée ; une fonction qui doit transmettre le refus utilise `environmentVariable`.
|
|
54
|
+
|
|
55
|
+
Voir [la validation de l'environnement au démarrage](examples/environment-initialization.ts). Pour les entrées reçues pendant le fonctionnement du logiciel, conserver les résultats de validation jusqu'à leur interprétation par la frontière concernée.
|
|
56
|
+
|
|
57
|
+
En tests, `OrThrow` peut extraire le résultat attendu ou préparer une fixture : une issue différente doit interrompre le test. Une déclaration sûre reste adaptée aux constantes connues, comme dans [les déclarations sûres](examples/safe-declarations.ts). Le code testé conserve ses résultats ; ces assertions ne justifient pas de le faire lever sur ses refus prévisibles.
|
|
58
|
+
|
|
59
|
+
Pour approfondir, rechercher les `Either`, l'environnement ou le contexte d'exécution concerné dans `docs/concepts.llms.md`, depuis la racine AgentKit indiquée par les instructions du projet.
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: duplojs-http-client
|
|
3
|
+
description: "Appeler une API HTTP DuploJS ou externe avec le client typé de @duplojs/http/client : configurer son contrat, sélectionner les réponses, traiter les erreurs et consommer les flux."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Client HTTP DuploJS
|
|
7
|
+
|
|
8
|
+
## Trouver les concepts
|
|
9
|
+
|
|
10
|
+
Appliquer la démarche du skill et lire les ressources indiquées lorsque leur condition est rencontrée. Pour rechercher un concept ou un mécanisme non couvert, consulter `docs/concepts.llms.md` du package `@duplojs/agents-kit`.
|
|
11
|
+
|
|
12
|
+
Le setup indique ce chemin dans `AGENTS.md` ou `CLAUDE.md`, relativement à leur dossier. Les chemins `docs/` partent du package installé, même avec `--copy`. Les références du skill partent de son dossier ; les liens d'un document se résolvent depuis ce document.
|
|
13
|
+
|
|
14
|
+
Si le chemin du routeur manque, le retrouver depuis le projet consommateur :
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
node --input-type=module -e 'import { fileURLToPath } from "node:url"; console.log(fileURLToPath(import.meta.resolve("@duplojs/agents-kit/docs/concepts.llms.md")))'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Retrouver le contrat et configurer le client
|
|
21
|
+
|
|
22
|
+
Importer `@duplojs/http/client` sous le namespace `DHttpClient`. `createHttpClient<Routes>` reçoit le contrat des méthodes, chemins, entrées et réponses de l'API. Ce contrat peut être généré, écrit à la main ou composé ; le client fonctionne aussi avec un serveur externe à DuploJS.
|
|
23
|
+
|
|
24
|
+
Retrouver les routes consommées et le client existant avant d'en créer un. Pour créer le client ou modifier son contrat et sa configuration, lire [Contrat et configuration](references/configuration.md). L'[exemple d'API externe](references/examples/external-client.ts) montre un contrat écrit à la main et la sélection par code.
|
|
25
|
+
|
|
26
|
+
Le mode Predicted est actif par défaut : les attentes refusent une réponse sans header `predicted`, même si son code ou son information correspond. Pour un fournisseur sans ce marqueur, configurer **`disabledPredictedMode: true`**. Le contrat TypeScript et ce marqueur ne valident pas le body au runtime ; utiliser une data structure lorsque le traitement exige cette garantie.
|
|
27
|
+
|
|
28
|
+
## Sélectionner la réponse et traiter le résultat
|
|
29
|
+
|
|
30
|
+
Chaque appel produit une `PromiseRequest`, sur laquelle les réactions locales s'enregistrent avant la sélection. Une réponse **prévue** appartient au contrat de l'API ; la réponse **voulue** est celle que le traitement accepte à cet endroit. Un refus métier prévu peut donc être rejeté ici.
|
|
31
|
+
|
|
32
|
+
1. Fournir les paramètres typés de l'appel et attacher les hooks ou intercepteurs locaux nécessaires.
|
|
33
|
+
2. Sélectionner le cas voulu avec `iWantInformation`, ou `iWantCode` si l'API ne fournit pas d'information. Pour répartir explicitement toutes les variantes du contrat, utiliser un sélecteur exhaustif.
|
|
34
|
+
3. Attendre le résultat sélectionné. Les attentes sûres renvoient un `Either` ; elles ne renvoient plus une `PromiseRequest` à configurer.
|
|
35
|
+
4. Discriminer le résultat, puis utiliser la réponse voulue ou traiter et propager les autres branches. Une réponse rejetée porte `unexpect-response` ; une erreur de requête porte `request-error`.
|
|
36
|
+
|
|
37
|
+
Pour écrire ou modifier une sélection, lire [Choisir et traiter les réponses](references/responses.md). L'[exemple de sélecteurs](references/examples/client-expectations.ts) distingue les résultats par information ou par code. Dans une fonction réutilisable qui transforme le résultat, conserver toutes les branches sous `Either`, y compris la nouvelle valeur de réussite.
|
|
38
|
+
|
|
39
|
+
## Ajouter les comportements nécessaires
|
|
40
|
+
|
|
41
|
+
| Condition rencontrée | Ressource à lire |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| Un comportement commun ou une réaction locale doit observer ou transformer l'échange | [Hooks et intercepteurs](references/hooks.md), avant de placer la réaction dans le cycle. |
|
|
44
|
+
| La réponse contient des SSE ou des données à recevoir progressivement | [Consommation d'un flux](references/streams.md) et l'[exemple SSE et stream](references/examples/client-streams.ts), avant de lancer la lecture. |
|
|
45
|
+
|
|
46
|
+
Enregistrer les callbacks d'un flux ne démarre pas sa consommation. Après sélection de la réponse, parcourir son itérateur asynchrone ou appeler la méthode de consommation adaptée ; prévoir sa fermeture selon le cycle attendu.
|
|
47
|
+
|
|
48
|
+
## Vérifier l'intégration
|
|
49
|
+
|
|
50
|
+
Exécuter le typage et les vérifications du projet. Vérifier la réponse voulue et les branches de refus ou d'erreur concernées par la modification, y compris l'absence de traitement dépendant après un échec. Contrôler les headers réels du fournisseur pour le mode Predicted et valider le body lorsque le contrat exige une garantie runtime. Pour un flux, vérifier aussi le démarrage de la consommation et sa fermeture.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Contrat et configuration du client
|
|
2
|
+
|
|
3
|
+
Le client HTTP est utilisable partout où une application effectue une requête HTTP, que l'API soit développée avec DuploJS ou avec une autre technologie. `createHttpClient<Routes>` accepte un type compatible avec `ServerRoute` : chaque route décrit sa méthode, son chemin, ses entrées et l'union de ses réponses. Les types peuvent être écrits à la main, importés ou composés. La génération depuis un serveur DuploJS est une façon de produire ce contrat ; elle ne génère pas un client et n'est pas un prérequis à son utilisation. Pour configurer cette génération, utiliser le skill `duplojs-http-server` ou rechercher le partage des contrats HTTP dans `docs/concepts.llms.md` du package installé.
|
|
4
|
+
|
|
5
|
+
Décrire précisément les requêtes et les réponses connues, y compris les erreurs contractuelles. Éviter de perdre ces garanties avec un client non paramétré ou des assertions sur les résultats. Le typage décrit le contrat supposé de l'API ; il n'effectue pas de validation runtime du body. Utiliser une data structure lorsque cette validation est nécessaire.
|
|
6
|
+
|
|
7
|
+
Créer un client par configuration d'API. Y placer l'URL de base, les options globales telles que `credentials` et `cache`, les headers par défaut et les hooks transversaux. Un header peut être calculé à chaque requête, par exemple pour récupérer le token courant. Les paramètres d'un appel peuvent préciser ses headers, ses options `initParams` et son `abortController`. Voir [un client pour une API externe](examples/external-client.ts), avec un contrat écrit à la main, sans header `information` ni `predicted`.
|
|
8
|
+
|
|
9
|
+
Pour les exemples complémentaires de configuration et d’envoi de formulaires, rechercher le client HTTP dans `docs/concepts.llms.md` du package installé.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Choisir les réponses voulues depuis une PromiseRequest.
|
|
3
|
+
*
|
|
4
|
+
* Les sélecteurs imposent un choix pour chaque cas du contrat de la requête.
|
|
5
|
+
*/
|
|
6
|
+
import * as DHttpClient from "@duplojs/http/client";
|
|
7
|
+
import * as DEither from "@duplojs/lang/either";
|
|
8
|
+
import type * as DCommon from "@duplojs/lang/common";
|
|
9
|
+
|
|
10
|
+
interface Routes {
|
|
11
|
+
method: "GET";
|
|
12
|
+
path: "/profile";
|
|
13
|
+
responses: {
|
|
14
|
+
code: "200";
|
|
15
|
+
information: "profile.found";
|
|
16
|
+
body: { name: string };
|
|
17
|
+
} | {
|
|
18
|
+
code: "401";
|
|
19
|
+
information: "auth.required";
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const client = DHttpClient.createHttpClient<Routes>({
|
|
24
|
+
baseUrl: "https://duplo-api.example.com",
|
|
25
|
+
// Le mode Predicted reste actif pour cette API DuploJS.
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
export function requestProfile(onAuthenticationRequired: () => void) {
|
|
29
|
+
return client.get("/profile")
|
|
30
|
+
.addRequestInterceptor((params) => ({
|
|
31
|
+
...params,
|
|
32
|
+
headers: {
|
|
33
|
+
...params.headers,
|
|
34
|
+
"x-request-source": "profile-page",
|
|
35
|
+
},
|
|
36
|
+
}))
|
|
37
|
+
.whenInformation("auth.required", onAuthenticationRequired);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function selectProfile(onAuthenticationRequired: () => void) {
|
|
41
|
+
const result = await requestProfile(onAuthenticationRequired)
|
|
42
|
+
.toEitherByInformation({
|
|
43
|
+
"profile.found": true,
|
|
44
|
+
"auth.required": false,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (DEither.hasInformation(result, "profile.found")) {
|
|
48
|
+
const response = DEither.unwrapRight(result);
|
|
49
|
+
|
|
50
|
+
type _CheckCode = DCommon.ExpectType<typeof response.code, "200", "strict">;
|
|
51
|
+
type _CheckBody = DCommon.ExpectType<typeof response.body, { name: string }, "strict">;
|
|
52
|
+
|
|
53
|
+
return DEither.success(response.body);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Les autres branches portent unexpect-response ou request-error.
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export async function classifyProfileByCode() {
|
|
61
|
+
const result = await client.get("/profile").toEitherByCode({
|
|
62
|
+
200: true,
|
|
63
|
+
401: true,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Une erreur métier peut être un résultat voulu à cet endroit du programme.
|
|
67
|
+
if (DEither.hasInformation(result, "response-401")) {
|
|
68
|
+
const response = DEither.unwrapRight(result);
|
|
69
|
+
|
|
70
|
+
type _CheckInformation = DCommon.ExpectType<typeof response.information, "auth.required", "strict">;
|
|
71
|
+
void response;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return result;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Illustration de compilation, sans créer de requête supplémentaire.
|
|
78
|
+
export function checkSelectorContract(request: ReturnType<typeof client.get>) {
|
|
79
|
+
// @ts-expect-error Le sélecteur doit aussi décider du cas auth.required.
|
|
80
|
+
void request.toEitherByInformation({ "profile.found": true });
|
|
81
|
+
|
|
82
|
+
// @ts-expect-error Le sélecteur doit aussi décider du code 401.
|
|
83
|
+
void request.toEitherByCode({ 200: true });
|
|
84
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Consommer des événements SSE et un stream typés.
|
|
3
|
+
*
|
|
4
|
+
* La sélection de la réponse précède la lecture progressive du flux.
|
|
5
|
+
*/
|
|
6
|
+
import * as DHttpClient from "@duplojs/http/client";
|
|
7
|
+
import * as DEither from "@duplojs/lang/either";
|
|
8
|
+
import type * as DCommon from "@duplojs/lang/common";
|
|
9
|
+
|
|
10
|
+
type Routes = {
|
|
11
|
+
method: "GET";
|
|
12
|
+
path: "/events";
|
|
13
|
+
responses: {
|
|
14
|
+
code: "200";
|
|
15
|
+
information: "events.open";
|
|
16
|
+
events: {
|
|
17
|
+
progress: { percent: number };
|
|
18
|
+
finished: { id: string };
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
} | {
|
|
22
|
+
method: "GET";
|
|
23
|
+
path: "/text-stream";
|
|
24
|
+
responses: {
|
|
25
|
+
code: "200";
|
|
26
|
+
information: "text.open";
|
|
27
|
+
flux: string;
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const client = DHttpClient.createHttpClient<Routes>({
|
|
32
|
+
baseUrl: "https://duplo-api.example.com",
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export async function consumeEvents(onProgress: (percent: number) => void) {
|
|
36
|
+
const result = await client.get("/events").iWantInformation("events.open");
|
|
37
|
+
|
|
38
|
+
if (DEither.isLeft(result)) {
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const response = DEither.unwrapRight(result);
|
|
43
|
+
response.onReceiveEvent("progress", (event) => {
|
|
44
|
+
type _CheckData = DCommon.ExpectType<typeof event.data, { percent: number }, "strict">;
|
|
45
|
+
|
|
46
|
+
onProgress(event.data.percent);
|
|
47
|
+
});
|
|
48
|
+
response.onReceiveEvent("finished", (_event, stream) => {
|
|
49
|
+
stream.closeEventStream();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// Enregistrer les callbacks ne démarre pas la lecture.
|
|
53
|
+
await response.consumeEventStream();
|
|
54
|
+
return DEither.ok();
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function consumeText(onChunk: (chunk: string) => void) {
|
|
58
|
+
// Cette réponse fournit predicted, x-duplojs-body-options: stream
|
|
59
|
+
// et un content-type text/plain, cohérents avec le contrat flux: string.
|
|
60
|
+
const result = await client.get("/text-stream").iWantInformation("text.open");
|
|
61
|
+
|
|
62
|
+
if (DEither.isLeft(result)) {
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const response = DEither.unwrapRight(result);
|
|
67
|
+
for await (const chunk of response) {
|
|
68
|
+
type _CheckChunk = DCommon.ExpectType<typeof chunk, string, "strict">;
|
|
69
|
+
|
|
70
|
+
onChunk(chunk);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return DEither.ok();
|
|
74
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Typer une API externe sans génération DuploJS.
|
|
3
|
+
*
|
|
4
|
+
* Le contrat est écrit à la main ; les réponses n'ont aucun header DuploJS.
|
|
5
|
+
*/
|
|
6
|
+
import * as DHttpClient from "@duplojs/http/client";
|
|
7
|
+
import * as DEither from "@duplojs/lang/either";
|
|
8
|
+
import type * as DCommon from "@duplojs/lang/common";
|
|
9
|
+
|
|
10
|
+
interface ExternalRoutes {
|
|
11
|
+
method: "GET";
|
|
12
|
+
path: "/users/{userId}";
|
|
13
|
+
params: {
|
|
14
|
+
userId: number;
|
|
15
|
+
};
|
|
16
|
+
responses: {
|
|
17
|
+
code: "200";
|
|
18
|
+
// Rendre l'absence explicite préserve l'inférence avec l'API actuelle.
|
|
19
|
+
information?: undefined;
|
|
20
|
+
body: {
|
|
21
|
+
id: number;
|
|
22
|
+
name: string;
|
|
23
|
+
};
|
|
24
|
+
} | {
|
|
25
|
+
code: "404";
|
|
26
|
+
information?: undefined;
|
|
27
|
+
body: {
|
|
28
|
+
message: string;
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const externalClient = DHttpClient.createHttpClient<ExternalRoutes>({
|
|
34
|
+
baseUrl: "https://api.example.com",
|
|
35
|
+
// L'API ne fournit pas le marqueur de réponses prévues.
|
|
36
|
+
disabledPredictedMode: true,
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export function configureExternalClient(getToken: () => string) {
|
|
40
|
+
externalClient.addDefaultHeader("authorization", () => `Bearer ${getToken()}`);
|
|
41
|
+
// Transformer ici les options communes à tous les appels de cette API.
|
|
42
|
+
externalClient.addRequestHook((params) => ({
|
|
43
|
+
...params,
|
|
44
|
+
initParams: {
|
|
45
|
+
...params.initParams,
|
|
46
|
+
credentials: "omit",
|
|
47
|
+
},
|
|
48
|
+
}));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function readExternalUser(userId: number) {
|
|
52
|
+
const result = await externalClient
|
|
53
|
+
.get("/users/{userId}", { params: { userId } })
|
|
54
|
+
.whenCode("404", ({ body }) => {
|
|
55
|
+
type _CheckError = DCommon.ExpectType<typeof body, { message: string }, "strict">;
|
|
56
|
+
console.log(body.message);
|
|
57
|
+
})
|
|
58
|
+
.iWantCode("200");
|
|
59
|
+
|
|
60
|
+
if (DEither.isRight(result)) {
|
|
61
|
+
const response = DEither.unwrapRight(result);
|
|
62
|
+
|
|
63
|
+
type _CheckBody = DCommon.ExpectType<
|
|
64
|
+
typeof response.body,
|
|
65
|
+
{
|
|
66
|
+
id: number;
|
|
67
|
+
name: string;
|
|
68
|
+
},
|
|
69
|
+
"strict"
|
|
70
|
+
>;
|
|
71
|
+
|
|
72
|
+
return DEither.success(response.body);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Le 404 et les autres réponses reçues restent accessibles via unexpect-response.
|
|
76
|
+
// Les erreurs de transport ou de traitement portent request-error.
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Placer les hooks et intercepteurs
|
|
2
|
+
|
|
3
|
+
Le client porte les comportements communs : `addRequestHook`, `addResponseHook`, `addErrorHook` et les hooks ciblant une information, un code ou une famille de réponses. Les hooks de requête et de réponse peuvent transformer leur entrée ; retourner la valeur destinée à la suite du cycle. Les réactions globales telles que les loaders ou la journalisation se placent à ce niveau.
|
|
4
|
+
|
|
5
|
+
Chaque appel retourne une `PromiseRequest`, représentation de cet échange. Lui attacher immédiatement les traitements locaux avant `await` : les `when*` enregistrent des callbacks et renvoient la même `PromiseRequest`. Ils permettent de composer plusieurs réactions sans sélectionner ni extraire le résultat. `addRequestInterceptor` et `addResponseInterceptor` permettent les transformations locales. `whenError` traite une erreur de requête ; `whenNotPredictedResponse` observe une réponse sans marqueur lorsque le mode de réponses prévues est actif.
|
|
6
|
+
|
|
7
|
+
Après les hooks locaux, choisir l’attente ou le sélecteur selon [le résultat voulu](responses.md). Pour ajouter un loader ou une instrumentation globale, lire `docs/concepts/03-client/10-http/30-hook.ts` depuis le package installé : cet exemple suit les effets communs pendant le cycle d'un échange.
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Choisir et traiter les réponses
|
|
2
|
+
|
|
3
|
+
## Attentes et sélecteurs
|
|
4
|
+
|
|
5
|
+
Les méthodes d'attente transforment ensuite le résultat en une promesse de réponse ou d'`Either`. Choisir l'attente après les hooks locaux ; un appel à `iWant*` ne renvoie plus une `PromiseRequest`. Voir [les attentes et sélecteurs](examples/client-expectations.ts).
|
|
6
|
+
|
|
7
|
+
| Besoin | Choix et résultat après `await` |
|
|
8
|
+
| --- | --- |
|
|
9
|
+
| Réagir à un cas sans modifier le résultat | `whenInformation`, `whenCode` ou une famille `when*` ; callback avec la réponse ciblée |
|
|
10
|
+
| Exiger un cas précis | `iWantInformation` ou `iWantCode` ; `Right<"response", RéponseVoulue>` ou un `Left` |
|
|
11
|
+
| À la consommation finale du résultat, obtenir la réponse ou interrompre l'exécution | Variante `OrThrow` ; réponse voulue ou exception. Dans une fonction réutilisable, conserver le `Either`. |
|
|
12
|
+
| Répartir toutes les informations du contrat entre résultats voulus et non voulus | `iSelectExpectedResponseByInformation` ; sélecteur exhaustif `true` / `false`, résultat sous `Either` |
|
|
13
|
+
| Discriminer les `Right` par l'information de la réponse | `toEitherByInformation` ; sélecteur exhaustif, `Right<Information, Réponse>` pour les entrées `true` |
|
|
14
|
+
| Discriminer les `Right` par le code HTTP | `toEitherByCode` ; sélecteur exhaustif, `Right<"response-<code>", Réponse>` pour les entrées `true` |
|
|
15
|
+
|
|
16
|
+
Les sélecteurs exigent une décision pour chaque information ou code déclaré dans les réponses de la requête. Une évolution du contrat impose ainsi de revoir ce choix. `false` conserve la réponse dans un `Left<"unexpect-response", ...>` ; les erreurs de requête restent des `Left<"request-error", ...>`. Les `Left` ne prennent pas le nom de l'information ou du code rejeté. Traiter ces branches avec les outils `Either` ; une réponse non voulue n'est pas supprimée silencieusement. Les variantes `OrThrow` lèvent une erreur pour ces branches, y compris les erreurs de requête.
|
|
17
|
+
|
|
18
|
+
La famille `ExpectedResponse` sans sélecteur (`whenExpectedResponse`, `iWantExpectedResponse`) regroupe les codes `2xx` et `4xx`. Elle ne signifie pas « tous les codes déclarés dans le contrat » et ne remplace pas le choix des cas utiles à l'application. Pour un scénario précis, sélectionner l'information attendue, ou le code si l'API ne fournit pas d'information.
|
|
19
|
+
|
|
20
|
+
## Réponses prévues et mode Predicted
|
|
21
|
+
|
|
22
|
+
Une réponse **prévue** appartient aux réponses contractuelles de l'API. Elle peut être un succès ou une erreur métier, par exemple un `404` déclaré. Une réponse **voulue** est celle que le consommateur décide d'accepter à cet endroit du programme. Une réponse prévue peut donc être rejetée par un sélecteur.
|
|
23
|
+
|
|
24
|
+
DuploJS marque ses réponses contractuelles : les réponses `PredictedResponse` et leurs équivalents SSE et stream conduisent le serveur à ajouter le header `predicted`. Cette classe marque la réponse ; elle n'ajoute pas de traitement métier. Une erreur de parsing du body ou une erreur interne hors contrat peut produire une réponse imprévue. Son code ou son information peut coïncider avec celui d'une réponse déclarée, sans garantir le même body.
|
|
25
|
+
|
|
26
|
+
Par défaut, `disabledPredictedMode` vaut `false`. Le client vérifie la **présence** du header indiqué par `predictedHeaderKey` (`predicted` par défaut). Sans ce header, les hooks ciblés par information, code ou famille ne s'exécutent pas et les attentes et sélecteurs renvoient `Left<"unexpect-response", ...>`, même si le code ou l'information correspond. Cela évite d'utiliser sous un type contractuel le contenu d'une autre réponse. Les hooks généraux de réponse et le hook dédié aux réponses imprévues restent disponibles.
|
|
27
|
+
|
|
28
|
+
Cette règle concerne les attentes : un `await` direct sur la `PromiseRequest`, sans sélection, conserve une réponse HTTP reçue dans un `Right<"response", ...>`, y compris sans marqueur. Utiliser une attente pour obtenir la réponse correspondant au besoin ; ne pas confondre réception d'une réponse et acceptation de son contrat.
|
|
29
|
+
|
|
30
|
+
## Adapter le client au protocole du fournisseur
|
|
31
|
+
|
|
32
|
+
Pour une API **sans ce marqueur**, créer son client avec `disabledPredictedMode: true`. Les attentes se fondent alors sur le code ou l'information sans imposer le header. Sans information de réponse, sélectionner par code. Si seuls les noms des headers diffèrent, configurer `predictedHeaderKey` et `informationHeaderKey` selon le protocole de l'API. Conserver le mode actif pour une API DuploJS qui fournit le marqueur.
|
|
33
|
+
|
|
34
|
+
Le marqueur est une convention du protocole, pas une validation du contenu ni une preuve d'authenticité. Le body reste à valider lorsque le traitement exige une garantie runtime.
|
|
35
|
+
|
|
36
|
+
## Particularité d'inférence d'un contrat sans information
|
|
37
|
+
|
|
38
|
+
Avec l'API actuelle, un contrat de réponses sans header d'information doit déclarer explicitement `information?: undefined` dans chaque réponse pour conserver leur inférence. L'[exemple d'API externe](examples/external-client.ts) applique cette forme et sélectionne par code. Cette déclaration répond au typage de l'API cliente ; elle n'ajoute aucun header au protocole.
|
|
39
|
+
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Consommer progressivement un flux
|
|
2
|
+
|
|
3
|
+
Décrire les événements SSE avec `responses.events` et les données d'un stream avec `responses.flux`. Après sélection de la réponse, consommer l'itérateur asynchrone pour traiter les éléments au fur et à mesure, ou enregistrer les callbacks puis lancer la consommation. Voir [SSE et stream](examples/client-streams.ts).
|
|
4
|
+
|
|
5
|
+
- **SSE** : `onReceiveEvent` cible un événement typé, `onStreamEvent` observe le cycle, `consumeEventStream` lance la lecture et `closeEventStream` ferme le flux. La réponse est reconnue par le content-type `text/event-stream`.
|
|
6
|
+
- **Stream** : `onStream` observe notamment `receiveData`, `consumeStream` lance la lecture et `closeStream` ferme le flux. Cette couche est activée par le header `x-duplojs-body-options` contenant `stream` ; les chunks sont décodés en texte si le content-type contient `text`, sinon ils restent des `Uint8Array`. Les chunks ne sont pas nécessairement des messages applicatifs complets : gérer le découpage si le protocole l'exige.
|
|
7
|
+
|
|
8
|
+
`whenReceiveServerEvent` et `whenReceiveDataStream` permettent aussi d'attacher les callbacks depuis la `PromiseRequest` ; ils ne lancent pas à eux seuls la consommation. Les hooks globaux du client peuvent instrumenter le démarrage, la réception, les erreurs et la fermeture. Le mode de réponses prévues s'applique également à ces réponses : le désactiver pour un fournisseur sans marqueur. Le typage seul ne transforme pas un flux arbitraire en SSE ou en stream reconnu par cette couche ; vérifier les headers et le format de l'API.
|
|
9
|
+
|
|
10
|
+
Pour choisir la réponse avant sa consommation, consulter [les attentes et le mode Predicted](responses.md).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: duplojs-http-server
|
|
3
|
+
description: "Créer ou modifier des routes et un serveur HTTP DuploJS : Hub, entrées validées, réponses contractuelles, traitements réutilisables et génération des contrats partagés."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Serveur HTTP DuploJS
|
|
7
|
+
|
|
8
|
+
## Trouver les concepts
|
|
9
|
+
|
|
10
|
+
Appliquer la démarche du skill et lire les ressources indiquées lorsque leur condition est rencontrée. Pour rechercher un concept ou un mécanisme non couvert, consulter `docs/concepts.llms.md` du package `@duplojs/agents-kit`.
|
|
11
|
+
|
|
12
|
+
Le setup indique ce chemin dans `AGENTS.md` ou `CLAUDE.md`, relativement à leur dossier. Les chemins `docs/` partent du package installé, même avec `--copy`. Les références du skill partent de son dossier ; les liens d'un document se résolvent depuis ce document.
|
|
13
|
+
|
|
14
|
+
Si le chemin du routeur manque, le retrouver depuis le projet consommateur :
|
|
15
|
+
|
|
16
|
+
```sh
|
|
17
|
+
node --input-type=module -e 'import { fileURLToPath } from "node:url"; console.log(fileURLToPath(import.meta.resolve("@duplojs/agents-kit/docs/concepts.llms.md")))'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Construire le flux d'une route
|
|
21
|
+
|
|
22
|
+
Partir de la route concernée, de ses entrées et de ses réponses attendues. Reprendre le builder de sa famille dans le projet : il peut déjà porter des préconditions communes. Pour une route sans politique commune, utiliser `useRouteBuilder`.
|
|
23
|
+
|
|
24
|
+
Une route enchaîne des étapes qui enrichissent un contexte typé, le **floor**. Chaque étape reçoit les données garanties par les précédentes. Une réponse termine le flux ; dans un `cut`, `output(...)` enrichit le floor et permet de continuer.
|
|
25
|
+
|
|
26
|
+
1. Déclarer les entrées avec `.extract` et les data structures du contrat. L'extraction les valide avant de poursuivre.
|
|
27
|
+
2. Préparer les préconditions et traiter les refus dans les étapes précédant le handler. Un `.cut` convient à une adaptation propre au scénario courant ; reprendre les traitements réutilisables existants lorsqu'ils portent la même responsabilité.
|
|
28
|
+
3. Déclarer chaque réponse avec un `ResponseContract` : statut, `information` discriminante et schéma du body éventuel.
|
|
29
|
+
4. Terminer le chemin de réussite avec `.handler` et son outil `response`.
|
|
30
|
+
|
|
31
|
+
Pour créer une route ou modifier ses extractions et étapes, lire [Routes et floor](references/routes-and-floor.md). La [route minimale](references/examples/minimal-route.ts) montre validation et réponse sans dépendance applicative ; la [route de modification](references/examples/rename-user-route.ts) adapte un résultat applicatif en amont du handler.
|
|
32
|
+
|
|
33
|
+
## Raccorder l'application
|
|
34
|
+
|
|
35
|
+
La route est un point d'entrée d'infrastructure : elle adapte les données validées aux capacités de l'application, appelle les traitements prévus et traduit leurs résultats vers HTTP. Elle peut établir une précondition avec une qualification du domaine. L'orchestration métier et les transitions restent dans leurs couches ; ne pas les réimplémenter dans les steps.
|
|
36
|
+
|
|
37
|
+
Traiter les résultats attendus avec les outils `Either` et les réponses contractuelles. Les fonctions réutilisables conservent leurs échecs typés ; une réponse HTTP relève du flux HTTP qui les consomme.
|
|
38
|
+
|
|
39
|
+
Si la tâche raccorde un domaine existant ou modifie une responsabilité métier, appliquer le skill `duplojs-modeling` lorsqu'il est installé, ou lire `docs/concepts/05-type-driven-design/01-architecture/10-boundaries.md`.
|
|
40
|
+
|
|
41
|
+
## Réutiliser au niveau approprié
|
|
42
|
+
|
|
43
|
+
| Ce qui doit être réutilisé | Mécanisme |
|
|
44
|
+
| --- | --- |
|
|
45
|
+
| Une opération avec plusieurs résultats, interprétés différemment selon la route | Checker créé par `useCheckerBuilder`, appelé avec `.check`. |
|
|
46
|
+
| La sélection d'un résultat de checker et sa réponse HTTP d'échec | Preset créé par `createPresetChecker`, appelé avec `.presetCheck`. |
|
|
47
|
+
| Une séquence d'étapes et les données qu'elle garantit | Process créé par `useProcessBuilder`, appelé avec `.exec`. |
|
|
48
|
+
| Des processus appliqués avant chaque route d'une famille | `usePreflightBuilder`, puis sa fonction `useRouteBuilder`. |
|
|
49
|
+
|
|
50
|
+
Quand l'un de ces besoins apparaît, lire [Checkers, processus et builders communs](references/reusable-flows.md) avant de l'assembler. Éviter de recopier des `cut` portant la même opération et la même réponse. L'[exemple de preflight](references/examples/authentication.ts) et la [route protégée](references/examples/protected-route.ts) montrent comment transmettre les garanties d'une séquence commune.
|
|
51
|
+
|
|
52
|
+
## Assembler et démarrer le serveur
|
|
53
|
+
|
|
54
|
+
Le `Hub` rassemble les routes, les plugins et leur cycle de vie indépendamment du runtime. Créer le Hub avec `createHub`, ajouter les plugins avec `.plug` et les routes avec `.register`, puis appeler le connecteur de l'environnement. Sur Node, utiliser `createHttpServer` depuis `@duplojs/http/node`.
|
|
55
|
+
|
|
56
|
+
Au démarrage, valider la configuration avec `DSCommon.environmentVariableOrThrow` depuis `@duplojs/server/common`, puis fournir les valeurs au Hub et au connecteur. Pour les sources d'environnement et les interactions système, consulter `duplojs-server` ou les concepts serveur du routeur.
|
|
57
|
+
|
|
58
|
+
Si la tâche touche le démarrage ou l'enregistrement des routes, lire [Initialisation et enregistrement](references/initialization.md) et l'[exemple minimal](references/examples/initialize.ts). Avec `routeStore.getAll()`, importer d'abord les modules de routes : le store collecte les déclarations finalisées par `.handler`, sans découvrir ni importer leurs fichiers.
|
|
59
|
+
|
|
60
|
+
## Partager les contrats et les schémas
|
|
61
|
+
|
|
62
|
+
Lorsque la tâche partage des types de routes ou des schémas, lire [Génération et consommation des contrats](references/code-generation.md) et l'[exemple de génération](references/examples/generate-sdk.ts). `codeGeneratorPlugin` produit ces ressources à partir des contrats du serveur ; il ne crée pas d'instance de client. Sa configuration seule ne lance pas la génération : celle-ci dépend du cycle de vie du Hub. Pour consommer l'API, utiliser le skill `duplojs-http-client` ou les concepts du client HTTP.
|
|
63
|
+
|
|
64
|
+
## Vérifier le flux exposé
|
|
65
|
+
|
|
66
|
+
Exécuter le typage et les vérifications du projet. Vérifier que la route est effectivement enregistrée, qu'une entrée invalide est refusée et que chaque issue concernée produit le statut, l'information et le body déclarés. Vérifier aussi qu'un refus arrête les étapes dépendantes. Si la tâche touche la génération, exécuter celle-ci en `BUILD` puis vérifier les fichiers produits et leur utilisation depuis le consommateur.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Générer et consommer les contrats
|
|
2
|
+
|
|
3
|
+
## Une source de vérité dans les routes
|
|
4
|
+
|
|
5
|
+
Le plugin `codeGeneratorPlugin`, importé depuis `@duplojs/http/codeGenerator`, produit le contrat TypeScript des routes enregistrées sur le Hub. Les entrées et les réponses déclarées dans les étapes alimentent ce contrat ; maintenir aussi les contrats des échecs prévus.
|
|
6
|
+
|
|
7
|
+
`outputFile` choisit le fichier de types généré. `generateStructure.outputFolder` active aussi la génération de data structures réutilisables au runtime. Voir [la génération pour un SDK](examples/generate-sdk.ts).
|
|
8
|
+
|
|
9
|
+
Les types permettent de construire un client déjà informé des méthodes, chemins, paramètres et réponses. Les structures permettent de partager les mêmes schémas de validation avec un consommateur, par exemple dans un SDK utilisé par une autre application.
|
|
10
|
+
|
|
11
|
+
## Identifier les structures à partager
|
|
12
|
+
|
|
13
|
+
Donner un identifiant stable aux structures exportables avec `.addIdentifier(...)`, qui retourne une copie nommée. Cette méthode est ajoutée par l'extension `@duplojs/tools/toTypescript` : importer explicitement cette extension dans le module qui appelle la méthode. Les [contrats ordinaires](examples/contracts.ts) restent utilisables sans cette extension ; le [point d'entrée de génération](examples/generate-sdk.ts) crée leurs copies nommées pour le SDK.
|
|
14
|
+
|
|
15
|
+
L'exemple fournit ces copies avec `generateStructure.structures` et active `generateStructure.disabledFromRoute` pour limiter la génération à cette sélection. Pour une découverte depuis les routes, conserver cette option désactivée et employer les structures identifiées dans les contrats des routes ; le générateur parcourt aussi leurs sous-structures. Ne pas supposer qu'un schéma anonyme produira un export nommé. Vérifier les capacités de génération des structures et contraintes personnalisées dans la documentation des outils.
|
|
16
|
+
|
|
17
|
+
Réserver le dossier de sortie aux fichiers générés : le plugin remplace ce dossier pendant la génération. Garder les sources écrites à la main ailleurs.
|
|
18
|
+
|
|
19
|
+
## Déclencher la génération
|
|
20
|
+
|
|
21
|
+
Importer les modules de routes, enregistrer les routes et brancher le plugin avant de démarrer le cycle avec le connecteur. Le plugin travaille sur le hook `beforeStartServer`, dans les environnements `DEV` et `BUILD` ; créer le Hub et le plugin sans appeler le connecteur ne suffit pas.
|
|
22
|
+
|
|
23
|
+
Pour un script de génération, utiliser `BUILD`. L'[exemple Node](examples/generate-sdk.ts) appelle `createHttpServer` dans ce mode : le cycle et la génération s'exécutent sans ouvrir l'écoute HTTP. Le Hub doit contenir des routes pour que le plugin produise les fichiers attendus.
|
|
24
|
+
|
|
25
|
+
Les routes de cet exemple déclarent certaines capacités avec `declare function` : elles démontrent leurs contrats sans fournir d'implémentation applicative. La génération n'exécute pas leurs handlers. Pour servir ces routes, raccorder les capacités réelles ; pour démarrer un exemple autonome, utiliser [l'initialisation minimale](examples/initialize.ts).
|
|
26
|
+
|
|
27
|
+
## Distribuer et utiliser le résultat
|
|
28
|
+
|
|
29
|
+
Publier les types et structures générés dans le package consommateur ou le SDK selon son organisation. Importer le type généré `Routes` pour paramétrer `createHttpClient` depuis `@duplojs/http/client`, et importer les structures générées lorsque le consommateur doit valider des données. Garder ces ressources issues de la génération, sans recopier à la main les contrats du serveur.
|
|
30
|
+
|
|
31
|
+
Pour le raccordement concret du client, ses sélecteurs et les API sans contrats générés, utiliser le skill `duplojs-http-client` ou rechercher le client HTTP dans `docs/concepts.llms.md` du package installé. Pour les options de génération, rechercher le partage des contrats HTTP et les outils de transformation des data structures dans `docs/concepts.llms.md`.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Équiper une famille de routes d'un processus commun.
|
|
3
|
+
*
|
|
4
|
+
* Le preflight exporte une fonction qui crée des routes avec authentification.
|
|
5
|
+
*/
|
|
6
|
+
import { ResponseContract, useCheckerBuilder, usePreflightBuilder, useProcessBuilder } from "@duplojs/http";
|
|
7
|
+
import * as DDataStructure from "@duplojs/lang/dataStructure";
|
|
8
|
+
import * as DEither from "@duplojs/lang/either";
|
|
9
|
+
import { type User } from "./contracts";
|
|
10
|
+
|
|
11
|
+
// La politique de vérification est fournie par l'application.
|
|
12
|
+
declare function authenticateToken(token: string): Promise<DEither.Success<User> | DEither.Fail>;
|
|
13
|
+
|
|
14
|
+
const tokenChecker = useCheckerBuilder()
|
|
15
|
+
.handler(async(token: string, { output }) => {
|
|
16
|
+
const result = await authenticateToken(token);
|
|
17
|
+
|
|
18
|
+
return DEither.whenIsRightOtherwise(
|
|
19
|
+
result,
|
|
20
|
+
(user) => output("token.valid", user),
|
|
21
|
+
() => output("token.invalid", null),
|
|
22
|
+
);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export const authenticationProcess = useProcessBuilder()
|
|
26
|
+
.extract({
|
|
27
|
+
headers: {
|
|
28
|
+
authorization: DDataStructure.string(),
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
.check(tokenChecker, {
|
|
32
|
+
input: ({ authorization }) => authorization,
|
|
33
|
+
result: "token.valid",
|
|
34
|
+
otherwise: ResponseContract.unauthorized("authentication.invalid"),
|
|
35
|
+
indexing: "user",
|
|
36
|
+
})
|
|
37
|
+
// authorization reste interne au process ; seul user est exposé.
|
|
38
|
+
.exports(["user"]);
|
|
39
|
+
|
|
40
|
+
export const useAuthenticatedRouteBuilder = usePreflightBuilder()
|
|
41
|
+
.exec(authenticationProcess, { imports: ["user"] })
|
|
42
|
+
.useRouteBuilder;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Définir les contrats partagés des exemples HTTP.
|
|
3
|
+
*
|
|
4
|
+
* Les routes partagent leurs schémas sans dépendre d'une génération de SDK.
|
|
5
|
+
*/
|
|
6
|
+
import * as DDataStructure from "@duplojs/lang/dataStructure";
|
|
7
|
+
|
|
8
|
+
export const userStructure = DDataStructure.object({
|
|
9
|
+
id: DDataStructure.string([DDataStructure.uuid()]),
|
|
10
|
+
name: DDataStructure.string([DDataStructure.minCharacters(3)]),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type User = DDataStructure.StructureValue<typeof userStructure>;
|
|
14
|
+
|
|
15
|
+
export const renameUserBody = DDataStructure.object({
|
|
16
|
+
name: DDataStructure.string([DDataStructure.minCharacters(3)]),
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export type RenameUserBody = DDataStructure.StructureValue<typeof renameUserBody>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @title Générer les contrats et les schémas d'un SDK.
|
|
3
|
+
*
|
|
4
|
+
* Déclencher le cycle du Hub en BUILD pour générer sans écoute HTTP.
|
|
5
|
+
*/
|
|
6
|
+
import "@duplojs/tools/toTypescript";
|
|
7
|
+
import "./user-route";
|
|
8
|
+
import "./rename-user-route";
|
|
9
|
+
import { createHub, routeStore } from "@duplojs/http";
|
|
10
|
+
import { createHttpServer } from "@duplojs/http/node";
|
|
11
|
+
import { codeGeneratorPlugin } from "@duplojs/http/codeGenerator";
|
|
12
|
+
import * as DPath from "@duplojs/lang/path";
|
|
13
|
+
import { renameUserBody, userStructure } from "./contracts";
|
|
14
|
+
|
|
15
|
+
// Les dossiers parents de sortie sont préparés par le projet.
|
|
16
|
+
const hub = createHub({ environment: "BUILD" })
|
|
17
|
+
.register(routeStore.getAll())
|
|
18
|
+
.plug(codeGeneratorPlugin({
|
|
19
|
+
outputFile: DPath.declarePath("sdk/routes.d.ts"),
|
|
20
|
+
generateStructure: {
|
|
21
|
+
// Ce dossier contient exclusivement les sources générées.
|
|
22
|
+
outputFolder: DPath.declarePath("sdk/dataStructures"),
|
|
23
|
+
// L'extension est chargée dans ce module, avant ces appels.
|
|
24
|
+
// Les copies nommées ne modifient pas les schémas des routes.
|
|
25
|
+
structures: [
|
|
26
|
+
userStructure.addIdentifier("User"),
|
|
27
|
+
renameUserBody.addIdentifier("RenameUserBody"),
|
|
28
|
+
],
|
|
29
|
+
disabledFromRoute: true,
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
await createHttpServer(hub, {
|
|
34
|
+
host: "localhost",
|
|
35
|
+
port: 1506,
|
|
36
|
+
});
|