@panorama-industries/effect-vercel-queue 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +13 -2
- package/dist/contracts/message-handling.d.ts +128 -0
- package/dist/contracts/message-handling.d.ts.map +1 -0
- package/dist/contracts/message-handling.js +4 -0
- package/dist/contracts/message-handling.js.map +1 -0
- package/dist/contracts/queue-api.d.ts +255 -0
- package/dist/contracts/queue-api.d.ts.map +1 -0
- package/dist/contracts/queue-api.js +18 -0
- package/dist/contracts/queue-api.js.map +1 -0
- package/dist/contracts/queue-config.d.ts +87 -0
- package/dist/contracts/queue-config.d.ts.map +1 -0
- package/dist/contracts/queue-config.js +7 -0
- package/dist/contracts/queue-config.js.map +1 -0
- package/dist/contracts/queue-consumer.d.ts +30 -0
- package/dist/contracts/queue-consumer.d.ts.map +1 -0
- package/dist/contracts/queue-consumer.js +15 -0
- package/dist/contracts/queue-consumer.js.map +1 -0
- package/dist/contracts/queue-domain.d.ts +171 -0
- package/dist/contracts/queue-domain.d.ts.map +1 -0
- package/dist/contracts/queue-domain.js +137 -0
- package/dist/contracts/queue-domain.js.map +1 -0
- package/dist/contracts/queue-poller.d.ts +169 -0
- package/dist/contracts/queue-poller.d.ts.map +1 -0
- package/dist/contracts/queue-poller.js +10 -0
- package/dist/contracts/queue-poller.js.map +1 -0
- package/dist/contracts/queue-producer.d.ts +23 -0
- package/dist/contracts/queue-producer.d.ts.map +1 -0
- package/dist/contracts/queue-producer.js +5 -0
- package/dist/contracts/queue-producer.js.map +1 -0
- package/dist/contracts/topic.d.ts +47 -0
- package/dist/contracts/topic.d.ts.map +1 -0
- package/dist/contracts/topic.js +34 -0
- package/dist/contracts/topic.js.map +1 -0
- package/dist/implementation/queue-api-live.d.ts +16 -0
- package/dist/implementation/queue-api-live.d.ts.map +1 -0
- package/dist/implementation/queue-api-live.js +326 -0
- package/dist/implementation/queue-api-live.js.map +1 -0
- package/dist/implementation/queue-config-live.d.ts +37 -0
- package/dist/implementation/queue-config-live.d.ts.map +1 -0
- package/dist/implementation/queue-config-live.js +99 -0
- package/dist/implementation/queue-config-live.js.map +1 -0
- package/dist/implementation/queue-consumer-live.d.ts +14 -0
- package/dist/implementation/queue-consumer-live.d.ts.map +1 -0
- package/dist/implementation/queue-consumer-live.js +56 -0
- package/dist/implementation/queue-consumer-live.js.map +1 -0
- package/dist/implementation/queue-live.d.ts +15 -0
- package/dist/implementation/queue-live.d.ts.map +1 -0
- package/dist/implementation/queue-live.js +16 -0
- package/dist/implementation/queue-live.js.map +1 -0
- package/dist/implementation/queue-poller-live.d.ts +14 -0
- package/dist/implementation/queue-poller-live.d.ts.map +1 -0
- package/dist/implementation/queue-poller-live.js +66 -0
- package/dist/implementation/queue-poller-live.js.map +1 -0
- package/dist/implementation/queue-producer-live.d.ts +9 -0
- package/dist/implementation/queue-producer-live.d.ts.map +1 -0
- package/dist/implementation/queue-producer-live.js +54 -0
- package/dist/implementation/queue-producer-live.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/cloud-event.d.ts +46 -0
- package/dist/internal/cloud-event.d.ts.map +1 -0
- package/dist/internal/cloud-event.js +140 -0
- package/dist/internal/cloud-event.js.map +1 -0
- package/dist/internal/lease.d.ts +23 -0
- package/dist/internal/lease.d.ts.map +1 -0
- package/dist/internal/lease.js +44 -0
- package/dist/internal/lease.js.map +1 -0
- package/dist/internal/multipart.d.ts +23 -0
- package/dist/internal/multipart.d.ts.map +1 -0
- package/dist/internal/multipart.js +205 -0
- package/dist/internal/multipart.js.map +1 -0
- package/dist/internal/process.d.ts +25 -0
- package/dist/internal/process.d.ts.map +1 -0
- package/dist/internal/process.js +95 -0
- package/dist/internal/process.js.map +1 -0
- package/dist/internal/queue-protocol.d.ts +38 -0
- package/dist/internal/queue-protocol.d.ts.map +1 -0
- package/dist/internal/queue-protocol.js +119 -0
- package/dist/internal/queue-protocol.js.map +1 -0
- package/dist/internal/version.d.ts +4 -0
- package/dist/internal/version.d.ts.map +1 -0
- package/dist/internal/version.js +4 -0
- package/dist/internal/version.js.map +1 -0
- package/dist/retry-policy.d.ts +26 -0
- package/dist/retry-policy.d.ts.map +1 -0
- package/dist/retry-policy.js +34 -0
- package/dist/retry-policy.js.map +1 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +2 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/test-queue.d.ts +74 -0
- package/dist/testing/test-queue.d.ts.map +1 -0
- package/dist/testing/test-queue.js +253 -0
- package/dist/testing/test-queue.js.map +1 -0
- package/package.json +59 -3
- package/src/contracts/message-handling.ts +68 -0
- package/src/contracts/queue-api.ts +199 -0
- package/src/contracts/queue-config.ts +47 -0
- package/src/contracts/queue-consumer.ts +40 -0
- package/src/contracts/queue-domain.ts +202 -0
- package/src/contracts/queue-poller.ts +76 -0
- package/src/contracts/queue-producer.ts +40 -0
- package/src/contracts/topic.ts +76 -0
- package/src/implementation/queue-api-live.ts +637 -0
- package/src/implementation/queue-config-live.ts +178 -0
- package/src/implementation/queue-consumer-live.ts +112 -0
- package/src/implementation/queue-live.ts +32 -0
- package/src/implementation/queue-poller-live.ts +130 -0
- package/src/implementation/queue-producer-live.ts +89 -0
- package/src/index.ts +19 -0
- package/src/internal/cloud-event.ts +244 -0
- package/src/internal/lease.ts +84 -0
- package/src/internal/multipart.ts +240 -0
- package/src/internal/process.ts +194 -0
- package/src/internal/queue-protocol.ts +169 -0
- package/src/internal/version.ts +5 -0
- package/src/retry-policy.ts +48 -0
- package/src/testing/index.ts +1 -0
- package/src/testing/test-queue.ts +469 -0
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Config } from "effect";
|
|
2
|
+
import type { HttpClient } from "effect/http";
|
|
3
|
+
import { Layer } from "effect";
|
|
4
|
+
import type { QueueConsumer } from "../contracts/queue-consumer.ts";
|
|
5
|
+
import type { QueuePoller } from "../contracts/queue-poller.ts";
|
|
6
|
+
import type { QueueProducer } from "../contracts/queue-producer.ts";
|
|
7
|
+
/**
|
|
8
|
+
* Producer, push consumer and poller configured from the Vercel environment, authenticated with
|
|
9
|
+
* the function's OIDC token. Provide an `HttpClient`, e.g. `FetchHttpClient.layer`.
|
|
10
|
+
*
|
|
11
|
+
* Compose the individual layers instead to override configuration (`queueConfigLayer`) or
|
|
12
|
+
* credentials.
|
|
13
|
+
*/
|
|
14
|
+
export declare const QueueLive: Layer.Layer<QueueProducer | QueueConsumer | QueuePoller, Config.ConfigError, HttpClient.HttpClient>;
|
|
15
|
+
//# sourceMappingURL=queue-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-live.d.ts","sourceRoot":"","sources":["../../src/implementation/queue-live.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAG9C,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AACpE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAQpE;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,KAAK,CACjC,aAAa,GAAG,aAAa,GAAG,WAAW,EAC3C,MAAM,CAAC,WAAW,EAClB,UAAU,CAAC,UAAU,CAKtB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { VercelOidcLive, VercelSystemEnvLive } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { Layer } from "effect";
|
|
3
|
+
import { QueueApiLive } from "./queue-api-live.js";
|
|
4
|
+
import { QueueConfigLive } from "./queue-config-live.js";
|
|
5
|
+
import { QueueConsumerLive } from "./queue-consumer-live.js";
|
|
6
|
+
import { QueuePollerLive } from "./queue-poller-live.js";
|
|
7
|
+
import { QueueProducerLive } from "./queue-producer-live.js";
|
|
8
|
+
/**
|
|
9
|
+
* Producer, push consumer and poller configured from the Vercel environment, authenticated with
|
|
10
|
+
* the function's OIDC token. Provide an `HttpClient`, e.g. `FetchHttpClient.layer`.
|
|
11
|
+
*
|
|
12
|
+
* Compose the individual layers instead to override configuration (`queueConfigLayer`) or
|
|
13
|
+
* credentials.
|
|
14
|
+
*/
|
|
15
|
+
export const QueueLive = Layer.mergeAll(QueueProducerLive, QueueConsumerLive, QueuePollerLive).pipe(Layer.provideMerge(QueueApiLive), Layer.provide(Layer.mergeAll(QueueConfigLive, VercelOidcLive)), Layer.provide(VercelSystemEnvLive));
|
|
16
|
+
//# sourceMappingURL=queue-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-live.js","sourceRoot":"","sources":["../../src/implementation/queue-live.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAC9F,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAM/B,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,SAAS,GAIlB,KAAK,CAAC,QAAQ,CAAC,iBAAiB,EAAE,iBAAiB,EAAE,eAAe,CAAC,CAAC,IAAI,CAC5E,KAAK,CAAC,YAAY,CAAC,YAAY,CAAC,EAChC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,eAAe,EAAE,cAAc,CAAC,CAAC,EAC9D,KAAK,CAAC,OAAO,CAAC,mBAAmB,CAAC,CACnC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { QueueApi } from "../contracts/queue-api.ts";
|
|
3
|
+
import { QueuePoller } from "../contracts/queue-poller.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Implements {@link QueuePoller}, as `@vercel/queue`'s `PollingQueueClient.receive`.
|
|
6
|
+
*
|
|
7
|
+
* Requires `QueueApi`. Leases default to 5 minutes (at least 30 seconds) and are renewed while each
|
|
8
|
+
* handler runs. A batch is handled concurrently up to `concurrency` (unbounded by default), and
|
|
9
|
+
* messages waiting their turn keep their leases renewed. When handlers fail, every message is still
|
|
10
|
+
* settled and the first failure in delivery order is returned. An undecodable payload whose error
|
|
11
|
+
* policy answers `Fail` is reported as `MessageCorrupted`.
|
|
12
|
+
*/
|
|
13
|
+
export declare const QueuePollerLive: Layer.Layer<QueuePoller, never, QueueApi>;
|
|
14
|
+
//# sourceMappingURL=queue-poller-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-poller-live.d.ts","sourceRoot":"","sources":["../../src/implementation/queue-poller-live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,EAA4B,MAAM,QAAQ,CAAC;AAcvE,OAAO,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAErD,OAAO,EAAE,WAAW,EAAkB,MAAM,8BAA8B,CAAC;AAI3E;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,2CAoG3B,CAAC"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { Effect, Exit, Layer, Option, Predicate, Scope } from "effect";
|
|
2
|
+
import { QueueApi } from "../contracts/queue-api.js";
|
|
3
|
+
import { MessageCorrupted, PayloadDecodeFailed } from "../contracts/queue-domain.js";
|
|
4
|
+
import { QueuePoller, ReceiveOutcome } from "../contracts/queue-poller.js";
|
|
5
|
+
import { keepLeaseAlive, leaseVisibilityTimeout } from "../internal/lease.js";
|
|
6
|
+
import { processDelivery, withProcessSpan } from "../internal/process.js";
|
|
7
|
+
/**
|
|
8
|
+
* Implements {@link QueuePoller}, as `@vercel/queue`'s `PollingQueueClient.receive`.
|
|
9
|
+
*
|
|
10
|
+
* Requires `QueueApi`. Leases default to 5 minutes (at least 30 seconds) and are renewed while each
|
|
11
|
+
* handler runs. A batch is handled concurrently up to `concurrency` (unbounded by default), and
|
|
12
|
+
* messages waiting their turn keep their leases renewed. When handlers fail, every message is still
|
|
13
|
+
* settled and the first failure in delivery order is returned. An undecodable payload whose error
|
|
14
|
+
* policy answers `Fail` is reported as `MessageCorrupted`.
|
|
15
|
+
*/
|
|
16
|
+
export const QueuePollerLive = Layer.effect(QueuePoller, Effect.gen(function* () {
|
|
17
|
+
const api = yield* QueueApi;
|
|
18
|
+
const handleOne = (topic, handler, options, message) => processDelivery(api, topic, handler, options, {
|
|
19
|
+
message,
|
|
20
|
+
deadline: Option.none(),
|
|
21
|
+
}).pipe(withProcessSpan([]), Effect.mapError((error) => error instanceof PayloadDecodeFailed
|
|
22
|
+
? new MessageCorrupted({ messageId: error.messageId, message: error.message })
|
|
23
|
+
: error));
|
|
24
|
+
const receive = (topic, consumerGroup, handler, options = {}) => Effect.gen(function* () {
|
|
25
|
+
const messages = yield* api.receive(topic.name, consumerGroup, {
|
|
26
|
+
visibilityTimeout: leaseVisibilityTimeout(options.visibilityTimeout),
|
|
27
|
+
...(options.limit === undefined ? {} : { limit: options.limit }),
|
|
28
|
+
...(options.cursorFallback === undefined
|
|
29
|
+
? {}
|
|
30
|
+
: { cursorFallback: options.cursorFallback }),
|
|
31
|
+
...(options.region === undefined ? {} : { region: options.region }),
|
|
32
|
+
});
|
|
33
|
+
if (messages.length === 0)
|
|
34
|
+
return ReceiveOutcome.Empty();
|
|
35
|
+
const timeout = leaseVisibilityTimeout(options.visibilityTimeout);
|
|
36
|
+
const waiting = yield* Effect.forEach(messages, (message) => Effect.gen(function* () {
|
|
37
|
+
const scope = yield* Scope.make();
|
|
38
|
+
yield* keepLeaseAlive(api, message.handle, timeout, Option.none()).pipe(Scope.provide(scope));
|
|
39
|
+
return { message, scope };
|
|
40
|
+
}));
|
|
41
|
+
const exits = yield* Effect.forEach(waiting, ({ message, scope }) => Scope.close(scope, Exit.void).pipe(Effect.andThen(Effect.exit(handleOne(topic, handler, options, message)))), { concurrency: options.concurrency ?? "unbounded" }).pipe(Effect.ensuring(Effect.forEach(waiting, ({ scope }) => Scope.close(scope, Exit.void))));
|
|
42
|
+
const failure = exits.find(Exit.isFailure);
|
|
43
|
+
if (failure !== undefined)
|
|
44
|
+
return yield* Effect.failCause(failure.cause);
|
|
45
|
+
return ReceiveOutcome.Processed({ count: messages.length });
|
|
46
|
+
});
|
|
47
|
+
const receiveById = (topic, consumerGroup, messageId, handler, options = {}) => api
|
|
48
|
+
.receiveById(topic.name, consumerGroup, messageId, {
|
|
49
|
+
visibilityTimeout: leaseVisibilityTimeout(options.visibilityTimeout),
|
|
50
|
+
...(options.region === undefined ? {} : { region: options.region }),
|
|
51
|
+
})
|
|
52
|
+
.pipe(Effect.flatMap((message) => handleOne(topic, handler, options, message)), Effect.as(ReceiveOutcome.Processed({ count: 1 })), Effect.catch((error) => {
|
|
53
|
+
if (Predicate.isTagged(error, "MessageNotFound")) {
|
|
54
|
+
return Effect.succeed(ReceiveOutcome.NotFound({ messageId }));
|
|
55
|
+
}
|
|
56
|
+
if (Predicate.isTagged(error, "MessageNotAvailable")) {
|
|
57
|
+
return Effect.succeed(ReceiveOutcome.NotAvailable({ messageId }));
|
|
58
|
+
}
|
|
59
|
+
if (Predicate.isTagged(error, "MessageAlreadyProcessed")) {
|
|
60
|
+
return Effect.succeed(ReceiveOutcome.AlreadyProcessed({ messageId }));
|
|
61
|
+
}
|
|
62
|
+
return Effect.fail(error);
|
|
63
|
+
}));
|
|
64
|
+
return QueuePoller.of({ receive, receiveById });
|
|
65
|
+
}));
|
|
66
|
+
//# sourceMappingURL=queue-poller-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-poller-live.js","sourceRoot":"","sources":["../../src/implementation/queue-poller-live.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { QueueApi } from "../contracts/queue-api.ts";
|
|
3
|
+
import { QueueProducer } from "../contracts/queue-producer.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Implements {@link QueueProducer} over `QueueApi`: encodes payloads with the topic's schema and
|
|
6
|
+
* publishes them in a `vqs.send` producer span.
|
|
7
|
+
*/
|
|
8
|
+
export declare const QueueProducerLive: Layer.Layer<QueueProducer, never, QueueApi>;
|
|
9
|
+
//# sourceMappingURL=queue-producer-live.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-producer-live.d.ts","sourceRoot":"","sources":["../../src/implementation/queue-producer-live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,EAAU,MAAM,QAAQ,CAAC;AAMtD,OAAO,EAAE,QAAQ,EAAc,MAAM,2BAA2B,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AA8B/D;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAAK,CAAC,KAAK,CAAC,aAAa,EAAE,KAAK,EAAE,QAAQ,CA8CzE,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { Array, Effect, Layer, Schema } from "effect";
|
|
2
|
+
import { QueueApi, SendResult } from "../contracts/queue-api.js";
|
|
3
|
+
import { BatchSizeOutOfRange, PayloadEncodeFailed } from "../contracts/queue-domain.js";
|
|
4
|
+
import { QueueProducer } from "../contracts/queue-producer.js";
|
|
5
|
+
const maxBatchSize = 100;
|
|
6
|
+
const encode = (topic, payload) => Schema.encodeEffect(topic.wire)(payload).pipe(Effect.mapError((error) => new PayloadEncodeFailed({ topic: topic.name, message: error.message })));
|
|
7
|
+
const publishOptions = (options) => ({
|
|
8
|
+
...(options.idempotencyKey !== undefined && { idempotencyKey: options.idempotencyKey }),
|
|
9
|
+
...(options.retention !== undefined && { retention: options.retention }),
|
|
10
|
+
...(options.delay !== undefined && { delay: options.delay }),
|
|
11
|
+
...(options.headers !== undefined && { headers: options.headers }),
|
|
12
|
+
...(options.experimentalConcurrencyKey !== undefined && {
|
|
13
|
+
experimentalConcurrencyKey: options.experimentalConcurrencyKey,
|
|
14
|
+
}),
|
|
15
|
+
});
|
|
16
|
+
const sendSpan = (topic) => Effect.withSpan("vqs.send", {
|
|
17
|
+
kind: "producer",
|
|
18
|
+
attributes: {
|
|
19
|
+
"messaging.system": "vercel-queue",
|
|
20
|
+
"messaging.destination.name": topic.name,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Implements {@link QueueProducer} over `QueueApi`: encodes payloads with the topic's schema and
|
|
25
|
+
* publishes them in a `vqs.send` producer span.
|
|
26
|
+
*/
|
|
27
|
+
export const QueueProducerLive = Layer.effect(QueueProducer, Effect.gen(function* () {
|
|
28
|
+
const api = yield* QueueApi;
|
|
29
|
+
const send = Effect.fnUntraced(function* (topic, payload, options = {}) {
|
|
30
|
+
const body = yield* encode(topic, payload);
|
|
31
|
+
return yield* api
|
|
32
|
+
.send(topic.name, { ...publishOptions(options), body, contentType: topic.contentType })
|
|
33
|
+
.pipe(Effect.tap(SendResult.$match({
|
|
34
|
+
Sent: ({ messageId }) => Effect.annotateCurrentSpan("messaging.message.id", messageId),
|
|
35
|
+
Deferred: () => Effect.void,
|
|
36
|
+
})), sendSpan(topic));
|
|
37
|
+
});
|
|
38
|
+
const sendBatch = Effect.fnUntraced(function* (topic, entries) {
|
|
39
|
+
if (entries.length === 0 || entries.length > maxBatchSize) {
|
|
40
|
+
return yield* new BatchSizeOutOfRange({ size: entries.length, maximum: maxBatchSize });
|
|
41
|
+
}
|
|
42
|
+
const toMessage = (entry) => Effect.map(encode(topic, entry.payload), (body) => ({
|
|
43
|
+
...publishOptions(entry),
|
|
44
|
+
body,
|
|
45
|
+
contentType: topic.contentType,
|
|
46
|
+
}));
|
|
47
|
+
const [head, ...tail] = entries;
|
|
48
|
+
const first = yield* toMessage(head);
|
|
49
|
+
const rest = yield* Effect.forEach(tail, toMessage);
|
|
50
|
+
return yield* api.sendBatch(topic.name, [first, ...rest]).pipe(sendSpan(topic));
|
|
51
|
+
});
|
|
52
|
+
return QueueProducer.of({ send, sendBatch });
|
|
53
|
+
}));
|
|
54
|
+
//# sourceMappingURL=queue-producer-live.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue-producer-live.js","sourceRoot":"","sources":["../../src/implementation/queue-producer-live.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./contracts/message-handling.ts";
|
|
2
|
+
export * from "./contracts/queue-api.ts";
|
|
3
|
+
export * from "./contracts/queue-config.ts";
|
|
4
|
+
export * from "./contracts/queue-consumer.ts";
|
|
5
|
+
export * from "./contracts/queue-domain.ts";
|
|
6
|
+
export * from "./contracts/queue-poller.ts";
|
|
7
|
+
export * from "./contracts/queue-producer.ts";
|
|
8
|
+
export * from "./contracts/topic.ts";
|
|
9
|
+
export { QueueApiLive } from "./implementation/queue-api-live.ts";
|
|
10
|
+
export { QueueConfigLive, type QueueConfigOptions, queueConfigLayer, } from "./implementation/queue-config-live.ts";
|
|
11
|
+
export { QueueConsumerLive } from "./implementation/queue-consumer-live.ts";
|
|
12
|
+
export { QueueLive } from "./implementation/queue-live.ts";
|
|
13
|
+
export { QueuePollerLive } from "./implementation/queue-poller-live.ts";
|
|
14
|
+
export { QueueProducerLive } from "./implementation/queue-producer-live.ts";
|
|
15
|
+
export { retryOnSchedule } from "./retry-policy.ts";
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EACL,eAAe,EACf,KAAK,kBAAkB,EACvB,gBAAgB,GACjB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export * from "./contracts/message-handling.js";
|
|
2
|
+
export * from "./contracts/queue-api.js";
|
|
3
|
+
export * from "./contracts/queue-config.js";
|
|
4
|
+
export * from "./contracts/queue-consumer.js";
|
|
5
|
+
export * from "./contracts/queue-domain.js";
|
|
6
|
+
export * from "./contracts/queue-poller.js";
|
|
7
|
+
export * from "./contracts/queue-producer.js";
|
|
8
|
+
export * from "./contracts/topic.js";
|
|
9
|
+
export { QueueApiLive } from "./implementation/queue-api-live.js";
|
|
10
|
+
export { QueueConfigLive, queueConfigLayer, } from "./implementation/queue-config-live.js";
|
|
11
|
+
export { QueueConsumerLive } from "./implementation/queue-consumer-live.js";
|
|
12
|
+
export { QueueLive } from "./implementation/queue-live.js";
|
|
13
|
+
export { QueuePollerLive } from "./implementation/queue-poller-live.js";
|
|
14
|
+
export { QueueProducerLive } from "./implementation/queue-producer-live.js";
|
|
15
|
+
export { retryOnSchedule } from "./retry-policy.js";
|
|
16
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,0BAA0B,CAAC;AACzC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAClE,OAAO,EACL,eAAe,EAEf,gBAAgB,GACjB,MAAM,uCAAuC,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,SAAS,EAAE,MAAM,gCAAgC,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,uCAAuC,CAAC;AACxE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yCAAyC,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { Headers } from "effect/http";
|
|
2
|
+
import { VercelRegion } from "@panorama-industries/effect-vercel-core";
|
|
3
|
+
import { Effect, Option, Schema } from "effect";
|
|
4
|
+
import type { LeaseDeadline } from "./lease.ts";
|
|
5
|
+
import { ConsumerGroupName, MessageId, ReceiptHandle, ReceivedMessage, TopicName } from "../contracts/queue-domain.ts";
|
|
6
|
+
export declare const CLOUD_EVENT_TYPE_V1BETA = "com.vercel.queue.v1beta";
|
|
7
|
+
export declare const CLOUD_EVENT_TYPE_V2BETA = "com.vercel.queue.v2beta";
|
|
8
|
+
declare const MalformedCloudEvent_base: Schema.Class<MalformedCloudEvent, Schema.TaggedStruct<"MalformedCloudEvent", {
|
|
9
|
+
readonly message: Schema.String;
|
|
10
|
+
}>, import("effect/Cause").YieldableError>;
|
|
11
|
+
/** A push delivery the queue could not have sent: answered with HTTP 400. */
|
|
12
|
+
export declare class MalformedCloudEvent extends MalformedCloudEvent_base {
|
|
13
|
+
}
|
|
14
|
+
export interface CallbackRoute {
|
|
15
|
+
readonly topic: TopicName;
|
|
16
|
+
readonly consumerGroup: ConsumerGroupName;
|
|
17
|
+
readonly messageId: MessageId;
|
|
18
|
+
readonly region: Option.Option<VercelRegion>;
|
|
19
|
+
}
|
|
20
|
+
/** Binary-mode delivery whose lease and payload arrived with the request. */
|
|
21
|
+
export interface InlineLease {
|
|
22
|
+
readonly receiptHandle: ReceiptHandle;
|
|
23
|
+
readonly deliveryCount: Option.Option<string>;
|
|
24
|
+
readonly createdAt: Option.Option<string>;
|
|
25
|
+
readonly expiresAt: Option.Option<string>;
|
|
26
|
+
readonly contentType: Option.Option<string>;
|
|
27
|
+
readonly visibilityDeadline: Option.Option<string>;
|
|
28
|
+
readonly handoffCount: Option.Option<number>;
|
|
29
|
+
}
|
|
30
|
+
export interface ParsedCallback extends CallbackRoute {
|
|
31
|
+
readonly inline: Option.Option<InlineLease>;
|
|
32
|
+
}
|
|
33
|
+
/** Reads `Vqs-Experimental-Handoff-Count`-style values: only positive integers count. */
|
|
34
|
+
export declare const parseHandoffCount: (value: Option.Option<string>) => Option.Option<number>;
|
|
35
|
+
/**
|
|
36
|
+
* Parses a push delivery like `@vercel/queue`'s `parseCallback`: binary mode
|
|
37
|
+
* (`com.vercel.queue.v2beta`, metadata in `ce-*` headers) or structured mode (JSON CloudEvent).
|
|
38
|
+
*/
|
|
39
|
+
export declare const parseCallback: (headers: Headers.Headers, text: Effect.Effect<string, unknown>) => Effect.Effect<ParsedCallback, MalformedCloudEvent>;
|
|
40
|
+
/** Builds the leased message a binary-mode delivery carries inline. */
|
|
41
|
+
export declare const inlineDelivery: (parsed: CallbackRoute, inline: InlineLease, region: string & import("effect/Brand").Brand<"VercelRegion">, defaultContentType: string, body: Uint8Array<ArrayBufferLike>) => Effect.Effect<{
|
|
42
|
+
message: ReceivedMessage;
|
|
43
|
+
deadline: LeaseDeadline;
|
|
44
|
+
}, never, never>;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=cloud-event.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-event.d.ts","sourceRoot":"","sources":["../../src/internal/cloud-event.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,EAAE,YAAY,EAAE,MAAM,yCAAyC,CAAC;AACvE,OAAO,EAAsB,MAAM,EAAE,MAAM,EAAa,MAAM,EAAE,MAAM,QAAQ,CAAC;AAE/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,OAAO,EACL,iBAAiB,EAEjB,SAAS,EAET,aAAa,EACb,eAAe,EACf,SAAS,EACV,MAAM,8BAA8B,CAAC;AAEtC,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;AACjE,eAAO,MAAM,uBAAuB,4BAA4B,CAAC;;;;AAKjE,6EAA6E;AAC7E,qBAAa,mBAAoB,SAAQ,wBAGxC;CAAG;AAEJ,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC;CAC9C;AAED,6EAA6E;AAC7E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC;IACtC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACnD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;CAC9C;AAED,MAAM,WAAW,cAAe,SAAQ,aAAa;IACnD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;CAC7C;AAUD,yFAAyF;AACzF,eAAO,MAAM,iBAAiB,UAAW,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAKjF,CAAC;AA4GL;;;GAGG;AACH,eAAO,MAAM,aAAa,YACf,OAAO,CAAC,OAAO,QAClB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KACnC,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,mBAAmB,CAOnD,CAAC;AAKF,uEAAuE;AACvE,eAAO,MAAM,cAAc;;;gBAkDzB,CAAC"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { VercelRegion } from "@panorama-industries/effect-vercel-core";
|
|
2
|
+
import { DateTime, Duration, Effect, Option, Predicate, Schema } from "effect";
|
|
3
|
+
import { ConsumerGroupName, MessageHandle, MessageId, MessageMetadata, ReceiptHandle, ReceivedMessage, TopicName, } from "../contracts/queue-domain.js";
|
|
4
|
+
export const CLOUD_EVENT_TYPE_V1BETA = "com.vercel.queue.v1beta";
|
|
5
|
+
export const CLOUD_EVENT_TYPE_V2BETA = "com.vercel.queue.v2beta";
|
|
6
|
+
const REGION_HEADER_PATTERN = /^[a-z]{2,5}[0-9]{1,2}$/;
|
|
7
|
+
const DEFAULT_RETENTION = Duration.hours(24);
|
|
8
|
+
/** A push delivery the queue could not have sent: answered with HTTP 400. */
|
|
9
|
+
export class MalformedCloudEvent extends Schema.TaggedError()("MalformedCloudEvent", { message: Schema.String }) {
|
|
10
|
+
}
|
|
11
|
+
const malformed = (message) => Effect.fail(new MalformedCloudEvent({ message }));
|
|
12
|
+
const header = (headers, name) => Option.fromNullishOr(headers[name]);
|
|
13
|
+
const nonEmptyHeader = (headers, name) => Option.filter(header(headers, name), (value) => value.length > 0);
|
|
14
|
+
/** Reads `Vqs-Experimental-Handoff-Count`-style values: only positive integers count. */
|
|
15
|
+
export const parseHandoffCount = (value) => Option.flatMap(value, (raw) => {
|
|
16
|
+
if (raw.length === 0)
|
|
17
|
+
return Option.none();
|
|
18
|
+
const count = Number(raw);
|
|
19
|
+
return Number.isInteger(count) && count > 0 ? Option.some(count) : Option.none();
|
|
20
|
+
});
|
|
21
|
+
const brand = (schema, field, value) => Schema.decodeUnknownEffect(schema)(value).pipe(Effect.catch(() => malformed(`Invalid CloudEvent: ${field} ${JSON.stringify(value)} is not valid`)));
|
|
22
|
+
const route = Effect.fnUntraced(function* (topic, consumerGroup, messageId, region) {
|
|
23
|
+
return {
|
|
24
|
+
topic: yield* brand(TopicName, "queueName", topic),
|
|
25
|
+
consumerGroup: yield* brand(ConsumerGroupName, "consumerGroup", consumerGroup),
|
|
26
|
+
messageId: yield* brand(MessageId, "messageId", messageId),
|
|
27
|
+
region,
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
const parseStructured = Effect.fnUntraced(function* (body, contentType) {
|
|
31
|
+
if (Option.isNone(contentType) || !contentType.value.includes("application/cloudevents+json")) {
|
|
32
|
+
return yield* malformed("Invalid content type: expected 'application/cloudevents+json'");
|
|
33
|
+
}
|
|
34
|
+
const event = Predicate.isObjectOrArray(body) ? body : undefined;
|
|
35
|
+
const data = Predicate.isObjectOrArray(event?.["data"])
|
|
36
|
+
? event["data"]
|
|
37
|
+
: undefined;
|
|
38
|
+
if (event === undefined || !event["type"] || !event["source"] || !event["id"] || !data) {
|
|
39
|
+
return yield* malformed("Invalid CloudEvent: missing required fields");
|
|
40
|
+
}
|
|
41
|
+
if (event["type"] !== CLOUD_EVENT_TYPE_V1BETA) {
|
|
42
|
+
return yield* malformed(
|
|
43
|
+
// oxlint-disable-next-line typescript/no-base-to-string -- matches @vercel/queue's message
|
|
44
|
+
`Invalid CloudEvent type: expected '${CLOUD_EVENT_TYPE_V1BETA}', got '${String(event["type"])}'`);
|
|
45
|
+
}
|
|
46
|
+
const missing = ["queueName", "consumerGroup", "messageId"].filter((field) => !(field in data));
|
|
47
|
+
if (missing.length > 0) {
|
|
48
|
+
return yield* malformed(`Missing required CloudEvent data fields: ${missing.join(", ")}`);
|
|
49
|
+
}
|
|
50
|
+
const parsed = yield* route(String(data["queueName"]), String(data["consumerGroup"]), String(data["messageId"]), Option.none());
|
|
51
|
+
return { ...parsed, inline: Option.none() };
|
|
52
|
+
});
|
|
53
|
+
const parseBinary = Effect.fnUntraced(function* (headers) {
|
|
54
|
+
const queueName = nonEmptyHeader(headers, "ce-vqsqueuename");
|
|
55
|
+
const consumerGroup = nonEmptyHeader(headers, "ce-vqsconsumergroup");
|
|
56
|
+
const messageId = nonEmptyHeader(headers, "ce-vqsmessageid");
|
|
57
|
+
if (Option.isNone(queueName) || Option.isNone(consumerGroup) || Option.isNone(messageId)) {
|
|
58
|
+
const missing = [
|
|
59
|
+
Option.isNone(queueName) ? ["ce-vqsqueuename"] : [],
|
|
60
|
+
Option.isNone(consumerGroup) ? ["ce-vqsconsumergroup"] : [],
|
|
61
|
+
Option.isNone(messageId) ? ["ce-vqsmessageid"] : [],
|
|
62
|
+
].flat();
|
|
63
|
+
return yield* malformed(`Missing required CloudEvent headers: ${missing.join(", ")}`);
|
|
64
|
+
}
|
|
65
|
+
const rawRegion = header(headers, "ce-vqsregion");
|
|
66
|
+
let region = Option.none();
|
|
67
|
+
if (Option.isSome(rawRegion)) {
|
|
68
|
+
const decoded = REGION_HEADER_PATTERN.test(rawRegion.value)
|
|
69
|
+
? Schema.decodeUnknownOption(VercelRegion)(rawRegion.value)
|
|
70
|
+
: Option.none();
|
|
71
|
+
if (Option.isNone(decoded)) {
|
|
72
|
+
return yield* malformed(`Invalid ce-vqsregion header: ${JSON.stringify(rawRegion.value)}. ` +
|
|
73
|
+
`Region must match /^[a-z]{2,5}[0-9]{1,2}$/ (e.g. "iad1", "lhr1").`);
|
|
74
|
+
}
|
|
75
|
+
region = decoded;
|
|
76
|
+
}
|
|
77
|
+
const base = yield* route(queueName.value, consumerGroup.value, messageId.value, region);
|
|
78
|
+
const receiptHandle = nonEmptyHeader(headers, "ce-vqsreceipthandle");
|
|
79
|
+
if (Option.isNone(receiptHandle)) {
|
|
80
|
+
return { ...base, inline: Option.none() };
|
|
81
|
+
}
|
|
82
|
+
const inline = {
|
|
83
|
+
receiptHandle: yield* brand(ReceiptHandle, "receiptHandle", receiptHandle.value),
|
|
84
|
+
deliveryCount: nonEmptyHeader(headers, "ce-vqsdeliverycount"),
|
|
85
|
+
createdAt: nonEmptyHeader(headers, "ce-vqscreatedat"),
|
|
86
|
+
expiresAt: nonEmptyHeader(headers, "ce-vqsexpiresat"),
|
|
87
|
+
contentType: nonEmptyHeader(headers, "content-type"),
|
|
88
|
+
visibilityDeadline: nonEmptyHeader(headers, "ce-vqsvisibilitydeadline"),
|
|
89
|
+
handoffCount: parseHandoffCount(header(headers, "ce-vqsexperimentalhandoffcount")),
|
|
90
|
+
};
|
|
91
|
+
return { ...base, inline: Option.some(inline) };
|
|
92
|
+
});
|
|
93
|
+
const UnknownFromJson = Schema.fromJsonString(Schema.Unknown);
|
|
94
|
+
/**
|
|
95
|
+
* Parses a push delivery like `@vercel/queue`'s `parseCallback`: binary mode
|
|
96
|
+
* (`com.vercel.queue.v2beta`, metadata in `ce-*` headers) or structured mode (JSON CloudEvent).
|
|
97
|
+
*/
|
|
98
|
+
export const parseCallback = (headers, text) => {
|
|
99
|
+
if (headers["ce-type"] === CLOUD_EVENT_TYPE_V2BETA)
|
|
100
|
+
return parseBinary(headers);
|
|
101
|
+
return text.pipe(Effect.flatMap(Schema.decodeUnknownEffect(UnknownFromJson)), Effect.catch(() => malformed("Failed to parse CloudEvent from request body")), Effect.flatMap((body) => parseStructured(body, header(headers, "content-type"))));
|
|
102
|
+
};
|
|
103
|
+
const parseDate = (value) => Option.flatMap(value, (raw) => DateTime.make(raw)).pipe(Option.map(DateTime.toUtc));
|
|
104
|
+
/** Builds the leased message a binary-mode delivery carries inline. */
|
|
105
|
+
export const inlineDelivery = Effect.fnUntraced(function* (parsed, inline, region, defaultContentType, body) {
|
|
106
|
+
const now = yield* DateTime.now;
|
|
107
|
+
const createdAt = Option.getOrElse(parseDate(inline.createdAt), () => now);
|
|
108
|
+
const deliveryCount = Option.getOrElse(Option.filter(Option.map(inline.deliveryCount, (raw) => Number.parseInt(raw, 10)), (count) => !Number.isNaN(count)), () => 1);
|
|
109
|
+
const handle = new MessageHandle({
|
|
110
|
+
topic: parsed.topic,
|
|
111
|
+
consumerGroup: parsed.consumerGroup,
|
|
112
|
+
messageId: parsed.messageId,
|
|
113
|
+
receiptHandle: inline.receiptHandle,
|
|
114
|
+
region,
|
|
115
|
+
});
|
|
116
|
+
const metadata = new MessageMetadata({
|
|
117
|
+
messageId: parsed.messageId,
|
|
118
|
+
deliveryCount,
|
|
119
|
+
createdAt,
|
|
120
|
+
expiresAt: Option.getOrElse(parseDate(inline.expiresAt), () => DateTime.addDuration(createdAt, DEFAULT_RETENTION)),
|
|
121
|
+
topic: parsed.topic,
|
|
122
|
+
consumerGroup: parsed.consumerGroup,
|
|
123
|
+
region,
|
|
124
|
+
...Option.match(inline.handoffCount, {
|
|
125
|
+
onNone: () => ({}),
|
|
126
|
+
onSome: (experimentalHandoffCount) => ({ experimentalHandoffCount }),
|
|
127
|
+
}),
|
|
128
|
+
});
|
|
129
|
+
const deadline = Option.map(inline.visibilityDeadline, (raw) => Option.getOrElse(parseDate(Option.some(raw)), () => "expired"));
|
|
130
|
+
return {
|
|
131
|
+
message: new ReceivedMessage({
|
|
132
|
+
handle,
|
|
133
|
+
metadata,
|
|
134
|
+
contentType: Option.getOrElse(inline.contentType, () => defaultContentType),
|
|
135
|
+
body,
|
|
136
|
+
}),
|
|
137
|
+
deadline,
|
|
138
|
+
};
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=cloud-event.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud-event.js","sourceRoot":"","sources":["../../src/internal/cloud-event.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DateTime, Scope } from "effect";
|
|
2
|
+
import { Duration, Effect, Option } from "effect";
|
|
3
|
+
import type { MessageHandle } from "../contracts/queue-domain.ts";
|
|
4
|
+
export declare const leaseVisibilityTimeout: (input: Duration.Input | undefined) => Duration.Duration;
|
|
5
|
+
export declare const renewalInterval: (timeout: Duration.Duration) => Duration.Duration;
|
|
6
|
+
export type LeaseDeadline = Option.Option<DateTime.Utc | "expired">;
|
|
7
|
+
/**
|
|
8
|
+
* Keeps a lease alive until the enclosing scope closes. Transient failures retry every 3 seconds;
|
|
9
|
+
* a lost or rejected lease (400, 401, 403, 404, 409) ends renewal.
|
|
10
|
+
*/
|
|
11
|
+
export declare const keepLeaseAlive: (api: {
|
|
12
|
+
readonly send: (topic: import("../contracts/queue-domain.ts").TopicName, message: import("../contracts/queue-api.ts").OutgoingMessage) => Effect.Effect<import("../contracts/queue-api.ts").SendResult, import("../contracts/queue-api.ts").QueueSendError>;
|
|
13
|
+
readonly sendBatch: (topic: import("../contracts/queue-domain.ts").TopicName, messages: import("effect/Array").NonEmptyReadonlyArray<import("../contracts/queue-api.ts").OutgoingMessage>) => Effect.Effect<ReadonlyArray<import("../contracts/queue-api.ts").BatchSendResult>, import("../contracts/queue-api.ts").QueueSendBatchError>;
|
|
14
|
+
readonly receive: (topic: import("../contracts/queue-domain.ts").TopicName, consumerGroup: import("../contracts/queue-domain.ts").ConsumerGroupName, options?: import("../contracts/queue-api.ts").ReceiveOptions) => Effect.Effect<ReadonlyArray<import("../contracts/queue-domain.ts").ReceivedMessage>, import("../contracts/queue-api.ts").QueueRequestError | import("../contracts/queue-domain.ts").MessageCorrupted>;
|
|
15
|
+
readonly receiveById: (topic: import("../contracts/queue-domain.ts").TopicName, consumerGroup: import("../contracts/queue-domain.ts").ConsumerGroupName, messageId: import("../contracts/queue-domain.ts").MessageId, options?: import("../contracts/queue-api.ts").ReceiveByIdOptions) => Effect.Effect<import("../contracts/queue-domain.ts").ReceivedMessage, import("../contracts/queue-api.ts").QueueReceiveByIdError>;
|
|
16
|
+
readonly acknowledge: (handle: MessageHandle, options?: {
|
|
17
|
+
readonly experimentalIfCoalesced?: number;
|
|
18
|
+
}) => Effect.Effect<void, import("../contracts/queue-api.ts").QueueLeaseError>;
|
|
19
|
+
readonly changeVisibility: (handle: MessageHandle, visibilityTimeout: Duration.Input, options?: {
|
|
20
|
+
readonly experimentalHandoff?: boolean;
|
|
21
|
+
}) => Effect.Effect<Option.Option<import("../contracts/queue-api.ts").HandoffOutcome>, import("../contracts/queue-api.ts").QueueLeaseError>;
|
|
22
|
+
}, handle: MessageHandle, timeout: Duration.Duration, deadline: LeaseDeadline) => Effect.Effect<void, never, Scope.Scope>;
|
|
23
|
+
//# sourceMappingURL=lease.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lease.d.ts","sourceRoot":"","sources":["../../src/internal/lease.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAS,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAQlE,eAAO,MAAM,sBAAsB,UAAW,QAAQ,CAAC,KAAK,GAAG,SAAS,KAAG,QAAQ,CAAC,QAIjF,CAAC;AAEJ,eAAO,MAAM,eAAe,YAAa,QAAQ,CAAC,QAAQ,KAAG,QAAQ,CAAC,QAIlE,CAAC;AAEL,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;AAapE;;;GAGG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;yHAyC1B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Clock, Duration, Effect, Option } from "effect";
|
|
2
|
+
const DEFAULT_VISIBILITY_TIMEOUT = Duration.minutes(5);
|
|
3
|
+
const MIN_VISIBILITY_TIMEOUT = Duration.seconds(30);
|
|
4
|
+
const MIN_RENEWAL_INTERVAL = Duration.seconds(10);
|
|
5
|
+
const MAX_RENEWAL_INTERVAL = Duration.seconds(60);
|
|
6
|
+
const RENEWAL_RETRY_INTERVAL = Duration.seconds(3);
|
|
7
|
+
export const leaseVisibilityTimeout = (input) => Duration.max(MIN_VISIBILITY_TIMEOUT, input === undefined ? DEFAULT_VISIBILITY_TIMEOUT : Duration.fromInputUnsafe(input));
|
|
8
|
+
export const renewalInterval = (timeout) => Duration.clamp(Duration.millis(Duration.toMillis(timeout) / 5), {
|
|
9
|
+
minimum: MIN_RENEWAL_INTERVAL,
|
|
10
|
+
maximum: MAX_RENEWAL_INTERVAL,
|
|
11
|
+
});
|
|
12
|
+
const firstRenewalDelay = Effect.fnUntraced(function* (timeout, deadline) {
|
|
13
|
+
if (Option.isNone(deadline))
|
|
14
|
+
return renewalInterval(timeout);
|
|
15
|
+
if (deadline.value === "expired")
|
|
16
|
+
return Duration.zero;
|
|
17
|
+
const now = yield* Clock.currentTimeMillis;
|
|
18
|
+
const remaining = deadline.value.epochMilliseconds - now;
|
|
19
|
+
return remaining > 0 ? renewalInterval(Duration.millis(remaining)) : Duration.zero;
|
|
20
|
+
});
|
|
21
|
+
/**
|
|
22
|
+
* Keeps a lease alive until the enclosing scope closes. Transient failures retry every 3 seconds;
|
|
23
|
+
* a lost or rejected lease (400, 401, 403, 404, 409) ends renewal.
|
|
24
|
+
*/
|
|
25
|
+
export const keepLeaseAlive = Effect.fnUntraced(function* (api, handle, timeout, deadline) {
|
|
26
|
+
const interval = renewalInterval(timeout);
|
|
27
|
+
const stop = (error) => Effect.logError("Lease renewal failed with a client error; stopping renewal", error).pipe(Effect.as(Option.none()));
|
|
28
|
+
const renew = api.changeVisibility(handle, timeout).pipe(Effect.as(Option.some(interval)), Effect.catchTags({ MessageNotFound: stop, MessageNotAvailable: stop }), Effect.catchReasons("VercelApiError", {
|
|
29
|
+
ApiBadRequest: (_, error) => stop(error),
|
|
30
|
+
ApiUnauthorized: (_, error) => stop(error),
|
|
31
|
+
ApiForbidden: (_, error) => stop(error),
|
|
32
|
+
}), Effect.catch((error) => Effect.logError("Lease renewal failed; retrying in 3 seconds", error).pipe(Effect.as(Option.some(RENEWAL_RETRY_INTERVAL)))));
|
|
33
|
+
const loop = Effect.fnUntraced(function* (initialDelay) {
|
|
34
|
+
let delay = Option.some(initialDelay);
|
|
35
|
+
while (Option.isSome(delay)) {
|
|
36
|
+
yield* Effect.sleep(delay.value);
|
|
37
|
+
delay = yield* renew;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
yield* Effect.forkScoped(loop(yield* firstRenewalDelay(timeout, deadline)), {
|
|
41
|
+
startImmediately: true,
|
|
42
|
+
});
|
|
43
|
+
}, Effect.annotateLogs({ module: "QueueLease" }));
|
|
44
|
+
//# sourceMappingURL=lease.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lease.js","sourceRoot":"","sources":["../../src/internal/lease.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Option, Stream } from "effect";
|
|
2
|
+
export interface MultipartPart {
|
|
3
|
+
/** Header names in lower case; repeated headers are joined with `, `. */
|
|
4
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
5
|
+
readonly body: Uint8Array;
|
|
6
|
+
}
|
|
7
|
+
export interface OutgoingPart {
|
|
8
|
+
readonly headers: ReadonlyArray<readonly [name: string, value: string]>;
|
|
9
|
+
readonly body: Uint8Array;
|
|
10
|
+
}
|
|
11
|
+
declare const MultipartMixedError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
12
|
+
readonly _tag: "MultipartMixedError";
|
|
13
|
+
} & Readonly<A>;
|
|
14
|
+
export declare class MultipartMixedError extends MultipartMixedError_base<{
|
|
15
|
+
readonly message: string;
|
|
16
|
+
}> {
|
|
17
|
+
}
|
|
18
|
+
export declare const boundaryFromContentType: (contentType: string) => Option.Option<string>;
|
|
19
|
+
export declare const encodeMultipartMixed: (boundary: string, parts: ReadonlyArray<OutgoingPart>) => Uint8Array;
|
|
20
|
+
/** Parses a `multipart/mixed` body as it streams in, emitting each part once it is complete. */
|
|
21
|
+
export declare const decodeMultipartMixed: (boundary: string) => <E, R>(source: Stream.Stream<Uint8Array, E, R>) => Stream.Stream<MultipartPart, E | MultipartMixedError, R>;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=multipart.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"multipart.d.ts","sourceRoot":"","sources":["../../src/internal/multipart.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC5B,yEAAyE;IACzE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC;IACxE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;CAC3B;;;;AAED,qBAAa,mBAAoB,SAAQ,yBAAwC;IAC/E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,CAAC;CAAG;AAOL,eAAO,MAAM,uBAAuB,gBAAiB,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAGjF,CAAC;AAYF,eAAO,MAAM,oBAAoB,aACrB,MAAM,SACT,aAAa,CAAC,YAAY,CAAC,KACjC,UAUC,CAAC;AAgLL,gGAAgG;AAChG,eAAO,MAAM,oBAAoB,aACpB,MAAM,MAChB,CAAC,EAAE,CAAC,UACK,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC,CAAC,KACtC,MAAM,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,GAAG,mBAAmB,EAAE,CAAC,CAQtD,CAAC"}
|