fix: preserve logical mutation intent

This commit is contained in:
DongHyeonka
2026-08-02 01:07:19 +09:00
parent 53d181fbe4
commit cbcc7b5ed7
21 changed files with 724 additions and 96 deletions
@@ -1,6 +1,7 @@
import type { Result } from "../../../application/result.ts";
import type { ApiFailure, FailureKind } from "../../../contracts/errors.ts";
import type { FailureEffectCertainty } from "../../../contracts/errors.ts";
import type { MutationIntent } from "../../../contracts/mutation-intent.ts";
import {
createFailure,
kindForStatus,
@@ -22,7 +23,10 @@ export type InstalledContractOperationExecutor = Readonly<{
execute(
operationId: string,
input: unknown,
context?: Readonly<{ signal?: AbortSignal }>,
context?: Readonly<{
signal?: AbortSignal;
intent?: MutationIntent;
}>,
): Promise<HttpExecutionOutcome<unknown, unknown>>;
}>;
@@ -39,10 +43,14 @@ export function createReferenceFeatureInstalledInput(context: Readonly<{
const operationId = request.operationId;
const input = inputFor(request);
const signal = "signal" in request ? request.signal : undefined;
const intent = "intent" in request ? request.intent : undefined;
const outcome = await context.contractOperations.execute(
operationId,
input,
signal === undefined ? {} : { signal },
{
...(signal === undefined ? {} : { signal }),
...(intent === undefined ? {} : { intent }),
},
);
return projectExecutionOutcome(operationId, outcome);
},
@@ -9,6 +9,7 @@ import type {
ReferenceListFilters,
} from "../application/reference-feature-api.ts";
import type { ReferenceResource } from "../domain/reference-resource.ts";
import type { MutationIntent } from "../../../contracts/mutation-intent.ts";
type ReferenceOperationMap = Readonly<{
LIST_REFERENCE_RESOURCES: Readonly<{
@@ -26,6 +27,7 @@ type ReferenceOperationMap = Readonly<{
routeId: "REFERENCE_RESOURCE_LIST";
body: ReferenceCreateCommand;
signal?: AbortSignal;
intent?: MutationIntent;
}>;
value: ReferenceResource;
}>;
@@ -74,13 +76,17 @@ export function createReferenceHttpGateway(
},
async create(
command: ReferenceCreateCommand,
context?: Readonly<{ signal?: AbortSignal }>,
context?: Readonly<{
signal?: AbortSignal;
intent?: MutationIntent;
}>,
) {
const result = await http.execute({
operationId: "CREATE_REFERENCE_RESOURCE",
routeId: "REFERENCE_RESOURCE_LIST",
body: command,
signal: context?.signal,
intent: context?.intent,
});
return projectResourceResult("CREATE_REFERENCE_RESOURCE", result);
},
@@ -5,6 +5,7 @@ import {
type ReferenceResourceView,
} from "../contracts/reference-mapper.ts";
import type { ReferenceResource } from "../domain/reference-resource.ts";
import type { MutationIntent } from "../../../contracts/mutation-intent.ts";
export type ReferenceListFilters = Readonly<{
cursor?: string;
@@ -26,7 +27,10 @@ export type ReferenceFeatureInput = Readonly<{
): Promise<ReferenceResult<readonly ReferenceResourceView[]>>;
createResource(
command: ReferenceCreateCommand,
context?: Readonly<{ signal?: AbortSignal }>,
context?: Readonly<{
signal?: AbortSignal;
intent?: MutationIntent;
}>,
): Promise<ReferenceResult<ReferenceResourceView>>;
getResource(
resourceId: string,
@@ -47,7 +51,10 @@ export type ReferenceGateway = Readonly<{
): Promise<ReferenceResult<readonly ReferenceResource[]>>;
create(
command: ReferenceCreateCommand,
context?: Readonly<{ signal?: AbortSignal }>,
context?: Readonly<{
signal?: AbortSignal;
intent?: MutationIntent;
}>,
): Promise<ReferenceResult<ReferenceResource>>;
get(
resourceId: string,
@@ -87,6 +87,7 @@ export function useReferenceCreate() {
definitionId: "reference-resource-create-v1",
definitionVersion: 1,
operationId: "CREATE_REFERENCE_RESOURCE",
requiresIdempotencyKey: true,
owner: REFERENCE_FEATURE_ID,
duplicatePolicy: "REJECT_WHILE_ACTIVE",
scope,
@@ -123,6 +124,7 @@ export function useReferenceFeature() {
definitionId: "reference-resource-create-v1",
definitionVersion: 1,
operationId: "CREATE_REFERENCE_RESOURCE",
requiresIdempotencyKey: true,
owner: REFERENCE_FEATURE_ID,
duplicatePolicy: "REJECT_WHILE_ACTIVE",
scope,