@hatchet-dev/typescript-sdk 1.37.0 → 1.39.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.
Files changed (34) hide show
  1. package/clients/rest/generated/Api.d.ts +62 -1
  2. package/clients/rest/generated/Api.js +50 -0
  3. package/clients/rest/generated/data-contracts.d.ts +146 -15
  4. package/clients/rest/generated/data-contracts.js +8 -1
  5. package/clients/streams/rpc.d.ts +8 -0
  6. package/clients/streams/rpc.js +14 -0
  7. package/clients/transport/fetch-transport.js +18 -1
  8. package/core/client.d.ts +2 -1
  9. package/core/client.js +3 -1
  10. package/core/features/streams.d.ts +68 -3
  11. package/core/features/streams.js +206 -5
  12. package/core/index.d.ts +9 -5
  13. package/core/index.js +13 -7
  14. package/core/types.d.ts +20 -0
  15. package/dist/check-core-esm-exports.mjs +19 -0
  16. package/package.json +2 -2
  17. package/protoc/v1/streams.d.ts +18 -0
  18. package/protoc/v1/streams.js +115 -1
  19. package/protoc-es/v1/streams_pb.d.ts +35 -0
  20. package/protoc-es/v1/streams_pb.js +12 -2
  21. package/scripts/check-core-esm-exports.mjs +19 -0
  22. package/v1/client/features/streams.d.ts +12 -18
  23. package/v1/client/features/streams.js +15 -1
  24. package/v1/examples/durable-streams/run.d.ts +6 -0
  25. package/v1/examples/durable-streams/run.js +192 -0
  26. package/v1/examples/durable-streams/worker.d.ts +1 -0
  27. package/v1/examples/durable-streams/worker.js +24 -0
  28. package/v1/examples/durable-streams/workflow.d.ts +9 -0
  29. package/v1/examples/durable-streams/workflow.js +47 -0
  30. package/v1/examples/durable_eviction/graceful-worker.d.ts +1 -0
  31. package/v1/examples/durable_eviction/graceful-worker.js +49 -0
  32. package/v1/examples/e2e-worker.js +59 -56
  33. package/version.d.ts +1 -1
  34. package/version.js +1 -1
@@ -1,10 +1,82 @@
1
1
  "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
