effect-cf 0.20.1 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -0
- package/README.md +27 -3
- package/dist/{Hyperdrive-RTjgirMV.d.mts → Hyperdrive-COyg7R26.d.mts} +40 -13
- package/dist/HyperdrivePg.d.mts +13 -5
- package/dist/HyperdrivePg.mjs +12 -7
- package/dist/index.d.mts +1113 -922
- package/dist/index.mjs +980 -604
- package/package.json +10 -5
- package/src/AiGateway.ts +82 -47
- package/src/AnalyticsEngine.ts +74 -58
- package/src/Binding.ts +66 -13
- package/src/BrowserRendering.ts +30 -7
- package/src/Cache.ts +32 -8
- package/src/CloudflareOtlp.ts +32 -9
- package/src/ContainerNamespace.ts +251 -80
- package/src/D1.ts +13 -3
- package/src/DurableObject.ts +27 -164
- package/src/DurableObjectAlarm.ts +30 -9
- package/src/DurableObjectDefinition.ts +58 -54
- package/src/DurableObjectNamespace.ts +99 -96
- package/src/DurableObjectRpcWebSocket.ts +14 -6
- package/src/DurableObjectSqlite.ts +6 -3
- package/src/DurableObjectState.ts +63 -39
- package/src/DurableObjectStorage.ts +7 -1
- package/src/DurableObjectWebSocket.ts +51 -41
- package/src/Email.ts +40 -13
- package/src/Environment.ts +26 -6
- package/src/Hyperdrive.ts +2 -2
- package/src/HyperdrivePg.ts +25 -13
- package/src/Images.ts +77 -82
- package/src/Kv.ts +37 -27
- package/src/Queue.ts +6 -1
- package/src/QueueBinding.ts +18 -21
- package/src/QueueDefinition.ts +15 -14
- package/src/R2.ts +107 -29
- package/src/Rpc.ts +3 -1
- package/src/RpcDefinition.ts +177 -133
- package/src/ServiceBinding.ts +112 -108
- package/src/Vectorize.ts +59 -14
- package/src/Worker.ts +172 -192
- package/src/WorkerDefinition.ts +5 -10
- package/src/WorkersAi.ts +27 -17
- package/src/Workflow.ts +54 -49
- package/src/WorkflowBinding.ts +19 -11
- package/src/WorkflowDefinition.ts +24 -27
- package/src/index.ts +4 -3
- package/src/internal/Entrypoint.ts +3 -1
- package/src/internal/ErrorMessage.ts +24 -0
- package/src/internal/RpcInvocation.ts +11 -8
- package/src/internal/Runtime.ts +52 -0
- package/src/internal/WorkerContext.ts +39 -17
- package/src/Entry.ts +0 -259
- package/src/internal/Clock.ts +0 -37
package/src/ServiceBinding.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as Binding from "./Binding";
|
|
|
4
4
|
import * as CloudflareRpc from "./Rpc";
|
|
5
5
|
import * as RpcDefinition from "./RpcDefinition";
|
|
6
6
|
import type * as WorkerDefinition from "./WorkerDefinition";
|
|
7
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
7
8
|
import * as RpcInvocation from "./internal/RpcInvocation";
|
|
8
9
|
|
|
9
10
|
const TypeId = "effect-cf/ServiceBinding" as const;
|
|
@@ -58,7 +59,11 @@ export interface ServiceBindingDefinition<
|
|
|
58
59
|
export class ServiceBindingFetchError extends Data.TaggedError("ServiceBindingFetchError")<{
|
|
59
60
|
readonly binding: string;
|
|
60
61
|
readonly cause: unknown;
|
|
61
|
-
}> {
|
|
62
|
+
}> {
|
|
63
|
+
override get message(): string {
|
|
64
|
+
return `Service binding "${this.binding}" fetch failed: ${ErrorMessage.causeMessage(this.cause)}`;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
62
67
|
|
|
63
68
|
/**
|
|
64
69
|
* Failure raised when invoking an RPC method on a service binding.
|
|
@@ -67,7 +72,11 @@ export class ServiceBindingRpcError extends Data.TaggedError("ServiceBindingRpcE
|
|
|
67
72
|
readonly binding: string;
|
|
68
73
|
readonly method: string;
|
|
69
74
|
readonly cause: unknown;
|
|
70
|
-
}> {
|
|
75
|
+
}> {
|
|
76
|
+
override get message(): string {
|
|
77
|
+
return `Service binding "${this.binding}" RPC method "${this.method}" failed: ${ErrorMessage.causeMessage(this.cause)}`;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
71
80
|
|
|
72
81
|
type ServiceMethodKey<Api> = RpcInvocation.AsyncMethodKey<Api>;
|
|
73
82
|
type ServiceMethodArgs<Api, Method extends keyof Api> = RpcInvocation.AsyncMethodArgs<Api, Method>;
|
|
@@ -235,107 +244,106 @@ export const makeClient = <
|
|
|
235
244
|
definition: ServiceBindingDefinition<Definition>,
|
|
236
245
|
): ((service: ServiceBindingClient<Api>) => ServiceBindingEffectClient<Api, Definition>) => {
|
|
237
246
|
return (service: ServiceBindingClient<Api>) => {
|
|
238
|
-
const fetch = (
|
|
239
|
-
|
|
247
|
+
const fetch = Effect.fn("ServiceBinding.fetch")(function* (
|
|
248
|
+
input: RequestInfo | URL,
|
|
249
|
+
init?: RequestInit,
|
|
250
|
+
) {
|
|
251
|
+
return yield* Effect.tryPromise({
|
|
240
252
|
try: () => service.fetch(input, init),
|
|
241
253
|
catch: (cause) => new ServiceBindingFetchError({ binding: definition.binding, cause }),
|
|
242
254
|
});
|
|
255
|
+
});
|
|
243
256
|
|
|
244
|
-
const rpc = <Method extends ServiceMethodKey<Api>>(
|
|
257
|
+
const rpc = Effect.fn("ServiceBinding.rpc")(function* <Method extends ServiceMethodKey<Api>>(
|
|
245
258
|
method: Method,
|
|
246
259
|
...args: ServiceMethodArgs<Api, Method>
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
260
|
+
) {
|
|
261
|
+
const methodName = String(method);
|
|
262
|
+
const encodedArgs =
|
|
263
|
+
definition.definition === undefined
|
|
264
|
+
? args
|
|
265
|
+
: yield* RpcDefinition.encodeArgs(
|
|
266
|
+
definition.definition,
|
|
267
|
+
methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
|
|
268
|
+
args as never,
|
|
269
|
+
).pipe(
|
|
270
|
+
Effect.mapError(
|
|
271
|
+
(cause) =>
|
|
272
|
+
new ServiceBindingRpcError({
|
|
273
|
+
binding: definition.binding,
|
|
274
|
+
method: methodName,
|
|
275
|
+
cause,
|
|
276
|
+
}),
|
|
277
|
+
),
|
|
278
|
+
);
|
|
279
|
+
|
|
280
|
+
return yield* RpcInvocation.invokeRpcMethod(
|
|
281
|
+
service,
|
|
282
|
+
method,
|
|
283
|
+
encodedArgs as ServiceMethodArgs<Api, Method>,
|
|
284
|
+
(cause) =>
|
|
285
|
+
new ServiceBindingRpcError({
|
|
286
|
+
binding: definition.binding,
|
|
287
|
+
method: methodName,
|
|
288
|
+
cause,
|
|
289
|
+
}),
|
|
290
|
+
);
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const decodeSuccess = Effect.fnUntraced(function* <Method extends ServiceMethodKey<Api>>(
|
|
294
|
+
methodName: string,
|
|
295
|
+
value: Awaited<ServiceMethodCloudflareReturn<Api, Method>>,
|
|
296
|
+
) {
|
|
297
|
+
if (definition.definition === undefined) {
|
|
298
|
+
return value as ServiceMethodSuccess<Api, Method>;
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const decoded = yield* RpcDefinition.decodeSuccess(
|
|
302
|
+
definition.definition,
|
|
303
|
+
methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
|
|
304
|
+
value,
|
|
305
|
+
).pipe(
|
|
306
|
+
Effect.mapError(
|
|
272
307
|
(cause) =>
|
|
273
308
|
new ServiceBindingRpcError({
|
|
274
309
|
binding: definition.binding,
|
|
275
310
|
method: methodName,
|
|
276
311
|
cause,
|
|
277
312
|
}),
|
|
278
|
-
)
|
|
279
|
-
|
|
313
|
+
),
|
|
314
|
+
);
|
|
280
315
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
value: Awaited<ServiceMethodCloudflareReturn<Api, Method>>,
|
|
284
|
-
) =>
|
|
285
|
-
Effect.gen(function* () {
|
|
286
|
-
if (definition.definition === undefined) {
|
|
287
|
-
return value as ServiceMethodSuccess<Api, Method>;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
const decoded = yield* RpcDefinition.decodeSuccess(
|
|
291
|
-
definition.definition,
|
|
292
|
-
methodName as RpcDefinition.Definition.MethodNames<NonNullable<Definition>>,
|
|
293
|
-
value,
|
|
294
|
-
).pipe(
|
|
295
|
-
Effect.mapError(
|
|
296
|
-
(cause) =>
|
|
297
|
-
new ServiceBindingRpcError({
|
|
298
|
-
binding: definition.binding,
|
|
299
|
-
method: methodName,
|
|
300
|
-
cause,
|
|
301
|
-
}),
|
|
302
|
-
),
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
return decoded as ServiceMethodSuccess<Api, Method>;
|
|
306
|
-
});
|
|
316
|
+
return decoded as ServiceMethodSuccess<Api, Method>;
|
|
317
|
+
});
|
|
307
318
|
|
|
308
|
-
const call = <Method extends ServiceMethodKey<Api>>(
|
|
319
|
+
const call = Effect.fn("ServiceBinding.call")(function* <Method extends ServiceMethodKey<Api>>(
|
|
309
320
|
method: Method,
|
|
310
321
|
...args: ServiceMethodArgs<Api, Method>
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
(
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
);
|
|
324
|
-
|
|
325
|
-
return yield* decodeSuccess<Method>(methodName, value);
|
|
326
|
-
});
|
|
322
|
+
) {
|
|
323
|
+
const methodName = String(method);
|
|
324
|
+
const value = yield* CloudflareRpc.resolve(yield* rpc(method, ...args)).pipe(
|
|
325
|
+
Effect.mapError(
|
|
326
|
+
(cause) =>
|
|
327
|
+
new ServiceBindingRpcError({
|
|
328
|
+
binding: definition.binding,
|
|
329
|
+
method: methodName,
|
|
330
|
+
cause,
|
|
331
|
+
}),
|
|
332
|
+
),
|
|
333
|
+
);
|
|
327
334
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
...args: ServiceMethodArgs<Api, Method>
|
|
331
|
-
) =>
|
|
332
|
-
Effect.gen(function* () {
|
|
333
|
-
const methodName = String(method);
|
|
334
|
-
const result = yield* rpc(method, ...args);
|
|
335
|
-
const value = yield* CloudflareRpc.scoped(result);
|
|
335
|
+
return yield* decodeSuccess<Method>(methodName, value);
|
|
336
|
+
});
|
|
336
337
|
|
|
337
|
-
|
|
338
|
-
|
|
338
|
+
const scopedCall = Effect.fn("ServiceBinding.scopedCall")(function* <
|
|
339
|
+
Method extends ServiceMethodKey<Api>,
|
|
340
|
+
>(method: Method, ...args: ServiceMethodArgs<Api, Method>) {
|
|
341
|
+
const methodName = String(method);
|
|
342
|
+
const result = yield* rpc(method, ...args);
|
|
343
|
+
const value = yield* CloudflareRpc.scoped(result);
|
|
344
|
+
|
|
345
|
+
return yield* decodeSuccess<Method>(methodName, value);
|
|
346
|
+
});
|
|
339
347
|
|
|
340
348
|
const directMethods = makeDirectMethods<never, Api, Definition>(definition.definition, call);
|
|
341
349
|
|
|
@@ -411,42 +419,38 @@ export const Service =
|
|
|
411
419
|
makeClient<ServiceApi, Definition>(definition),
|
|
412
420
|
);
|
|
413
421
|
|
|
414
|
-
const fetch = (input: RequestInfo | URL, init?: RequestInit)
|
|
415
|
-
|
|
416
|
-
const service = yield* tag;
|
|
422
|
+
const fetch = Effect.fnUntraced(function* (input: RequestInfo | URL, init?: RequestInit) {
|
|
423
|
+
const service = yield* tag;
|
|
417
424
|
|
|
418
|
-
|
|
419
|
-
|
|
425
|
+
return yield* service.fetch(input, init);
|
|
426
|
+
});
|
|
420
427
|
|
|
421
|
-
const rpc = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
428
|
+
const rpc = Effect.fnUntraced(function* <Method extends ServiceMethodKey<ServiceApi>>(
|
|
422
429
|
method: Method,
|
|
423
430
|
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
424
|
-
)
|
|
425
|
-
|
|
426
|
-
const service = yield* tag;
|
|
431
|
+
) {
|
|
432
|
+
const service = yield* tag;
|
|
427
433
|
|
|
428
|
-
|
|
429
|
-
|
|
434
|
+
return yield* service.rpc(method, ...args);
|
|
435
|
+
});
|
|
430
436
|
|
|
431
|
-
const call = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
437
|
+
const call = Effect.fnUntraced(function* <Method extends ServiceMethodKey<ServiceApi>>(
|
|
432
438
|
method: Method,
|
|
433
439
|
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
434
|
-
)
|
|
435
|
-
|
|
436
|
-
const service = yield* tag;
|
|
440
|
+
) {
|
|
441
|
+
const service = yield* tag;
|
|
437
442
|
|
|
438
|
-
|
|
439
|
-
|
|
443
|
+
return yield* service.call(method, ...args);
|
|
444
|
+
});
|
|
440
445
|
|
|
441
|
-
const scopedCall = <Method extends ServiceMethodKey<ServiceApi>>(
|
|
446
|
+
const scopedCall = Effect.fnUntraced(function* <Method extends ServiceMethodKey<ServiceApi>>(
|
|
442
447
|
method: Method,
|
|
443
448
|
...args: ServiceMethodArgs<ServiceApi, Method>
|
|
444
|
-
)
|
|
445
|
-
|
|
446
|
-
const service = yield* tag;
|
|
449
|
+
) {
|
|
450
|
+
const service = yield* tag;
|
|
447
451
|
|
|
448
|
-
|
|
449
|
-
|
|
452
|
+
return yield* service.scopedCall(method, ...args);
|
|
453
|
+
});
|
|
450
454
|
|
|
451
455
|
const directMethods = makeDirectMethods<Self, ServiceApi, Definition>(
|
|
452
456
|
definition.definition,
|
package/src/Vectorize.ts
CHANGED
|
@@ -17,16 +17,31 @@ import type {
|
|
|
17
17
|
|
|
18
18
|
import * as Binding from "./Binding";
|
|
19
19
|
import type { WorkerEnvironment } from "./Environment";
|
|
20
|
+
import * as ErrorMessage from "./internal/ErrorMessage";
|
|
20
21
|
|
|
21
22
|
const expectedVectorizeBinding =
|
|
22
23
|
"Vectorize index binding with describe(), query(), insert(), upsert(), deleteByIds(), and getByIds()";
|
|
23
24
|
|
|
25
|
+
/** Vectorize operation represented by {@link VectorizeOperationError}. */
|
|
26
|
+
export type VectorizeOperation =
|
|
27
|
+
| "describe"
|
|
28
|
+
| "query"
|
|
29
|
+
| "queryById"
|
|
30
|
+
| "insert"
|
|
31
|
+
| "upsert"
|
|
32
|
+
| "deleteByIds"
|
|
33
|
+
| "getByIds";
|
|
34
|
+
|
|
24
35
|
/** Error raised when a Vectorize operation fails. */
|
|
25
36
|
export class VectorizeOperationError extends Data.TaggedError("VectorizeOperationError")<{
|
|
26
37
|
readonly binding: string;
|
|
27
|
-
readonly operation:
|
|
38
|
+
readonly operation: VectorizeOperation;
|
|
28
39
|
readonly cause: unknown;
|
|
29
|
-
}> {
|
|
40
|
+
}> {
|
|
41
|
+
override get message(): string {
|
|
42
|
+
return `Vectorize ${this.operation} failed for binding "${this.binding}": ${ErrorMessage.causeMessage(this.cause)}`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
30
45
|
|
|
31
46
|
/** Typed Vectorize binding definition. */
|
|
32
47
|
export interface VectorizeDefinition {
|
|
@@ -93,7 +108,7 @@ export interface VectorizeClient {
|
|
|
93
108
|
readonly getByIds: (
|
|
94
109
|
ids: ReadonlyArray<string>,
|
|
95
110
|
) => Effect.Effect<ReadonlyArray<VectorizeVector>, VectorizeOperationError>;
|
|
96
|
-
readonly
|
|
111
|
+
readonly rawUnsafe: Effect.Effect<VectorizeBinding>;
|
|
97
112
|
readonly definition: VectorizeDefinition;
|
|
98
113
|
}
|
|
99
114
|
|
|
@@ -125,12 +140,12 @@ export interface TagClass<Self, Id extends string> extends Context.ServiceClass<
|
|
|
125
140
|
>;
|
|
126
141
|
}
|
|
127
142
|
|
|
128
|
-
const vectorizeError = (binding: string, operation:
|
|
143
|
+
const vectorizeError = (binding: string, operation: VectorizeOperation, cause: unknown) =>
|
|
129
144
|
new VectorizeOperationError({ binding, operation, cause });
|
|
130
145
|
|
|
131
146
|
const tryVectorizePromise = <A>(
|
|
132
147
|
binding: string,
|
|
133
|
-
operation:
|
|
148
|
+
operation: VectorizeOperation,
|
|
134
149
|
evaluate: () => Promise<A>,
|
|
135
150
|
): Effect.Effect<A, VectorizeOperationError> =>
|
|
136
151
|
Effect.tryPromise({
|
|
@@ -138,6 +153,10 @@ const tryVectorizePromise = <A>(
|
|
|
138
153
|
catch: (cause) => vectorizeError(binding, operation, cause),
|
|
139
154
|
});
|
|
140
155
|
|
|
156
|
+
const spanOptions = (binding: string, operation: VectorizeOperation) => ({
|
|
157
|
+
attributes: { binding, operation },
|
|
158
|
+
});
|
|
159
|
+
|
|
141
160
|
const hasFunction = (value: object, key: string): boolean =>
|
|
142
161
|
typeof Reflect.get(value, key) === "function";
|
|
143
162
|
|
|
@@ -155,17 +174,30 @@ export const makeClient =
|
|
|
155
174
|
(definition: VectorizeDefinition) =>
|
|
156
175
|
(index: VectorizeBinding): VectorizeClient => {
|
|
157
176
|
const runtime = index as VectorizeRuntimeBinding;
|
|
158
|
-
const deleteByIds = (
|
|
159
|
-
|
|
177
|
+
const deleteByIds = Effect.fn(
|
|
178
|
+
"Vectorize.deleteByIds",
|
|
179
|
+
spanOptions(definition.binding, "deleteByIds"),
|
|
180
|
+
)((ids: ReadonlyArray<string>) =>
|
|
181
|
+
tryVectorizePromise(definition.binding, "deleteByIds", () => runtime.deleteByIds([...ids])),
|
|
182
|
+
);
|
|
160
183
|
|
|
161
184
|
return {
|
|
162
185
|
definition,
|
|
163
|
-
describe: tryVectorizePromise(definition.binding, "describe", () => runtime.describe())
|
|
164
|
-
|
|
186
|
+
describe: tryVectorizePromise(definition.binding, "describe", () => runtime.describe()).pipe(
|
|
187
|
+
Effect.withSpan("Vectorize.describe", spanOptions(definition.binding, "describe")),
|
|
188
|
+
),
|
|
189
|
+
query: Effect.fn(
|
|
190
|
+
"Vectorize.query",
|
|
191
|
+
spanOptions(definition.binding, "query"),
|
|
192
|
+
)((vector: VectorizeValues, options?: VectorizeQueryOptions) =>
|
|
165
193
|
tryVectorizePromise(definition.binding, "query", () =>
|
|
166
194
|
runtime.query(vector as Float32Array | Float64Array | number[], options),
|
|
167
195
|
),
|
|
168
|
-
|
|
196
|
+
),
|
|
197
|
+
queryById: Effect.fn(
|
|
198
|
+
"Vectorize.queryById",
|
|
199
|
+
spanOptions(definition.binding, "queryById"),
|
|
200
|
+
)((vectorId: string, options?: VectorizeQueryOptions) =>
|
|
169
201
|
runtime.queryById !== undefined
|
|
170
202
|
? tryVectorizePromise(definition.binding, "queryById", () =>
|
|
171
203
|
runtime.queryById!(vectorId, options),
|
|
@@ -177,15 +209,28 @@ export const makeClient =
|
|
|
177
209
|
new TypeError("Vectorize binding does not expose queryById()"),
|
|
178
210
|
),
|
|
179
211
|
),
|
|
180
|
-
|
|
212
|
+
),
|
|
213
|
+
insert: Effect.fn(
|
|
214
|
+
"Vectorize.insert",
|
|
215
|
+
spanOptions(definition.binding, "insert"),
|
|
216
|
+
)((vectors: ReadonlyArray<VectorizeVector>) =>
|
|
181
217
|
tryVectorizePromise(definition.binding, "insert", () => runtime.insert([...vectors])),
|
|
182
|
-
|
|
218
|
+
),
|
|
219
|
+
upsert: Effect.fn(
|
|
220
|
+
"Vectorize.upsert",
|
|
221
|
+
spanOptions(definition.binding, "upsert"),
|
|
222
|
+
)((vectors: ReadonlyArray<VectorizeVector>) =>
|
|
183
223
|
tryVectorizePromise(definition.binding, "upsert", () => runtime.upsert([...vectors])),
|
|
224
|
+
),
|
|
184
225
|
deleteByIds,
|
|
185
226
|
delete: deleteByIds,
|
|
186
|
-
getByIds: (
|
|
227
|
+
getByIds: Effect.fn(
|
|
228
|
+
"Vectorize.getByIds",
|
|
229
|
+
spanOptions(definition.binding, "getByIds"),
|
|
230
|
+
)((ids: ReadonlyArray<string>) =>
|
|
187
231
|
tryVectorizePromise(definition.binding, "getByIds", () => runtime.getByIds([...ids])),
|
|
188
|
-
|
|
232
|
+
),
|
|
233
|
+
rawUnsafe: Effect.succeed(index),
|
|
189
234
|
};
|
|
190
235
|
};
|
|
191
236
|
|