@effect-agent/storage-cloudflare 0.1.0-beta.11 → 0.1.0-beta.111
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/dist/DoMemoryStore.d.mts +29 -0
- package/dist/DoMemoryStore.mjs +55 -0
- package/dist/DoMemoryStore.mjs.map +1 -0
- package/dist/DoMessageDeliveryStore.d.mts +17 -0
- package/dist/DoMessageDeliveryStore.mjs +32 -0
- package/dist/DoMessageDeliveryStore.mjs.map +1 -0
- package/dist/DoScheduleStore.d.mts +36 -0
- package/dist/DoScheduleStore.mjs +388 -0
- package/dist/DoScheduleStore.mjs.map +1 -0
- package/dist/DoStorageConfig.d.mts +45 -0
- package/dist/DoStorageConfig.mjs +52 -0
- package/dist/DoStorageConfig.mjs.map +1 -0
- package/dist/DoStorageError-Cmhvl4TQ.d.mts +98 -0
- package/dist/DoStorageError.d.mts +2 -0
- package/dist/DoStorageError.mjs +164 -0
- package/dist/DoStorageError.mjs.map +1 -0
- package/dist/DoStorageFailpoint.d.mts +17 -0
- package/dist/DoStorageFailpoint.mjs +14 -0
- package/dist/DoStorageFailpoint.mjs.map +1 -0
- package/dist/DoStorageFailpointTesting.d.mts +33 -0
- package/dist/DoStorageFailpointTesting.mjs +35 -0
- package/dist/DoStorageFailpointTesting.mjs.map +1 -0
- package/dist/DoStorageVersion-Db6fjP-I.d.mts +12 -0
- package/dist/DoStorageVersion.d.mts +2 -0
- package/dist/DoStorageVersion.mjs +8 -0
- package/dist/DoStorageVersion.mjs.map +1 -0
- package/dist/DoSubmissionLedger.d.mts +23 -0
- package/dist/DoSubmissionLedger.mjs +1864 -0
- package/dist/DoSubmissionLedger.mjs.map +1 -0
- package/dist/DoSubscriptionStore.d.mts +25 -0
- package/dist/DoSubscriptionStore.mjs +183 -0
- package/dist/DoSubscriptionStore.mjs.map +1 -0
- package/dist/DoThreadStore.d.mts +59 -0
- package/dist/DoThreadStore.mjs +481 -0
- package/dist/DoThreadStore.mjs.map +1 -0
- package/dist/MemoryProtocol.d.mts +38160 -0
- package/dist/MemoryProtocol.mjs +219 -0
- package/dist/MemoryProtocol.mjs.map +1 -0
- package/dist/PortProtocol.d.mts +4933 -0
- package/dist/PortProtocol.mjs +193 -0
- package/dist/PortProtocol.mjs.map +1 -0
- package/dist/PortRouting.d.mts +86 -0
- package/dist/PortRouting.mjs +439 -0
- package/dist/PortRouting.mjs.map +1 -0
- package/dist/do-journal-THW8-ZeP.mjs +1041 -0
- package/dist/do-journal-THW8-ZeP.mjs.map +1 -0
- package/dist/index.d.mts +14 -1525
- package/dist/index.mjs +14 -3695
- package/dist/migrations-DZKTNU88.mjs +291 -0
- package/dist/migrations-DZKTNU88.mjs.map +1 -0
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +1 -45
- package/src/DoMemoryStore.ts +56 -0
- package/src/DoMessageDeliveryStore.ts +53 -0
- package/src/DoScheduleStore.ts +622 -0
- package/src/{errors.ts → DoStorageError.ts} +10 -3
- package/src/DoStorageFailpoint.ts +20 -0
- package/src/{do-storage-failpoint.ts → DoStorageFailpointTesting.ts} +5 -18
- package/src/DoStorageVersion.ts +2 -0
- package/src/{do-ledger.ts → DoSubmissionLedger.ts} +960 -237
- package/src/DoSubscriptionStore.ts +329 -0
- package/src/DoThreadStore.ts +1039 -0
- package/src/MemoryProtocol.ts +351 -0
- package/src/{port-protocol.ts → PortProtocol.ts} +76 -38
- package/src/{routing.ts → PortRouting.ts} +374 -264
- package/src/index.ts +13 -32
- package/src/internal/do-journal.ts +1656 -0
- package/src/internal/message-delivery-schema.ts +24 -0
- package/src/{migrations.ts → internal/migrations.ts} +55 -35
- package/src/internal/recovery-checkpoint-schema.ts +17 -0
- package/dist/index.mjs.map +0 -1
- package/src/do-conversation-store.ts +0 -850
- package/src/do-journal.ts +0 -1078
- /package/src/{do-storage-config.ts → DoStorageConfig.ts} +0 -0
|
@@ -1,25 +1,31 @@
|
|
|
1
|
+
import { Context, Effect, Layer, Option, Predicate, Schema, Stream } from "effect";
|
|
2
|
+
import { MessageDeliveryStore, MessageDeliveryError } from "effect-agent/message-delivery";
|
|
1
3
|
import {
|
|
2
4
|
AdmissionIndeterminate,
|
|
3
|
-
|
|
5
|
+
AdmissionConflict,
|
|
6
|
+
AdmissionPolicyError,
|
|
4
7
|
ChildAttachmentSnapshot,
|
|
5
|
-
ConversationMaterialization,
|
|
6
|
-
ConversationNotMaterialized,
|
|
7
|
-
ConversationStore,
|
|
8
|
-
ConversationStoreError,
|
|
9
|
-
FenceRejected,
|
|
10
8
|
JoinedToHost,
|
|
11
9
|
LedgerError,
|
|
12
10
|
RecoverySnapshot,
|
|
13
11
|
SettlementConflict,
|
|
14
12
|
SubmissionLedger,
|
|
15
13
|
SubmissionLookupById,
|
|
16
|
-
type AdmissionConflict,
|
|
17
14
|
type SubmissionLookupByKey,
|
|
18
15
|
type SubmissionSnapshot,
|
|
19
|
-
} from "
|
|
20
|
-
import {
|
|
16
|
+
} from "effect-agent/submission-ledger";
|
|
17
|
+
import {
|
|
18
|
+
AppendConflict,
|
|
19
|
+
ThreadMaterialization,
|
|
20
|
+
ThreadNotMaterialized,
|
|
21
|
+
ThreadStore,
|
|
22
|
+
ThreadStoreError,
|
|
23
|
+
FenceRejected,
|
|
24
|
+
} from "effect-agent/thread-store";
|
|
21
25
|
|
|
22
26
|
import {
|
|
27
|
+
MessageDeliveryListCall,
|
|
28
|
+
MessageDeliveryListResult,
|
|
23
29
|
boundPortDiagnostic,
|
|
24
30
|
decodePortRequest,
|
|
25
31
|
decodePortResponse,
|
|
@@ -42,6 +48,8 @@ import {
|
|
|
42
48
|
PortSucceeded,
|
|
43
49
|
StoreAppendCall,
|
|
44
50
|
StoreAppendResult,
|
|
51
|
+
StoreCountPeerMessagesCall,
|
|
52
|
+
StoreCountPeerMessagesResult,
|
|
45
53
|
StoreExportCall,
|
|
46
54
|
StoreExportResult,
|
|
47
55
|
StoreInspectTailCall,
|
|
@@ -55,13 +63,13 @@ import {
|
|
|
55
63
|
type PortRequestEnvelope,
|
|
56
64
|
type PortResponse,
|
|
57
65
|
type PortResult,
|
|
58
|
-
} from "./
|
|
66
|
+
} from "./PortProtocol.ts";
|
|
59
67
|
|
|
60
|
-
type
|
|
68
|
+
type ThreadId = ThreadMaterialization["threadId"];
|
|
61
69
|
type SubmissionId = SubmissionSnapshot["submissionId"];
|
|
62
70
|
|
|
63
|
-
const
|
|
64
|
-
const
|
|
71
|
+
const ThreadIdSchema = ThreadMaterialization.fields.threadId;
|
|
72
|
+
const decodeThreadId = Schema.decodeUnknownEffect(ThreadIdSchema);
|
|
65
73
|
|
|
66
74
|
/**
|
|
67
75
|
* The ledger row bound routable Submission identities must respect (mirrors the local
|
|
@@ -76,7 +84,7 @@ const UUID_HEAD_PATTERN =
|
|
|
76
84
|
|
|
77
85
|
/**
|
|
78
86
|
* A transport could not deliver a port request to (or an answer from) the owning
|
|
79
|
-
*
|
|
87
|
+
* Thread's Durable Object. `retryable` carries the platform's own stub signal when one
|
|
80
88
|
* exists. This error never crosses the wire — it is the CALLER-side evidence that the
|
|
81
89
|
* authority was unreachable, which is exactly the case `AdmissionIndeterminate` was
|
|
82
90
|
* specified for (SUB-031).
|
|
@@ -91,20 +99,37 @@ export class PortTransportError extends Schema.TaggedError<PortTransportError>()
|
|
|
91
99
|
},
|
|
92
100
|
) {}
|
|
93
101
|
|
|
102
|
+
const safeTransportDiagnostic = (cause: unknown): string => {
|
|
103
|
+
try {
|
|
104
|
+
const message = cause instanceof Error ? cause.message : cause;
|
|
105
|
+
|
|
106
|
+
return boundPortDiagnostic(typeof message === "string" ? message : String(message));
|
|
107
|
+
} catch {
|
|
108
|
+
return "[unavailable transport diagnostic]";
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const transportRetryableSignal = (cause: unknown): boolean | undefined => {
|
|
113
|
+
if (!Predicate.isObjectKeyword(cause)) return undefined;
|
|
114
|
+
try {
|
|
115
|
+
const signal = Reflect.get(cause, "retryable");
|
|
116
|
+
|
|
117
|
+
return typeof signal === "boolean" ? signal : undefined;
|
|
118
|
+
} catch {
|
|
119
|
+
return undefined;
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
94
123
|
/**
|
|
95
124
|
* Build a `PortTransportError` from an arbitrary thrown transport cause, preserving the
|
|
96
125
|
* platform stub's own `retryable` signal when present.
|
|
97
126
|
*/
|
|
98
127
|
export const portTransportFailure = (target: string, cause: unknown): PortTransportError => {
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
if (typeof cause === "object" && cause !== null && "retryable" in cause) {
|
|
102
|
-
const signal = cause.retryable;
|
|
103
|
-
if (typeof signal === "boolean") retryable = signal;
|
|
104
|
-
}
|
|
128
|
+
const retryable = transportRetryableSignal(cause);
|
|
129
|
+
|
|
105
130
|
return PortTransportError.make({
|
|
106
131
|
target,
|
|
107
|
-
message:
|
|
132
|
+
message: safeTransportDiagnostic(cause),
|
|
108
133
|
...(retryable === undefined ? {} : { retryable }),
|
|
109
134
|
cause,
|
|
110
135
|
});
|
|
@@ -112,42 +137,42 @@ export const portTransportFailure = (target: string, cause: unknown): PortTransp
|
|
|
112
137
|
|
|
113
138
|
/**
|
|
114
139
|
* Delivery of Schema-encoded port envelopes to the Durable Object that owns a FOREIGN
|
|
115
|
-
*
|
|
140
|
+
* Thread (plan §1.3, D-P6-3). The shipped implementation (platform-cloudflare, WP3)
|
|
116
141
|
* calls the owner's `portCall` over native Durable Object JS RPC via
|
|
117
|
-
* `namespace.idFromName(
|
|
142
|
+
* `namespace.idFromName(threadId)`; the protocol is transport-agnostic and any carrier
|
|
118
143
|
* that moves the encoded envelopes verbatim satisfies this service. Implementations MUST
|
|
119
144
|
* surface every delivery problem as `PortTransportError` and must never fabricate an answer.
|
|
120
145
|
*/
|
|
121
|
-
export class
|
|
122
|
-
|
|
146
|
+
export class ThreadPortTransport extends Context.Service<
|
|
147
|
+
ThreadPortTransport,
|
|
123
148
|
{
|
|
124
149
|
readonly call: (
|
|
125
|
-
|
|
150
|
+
threadId: ThreadId,
|
|
126
151
|
request: PortRequestEnvelope,
|
|
127
152
|
) => Effect.Effect<unknown, PortTransportError>;
|
|
128
153
|
}
|
|
129
|
-
>()("@effect-agent/storage-cloudflare/
|
|
154
|
+
>()("@effect-agent/storage-cloudflare/ThreadPortTransport") {}
|
|
130
155
|
|
|
131
156
|
/** Construction options shared by both routed port Layers. */
|
|
132
157
|
export interface RoutedPortOptions {
|
|
133
158
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
159
|
+
* Decide whether this physical owner stores the addressed logical Thread. Local
|
|
160
|
+
* requests use the same SQLite facets; foreign requests use the transport or fail
|
|
161
|
+
* fast typed. The predicate determines placement, never caller authorization.
|
|
137
162
|
*/
|
|
138
|
-
readonly
|
|
163
|
+
readonly ownsThread: (threadId: ThreadId) => boolean;
|
|
139
164
|
}
|
|
140
165
|
|
|
141
166
|
/** Where one port request must execute. */
|
|
142
167
|
type RouteTarget =
|
|
143
168
|
| { readonly _tag: "local" }
|
|
144
|
-
| { readonly _tag: "foreign"; readonly
|
|
169
|
+
| { readonly _tag: "foreign"; readonly threadId: ThreadId };
|
|
145
170
|
|
|
146
171
|
const LOCAL: RouteTarget = { _tag: "local" };
|
|
147
172
|
|
|
148
173
|
/**
|
|
149
|
-
* Parse a DC-minted routable Submission identity — `{uuidv7}:{
|
|
150
|
-
* FIRST `:` because the
|
|
174
|
+
* Parse a DC-minted routable Submission identity — `{uuidv7}:{threadId}`, split at the
|
|
175
|
+
* FIRST `:` because the Thread tail may itself contain colons (D-P6-5). This adapter
|
|
151
176
|
* minted the format at admission and is the ONLY component that parses it; identities that do
|
|
152
177
|
* not carry the minted shape (no separator, non-UUID head, empty tail) fall back to the local
|
|
153
178
|
* facet, which is the only authority this Object can consult without inventing an owner.
|
|
@@ -155,7 +180,7 @@ const LOCAL: RouteTarget = { _tag: "local" };
|
|
|
155
180
|
* refused them at admission, so they cannot name any stored row anywhere.
|
|
156
181
|
*/
|
|
157
182
|
const routableSubmissionTarget = (
|
|
158
|
-
|
|
183
|
+
ownsThread: RoutedPortOptions["ownsThread"],
|
|
159
184
|
): ((operation: string, submissionId: string) => Effect.Effect<RouteTarget, LedgerError>) =>
|
|
160
185
|
Effect.fn("DoPortRouting.routableSubmissionTarget")(function* (
|
|
161
186
|
operation: string,
|
|
@@ -171,63 +196,49 @@ const routableSubmissionTarget = (
|
|
|
171
196
|
});
|
|
172
197
|
}
|
|
173
198
|
const separator = submissionId.indexOf(":");
|
|
199
|
+
|
|
174
200
|
if (separator === -1) return LOCAL;
|
|
175
201
|
if (!UUID_HEAD_PATTERN.test(submissionId.slice(0, separator))) return LOCAL;
|
|
176
202
|
const tail = submissionId.slice(separator + 1);
|
|
177
|
-
|
|
178
|
-
return yield*
|
|
179
|
-
Effect.map((
|
|
203
|
+
|
|
204
|
+
return yield* decodeThreadId(tail).pipe(
|
|
205
|
+
Effect.map((threadId): RouteTarget =>
|
|
206
|
+
ownsThread(threadId) ? LOCAL : { _tag: "foreign", threadId },
|
|
207
|
+
),
|
|
180
208
|
Effect.orElseSucceed(() => LOCAL),
|
|
181
209
|
);
|
|
182
210
|
});
|
|
183
211
|
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
result._tag === tag;
|
|
188
|
-
|
|
189
|
-
const isAdmitConflict = (failure: PortFailure): failure is AdmissionConflict =>
|
|
190
|
-
failure._tag === "AdmissionConflict";
|
|
191
|
-
const isAbortConflict = (failure: PortFailure): failure is SettlementConflict | JoinedToHost =>
|
|
192
|
-
failure._tag === "SettlementConflict" || failure._tag === "JoinedToHost";
|
|
193
|
-
const noExtraFailure = (_failure: PortFailure): _failure is never => false;
|
|
194
|
-
const isFenceRejected = (failure: PortFailure): failure is FenceRejected =>
|
|
195
|
-
failure._tag === "FenceRejected";
|
|
196
|
-
const isAppendFailure = (
|
|
197
|
-
failure: PortFailure,
|
|
198
|
-
): failure is ConversationNotMaterialized | AppendConflict | FenceRejected =>
|
|
199
|
-
failure._tag === "ConversationNotMaterialized" ||
|
|
200
|
-
failure._tag === "AppendConflict" ||
|
|
201
|
-
failure._tag === "FenceRejected";
|
|
202
|
-
const isNotMaterialized = (failure: PortFailure): failure is ConversationNotMaterialized =>
|
|
203
|
-
failure._tag === "ConversationNotMaterialized";
|
|
212
|
+
const NoAdditionalPortFailure = Schema.Never;
|
|
213
|
+
const AbortPortFailure = Schema.Union([SettlementConflict, JoinedToHost]);
|
|
214
|
+
const AppendPortFailure = Schema.Union([ThreadNotMaterialized, AppendConflict, FenceRejected]);
|
|
204
215
|
|
|
205
216
|
/**
|
|
206
217
|
* The fail-fast refusal for any foreign operation OUTSIDE the closed route-capable subset
|
|
207
218
|
* (plan §1.3): honesty over accidental distribution.
|
|
208
219
|
*/
|
|
209
|
-
const
|
|
220
|
+
const crossThreadLedgerError = (operation: string, target: string): LedgerError =>
|
|
210
221
|
LedgerError.make({
|
|
211
222
|
operation,
|
|
212
223
|
message:
|
|
213
|
-
`${operation} addressed to foreign
|
|
224
|
+
`${operation} addressed to foreign Thread ${target} is not route-capable; the ` +
|
|
214
225
|
"closed cross-Object subset is admit, markReady, lookup, resolveAdmission, " +
|
|
215
226
|
"requestAbort, and recordChildSettled. Every other ledger operation is lane-local by " +
|
|
216
|
-
"construction and must execute inside the owning
|
|
227
|
+
"construction and must execute inside the owning Thread's Durable Object.",
|
|
217
228
|
});
|
|
218
229
|
|
|
219
|
-
const
|
|
220
|
-
|
|
230
|
+
const crossThreadStoreError = (operation: string, target: string): ThreadStoreError =>
|
|
231
|
+
ThreadStoreError.make({
|
|
221
232
|
operation,
|
|
222
233
|
message:
|
|
223
|
-
`${operation} addressed to foreign
|
|
234
|
+
`${operation} addressed to foreign Thread ${target} is not route-capable; the ` +
|
|
224
235
|
"closed cross-Object subset is materialize, append, read (paged), inspectTail, and " +
|
|
225
236
|
"export. Observation and checkpoints are lane-local by construction and must execute " +
|
|
226
|
-
"inside the owning
|
|
237
|
+
"inside the owning Thread's Durable Object.",
|
|
227
238
|
});
|
|
228
239
|
|
|
229
|
-
const makeTransportCall = (transport:
|
|
230
|
-
Effect.fn("DoPortRouting.transportCall")(function* (target:
|
|
240
|
+
const makeTransportCall = (transport: ThreadPortTransport["Service"]) =>
|
|
241
|
+
Effect.fn("DoPortRouting.transportCall")(function* (target: ThreadId, call: PortRequest) {
|
|
231
242
|
const encoded = yield* encodePortRequest(call).pipe(
|
|
232
243
|
Effect.mapError((error) =>
|
|
233
244
|
PortProtocolError.make({
|
|
@@ -235,7 +246,9 @@ const makeTransportCall = (transport: ConversationPortTransport["Service"]) =>
|
|
|
235
246
|
}),
|
|
236
247
|
),
|
|
237
248
|
);
|
|
249
|
+
|
|
238
250
|
const raw = yield* transport.call(target, encoded);
|
|
251
|
+
|
|
239
252
|
return yield* decodePortResponse(raw).pipe(
|
|
240
253
|
Effect.mapError((error) =>
|
|
241
254
|
PortProtocolError.make({
|
|
@@ -251,9 +264,9 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
251
264
|
options: RoutedPortOptions,
|
|
252
265
|
) {
|
|
253
266
|
const local = yield* SubmissionLedger;
|
|
254
|
-
const transport = yield*
|
|
267
|
+
const transport = yield* ThreadPortTransport;
|
|
255
268
|
const transportCall: TransportCall = makeTransportCall(transport);
|
|
256
|
-
const submissionTarget = routableSubmissionTarget(options.
|
|
269
|
+
const submissionTarget = routableSubmissionTarget(options.ownsThread);
|
|
257
270
|
|
|
258
271
|
const routeFailure =
|
|
259
272
|
(operation: string, target: string) =>
|
|
@@ -261,7 +274,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
261
274
|
LedgerError.make({
|
|
262
275
|
operation,
|
|
263
276
|
message: boundPortDiagnostic(
|
|
264
|
-
`Routed ${operation} to the
|
|
277
|
+
`Routed ${operation} to the Thread Object owning ${target} failed: ${error.message}`,
|
|
265
278
|
),
|
|
266
279
|
cause: error,
|
|
267
280
|
});
|
|
@@ -272,48 +285,50 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
272
285
|
* any failure outside the operation's declared surface — including protocol anomalies — is
|
|
273
286
|
* folded into a `LedgerError` naming the anomaly instead of being erased or re-thrown raw.
|
|
274
287
|
*/
|
|
275
|
-
const foreignLedgerCall = <
|
|
288
|
+
const foreignLedgerCall = <ResultSchema extends Schema.Top, FailureSchema extends Schema.Top>(
|
|
276
289
|
operation: string,
|
|
277
|
-
target:
|
|
290
|
+
target: ThreadId,
|
|
278
291
|
call: PortRequest,
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
): Effect.Effect<
|
|
282
|
-
|
|
292
|
+
resultSchema: ResultSchema,
|
|
293
|
+
failureSchema: FailureSchema,
|
|
294
|
+
): Effect.Effect<ResultSchema["Type"], FailureSchema["Type"] | LedgerError> => {
|
|
295
|
+
const isExpectedResult = Schema.is(resultSchema);
|
|
296
|
+
const isExpectedFailure = Schema.is(failureSchema);
|
|
297
|
+
|
|
298
|
+
return transportCall(target, call).pipe(
|
|
283
299
|
Effect.mapError(routeFailure(operation, target)),
|
|
284
300
|
Effect.flatMap(
|
|
285
|
-
(
|
|
286
|
-
response,
|
|
287
|
-
): Effect.Effect<
|
|
288
|
-
Extract<PortResult, { readonly _tag: Tag }>,
|
|
289
|
-
ExpectedFailure | LedgerError
|
|
290
|
-
> => {
|
|
301
|
+
(response): Effect.Effect<ResultSchema["Type"], FailureSchema["Type"] | LedgerError> => {
|
|
291
302
|
if (response._tag === "PortFailed") {
|
|
292
303
|
const failure = response.failure;
|
|
304
|
+
|
|
293
305
|
if (isExpectedFailure(failure)) return Effect.fail(failure);
|
|
294
306
|
if (failure._tag === "LedgerError") return Effect.fail(failure);
|
|
307
|
+
|
|
295
308
|
return Effect.fail(
|
|
296
309
|
LedgerError.make({
|
|
297
310
|
operation,
|
|
298
311
|
message: boundPortDiagnostic(
|
|
299
|
-
`The
|
|
300
|
-
`out-of-contract failure ${failure._tag}
|
|
312
|
+
`The Thread Object owning ${target} answered ${operation} with the ` +
|
|
313
|
+
`out-of-contract failure ${failure._tag}`,
|
|
301
314
|
),
|
|
302
315
|
cause: failure,
|
|
303
316
|
}),
|
|
304
317
|
);
|
|
305
318
|
}
|
|
306
319
|
const result = response.result;
|
|
307
|
-
|
|
320
|
+
|
|
321
|
+
if (!isExpectedResult(result)) {
|
|
308
322
|
return Effect.fail(
|
|
309
323
|
LedgerError.make({
|
|
310
324
|
operation,
|
|
311
325
|
message:
|
|
312
|
-
`The
|
|
313
|
-
`mismatched result ${result._tag}
|
|
326
|
+
`The Thread Object owning ${target} answered ${operation} with the ` +
|
|
327
|
+
`mismatched result ${result._tag}.`,
|
|
314
328
|
}),
|
|
315
329
|
);
|
|
316
330
|
}
|
|
331
|
+
|
|
317
332
|
return Effect.succeed(result);
|
|
318
333
|
},
|
|
319
334
|
),
|
|
@@ -321,6 +336,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
321
336
|
attributes: { operation, target },
|
|
322
337
|
}),
|
|
323
338
|
);
|
|
339
|
+
};
|
|
324
340
|
|
|
325
341
|
/**
|
|
326
342
|
* Routed `resolveAdmission` — where the S2 tri-state becomes real (plan §1.3): when the
|
|
@@ -331,7 +347,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
331
347
|
* reached and reported its own storage failure.
|
|
332
348
|
*/
|
|
333
349
|
const resolveForeignAdmission = (
|
|
334
|
-
target:
|
|
350
|
+
target: ThreadId,
|
|
335
351
|
request: SubmissionLookupByKey,
|
|
336
352
|
): Effect.Effect<
|
|
337
353
|
| AdmissionIndeterminate
|
|
@@ -342,10 +358,11 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
342
358
|
Effect.flatMap((response) => {
|
|
343
359
|
if (response._tag === "PortFailed") {
|
|
344
360
|
if (response.failure._tag === "LedgerError") return Effect.fail(response.failure);
|
|
361
|
+
|
|
345
362
|
return Effect.succeed(
|
|
346
363
|
AdmissionIndeterminate.make({
|
|
347
364
|
reason: boundPortDiagnostic(
|
|
348
|
-
`The
|
|
365
|
+
`The Thread Object owning ${target} answered resolveAdmission with the ` +
|
|
349
366
|
`out-of-contract failure ${response.failure._tag}: ${response.failure.message}`,
|
|
350
367
|
),
|
|
351
368
|
}),
|
|
@@ -355,12 +372,13 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
355
372
|
return Effect.succeed(
|
|
356
373
|
AdmissionIndeterminate.make({
|
|
357
374
|
reason: boundPortDiagnostic(
|
|
358
|
-
`The
|
|
375
|
+
`The Thread Object owning ${target} answered resolveAdmission with the ` +
|
|
359
376
|
`mismatched result ${response.result._tag}.`,
|
|
360
377
|
),
|
|
361
378
|
}),
|
|
362
379
|
);
|
|
363
380
|
}
|
|
381
|
+
|
|
364
382
|
return Effect.succeed(response.result.resolution);
|
|
365
383
|
}),
|
|
366
384
|
Effect.catchTags({
|
|
@@ -368,7 +386,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
368
386
|
Effect.succeed(
|
|
369
387
|
AdmissionIndeterminate.make({
|
|
370
388
|
reason: boundPortDiagnostic(
|
|
371
|
-
`The
|
|
389
|
+
`The Thread Object owning ${target} is unreachable: ${error.message}`,
|
|
372
390
|
),
|
|
373
391
|
}),
|
|
374
392
|
),
|
|
@@ -376,7 +394,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
376
394
|
Effect.succeed(
|
|
377
395
|
AdmissionIndeterminate.make({
|
|
378
396
|
reason: boundPortDiagnostic(
|
|
379
|
-
`The answer of the
|
|
397
|
+
`The answer of the Thread Object owning ${target} could not be ` +
|
|
380
398
|
`understood: ${error.message}`,
|
|
381
399
|
),
|
|
382
400
|
}),
|
|
@@ -387,15 +405,15 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
387
405
|
|
|
388
406
|
const foreignLookupById = (
|
|
389
407
|
operation: string,
|
|
390
|
-
target:
|
|
408
|
+
target: ThreadId,
|
|
391
409
|
submissionId: SubmissionId,
|
|
392
410
|
): Effect.Effect<Option.Option<SubmissionSnapshot>, LedgerError> =>
|
|
393
411
|
foreignLedgerCall(
|
|
394
412
|
operation,
|
|
395
413
|
target,
|
|
396
414
|
LedgerLookupCall.make({ request: SubmissionLookupById.make({ submissionId }) }),
|
|
397
|
-
|
|
398
|
-
|
|
415
|
+
LedgerLookupResult,
|
|
416
|
+
NoAdditionalPortFailure,
|
|
399
417
|
).pipe(
|
|
400
418
|
Effect.map((result) =>
|
|
401
419
|
result.submission === undefined ? Option.none() : Option.some(result.submission),
|
|
@@ -413,18 +431,24 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
413
431
|
snapshot: RecoverySnapshot,
|
|
414
432
|
): Effect.fn.Return<RecoverySnapshot, LedgerError> {
|
|
415
433
|
const operation = "ledger load recovery snapshot";
|
|
434
|
+
|
|
416
435
|
const attachments = new Map(
|
|
417
436
|
snapshot.childAttachments.map((attachment) => [attachment.childSubmissionId, attachment]),
|
|
418
437
|
);
|
|
438
|
+
|
|
419
439
|
let enriched = false;
|
|
440
|
+
|
|
420
441
|
for (const reservation of snapshot.childReservations) {
|
|
421
442
|
const childSubmissionId = reservation.childSubmissionId;
|
|
443
|
+
|
|
422
444
|
if (childSubmissionId === undefined || attachments.has(childSubmissionId)) continue;
|
|
423
445
|
const target = yield* submissionTarget(operation, childSubmissionId);
|
|
446
|
+
|
|
424
447
|
// A local or opaque child identity was already answered authoritatively by the local
|
|
425
448
|
// facet; absence there means the child admission never committed.
|
|
426
449
|
if (target._tag !== "foreign") continue;
|
|
427
|
-
const child = yield* foreignLookupById(operation, target.
|
|
450
|
+
const child = yield* foreignLookupById(operation, target.threadId, childSubmissionId);
|
|
451
|
+
|
|
428
452
|
if (Option.isNone(child)) continue;
|
|
429
453
|
attachments.set(
|
|
430
454
|
childSubmissionId,
|
|
@@ -442,11 +466,14 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
442
466
|
if (!enriched) return snapshot;
|
|
443
467
|
// Rebuild in reservation (parent Tool Call) order, the order the local facet documents.
|
|
444
468
|
const ordered: Array<ChildAttachmentSnapshot> = [];
|
|
469
|
+
|
|
445
470
|
for (const reservation of snapshot.childReservations) {
|
|
446
471
|
if (reservation.childSubmissionId === undefined) continue;
|
|
447
472
|
const attachment = attachments.get(reservation.childSubmissionId);
|
|
473
|
+
|
|
448
474
|
if (attachment !== undefined) ordered.push(attachment);
|
|
449
475
|
}
|
|
476
|
+
|
|
450
477
|
return RecoverySnapshot.make({ ...snapshot, childAttachments: ordered });
|
|
451
478
|
});
|
|
452
479
|
|
|
@@ -454,14 +481,14 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
454
481
|
capabilities: local.capabilities,
|
|
455
482
|
|
|
456
483
|
admit: (request) =>
|
|
457
|
-
request.
|
|
484
|
+
options.ownsThread(request.threadId)
|
|
458
485
|
? local.admit(request)
|
|
459
486
|
: foreignLedgerCall(
|
|
460
487
|
"ledger admit",
|
|
461
|
-
request.
|
|
488
|
+
request.threadId,
|
|
462
489
|
LedgerAdmitCall.make({ request }),
|
|
463
|
-
|
|
464
|
-
|
|
490
|
+
LedgerAdmitResult,
|
|
491
|
+
Schema.Union([AdmissionConflict, AdmissionPolicyError]),
|
|
465
492
|
).pipe(Effect.map((reply) => reply.result)),
|
|
466
493
|
|
|
467
494
|
markReady: (request) =>
|
|
@@ -471,10 +498,10 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
471
498
|
? local.markReady(request)
|
|
472
499
|
: foreignLedgerCall(
|
|
473
500
|
"ledger mark ready",
|
|
474
|
-
target.
|
|
501
|
+
target.threadId,
|
|
475
502
|
LedgerMarkReadyCall.make({ request }),
|
|
476
|
-
|
|
477
|
-
|
|
503
|
+
LedgerMarkReadyResult,
|
|
504
|
+
NoAdditionalPortFailure,
|
|
478
505
|
).pipe(Effect.asVoid),
|
|
479
506
|
),
|
|
480
507
|
),
|
|
@@ -485,17 +512,17 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
485
512
|
Effect.flatMap((target) =>
|
|
486
513
|
target._tag === "local"
|
|
487
514
|
? local.lookup(request)
|
|
488
|
-
: foreignLookupById("ledger lookup", target.
|
|
515
|
+
: foreignLookupById("ledger lookup", target.threadId, request.submissionId),
|
|
489
516
|
),
|
|
490
517
|
)
|
|
491
|
-
: request.
|
|
518
|
+
: options.ownsThread(request.threadId)
|
|
492
519
|
? local.lookup(request)
|
|
493
520
|
: foreignLedgerCall(
|
|
494
521
|
"ledger lookup",
|
|
495
|
-
request.
|
|
522
|
+
request.threadId,
|
|
496
523
|
LedgerLookupCall.make({ request }),
|
|
497
|
-
|
|
498
|
-
|
|
524
|
+
LedgerLookupResult,
|
|
525
|
+
NoAdditionalPortFailure,
|
|
499
526
|
).pipe(
|
|
500
527
|
Effect.map((result) =>
|
|
501
528
|
result.submission === undefined ? Option.none() : Option.some(result.submission),
|
|
@@ -503,9 +530,9 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
503
530
|
),
|
|
504
531
|
|
|
505
532
|
resolveAdmission: (request) =>
|
|
506
|
-
request.
|
|
533
|
+
options.ownsThread(request.threadId)
|
|
507
534
|
? local.resolveAdmission(request)
|
|
508
|
-
: resolveForeignAdmission(request.
|
|
535
|
+
: resolveForeignAdmission(request.threadId, request),
|
|
509
536
|
|
|
510
537
|
requestAbort: (request) =>
|
|
511
538
|
submissionTarget("ledger request abort", request.submissionId).pipe(
|
|
@@ -514,10 +541,10 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
514
541
|
? local.requestAbort(request)
|
|
515
542
|
: foreignLedgerCall(
|
|
516
543
|
"ledger request abort",
|
|
517
|
-
target.
|
|
544
|
+
target.threadId,
|
|
518
545
|
LedgerRequestAbortCall.make({ request }),
|
|
519
|
-
|
|
520
|
-
|
|
546
|
+
LedgerRequestAbortResult,
|
|
547
|
+
AbortPortFailure,
|
|
521
548
|
).pipe(Effect.map((reply) => reply.intent)),
|
|
522
549
|
),
|
|
523
550
|
),
|
|
@@ -529,10 +556,10 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
529
556
|
? local.recordChildSettled(request)
|
|
530
557
|
: foreignLedgerCall(
|
|
531
558
|
"ledger record child settled",
|
|
532
|
-
target.
|
|
559
|
+
target.threadId,
|
|
533
560
|
LedgerRecordChildSettledCall.make({ request }),
|
|
534
|
-
|
|
535
|
-
|
|
561
|
+
LedgerRecordChildSettledResult,
|
|
562
|
+
NoAdditionalPortFailure,
|
|
536
563
|
).pipe(Effect.map((reply) => reply.outcome)),
|
|
537
564
|
),
|
|
538
565
|
),
|
|
@@ -540,23 +567,21 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
540
567
|
// Every operation below is lane-local by construction (plan §1.3): a foreign address is
|
|
541
568
|
// an out-of-contract call and fails fast typed instead of being quietly distributed.
|
|
542
569
|
claim: (request) =>
|
|
543
|
-
request.
|
|
570
|
+
options.ownsThread(request.threadId)
|
|
544
571
|
? local.claim(request)
|
|
545
|
-
: Effect.fail(
|
|
572
|
+
: Effect.fail(crossThreadLedgerError("ledger claim", request.threadId)),
|
|
546
573
|
|
|
547
574
|
claimJoining: (request) =>
|
|
548
|
-
request.
|
|
575
|
+
options.ownsThread(request.threadId)
|
|
549
576
|
? local.claimJoining(request)
|
|
550
|
-
: Effect.fail(
|
|
577
|
+
: Effect.fail(crossThreadLedgerError("ledger claim joining", request.threadId)),
|
|
551
578
|
|
|
552
579
|
renewOwnership: (request) =>
|
|
553
580
|
submissionTarget("ledger renew ownership", request.submissionId).pipe(
|
|
554
581
|
Effect.flatMap((target) =>
|
|
555
582
|
target._tag === "local"
|
|
556
583
|
? local.renewOwnership(request)
|
|
557
|
-
: Effect.fail(
|
|
558
|
-
crossConversationLedgerError("ledger renew ownership", target.conversationId),
|
|
559
|
-
),
|
|
584
|
+
: Effect.fail(crossThreadLedgerError("ledger renew ownership", target.threadId)),
|
|
560
585
|
),
|
|
561
586
|
),
|
|
562
587
|
|
|
@@ -565,9 +590,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
565
590
|
Effect.flatMap((target) =>
|
|
566
591
|
target._tag === "local"
|
|
567
592
|
? local.releaseOwnership(request)
|
|
568
|
-
: Effect.fail(
|
|
569
|
-
crossConversationLedgerError("ledger release ownership", target.conversationId),
|
|
570
|
-
),
|
|
593
|
+
: Effect.fail(crossThreadLedgerError("ledger release ownership", target.threadId)),
|
|
571
594
|
),
|
|
572
595
|
),
|
|
573
596
|
|
|
@@ -576,9 +599,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
576
599
|
Effect.flatMap((target) =>
|
|
577
600
|
target._tag === "local"
|
|
578
601
|
? local.markInputApplied(request)
|
|
579
|
-
: Effect.fail(
|
|
580
|
-
crossConversationLedgerError("ledger mark input applied", target.conversationId),
|
|
581
|
-
),
|
|
602
|
+
: Effect.fail(crossThreadLedgerError("ledger mark input applied", target.threadId)),
|
|
582
603
|
),
|
|
583
604
|
),
|
|
584
605
|
|
|
@@ -587,9 +608,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
587
608
|
Effect.flatMap((target) =>
|
|
588
609
|
target._tag === "local"
|
|
589
610
|
? local.reserveSettlement(request)
|
|
590
|
-
: Effect.fail(
|
|
591
|
-
crossConversationLedgerError("ledger reserve settlement", target.conversationId),
|
|
592
|
-
),
|
|
611
|
+
: Effect.fail(crossThreadLedgerError("ledger reserve settlement", target.threadId)),
|
|
593
612
|
),
|
|
594
613
|
),
|
|
595
614
|
|
|
@@ -598,9 +617,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
598
617
|
Effect.flatMap((target) =>
|
|
599
618
|
target._tag === "local"
|
|
600
619
|
? local.finalizeSettlement(request)
|
|
601
|
-
: Effect.fail(
|
|
602
|
-
crossConversationLedgerError("ledger finalize settlement", target.conversationId),
|
|
603
|
-
),
|
|
620
|
+
: Effect.fail(crossThreadLedgerError("ledger finalize settlement", target.threadId)),
|
|
604
621
|
),
|
|
605
622
|
),
|
|
606
623
|
|
|
@@ -609,9 +626,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
609
626
|
Effect.flatMap((target) =>
|
|
610
627
|
target._tag === "local"
|
|
611
628
|
? local.markJoined(request)
|
|
612
|
-
: Effect.fail(
|
|
613
|
-
crossConversationLedgerError("ledger mark joined", target.conversationId),
|
|
614
|
-
),
|
|
629
|
+
: Effect.fail(crossThreadLedgerError("ledger mark joined", target.threadId)),
|
|
615
630
|
),
|
|
616
631
|
),
|
|
617
632
|
|
|
@@ -620,9 +635,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
620
635
|
Effect.flatMap((target) =>
|
|
621
636
|
target._tag === "local"
|
|
622
637
|
? local.revertJoining(request)
|
|
623
|
-
: Effect.fail(
|
|
624
|
-
crossConversationLedgerError("ledger revert joining", target.conversationId),
|
|
625
|
-
),
|
|
638
|
+
: Effect.fail(crossThreadLedgerError("ledger revert joining", target.threadId)),
|
|
626
639
|
),
|
|
627
640
|
),
|
|
628
641
|
|
|
@@ -631,7 +644,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
631
644
|
Effect.flatMap((target) =>
|
|
632
645
|
target._tag === "local"
|
|
633
646
|
? local.suspend(request)
|
|
634
|
-
: Effect.fail(
|
|
647
|
+
: Effect.fail(crossThreadLedgerError("ledger suspend", target.threadId)),
|
|
635
648
|
),
|
|
636
649
|
),
|
|
637
650
|
|
|
@@ -641,10 +654,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
641
654
|
target._tag === "local"
|
|
642
655
|
? local.recordApprovalDecision(command)
|
|
643
656
|
: Effect.fail(
|
|
644
|
-
|
|
645
|
-
"ledger record approval decision",
|
|
646
|
-
target.conversationId,
|
|
647
|
-
),
|
|
657
|
+
crossThreadLedgerError("ledger record approval decision", target.threadId),
|
|
648
658
|
),
|
|
649
659
|
),
|
|
650
660
|
),
|
|
@@ -654,9 +664,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
654
664
|
Effect.flatMap((target) =>
|
|
655
665
|
target._tag === "local"
|
|
656
666
|
? local.markUnknown(request)
|
|
657
|
-
: Effect.fail(
|
|
658
|
-
crossConversationLedgerError("ledger mark unknown", target.conversationId),
|
|
659
|
-
),
|
|
667
|
+
: Effect.fail(crossThreadLedgerError("ledger mark unknown", target.threadId)),
|
|
660
668
|
),
|
|
661
669
|
),
|
|
662
670
|
|
|
@@ -666,10 +674,7 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
666
674
|
target._tag === "local"
|
|
667
675
|
? local.recordUnknownResolution(command)
|
|
668
676
|
: Effect.fail(
|
|
669
|
-
|
|
670
|
-
"ledger record unknown resolution",
|
|
671
|
-
target.conversationId,
|
|
672
|
-
),
|
|
677
|
+
crossThreadLedgerError("ledger record unknown resolution", target.threadId),
|
|
673
678
|
),
|
|
674
679
|
),
|
|
675
680
|
),
|
|
@@ -679,33 +684,35 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
679
684
|
Effect.flatMap((target) =>
|
|
680
685
|
target._tag === "local"
|
|
681
686
|
? local.reserveChildBudget(request)
|
|
682
|
-
: Effect.fail(
|
|
683
|
-
crossConversationLedgerError("ledger reserve child budget", target.conversationId),
|
|
684
|
-
),
|
|
687
|
+
: Effect.fail(crossThreadLedgerError("ledger reserve child budget", target.threadId)),
|
|
685
688
|
),
|
|
686
689
|
),
|
|
687
690
|
|
|
688
|
-
// Reservation identities carry no
|
|
691
|
+
// Reservation identities carry no Thread address; the reservation row lives in the
|
|
689
692
|
// parent's own Object and these transitions are parent-lane-local by construction, so
|
|
690
693
|
// they always execute on the local facet (which fails typed for an unknown row).
|
|
691
694
|
attachChildToReservation: local.attachChildToReservation,
|
|
692
695
|
beginChildBudgetRelease: local.beginChildBudgetRelease,
|
|
693
696
|
releaseChildBudget: local.releaseChildBudget,
|
|
694
697
|
|
|
695
|
-
// The local scan IS the whole worklist: one
|
|
698
|
+
// The local scan IS the whole worklist: one Thread per Object (durability §5).
|
|
696
699
|
scanNonterminal: local.scanNonterminal,
|
|
697
700
|
|
|
701
|
+
readAbortIntent: (request) =>
|
|
702
|
+
submissionTarget("ledger read abort intent", request.submissionId).pipe(
|
|
703
|
+
Effect.flatMap((target) =>
|
|
704
|
+
target._tag === "local"
|
|
705
|
+
? local.readAbortIntent(request)
|
|
706
|
+
: Effect.fail(crossThreadLedgerError("ledger read abort intent", target.threadId)),
|
|
707
|
+
),
|
|
708
|
+
),
|
|
709
|
+
|
|
698
710
|
loadRecoverySnapshot: (request) =>
|
|
699
711
|
submissionTarget("ledger load recovery snapshot", request.submissionId).pipe(
|
|
700
712
|
Effect.flatMap((target) =>
|
|
701
713
|
target._tag === "local"
|
|
702
714
|
? local.loadRecoverySnapshot(request).pipe(Effect.flatMap(enrichChildAttachments))
|
|
703
|
-
: Effect.fail(
|
|
704
|
-
crossConversationLedgerError(
|
|
705
|
-
"ledger load recovery snapshot",
|
|
706
|
-
target.conversationId,
|
|
707
|
-
),
|
|
708
|
-
),
|
|
715
|
+
: Effect.fail(crossThreadLedgerError("ledger load recovery snapshot", target.threadId)),
|
|
709
716
|
),
|
|
710
717
|
),
|
|
711
718
|
});
|
|
@@ -716,67 +723,70 @@ const makeRoutedLedgerServices = Effect.fn("DoPortRouting.makeRoutedLedgerServic
|
|
|
716
723
|
const makeRoutedStoreServices = Effect.fn("DoPortRouting.makeRoutedStoreServices")(function* (
|
|
717
724
|
options: RoutedPortOptions,
|
|
718
725
|
) {
|
|
719
|
-
const local = yield*
|
|
720
|
-
const
|
|
726
|
+
const local = yield* ThreadStore;
|
|
727
|
+
const checkpoints = local.checkpoints;
|
|
728
|
+
const recoveryCheckpoints = local.recoveryCheckpoints;
|
|
729
|
+
const transport = yield* ThreadPortTransport;
|
|
721
730
|
const transportCall: TransportCall = makeTransportCall(transport);
|
|
722
731
|
|
|
723
732
|
const routeFailure =
|
|
724
733
|
(operation: string, target: string) =>
|
|
725
|
-
(error: PortTransportError | PortProtocolError):
|
|
726
|
-
|
|
734
|
+
(error: PortTransportError | PortProtocolError): ThreadStoreError =>
|
|
735
|
+
ThreadStoreError.make({
|
|
727
736
|
operation,
|
|
728
737
|
message: boundPortDiagnostic(
|
|
729
|
-
`Routed ${operation} to the
|
|
738
|
+
`Routed ${operation} to the Thread Object owning ${target} failed: ${error.message}`,
|
|
730
739
|
),
|
|
731
740
|
cause: error,
|
|
732
741
|
});
|
|
733
742
|
|
|
734
|
-
/** The store twin of `foreignLedgerCall` with `
|
|
735
|
-
const foreignStoreCall = <
|
|
743
|
+
/** The store twin of `foreignLedgerCall` with `ThreadStoreError` as the base error. */
|
|
744
|
+
const foreignStoreCall = <ResultSchema extends Schema.Top, FailureSchema extends Schema.Top>(
|
|
736
745
|
operation: string,
|
|
737
|
-
target:
|
|
746
|
+
target: ThreadId,
|
|
738
747
|
call: PortRequest,
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
): Effect.Effect<
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
transportCall(target, call).pipe(
|
|
748
|
+
resultSchema: ResultSchema,
|
|
749
|
+
failureSchema: FailureSchema,
|
|
750
|
+
): Effect.Effect<ResultSchema["Type"], FailureSchema["Type"] | ThreadStoreError> => {
|
|
751
|
+
const isExpectedResult = Schema.is(resultSchema);
|
|
752
|
+
const isExpectedFailure = Schema.is(failureSchema);
|
|
753
|
+
|
|
754
|
+
return transportCall(target, call).pipe(
|
|
746
755
|
Effect.mapError(routeFailure(operation, target)),
|
|
747
756
|
Effect.flatMap(
|
|
748
757
|
(
|
|
749
758
|
response,
|
|
750
|
-
): Effect.Effect<
|
|
751
|
-
Extract<PortResult, { readonly _tag: Tag }>,
|
|
752
|
-
ExpectedFailure | ConversationStoreError
|
|
753
|
-
> => {
|
|
759
|
+
): Effect.Effect<ResultSchema["Type"], FailureSchema["Type"] | ThreadStoreError> => {
|
|
754
760
|
if (response._tag === "PortFailed") {
|
|
755
761
|
const failure = response.failure;
|
|
762
|
+
|
|
756
763
|
if (isExpectedFailure(failure)) return Effect.fail(failure);
|
|
757
|
-
if (failure._tag === "
|
|
764
|
+
if (failure._tag === "ThreadStoreError") return Effect.fail(failure);
|
|
765
|
+
|
|
758
766
|
return Effect.fail(
|
|
759
|
-
|
|
767
|
+
ThreadStoreError.make({
|
|
760
768
|
operation,
|
|
761
769
|
message: boundPortDiagnostic(
|
|
762
|
-
`The
|
|
763
|
-
`out-of-contract failure ${failure._tag}
|
|
770
|
+
`The Thread Object owning ${target} answered ${operation} with the ` +
|
|
771
|
+
`out-of-contract failure ${failure._tag}`,
|
|
764
772
|
),
|
|
765
773
|
cause: failure,
|
|
766
774
|
}),
|
|
767
775
|
);
|
|
768
776
|
}
|
|
769
777
|
const result = response.result;
|
|
770
|
-
|
|
778
|
+
|
|
779
|
+
if (!isExpectedResult(result)) {
|
|
771
780
|
return Effect.fail(
|
|
772
|
-
|
|
781
|
+
ThreadStoreError.make({
|
|
773
782
|
operation,
|
|
774
783
|
message:
|
|
775
|
-
`The
|
|
776
|
-
`mismatched result ${result._tag}
|
|
784
|
+
`The Thread Object owning ${target} answered ${operation} with the ` +
|
|
785
|
+
`mismatched result ${result._tag}.`,
|
|
777
786
|
}),
|
|
778
787
|
);
|
|
779
788
|
}
|
|
789
|
+
|
|
780
790
|
return Effect.succeed(result);
|
|
781
791
|
},
|
|
782
792
|
),
|
|
@@ -784,120 +794,192 @@ const makeRoutedStoreServices = Effect.fn("DoPortRouting.makeRoutedStoreServices
|
|
|
784
794
|
attributes: { operation, target },
|
|
785
795
|
}),
|
|
786
796
|
);
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
const routed = ThreadStore.of({
|
|
800
|
+
countPeerMessages: (request) =>
|
|
801
|
+
options.ownsThread(request.threadId)
|
|
802
|
+
? local.countPeerMessages === undefined
|
|
803
|
+
? Effect.fail(crossThreadStoreError("peer count unavailable", request.threadId))
|
|
804
|
+
: local.countPeerMessages(request)
|
|
805
|
+
: foreignStoreCall(
|
|
806
|
+
"thread countPeerMessages",
|
|
807
|
+
request.threadId,
|
|
808
|
+
StoreCountPeerMessagesCall.make({ request }),
|
|
809
|
+
StoreCountPeerMessagesResult,
|
|
810
|
+
ThreadNotMaterialized,
|
|
811
|
+
).pipe(Effect.map((reply) => reply.count)),
|
|
787
812
|
|
|
788
|
-
const routed = ConversationStore.of({
|
|
789
813
|
materialize: (request) =>
|
|
790
|
-
request.
|
|
814
|
+
options.ownsThread(request.threadId)
|
|
791
815
|
? local.materialize(request)
|
|
792
816
|
: foreignStoreCall(
|
|
793
|
-
"
|
|
794
|
-
request.
|
|
817
|
+
"thread materialize",
|
|
818
|
+
request.threadId,
|
|
795
819
|
StoreMaterializeCall.make({ request }),
|
|
796
|
-
|
|
797
|
-
|
|
820
|
+
StoreMaterializeResult,
|
|
821
|
+
FenceRejected,
|
|
798
822
|
).pipe(Effect.asVoid),
|
|
799
823
|
|
|
800
824
|
append: (request) =>
|
|
801
|
-
request.
|
|
825
|
+
options.ownsThread(request.threadId)
|
|
802
826
|
? local.append(request)
|
|
803
827
|
: foreignStoreCall(
|
|
804
|
-
"
|
|
805
|
-
request.
|
|
828
|
+
"thread append",
|
|
829
|
+
request.threadId,
|
|
806
830
|
StoreAppendCall.make({ request }),
|
|
807
|
-
|
|
808
|
-
|
|
831
|
+
StoreAppendResult,
|
|
832
|
+
AppendPortFailure,
|
|
809
833
|
).pipe(Effect.map((reply) => reply.result)),
|
|
810
834
|
|
|
811
835
|
read: (request) =>
|
|
812
|
-
request.
|
|
836
|
+
options.ownsThread(request.threadId)
|
|
813
837
|
? local.read(request)
|
|
814
838
|
: Stream.unwrap(
|
|
815
839
|
foreignStoreCall(
|
|
816
|
-
"
|
|
817
|
-
request.
|
|
840
|
+
"thread read",
|
|
841
|
+
request.threadId,
|
|
818
842
|
StoreReadPageCall.make({ request }),
|
|
819
|
-
|
|
820
|
-
|
|
843
|
+
StoreReadPageResult,
|
|
844
|
+
ThreadNotMaterialized,
|
|
821
845
|
).pipe(Effect.map((reply) => Stream.fromIterable(reply.records))),
|
|
822
846
|
),
|
|
823
847
|
|
|
824
848
|
inspectTail: (request) =>
|
|
825
|
-
request.
|
|
849
|
+
options.ownsThread(request.threadId)
|
|
826
850
|
? local.inspectTail(request)
|
|
827
851
|
: foreignStoreCall(
|
|
828
|
-
"
|
|
829
|
-
request.
|
|
852
|
+
"thread inspect tail",
|
|
853
|
+
request.threadId,
|
|
830
854
|
StoreInspectTailCall.make({ request }),
|
|
831
|
-
|
|
832
|
-
|
|
855
|
+
StoreInspectTailResult,
|
|
856
|
+
ThreadNotMaterialized,
|
|
833
857
|
).pipe(Effect.map((reply) => reply.tail)),
|
|
834
858
|
|
|
835
859
|
export: (request) =>
|
|
836
|
-
request.
|
|
860
|
+
options.ownsThread(request.threadId)
|
|
837
861
|
? local.export(request)
|
|
838
862
|
: foreignStoreCall(
|
|
839
|
-
"
|
|
840
|
-
request.
|
|
863
|
+
"thread export",
|
|
864
|
+
request.threadId,
|
|
841
865
|
StoreExportCall.make({ request }),
|
|
842
|
-
|
|
843
|
-
|
|
866
|
+
StoreExportResult,
|
|
867
|
+
ThreadNotMaterialized,
|
|
844
868
|
).pipe(Effect.map((reply) => reply.export)),
|
|
845
869
|
|
|
846
|
-
// Observation and checkpoints are lane-local
|
|
847
|
-
//
|
|
848
|
-
//
|
|
870
|
+
// Observation and checkpoints are lane-local: the closed route-capable store subset
|
|
871
|
+
// is materialize/append/read/inspectTail/export. Recovery cache misses can fall back
|
|
872
|
+
// to those canonical reads, including when the cache belongs to a foreign Object.
|
|
849
873
|
observe: (request) =>
|
|
850
|
-
request.
|
|
874
|
+
options.ownsThread(request.threadId)
|
|
851
875
|
? local.observe(request)
|
|
852
|
-
: Stream.unwrap(
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
876
|
+
: Stream.unwrap(Effect.fail(crossThreadStoreError("thread observe", request.threadId))),
|
|
877
|
+
|
|
878
|
+
...(recoveryCheckpoints === undefined
|
|
879
|
+
? {}
|
|
880
|
+
: {
|
|
881
|
+
recoveryCheckpoints: {
|
|
882
|
+
save: (request) =>
|
|
883
|
+
options.ownsThread(request.checkpoint.threadId)
|
|
884
|
+
? recoveryCheckpoints.save(request)
|
|
885
|
+
: Effect.fail(
|
|
886
|
+
crossThreadStoreError(
|
|
887
|
+
"thread save recovery checkpoint",
|
|
888
|
+
request.checkpoint.threadId,
|
|
889
|
+
),
|
|
890
|
+
),
|
|
891
|
+
load: (request) =>
|
|
892
|
+
options.ownsThread(request.threadId)
|
|
893
|
+
? recoveryCheckpoints.load(request)
|
|
894
|
+
: Effect.succeed(Option.none()),
|
|
895
|
+
},
|
|
896
|
+
}),
|
|
897
|
+
...(checkpoints === undefined
|
|
898
|
+
? {}
|
|
899
|
+
: {
|
|
900
|
+
checkpoints: {
|
|
901
|
+
save: (request) =>
|
|
902
|
+
options.ownsThread(request.checkpoint.threadId)
|
|
903
|
+
? checkpoints.save(request)
|
|
904
|
+
: Effect.fail(
|
|
905
|
+
crossThreadStoreError("thread save checkpoint", request.checkpoint.threadId),
|
|
906
|
+
),
|
|
907
|
+
load: (request) =>
|
|
908
|
+
options.ownsThread(request.threadId)
|
|
909
|
+
? checkpoints.load(request)
|
|
910
|
+
: Effect.fail(crossThreadStoreError("thread load checkpoint", request.threadId)),
|
|
911
|
+
},
|
|
912
|
+
}),
|
|
874
913
|
});
|
|
875
914
|
|
|
876
|
-
return Context.make(
|
|
915
|
+
return Context.make(ThreadStore, routed);
|
|
877
916
|
});
|
|
878
917
|
|
|
879
918
|
/**
|
|
880
919
|
* Routing decorator over the LOCAL `SubmissionLedger` facet (plan §1.3): a request addressing
|
|
881
|
-
* this Object's
|
|
882
|
-
*
|
|
920
|
+
* this Object's Thread executes locally; a route-capable request addressing another
|
|
921
|
+
* Thread is Schema-encoded onto the `ThreadPortTransport` and executed by the
|
|
883
922
|
* owning Object's local facet; any other foreign request fails fast typed. Provide the WP1
|
|
884
923
|
* local facet (`submissionLedgerLayer`/`ledgerLayer`) and a transport to close it.
|
|
885
924
|
*/
|
|
886
925
|
export const routedSubmissionLedgerLayer = (
|
|
887
926
|
options: RoutedPortOptions,
|
|
888
|
-
): Layer.Layer<SubmissionLedger, never, SubmissionLedger |
|
|
927
|
+
): Layer.Layer<SubmissionLedger, never, SubmissionLedger | ThreadPortTransport> =>
|
|
889
928
|
Layer.effectContext(makeRoutedLedgerServices(options));
|
|
890
929
|
|
|
891
930
|
/**
|
|
892
|
-
* Routing decorator over the LOCAL `
|
|
931
|
+
* Routing decorator over the LOCAL `ThreadStore` facet (plan §1.3): this-thread
|
|
893
932
|
* requests execute locally; foreign materialize/append/read/inspectTail/export travel the
|
|
894
|
-
* transport
|
|
933
|
+
* transport. Foreign recovery-cache loads return none for canonical replay; other foreign
|
|
934
|
+
* checkpoint operations and observation fail fast typed.
|
|
895
935
|
*/
|
|
896
|
-
export const
|
|
936
|
+
export const routedThreadStoreLayer = (
|
|
897
937
|
options: RoutedPortOptions,
|
|
898
|
-
): Layer.Layer<
|
|
938
|
+
): Layer.Layer<ThreadStore, never, ThreadStore | ThreadPortTransport> =>
|
|
899
939
|
Layer.effectContext(makeRoutedStoreServices(options));
|
|
900
940
|
|
|
941
|
+
/** Route the existing owner-scoped list; delivery mutations remain source local. */
|
|
942
|
+
export const routedMessageDeliveryStoreLayer = (options: RoutedPortOptions) =>
|
|
943
|
+
Layer.effect(
|
|
944
|
+
MessageDeliveryStore,
|
|
945
|
+
Effect.gen(function* () {
|
|
946
|
+
const local = yield* MessageDeliveryStore;
|
|
947
|
+
const call = makeTransportCall(yield* ThreadPortTransport);
|
|
948
|
+
|
|
949
|
+
return MessageDeliveryStore.of({
|
|
950
|
+
...local,
|
|
951
|
+
list: (request) =>
|
|
952
|
+
options.ownsThread(request.ownerThreadId)
|
|
953
|
+
? local.list(request)
|
|
954
|
+
: call(request.ownerThreadId, MessageDeliveryListCall.make({ request })).pipe(
|
|
955
|
+
Effect.mapError(() =>
|
|
956
|
+
MessageDeliveryError.make({
|
|
957
|
+
reason: "storage",
|
|
958
|
+
operation: "route delivery list",
|
|
959
|
+
}),
|
|
960
|
+
),
|
|
961
|
+
Effect.flatMap((response) => {
|
|
962
|
+
if (
|
|
963
|
+
response._tag === "PortSucceeded" &&
|
|
964
|
+
response.result._tag === "MessageDeliveryListResult"
|
|
965
|
+
)
|
|
966
|
+
return Effect.succeed(response.result.page);
|
|
967
|
+
|
|
968
|
+
return Effect.fail(
|
|
969
|
+
response._tag === "PortFailed" &&
|
|
970
|
+
response.failure._tag === "MessageDeliveryError"
|
|
971
|
+
? response.failure
|
|
972
|
+
: MessageDeliveryError.make({
|
|
973
|
+
reason: "storage",
|
|
974
|
+
operation: "route delivery list",
|
|
975
|
+
}),
|
|
976
|
+
);
|
|
977
|
+
}),
|
|
978
|
+
),
|
|
979
|
+
});
|
|
980
|
+
}),
|
|
981
|
+
);
|
|
982
|
+
|
|
901
983
|
// ---------------------------------------------------------------------------
|
|
902
984
|
// Owner-side execution
|
|
903
985
|
// ---------------------------------------------------------------------------
|
|
@@ -915,16 +997,37 @@ const capture = <Failure extends PortFailure>(
|
|
|
915
997
|
* Execute one decoded port request against THIS Object's LOCAL facets — the owner-side half
|
|
916
998
|
* of the routed ports (plan §1.3). Callers must provide the WP1 local facets, never the
|
|
917
999
|
* routed decorators: the routing layer already established that this Object owns the
|
|
918
|
-
* addressed
|
|
1000
|
+
* addressed Thread, and re-routing here could bounce a request between Objects.
|
|
919
1001
|
* Failures never escape — every typed port failure becomes a `PortFailed` envelope that
|
|
920
1002
|
* re-decodes on the caller side.
|
|
921
1003
|
*/
|
|
922
1004
|
export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(function* (
|
|
923
1005
|
request: PortRequest,
|
|
924
|
-
): Effect.fn.Return<PortResponse, never, SubmissionLedger |
|
|
1006
|
+
): Effect.fn.Return<PortResponse, never, SubmissionLedger | ThreadStore | MessageDeliveryStore> {
|
|
925
1007
|
switch (request._tag) {
|
|
1008
|
+
case "MessageDeliveryList": {
|
|
1009
|
+
const store = yield* MessageDeliveryStore;
|
|
1010
|
+
|
|
1011
|
+
return yield* capture(
|
|
1012
|
+
store
|
|
1013
|
+
.list(request.request)
|
|
1014
|
+
.pipe(Effect.map((page) => MessageDeliveryListResult.make({ page }))),
|
|
1015
|
+
);
|
|
1016
|
+
}
|
|
1017
|
+
case "StoreCountPeerMessages": {
|
|
1018
|
+
const store = yield* ThreadStore;
|
|
1019
|
+
|
|
1020
|
+
return yield* capture(
|
|
1021
|
+
store.countPeerMessages === undefined
|
|
1022
|
+
? Effect.fail(crossThreadStoreError("native read unavailable", request.request.threadId))
|
|
1023
|
+
: store
|
|
1024
|
+
.countPeerMessages(request.request)
|
|
1025
|
+
.pipe(Effect.map((count) => StoreCountPeerMessagesResult.make({ count }))),
|
|
1026
|
+
);
|
|
1027
|
+
}
|
|
926
1028
|
case "LedgerAdmit": {
|
|
927
1029
|
const ledger = yield* SubmissionLedger;
|
|
1030
|
+
|
|
928
1031
|
return yield* capture(
|
|
929
1032
|
ledger
|
|
930
1033
|
.admit(request.request)
|
|
@@ -933,12 +1036,14 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
933
1036
|
}
|
|
934
1037
|
case "LedgerMarkReady": {
|
|
935
1038
|
const ledger = yield* SubmissionLedger;
|
|
1039
|
+
|
|
936
1040
|
return yield* capture(
|
|
937
1041
|
ledger.markReady(request.request).pipe(Effect.map(() => LedgerMarkReadyResult.make({}))),
|
|
938
1042
|
);
|
|
939
1043
|
}
|
|
940
1044
|
case "LedgerLookup": {
|
|
941
1045
|
const ledger = yield* SubmissionLedger;
|
|
1046
|
+
|
|
942
1047
|
return yield* capture(
|
|
943
1048
|
ledger
|
|
944
1049
|
.lookup(request.request)
|
|
@@ -953,6 +1058,7 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
953
1058
|
}
|
|
954
1059
|
case "LedgerResolveAdmission": {
|
|
955
1060
|
const ledger = yield* SubmissionLedger;
|
|
1061
|
+
|
|
956
1062
|
return yield* capture(
|
|
957
1063
|
ledger
|
|
958
1064
|
.resolveAdmission(request.request)
|
|
@@ -961,6 +1067,7 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
961
1067
|
}
|
|
962
1068
|
case "LedgerRequestAbort": {
|
|
963
1069
|
const ledger = yield* SubmissionLedger;
|
|
1070
|
+
|
|
964
1071
|
return yield* capture(
|
|
965
1072
|
ledger
|
|
966
1073
|
.requestAbort(request.request)
|
|
@@ -969,6 +1076,7 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
969
1076
|
}
|
|
970
1077
|
case "LedgerRecordChildSettled": {
|
|
971
1078
|
const ledger = yield* SubmissionLedger;
|
|
1079
|
+
|
|
972
1080
|
return yield* capture(
|
|
973
1081
|
ledger
|
|
974
1082
|
.recordChildSettled(request.request)
|
|
@@ -976,13 +1084,15 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
976
1084
|
);
|
|
977
1085
|
}
|
|
978
1086
|
case "StoreMaterialize": {
|
|
979
|
-
const store = yield*
|
|
1087
|
+
const store = yield* ThreadStore;
|
|
1088
|
+
|
|
980
1089
|
return yield* capture(
|
|
981
1090
|
store.materialize(request.request).pipe(Effect.map(() => StoreMaterializeResult.make({}))),
|
|
982
1091
|
);
|
|
983
1092
|
}
|
|
984
1093
|
case "StoreAppend": {
|
|
985
|
-
const store = yield*
|
|
1094
|
+
const store = yield* ThreadStore;
|
|
1095
|
+
|
|
986
1096
|
return yield* capture(
|
|
987
1097
|
store
|
|
988
1098
|
.append(request.request)
|
|
@@ -990,7 +1100,8 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
990
1100
|
);
|
|
991
1101
|
}
|
|
992
1102
|
case "StoreReadPage": {
|
|
993
|
-
const store = yield*
|
|
1103
|
+
const store = yield* ThreadStore;
|
|
1104
|
+
|
|
994
1105
|
return yield* capture(
|
|
995
1106
|
store.read(request.request).pipe(
|
|
996
1107
|
Stream.runCollect,
|
|
@@ -999,7 +1110,8 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
999
1110
|
);
|
|
1000
1111
|
}
|
|
1001
1112
|
case "StoreInspectTail": {
|
|
1002
|
-
const store = yield*
|
|
1113
|
+
const store = yield* ThreadStore;
|
|
1114
|
+
|
|
1003
1115
|
return yield* capture(
|
|
1004
1116
|
store
|
|
1005
1117
|
.inspectTail(request.request)
|
|
@@ -1007,15 +1119,12 @@ export const executePortRequest = Effect.fn("DoPortRouting.executePortRequest")(
|
|
|
1007
1119
|
);
|
|
1008
1120
|
}
|
|
1009
1121
|
case "StoreExport": {
|
|
1010
|
-
const store = yield*
|
|
1122
|
+
const store = yield* ThreadStore;
|
|
1123
|
+
|
|
1011
1124
|
return yield* capture(
|
|
1012
1125
|
store
|
|
1013
1126
|
.export(request.request)
|
|
1014
|
-
.pipe(
|
|
1015
|
-
Effect.map((conversationExport) =>
|
|
1016
|
-
StoreExportResult.make({ export: conversationExport }),
|
|
1017
|
-
),
|
|
1018
|
-
),
|
|
1127
|
+
.pipe(Effect.map((threadExport) => StoreExportResult.make({ export: threadExport }))),
|
|
1019
1128
|
);
|
|
1020
1129
|
}
|
|
1021
1130
|
}
|
|
@@ -1041,7 +1150,7 @@ const encodedProtocolFailure = (message: string): unknown => ({
|
|
|
1041
1150
|
export const handleEncodedPortRequest = Effect.fn("DoPortRouting.handleEncodedPortRequest")(
|
|
1042
1151
|
function* (
|
|
1043
1152
|
encoded: unknown,
|
|
1044
|
-
): Effect.fn.Return<unknown, never, SubmissionLedger |
|
|
1153
|
+
): Effect.fn.Return<unknown, never, SubmissionLedger | ThreadStore | MessageDeliveryStore> {
|
|
1045
1154
|
const response = yield* decodePortRequest(encoded).pipe(
|
|
1046
1155
|
Effect.flatMap(executePortRequest),
|
|
1047
1156
|
Effect.catch((error) =>
|
|
@@ -1056,6 +1165,7 @@ export const handleEncodedPortRequest = Effect.fn("DoPortRouting.handleEncodedPo
|
|
|
1056
1165
|
),
|
|
1057
1166
|
),
|
|
1058
1167
|
);
|
|
1168
|
+
|
|
1059
1169
|
return yield* encodePortResponse(response).pipe(
|
|
1060
1170
|
Effect.catch((error) =>
|
|
1061
1171
|
Effect.succeed(
|