2
14
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.StreamsClient = void 0;
4
- /** Publishes stream chunks from a task run, the way `ctx.putStream` does from a worker. */
15
+ exports.StreamsClient = exports.MAX_TRACKED_TOPICS = exports.MAX_STREAM_MESSAGE_BYTES = void 0;
16
+ const connect_1 = require("@connectrpc/connect");
17
+ const hatchet_error_1 = __importDefault(require("../../util/errors/hatchet-error"));
18
+ const abort_error_1 = require("../../util/abort-error");
19
+ /**
20
+ * The largest payload one `publish` carries: the engine's limit for a payload sent inline
21
+ * (`MaxStreamMessagePayloadBytes`). The Node client uploads larger payloads over its REST
22
+ * client first; this client has none, so it rejects them.
23
+ */
24
+ exports.MAX_STREAM_MESSAGE_BYTES = 4 * 1024 * 1024 - 5 * 1024;
25
+ /**
26
+ * How many (namespace, topic) producers the client remembers. A topic past the cap starts
27
+ * over with a new producer id, which the engine orders after the old one, so correctness
28
+ * does not depend on the cap; it only bounds memory for clients that publish to many
29
+ * short-lived topics.
30
+ */
31
+ exports.MAX_TRACKED_TOPICS = 1024;
32
+ function isEventsService(deps) {
33
+ return typeof deps.putStreamEvent === 'function';
34
+ }
35
+ /** The engine stored nothing, so the producer's sequence number is still unused. */
36
+ function publishRejectedBeforeStoring(err) {
37
+ return (err instanceof connect_1.ConnectError &&
38
+ (err.code === connect_1.Code.InvalidArgument ||
39
+ err.code === connect_1.Code.ResourceExhausted ||
40
+ err.code === connect_1.Code.Unauthenticated ||
41
+ err.code === connect_1.Code.PermissionDenied));
42
+ }
43
+ /**
44
+ * Task run streams and durable stream topics.
45
+ *
46
+ * `put` publishes a chunk on a task run's stream, the way `ctx.putStream` does from a worker.
47
+ * `publish`, `reset` and `topicMetadata` are the Node client's durable topic calls
48
+ * (`hatchet.streams`), with the same names and options. `events()` is not here: it is a
49
+ * server stream, which the unary transport does not carry. Read a topic with the Node client
50
+ * (`hatchet.streams.events(topic)`), or from a serverless task over the operator socket once
51
+ * the operator relays the subscription.
52
+ */
5
53
  class StreamsClient {
6
- constructor(rpc) {
7
- this.rpc = rpc;
54
+ /**
55
+ * Takes the events and durable streams services, or only the events service, which
56
+ * serves `put` and leaves the durable stream calls unavailable.
57
+ */
58
+ constructor(deps) {
59
+ /** Per (namespace, topic); the sequence number only advances after a publish succeeds. */
60
+ this.producers = new Map();
61
+ /**
62
+ * Serializes publishes per (namespace, topic) so two never share a sequence number. The
63
+ * stored promise always resolves, so one failure does not block later calls.
64
+ */
65
+ this.publishChains = new Map();
66
+ if (isEventsService(deps)) {
67
+ this.events = deps;
68
+ this.streams = undefined;
69
+ }
70
+ else {
71
+ this.events = deps.events;
72
+ this.streams = deps.streams;
73
+ }
74
+ }
75
+ durable() {
76
+ if (!this.streams) {
77
+ throw new hatchet_error_1.default('durable streams are unavailable: this StreamsClient was built with the events service only; build it with { events, streams }');
78
+ }
79
+ return this.streams;
8
80
  }
9
81
  /**
10
82
  * Publishes one chunk on a task run's stream. `index` orders chunks that are published
@@ -12,12 +84,141 @@ class StreamsClient {
12
84
  */
13
85
  put(taskRunExternalId, data, index) {
14
86
  const message = typeof data === 'string' ? new TextEncoder().encode(data) : data;
15
- return this.rpc.putStreamEvent({
87
+ return this.events.putStreamEvent({
16
88
  taskRunExternalId,
17
89
  createdAt: new Date(),
18
90
  message,
19
91
  eventIndex: index,
20
92
  });
21
93
  }
94
+ /**
95
+ * Publishes a message to a durable topic and resolves once it is stored. A client's
96
+ * messages to a topic are delivered in the order `publish` was called. A payload over
97
+ * `MAX_STREAM_MESSAGE_BYTES` rejects with a `HatchetError` before anything is sent.
98
+ * @param topic - the topic to publish to
99
+ * @param message - the message payload
100
+ * @param options - optional namespace override and abort signal
101
+ */
102
+ publish(topic, message, options) {
103
+ return __awaiter(this, void 0, void 0, function* () {
104
+ var _a, _b;
105
+ const payload = typeof message === 'string' ? new TextEncoder().encode(message) : message;
106
+ const namespace = (_a = options === null || options === void 0 ? void 0 : options.namespace) !== null && _a !== void 0 ? _a : '';
107
+ const key = `${namespace}\0${topic}`;
108
+ if (payload.byteLength > exports.MAX_STREAM_MESSAGE_BYTES) {
109
+ throw new hatchet_error_1.default(`stream payload is ${payload.byteLength} bytes, over the ${exports.MAX_STREAM_MESSAGE_BYTES}-byte limit of one publish; publish it from the Node client, which uploads larger payloads`);
110
+ }
111
+ const signal = options === null || options === void 0 ? void 0 : options.signal;
112
+ const previous = (_b = this.publishChains.get(key)) !== null && _b !== void 0 ? _b : Promise.resolve();
113
+ const publishPromise = previous.then(() => {
114
+ // An abort while this publish waited behind earlier ones sends nothing.
115
+ if (signal === null || signal === void 0 ? void 0 : signal.aborted) {
116
+ throw new abort_error_1.AbortError();
117
+ }
118
+ return this.publishOrdered(key, namespace, topic, payload, signal);
119
+ });
120
+ const chain = publishPromise
121
+ .catch(() => { })
122
+ .then(() => {
123
+ // The topic's queue is idle once its last publish settled.
124
+ if (this.publishChains.get(key) === chain) {
125
+ this.publishChains.delete(key);
126
+ }
127
+ });
128
+ this.publishChains.set(key, chain);
129
+ if (!signal) {
130
+ return publishPromise;
131
+ }
132
+ // The caller is released as soon as its signal aborts, while the queue keeps its order
133
+ // and the aborted publish is skipped when its turn comes.
134
+ return new Promise((resolve, reject) => {
135
+ const onAbort = () => reject(new abort_error_1.AbortError());
136
+ if (signal.aborted) {
137
+ onAbort();
138
+ return;
139
+ }
140
+ signal.addEventListener('abort', onAbort, { once: true });
141
+ publishPromise.then(resolve, reject).finally(() => {
142
+ signal.removeEventListener('abort', onAbort);
143
+ });
144
+ });
145
+ });
146
+ }
147
+ /**
148
+ * Describes a topic's retained messages. Rejects with a `ConnectError` of code `NotFound`
149
+ * for a topic nothing was published to.
150
+ * @param topic - the topic to describe
151
+ * @param options - optional namespace override and abort signal
152
+ */
153
+ topicMetadata(topic, options) {
154
+ return __awaiter(this, void 0, void 0, function* () {
155
+ var _a;
156
+ const res = yield this.durable().getTopicMetadata({ namespace: (_a = options === null || options === void 0 ? void 0 : options.namespace) !== null && _a !== void 0 ? _a : '', topic }, { signal: options === null || options === void 0 ? void 0 : options.signal });
157
+ return {
158
+ namespace: res.namespace,
159
+ topic: res.topic,
160
+ tenantId: res.tenantId,
161
+ messageCount: res.messageCount,
162
+ latestCursor: res.latestCursor,
163
+ lastPublishedAt: res.lastPublishedAt,
164
+ };
165
+ });
166
+ }
167
+ /**
168
+ * Makes `events()` calls without a cursor start after the topic's latest message. Readers
169
+ * already iterating, and any call with a cursor, are unaffected.
170
+ * @param topic - the topic to reset
171
+ * @param options - optional namespace override and abort signal
172
+ */
173
+ reset(topic, options) {
174
+ return __awaiter(this, void 0, void 0, function* () {
175
+ var _a;
176
+ yield this.durable().reset({ namespace: (_a = options === null || options === void 0 ? void 0 : options.namespace) !== null && _a !== void 0 ? _a : '', topic }, { signal: options === null || options === void 0 ? void 0 : options.signal });
177
+ });
178
+ }
179
+ publishOrdered(key_1, namespace_1, topic_1, payload_1, signal_1) {
180
+ return __awaiter(this, arguments, void 0, function* (key, namespace, topic, payload, signal, retryGap = true) {
181
+ const streams = this.durable();
182
+ let producer = this.producers.get(key);
183
+ if (producer) {
184
+ // re-inserting keeps the map in last-use order for the eviction below
185
+ this.producers.delete(key);
186
+ }
187
+ else {
188
+ producer = { producerId: crypto.randomUUID(), seq: 0 };
189
+ }
190
+ this.producers.set(key, producer);
191
+ while (this.producers.size > exports.MAX_TRACKED_TOPICS) {
192
+ const oldest = this.producers.keys().next().value;
193
+ if (oldest === undefined) {
194
+ break;
195
+ }
196
+ this.producers.delete(oldest);
197
+ }
198
+ try {
199
+ yield streams.publish({
200
+ namespace,
201
+ topic,
202
+ payload,
203
+ producerId: producer.producerId,
204
+ producerSeq: producer.seq,
205
+ }, { signal });
206
+ }
207
+ catch (err) {
208
+ // The message may still land, and a different payload under its sequence number
209
+ // would be dropped as a duplicate, so the next publish comes from a new producer.
210
+ if (!publishRejectedBeforeStoring(err)) {
211
+ this.producers.set(key, { producerId: crypto.randomUUID(), seq: 0 });
212
+ }
213
+ // A gap stored nothing (the watermark passed cursor retention, say): resend as the
214
+ // new producer.
215
+ if (retryGap && err instanceof connect_1.ConnectError && err.code === connect_1.Code.FailedPrecondition) {
216
+ return this.publishOrdered(key, namespace, topic, payload, signal, false);
217
+ }
218
+ throw err;
219
+ }
220
+ producer.seq += 1;
221
+ });
222
+ }
22
223
  }
23
224
  exports.StreamsClient = StreamsClient;
package/core/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * The core entry point: the application client for runtimes without gRPC. It triggers runs,
3
- * pushes events, waits for results by polling and manages workflows over unary Connect calls
4
- * on a fetch transport, and it is configured from an explicit object only.
3
+ * pushes events, waits for results by polling, publishes to durable streams and manages
4
+ * workflows over unary Connect calls on a fetch transport, and it is configured from an
5
+ * explicit object only.
5
6
  *
6
7
  * Nothing exported here imports from Node. `scripts/check-edge-entry.mjs` bundles this module
7
8
  * for a browser-like target and fails the build if a Node builtin, `axios` or a gRPC package
@@ -24,14 +25,15 @@ export { WorkflowRunRef, INITIAL_POLL_INTERVAL_MS, MAX_POLL_INTERVAL_MS } from '
24
25
  export type { RunRefClient } from './run-ref';
25
26
  export { toRunDetail, parseTaskOutput, runStatusToJSON } from './run-detail';
26
27
  export { ConsoleLogger, consoleLogger } from './logger';
27
- export type { CallOptions, CancelRunOpts, CoreClientConfig, CreateRateLimitOpts, DesiredWorkerLabelOpt, EventWithMetadata, LogConstructor, PushEventOptions, ReplayRunOpts, ResultOptions, RunDetail, RunFilter, RunFilterBase, TaskRunDetail, TriggerRun, TriggerRunOptions, } from './types';
28
+ export type { CallOptions, CancelRunOpts, CoreClientConfig, CreateRateLimitOpts, DesiredWorkerLabelOpt, EventWithMetadata, LogConstructor, PushEventOptions, ReplayRunOpts, ResultOptions, RunDetail, RunFilter, RunFilterBase, StreamCallOptions, StreamTopicMetadata, TaskRunDetail, TriggerRun, TriggerRunOptions, } from './types';
28
29
  export { EventsClient } from './features/events';
29
30
  export { RunsClient } from './features/runs';
30
31
  export { WorkflowsClient } from './features/workflows';
31
32
  export { RateLimitsClient } from './features/rate-limits';
32
33
  export { LogsClient, MAX_LOG_LINE_CHARS } from './features/logs';
33
34
  export type { PutLogOptions } from './features/logs';
34
- export { StreamsClient } from './features/streams';
35
+ export { StreamsClient, MAX_STREAM_MESSAGE_BYTES } from './features/streams';
36
+ export type { StreamsClientDeps } from './features/streams';
35
37
  export { createFetchTransport, limitMessageSizes, resolveServerUrl, type FetchTlsConfig, type FetchTransportOptions, type MessageSizeLimits, } from '../clients/transport/fetch-transport';
36
38
  export { createAuthInterceptor, DEFAULT_MAX_MESSAGE_BYTES, type Transport, } from '../clients/transport/transport';
37
39
  export { LogLevel } from '../clients/event/rpc';
@@ -40,7 +42,9 @@ export type { RunManyOpt, RunOpts } from '../v1/declaration';
40
42
  export { RateLimitDuration } from '../protoc/workflows/workflows';
41
43
  export { WorkerLabelComparator } from '../protoc/v1/shared/trigger';
42
44
  export { V1TaskStatus } from '../clients/rest/generated/data-contracts';
43
- export { default as HatchetError, getErrorMessage, toHatchetError, } from '../util/errors/hatchet-error';
45
+ import HatchetError from '../util/errors/hatchet-error';
46
+ export { HatchetError };
47
+ export { getErrorMessage, toHatchetError } from '../util/errors/hatchet-error';
44
48
  export { IdempotencyCollisionError } from '../util/errors/idempotency-collision-error';
45
49
  export { BulkTriggerIdempotencyCollisionError } from '../util/errors/bulk-trigger-idempotency-collision-error';
46
50
  export { BulkTriggerPartialError } from '../util/errors/bulk-trigger-partial-error';
package/core/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  "use strict";
2
2
  /**
3
3
  * The core entry point: the application client for runtimes without gRPC. It triggers runs,
4
- * pushes events, waits for results by polling and manages workflows over unary Connect calls
5
- * on a fetch transport, and it is configured from an explicit object only.
4
+ * pushes events, waits for results by polling, publishes to durable streams and manages
5
+ * workflows over unary Connect calls on a fetch transport, and it is configured from an
6
+ * explicit object only.
6
7
  *
7
8
  * Nothing exported here imports from Node. `scripts/check-edge-entry.mjs` bundles this module
8
9
  * for a browser-like target and fails the build if a Node builtin, `axios` or a gRPC package
@@ -21,7 +22,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
21
22
  return (mod && mod.__esModule) ? mod : { "default": mod };
22
23
  };
23
24
  Object.defineProperty(exports, "__esModule", { value: true });
24
- exports.isAbortError = exports.AbortError = exports.BulkTriggerPartialError = exports.BulkTriggerIdempotencyCollisionError = exports.IdempotencyCollisionError = exports.toHatchetError = exports.getErrorMessage = exports.HatchetError = exports.V1TaskStatus = exports.WorkerLabelComparator = exports.RateLimitDuration = exports.Priority = exports.LogLevel = exports.DEFAULT_MAX_MESSAGE_BYTES = exports.createAuthInterceptor = exports.resolveServerUrl = exports.limitMessageSizes = exports.createFetchTransport = exports.StreamsClient = exports.MAX_LOG_LINE_CHARS = exports.LogsClient = exports.RateLimitsClient = exports.WorkflowsClient = exports.RunsClient = exports.EventsClient = exports.consoleLogger = exports.ConsoleLogger = exports.runStatusToJSON = exports.parseTaskOutput = exports.toRunDetail = exports.MAX_POLL_INTERVAL_MS = exports.INITIAL_POLL_INTERVAL_MS = exports.WorkflowRunRef = exports.Hatchet = exports.HatchetCore = exports.CORE_ENTRY_VERSION = void 0;
25
+ exports.isAbortError = exports.AbortError = exports.BulkTriggerPartialError = exports.BulkTriggerIdempotencyCollisionError = exports.IdempotencyCollisionError = exports.toHatchetError = exports.getErrorMessage = exports.HatchetError = exports.V1TaskStatus = exports.WorkerLabelComparator = exports.RateLimitDuration = exports.Priority = exports.LogLevel = exports.DEFAULT_MAX_MESSAGE_BYTES = exports.createAuthInterceptor = exports.resolveServerUrl = exports.limitMessageSizes = exports.createFetchTransport = exports.MAX_STREAM_MESSAGE_BYTES = exports.StreamsClient = exports.MAX_LOG_LINE_CHARS = exports.LogsClient = exports.RateLimitsClient = exports.WorkflowsClient = exports.RunsClient = exports.EventsClient = exports.consoleLogger = exports.ConsoleLogger = exports.runStatusToJSON = exports.parseTaskOutput = exports.toRunDetail = exports.MAX_POLL_INTERVAL_MS = exports.INITIAL_POLL_INTERVAL_MS = exports.WorkflowRunRef = exports.Hatchet = exports.HatchetCore = exports.CORE_ENTRY_VERSION = void 0;
25
26
  /** Bumped whenever the surface exported from this entry changes incompatibly. */
26
27
  exports.CORE_ENTRY_VERSION = 1;
27
28
  var client_1 = require("./client");
@@ -52,6 +53,7 @@ Object.defineProperty(exports, "LogsClient", { enumerable: true, get: function (
52
53
  Object.defineProperty(exports, "MAX_LOG_LINE_CHARS", { enumerable: true, get: function () { return logs_1.MAX_LOG_LINE_CHARS; } });
53
54
  var streams_1 = require("./features/streams");
54
55
  Object.defineProperty(exports, "StreamsClient", { enumerable: true, get: function () { return streams_1.StreamsClient; } });
56
+ Object.defineProperty(exports, "MAX_STREAM_MESSAGE_BYTES", { enumerable: true, get: function () { return streams_1.MAX_STREAM_MESSAGE_BYTES; } });
55
57
  // Transport
56
58
  var fetch_transport_1 = require("../clients/transport/fetch-transport");
57
59
  Object.defineProperty(exports, "createFetchTransport", { enumerable: true, get: function () { return fetch_transport_1.createFetchTransport; } });
@@ -71,10 +73,14 @@ var trigger_1 = require("../protoc/v1/shared/trigger");
71
73
  Object.defineProperty(exports, "WorkerLabelComparator", { enumerable: true, get: function () { return trigger_1.WorkerLabelComparator; } });
72
74
  var data_contracts_1 = require("../clients/rest/generated/data-contracts");
73
75
  Object.defineProperty(exports, "V1TaskStatus", { enumerable: true, get: function () { return data_contracts_1.V1TaskStatus; } });
74
- var hatchet_error_1 = require("../util/errors/hatchet-error");
75
- Object.defineProperty(exports, "HatchetError", { enumerable: true, get: function () { return __importDefault(hatchet_error_1).default; } });
76
- Object.defineProperty(exports, "getErrorMessage", { enumerable: true, get: function () { return hatchet_error_1.getErrorMessage; } });
77
- Object.defineProperty(exports, "toHatchetError", { enumerable: true, get: function () { return hatchet_error_1.toHatchetError; } });
76
+ // HatchetError is imported and re-exported by name rather than as `default as`: tsc emits a
77
+ // getter for the latter that Node's CommonJS export detection cannot see, which hides the name
78
+ // from ESM importers of this entry.
79
+ const hatchet_error_1 = __importDefault(require("../util/errors/hatchet-error"));
80
+ exports.HatchetError = hatchet_error_1.default;
81
+ var hatchet_error_2 = require("../util/errors/hatchet-error");
82
+ Object.defineProperty(exports, "getErrorMessage", { enumerable: true, get: function () { return hatchet_error_2.getErrorMessage; } });
83
+ Object.defineProperty(exports, "toHatchetError", { enumerable: true, get: function () { return hatchet_error_2.toHatchetError; } });
78
84
  var idempotency_collision_error_1 = require("../util/errors/idempotency-collision-error");
79
85
  Object.defineProperty(exports, "IdempotencyCollisionError", { enumerable: true, get: function () { return idempotency_collision_error_1.IdempotencyCollisionError; } });
80
86
  var bulk_trigger_idempotency_collision_error_1 = require("../util/errors/bulk-trigger-idempotency-collision-error");
package/core/types.d.ts CHANGED
@@ -180,3 +180,23 @@ export interface ResultOptions {
180
180
  /** Rejects with an `AbortError` when the signal fires. */
181
181
  signal?: AbortSignal;
182
182
  }
183
+ /** Per-call options of the durable stream calls; the same shape on the core and Node clients. */
184
+ export type StreamCallOptions = {
185
+ /** The topic's namespace; the empty namespace when omitted. */
186
+ namespace?: string;
187
+ /** Resumes an `events()` iteration right after this message. */
188
+ cursor?: string;
189
+ /** Ends an `events()` iteration cleanly, without throwing; aborts a unary call. */
190
+ signal?: AbortSignal;
191
+ };
192
+ /** What a durable stream topic retains; counts and the latest message cover the tenant's retention. */
193
+ export type StreamTopicMetadata = {
194
+ namespace: string;
195
+ topic: string;
196
+ tenantId: string;
197
+ messageCount: number;
198
+ /** Resumes `events()` after the newest retained message; undefined when none is retained. */
199
+ latestCursor?: string;
200
+ /** When the newest retained message was stored; undefined when none is retained. */
201
+ lastPublishedAt?: Date;
202
+ };
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ // Verifies that every export of the built core entry is visible to an ESM importer under Node:
3
+ // the entry is CommonJS, and Node derives its named exports statically, so a re-export written
4
+ // in a form that detection misses (a getter over a default import) vanishes for `import { X }`.
5
+ import { createRequire } from 'node:module';
6
+ import { pathToFileURL } from 'node:url';
7
+ import { resolve } from 'node:path';
8
+
9
+ const entry = resolve('dist/core/index.js');
10
+ const cjs = createRequire(import.meta.url)(entry);
11
+ const esm = await import(pathToFileURL(entry).href);
12
+ const missing = Object.keys(cjs).filter((name) => name !== '__esModule' && !(name in esm));
13
+
14
+ if (missing.length > 0) {
15
+ console.error(`core entry exports hidden from ESM importers: ${missing.join(', ')}`);
16
+ process.exit(1);
17
+ }
18
+
19
+ console.log(`core entry: ${Object.keys(cjs).length} exports visible to ESM importers`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatchet-dev/typescript-sdk",
3
- "version": "1.37.0",
3
+ "version": "1.39.0",
4
4
  "engines": {
5
5
  "node": ">=20"
6
6
  },
@@ -238,7 +238,7 @@
238
238
  "tsc:build": "pnpm run dump-version && tsc && resolve-tspaths",
239
239
  "test:unit": "jest --testMatch='**/*.test.ts'",
240
240
  "check:edge": "pnpm run tsc:build && node scripts/check-edge-entry.mjs",
241
- "check:core": "pnpm run tsc:build && node scripts/check-edge-entry.mjs dist/core/index.js --forbid axios,nice-grpc,@grpc/grpc-js,@connectrpc/connect-node,long,protobufjs,yaml",
241
+ "check:core": "pnpm run tsc:build && node scripts/check-edge-entry.mjs dist/core/index.js --forbid axios,nice-grpc,@grpc/grpc-js,@connectrpc/connect-node,long,protobufjs,yaml && node scripts/check-core-esm-exports.mjs",
242
242
  "check:exports": "pnpm run tsc:build && node scripts/check-exports.mjs",
243
243
  "test:e2e": "jest --config jest.e2e.config.ts --silent --forceExit --runInBand",
244
244
  "test:unit:watch": "jest --testMatch='**/*.test.ts' --watch",
@@ -47,6 +47,12 @@ export interface StreamTopicMetadata {
47
47
  /** when the newest retained message was stored; unset when none is retained */
48
48
  lastPublishedAt: Date | undefined;
49
49
  }
50
+ export interface ResetStreamTopicRequest {
51
+ namespace: string;
52
+ topic: string;
53
+ }
54
+ export interface ResetStreamTopicResponse {
55
+ }
50
56
  export declare const PublishStreamMessageRequest: MessageFns<PublishStreamMessageRequest>;
51
57
  export declare const PublishStreamMessageResponse: MessageFns<PublishStreamMessageResponse>;
52
58
  export declare const SubscribeStreamRequest: MessageFns<SubscribeStreamRequest>;
@@ -54,6 +60,8 @@ export declare const StreamMessage: MessageFns<StreamMessage>;
54
60
  export declare const StreamEntry: MessageFns<StreamEntry>;
55
61
  export declare const GetStreamTopicMetadataRequest: MessageFns<GetStreamTopicMetadataRequest>;
56
62
  export declare const StreamTopicMetadata: MessageFns<StreamTopicMetadata>;
63
+ export declare const ResetStreamTopicRequest: MessageFns<ResetStreamTopicRequest>;
64
+ export declare const ResetStreamTopicResponse: MessageFns<ResetStreamTopicResponse>;
57
65
  export type V1StreamsDefinition = typeof V1StreamsDefinition;
58
66
  export declare const V1StreamsDefinition: {
59
67
  readonly name: "V1Streams";
@@ -83,17 +91,27 @@ export declare const V1StreamsDefinition: {
83
91
  readonly responseStream: false;
84
92
  readonly options: {};
85
93
  };
94
+ readonly reset: {
95
+ readonly name: "Reset";
96
+ readonly requestType: typeof ResetStreamTopicRequest;
97
+ readonly requestStream: false;
98
+ readonly responseType: typeof ResetStreamTopicResponse;
99
+ readonly responseStream: false;
100
+ readonly options: {};
101
+ };
86
102
  };
87
103
  };
88
104
  export interface V1StreamsServiceImplementation<CallContextExt = {}> {
89
105
  publish(request: PublishStreamMessageRequest, context: CallContext & CallContextExt): Promise<DeepPartial<PublishStreamMessageResponse>>;
90
106
  subscribe(request: SubscribeStreamRequest, context: CallContext & CallContextExt): ServerStreamingMethodResult<DeepPartial<StreamMessage>>;
91
107
  getTopicMetadata(request: GetStreamTopicMetadataRequest, context: CallContext & CallContextExt): Promise<DeepPartial<StreamTopicMetadata>>;
108
+ reset(request: ResetStreamTopicRequest, context: CallContext & CallContextExt): Promise<DeepPartial<ResetStreamTopicResponse>>;
92
109
  }
93
110
  export interface V1StreamsClient<CallOptionsExt = {}> {
94
111
  publish(request: DeepPartial<PublishStreamMessageRequest>, options?: CallOptions & CallOptionsExt): Promise<PublishStreamMessageResponse>;
95
112
  subscribe(request: DeepPartial<SubscribeStreamRequest>, options?: CallOptions & CallOptionsExt): AsyncIterable<StreamMessage>;
96
113
  getTopicMetadata(request: DeepPartial<GetStreamTopicMetadataRequest>, options?: CallOptions & CallOptionsExt): Promise<StreamTopicMetadata>;
114
+ reset(request: DeepPartial<ResetStreamTopicRequest>, options?: CallOptions & CallOptionsExt): Promise<ResetStreamTopicResponse>;
97
115
  }
98
116
  type Builtin = Date | Function | Uint8Array | string | number | boolean | undefined;
99
117
  export type DeepPartial<T> = T extends Builtin ? T : T extends globalThis.Array<infer U> ? globalThis.Array<DeepPartial<U>> : T extends ReadonlyArray<infer U> ? ReadonlyArray<DeepPartial<U>> : T extends {} ? {
@@ -5,7 +5,7 @@
5
5
  // protoc v3.19.1
6
6
  // source: v1/streams.proto
7
7
  Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.V1StreamsDefinition = exports.StreamTopicMetadata = exports.GetStreamTopicMetadataRequest = exports.StreamEntry = exports.StreamMessage = exports.SubscribeStreamRequest = exports.PublishStreamMessageResponse = exports.PublishStreamMessageRequest = exports.protobufPackage = void 0;
8
+ exports.V1StreamsDefinition = exports.ResetStreamTopicResponse = exports.ResetStreamTopicRequest = exports.StreamTopicMetadata = exports.GetStreamTopicMetadataRequest = exports.StreamEntry = exports.StreamMessage = exports.SubscribeStreamRequest = exports.PublishStreamMessageResponse = exports.PublishStreamMessageRequest = exports.protobufPackage = void 0;
9
9
  /* eslint-disable */
10
10
  const wire_1 = require("@bufbuild/protobuf/wire");
11
11
  const timestamp_1 = require("../google/protobuf/timestamp");
@@ -694,6 +694,112 @@ exports.StreamTopicMetadata = {
694
694
  return message;
695
695
  },
696
696
  };
697
+ function createBaseResetStreamTopicRequest() {
698
+ return { namespace: '', topic: '' };
699
+ }
700
+ exports.ResetStreamTopicRequest = {
701
+ encode(message, writer = new wire_1.BinaryWriter()) {
702
+ if (message.namespace !== '') {
703
+ writer.uint32(10).string(message.namespace);
704
+ }
705
+ if (message.topic !== '') {
706
+ writer.uint32(18).string(message.topic);
707
+ }
708
+ return writer;
709
+ },
710
+ decode(input, length) {
711
+ const reader = input instanceof wire_1.BinaryReader ? input : new wire_1.BinaryReader(input);
712
+ const end = length === undefined ? reader.len : reader.pos + length;
713
+ const message = createBaseResetStreamTopicRequest();
714
+ while (reader.pos < end) {
715
+ const tag = reader.uint32();
716
+ switch (tag >>> 3) {
717
+ case 1: {
718
+ if (tag !== 10) {
719
+ break;
720
+ }
721
+ message.namespace = reader.string();
722
+ continue;
723
+ }
724
+ case 2: {
725
+ if (tag !== 18) {
726
+ break;
727
+ }
728
+ message.topic = reader.string();
729
+ continue;
730
+ }
731
+ }
732
+ if ((tag & 7) === 4 || tag === 0) {
733
+ break;
734
+ }
735
+ reader.skip(tag & 7);
736
+ }
737
+ return message;
738
+ },
739
+ fromJSON(object) {
740
+ return {
741
+ namespace: isSet(object.namespace) ? globalThis.String(object.namespace) : '',
742
+ topic: isSet(object.topic) ? globalThis.String(object.topic) : '',
743
+ };
744
+ },
745
+ toJSON(message) {
746
+ const obj = {};
747
+ if (message.namespace !== '') {
748
+ obj.namespace = message.namespace;
749
+ }
750
+ if (message.topic !== '') {
751
+ obj.topic = message.topic;
752
+ }
753
+ return obj;
754
+ },
755
+ create(base) {
756
+ return exports.ResetStreamTopicRequest.fromPartial(base !== null && base !== void 0 ? base : {});
757
+ },
758
+ fromPartial(object) {
759
+ var _a, _b;
760
+ const message = createBaseResetStreamTopicRequest();
761
+ message.namespace = (_a = object.namespace) !== null && _a !== void 0 ? _a : '';
762
+ message.topic = (_b = object.topic) !== null && _b !== void 0 ? _b : '';
763
+ return message;
764
+ },
765
+ };
766
+ function createBaseResetStreamTopicResponse() {
767
+ return {};
768
+ }
769
+ exports.ResetStreamTopicResponse = {
770
+ encode(_, writer = new wire_1.BinaryWriter()) {
771
+ return writer;
772
+ },
773
+ decode(input, length) {
774
+ const reader = input instanceof wire_1.BinaryReader ? input : new wire_1.BinaryReader(input);
775
+ const end = length === undefined ? reader.len : reader.pos + length;
776
+ const message = createBaseResetStreamTopicResponse();
777
+ while (reader.pos < end) {
778
+ const tag = reader.uint32();
779
+ switch (tag >>> 3) {
780
+ }
781
+ if ((tag & 7) === 4 || tag === 0) {
782
+ break;
783
+ }
784
+ reader.skip(tag & 7);
785
+ }
786
+ return message;
787
+ },
788
+ fromJSON(_) {
789
+ return {};
790
+ },
791
+ toJSON(_) {
792
+ const obj = {};
793
+ return obj;
794
+ },
795
+ create(base) {
796
+ return exports.ResetStreamTopicResponse.fromPartial(base !== null && base !== void 0 ? base : {});
797
+ },
798
+ fromPartial(_) {
799
+ const message = createBaseResetStreamTopicResponse();
800
+ return message;
801
+ },
802
+ };
697
803
  exports.V1StreamsDefinition = {
698
804
  name: 'V1Streams',
699
805
  fullName: 'v1.V1Streams',
@@ -722,6 +828,14 @@ exports.V1StreamsDefinition = {
722
828
  responseStream: false,
723
829
  options: {},
724
830
  },
831
+ reset: {
832
+ name: 'Reset',
833
+ requestType: exports.ResetStreamTopicRequest,
834
+ requestStream: false,
835
+ responseType: exports.ResetStreamTopicResponse,
836
+ responseStream: false,
837
+ options: {},
838
+ },
725
839
  },
726
840
  };
727
841
  function bytesFromBase64(b64) {
@@ -181,6 +181,33 @@ export type StreamTopicMetadata = Message<"v1.StreamTopicMetadata"> & {
181
181
  * Use `create(StreamTopicMetadataSchema)` to create a new message.
182
182
  */
183
183
  export declare const StreamTopicMetadataSchema: GenMessage<StreamTopicMetadata>;
184
+ /**
185
+ * @generated from message v1.ResetStreamTopicRequest
186
+ */
187
+ export type ResetStreamTopicRequest = Message<"v1.ResetStreamTopicRequest"> & {
188
+ /**
189
+ * @generated from field: string namespace = 1;
190
+ */
191
+ namespace: string;
192
+ /**
193
+ * @generated from field: string topic = 2;
194
+ */
195
+ topic: string;
196
+ };
197
+ /**
198
+ * Describes the message v1.ResetStreamTopicRequest.
199
+ * Use `create(ResetStreamTopicRequestSchema)` to create a new message.
200
+ */
201
+ export declare const ResetStreamTopicRequestSchema: GenMessage<ResetStreamTopicRequest>;
202
+ /**
203
+ * @generated from message v1.ResetStreamTopicResponse
204
+ */
205
+ export type ResetStreamTopicResponse = Message<"v1.ResetStreamTopicResponse"> & {};
206
+ /**
207
+ * Describes the message v1.ResetStreamTopicResponse.
208
+ * Use `create(ResetStreamTopicResponseSchema)` to create a new message.
209
+ */
210
+ export declare const ResetStreamTopicResponseSchema: GenMessage<ResetStreamTopicResponse>;
184
211
  /**
185
212
  * @generated from service v1.V1Streams
186
213
  */
@@ -209,4 +236,12 @@ export declare const V1Streams: GenService<{
209
236
  input: typeof GetStreamTopicMetadataRequestSchema;
210
237
  output: typeof StreamTopicMetadataSchema;
211
238
  };
239
+ /**
240
+ * @generated from rpc v1.V1Streams.Reset
241
+ */
242
+ reset: {
243
+ methodKind: "unary";
244
+ input: typeof ResetStreamTopicRequestSchema;
245
+ output: typeof ResetStreamTopicResponseSchema;
246
+ };
212
247
  }>;
@@ -3,13 +3,13 @@
3
3
  // @generated from file v1/streams.proto (package v1, syntax proto3)
4
4
  /* eslint-disable */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.V1Streams = exports.StreamTopicMetadataSchema = exports.GetStreamTopicMetadataRequestSchema = exports.StreamEntrySchema = exports.StreamMessageSchema = exports.SubscribeStreamRequestSchema = exports.PublishStreamMessageResponseSchema = exports.PublishStreamMessageRequestSchema = exports.file_v1_streams = void 0;
6
+ exports.V1Streams = exports.ResetStreamTopicResponseSchema = exports.ResetStreamTopicRequestSchema = exports.StreamTopicMetadataSchema = exports.GetStreamTopicMetadataRequestSchema = exports.StreamEntrySchema = exports.StreamMessageSchema = exports.SubscribeStreamRequestSchema = exports.PublishStreamMessageResponseSchema = exports.PublishStreamMessageRequestSchema = exports.file_v1_streams = void 0;
7
7
  const codegenv2_1 = require("@bufbuild/protobuf/codegenv2");
8
8
  const wkt_1 = require("@bufbuild/protobuf/wkt");
9
9
  /**
10
10
  * Describes the file v1/streams.proto.
11
11
  */
12
- exports.file_v1_streams = (0, codegenv2_1.fileDesc)("ChB2MS9zdHJlYW1zLnByb3RvEgJ2MSKQAQobUHVibGlzaFN0cmVhbU1lc3NhZ2VSZXF1ZXN0EhEKCW5hbWVzcGFjZRgBIAEoCRINCgV0b3BpYxgCIAEoCRIPCgdwYXlsb2FkGAMgASgMEhMKC3Byb2R1Y2VyX2lkGAQgASgJEhQKDHByb2R1Y2VyX3NlcRgFIAEoAxITCgtwYXlsb2FkX3JlZhgGIAEoCSIeChxQdWJsaXNoU3RyZWFtTWVzc2FnZVJlc3BvbnNlIloKFlN1YnNjcmliZVN0cmVhbVJlcXVlc3QSEQoJbmFtZXNwYWNlGAEgASgJEg0KBXRvcGljGAIgASgJEhMKBmN1cnNvchgDIAEoCUgAiAEBQgkKB19jdXJzb3IiUQoNU3RyZWFtTWVzc2FnZRIgCgdlbnRyaWVzGAEgAygLMg8udjEuU3RyZWFtRW50cnkSDgoGaGFuZ3VwGAIgASgIEg4KBmN1cnNvchgDIAEoCSJzCgtTdHJlYW1FbnRyeRIPCgdwYXlsb2FkGAEgASgMEg4KBmN1cnNvchgCIAEoCRIuCgpjcmVhdGVkX2F0GAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBITCgtwYXlsb2FkX3JlZhgEIAEoCSJBCh1HZXRTdHJlYW1Ub3BpY01ldGFkYXRhUmVxdWVzdBIRCgluYW1lc3BhY2UYASABKAkSDQoFdG9waWMYAiABKAkixgEKE1N0cmVhbVRvcGljTWV0YWRhdGESEQoJbmFtZXNwYWNlGAEgASgJEg0KBXRvcGljGAIgASgJEhEKCXRlbmFudF9pZBgDIAEoCRIaCg1sYXRlc3RfY3Vyc29yGAQgASgJSACIAQESFQoNbWVzc2FnZV9jb3VudBgFIAEoAxI1ChFsYXN0X3B1Ymxpc2hlZF9hdBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCEAoOX2xhdGVzdF9jdXJzb3Iy7QEKCVYxU3RyZWFtcxJOCgdQdWJsaXNoEh8udjEuUHVibGlzaFN0cmVhbU1lc3NhZ2VSZXF1ZXN0GiAudjEuUHVibGlzaFN0cmVhbU1lc3NhZ2VSZXNwb25zZSIAEj4KCVN1YnNjcmliZRIaLnYxLlN1YnNjcmliZVN0cmVhbVJlcXVlc3QaES52MS5TdHJlYW1NZXNzYWdlIgAwARJQChBHZXRUb3BpY01ldGFkYXRhEiEudjEuR2V0U3RyZWFtVG9waWNNZXRhZGF0YVJlcXVlc3QaFy52MS5TdHJlYW1Ub3BpY01ldGFkYXRhIgBCQlpAZ2l0aHViLmNvbS9oYXRjaGV0LWRldi9oYXRjaGV0L2ludGVybmFsL3NlcnZpY2VzL3NoYXJlZC9wcm90by92MWIGcHJvdG8z", [wkt_1.file_google_protobuf_timestamp]);
12
+ exports.file_v1_streams = (0, codegenv2_1.fileDesc)("ChB2MS9zdHJlYW1zLnByb3RvEgJ2MSKQAQobUHVibGlzaFN0cmVhbU1lc3NhZ2VSZXF1ZXN0EhEKCW5hbWVzcGFjZRgBIAEoCRINCgV0b3BpYxgCIAEoCRIPCgdwYXlsb2FkGAMgASgMEhMKC3Byb2R1Y2VyX2lkGAQgASgJEhQKDHByb2R1Y2VyX3NlcRgFIAEoAxITCgtwYXlsb2FkX3JlZhgGIAEoCSIeChxQdWJsaXNoU3RyZWFtTWVzc2FnZVJlc3BvbnNlIloKFlN1YnNjcmliZVN0cmVhbVJlcXVlc3QSEQoJbmFtZXNwYWNlGAEgASgJEg0KBXRvcGljGAIgASgJEhMKBmN1cnNvchgDIAEoCUgAiAEBQgkKB19jdXJzb3IiUQoNU3RyZWFtTWVzc2FnZRIgCgdlbnRyaWVzGAEgAygLMg8udjEuU3RyZWFtRW50cnkSDgoGaGFuZ3VwGAIgASgIEg4KBmN1cnNvchgDIAEoCSJzCgtTdHJlYW1FbnRyeRIPCgdwYXlsb2FkGAEgASgMEg4KBmN1cnNvchgCIAEoCRIuCgpjcmVhdGVkX2F0GAMgASgLMhouZ29vZ2xlLnByb3RvYnVmLlRpbWVzdGFtcBITCgtwYXlsb2FkX3JlZhgEIAEoCSJBCh1HZXRTdHJlYW1Ub3BpY01ldGFkYXRhUmVxdWVzdBIRCgluYW1lc3BhY2UYASABKAkSDQoFdG9waWMYAiABKAkixgEKE1N0cmVhbVRvcGljTWV0YWRhdGESEQoJbmFtZXNwYWNlGAEgASgJEg0KBXRvcGljGAIgASgJEhEKCXRlbmFudF9pZBgDIAEoCRIaCg1sYXRlc3RfY3Vyc29yGAQgASgJSACIAQESFQoNbWVzc2FnZV9jb3VudBgFIAEoAxI1ChFsYXN0X3B1Ymxpc2hlZF9hdBgGIAEoCzIaLmdvb2dsZS5wcm90b2J1Zi5UaW1lc3RhbXBCEAoOX2xhdGVzdF9jdXJzb3IiOwoXUmVzZXRTdHJlYW1Ub3BpY1JlcXVlc3QSEQoJbmFtZXNwYWNlGAEgASgJEg0KBXRvcGljGAIgASgJIhoKGFJlc2V0U3RyZWFtVG9waWNSZXNwb25zZTKzAgoJVjFTdHJlYW1zEk4KB1B1Ymxpc2gSHy52MS5QdWJsaXNoU3RyZWFtTWVzc2FnZVJlcXVlc3QaIC52MS5QdWJsaXNoU3RyZWFtTWVzc2FnZVJlc3BvbnNlIgASPgoJU3Vic2NyaWJlEhoudjEuU3Vic2NyaWJlU3RyZWFtUmVxdWVzdBoRLnYxLlN0cmVhbU1lc3NhZ2UiADABElAKEEdldFRvcGljTWV0YWRhdGESIS52MS5HZXRTdHJlYW1Ub3BpY01ldGFkYXRhUmVxdWVzdBoXLnYxLlN0cmVhbVRvcGljTWV0YWRhdGEiABJECgVSZXNldBIbLnYxLlJlc2V0U3RyZWFtVG9waWNSZXF1ZXN0GhwudjEuUmVzZXRTdHJlYW1Ub3BpY1Jlc3BvbnNlIgBCQlpAZ2l0aHViLmNvbS9oYXRjaGV0LWRldi9oYXRjaGV0L2ludGVybmFsL3NlcnZpY2VzL3NoYXJlZC9wcm90by92MWIGcHJvdG8z", [wkt_1.file_google_protobuf_timestamp]);
13
13
  /**
14
14
  * Describes the message v1.PublishStreamMessageRequest.
15
15
  * Use `create(PublishStreamMessageRequestSchema)` to create a new message.
@@ -45,6 +45,16 @@ exports.GetStreamTopicMetadataRequestSchema = (0, codegenv2_1.messageDesc)(expor
45
45
  * Use `create(StreamTopicMetadataSchema)` to create a new message.
46
46
  */
47
47
  exports.StreamTopicMetadataSchema = (0, codegenv2_1.messageDesc)(exports.file_v1_streams, 6);
48
+ /**
49
+ * Describes the message v1.ResetStreamTopicRequest.
50
+ * Use `create(ResetStreamTopicRequestSchema)` to create a new message.
51
+ */
52
+ exports.ResetStreamTopicRequestSchema = (0, codegenv2_1.messageDesc)(exports.file_v1_streams, 7);
53
+ /**
54
+ * Describes the message v1.ResetStreamTopicResponse.
55
+ * Use `create(ResetStreamTopicResponseSchema)` to create a new message.
56
+ */
57
+ exports.ResetStreamTopicResponseSchema = (0, codegenv2_1.messageDesc)(exports.file_v1_streams, 8);
48
58
  /**
49
59
  * @generated from service v1.V1Streams
50
60
  */