@hatchet-dev/typescript-sdk 1.38.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.
- package/clients/rest/generated/Api.d.ts +62 -1
- package/clients/rest/generated/Api.js +50 -0
- package/clients/rest/generated/data-contracts.d.ts +146 -15
- package/clients/rest/generated/data-contracts.js +8 -1
- package/clients/streams/rpc.d.ts +8 -0
- package/clients/streams/rpc.js +14 -0
- package/clients/transport/fetch-transport.js +18 -1
- package/core/client.d.ts +2 -1
- package/core/client.js +3 -1
- package/core/features/streams.d.ts +68 -3
- package/core/features/streams.js +206 -5
- package/core/index.d.ts +9 -5
- package/core/index.js +13 -7
- package/core/types.d.ts +20 -0
- package/dist/check-core-esm-exports.mjs +19 -0
- package/package.json +2 -2
- package/scripts/check-core-esm-exports.mjs +19 -0
- package/v1/client/features/streams.d.ts +2 -17
- package/v1/examples/durable_eviction/graceful-worker.d.ts +1 -0
- package/v1/examples/durable_eviction/graceful-worker.js +49 -0
- package/version.d.ts +1 -1
- package/version.js +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { APIErrors, APIMeta, AcceptInviteRequest, BulkCreateEventRequest, CancelEventRequest, CreateAPITokenRequest, CreateAPITokenResponse, CreateCronWorkflowTriggerRequest, CreateEventRequest, CreateSNSIntegrationRequest, CreateTenantAlertEmailGroupRequest, CreateTenantInviteRequest, CreateTenantRequest, CronWorkflows, CronWorkflowsList, CronWorkflowsOrderByField, Event, EventData, EventKey, EventKeyList, EventList, EventOrderByDirection, EventOrderByField, EventSearch, Events, FeatureFlagEvaluationResult, FeatureFlagId, ListAPIMetaIntegration, ListAPITokensResponse, ListSNSIntegrations, ListSlackWebhooks, OtelSpanList, RateLimitList, RateLimitOrderByDirection, RateLimitOrderByField, RejectInviteRequest, ReplayEventRequest, ReplayWorkflowRunsRequest, ReplayWorkflowRunsResponse, RerunStepRunRequest, SNSIntegration, ScheduleWorkflowRunRequest, ScheduledRunStatus, ScheduledWorkflows, ScheduledWorkflowsBulkDeleteRequest, ScheduledWorkflowsBulkDeleteResponse, ScheduledWorkflowsBulkUpdateRequest, ScheduledWorkflowsBulkUpdateResponse, ScheduledWorkflowsList, ScheduledWorkflowsOrderByField, StepRun, StepRunArchiveList, StepRunEventList, TaskStats, Tenant, TenantAlertEmailGroup, TenantAlertEmailGroupList, TenantAlertingSettings, TenantInvite, TenantInviteList, TenantMember, TenantMemberList, TenantQueueMetrics, TenantResourcePolicy, TenantStepRunQueueMetrics, TriggerRunResult, TriggerWorkflowRunRequest, UpdateCronWorkflowTriggerRequest, UpdateScheduledWorkflowRunRequest, UpdateTenantAlertEmailGroupRequest, UpdateTenantInviteRequest, UpdateTenantMemberRequest, UpdateTenantRequest, UpdateWorkerRequest, User, UserChangePasswordRequest, UserLoginRequest, UserRegisterRequest, UserTenantMembershipsList, V1AdditionalMetadataOperator, V1BranchDurableTaskRequest, V1BranchDurableTaskResponse, V1CELDebugRequest, V1CELDebugResponse, V1CancelTaskRequest, V1CancelledTasks, V1CreateFilterRequest, V1CreateWebhookRequest, V1DagChildren, V1DurableEventLogList, V1Event, V1EventList, V1Filter, V1FilterList, V1LogLineLevel, V1LogLineList, V1LogLineOrderByDirection, V1LogsPointMetrics, V1ReplayTaskRequest, V1ReplayedTasks, V1RestoreTaskResponse, V1RunningFilter, V1StreamPayloadRef, V1TaskEventList, V1TaskPointMetrics, V1TaskRunMetrics, V1TaskStatus, V1TaskSummary, V1TaskSummaryList, V1TaskTimingList, V1TriggerWorkflowRunRequest, V1UpdateFilterRequest, V1UpdateWebhookRequest, V1Webhook, V1WebhookList, V1WebhookResponse, V1WebhookSourceName, V1WorkflowRunCount, V1WorkflowRunDetails, V1WorkflowRunDisplayNameList, V1WorkflowRunExternalIdList, WebhookWorkerCreateRequest, WebhookWorkerCreated, WebhookWorkerListResponse, WebhookWorkerRequestListResponse, Worker, WorkerList, WorkerStatus, Workflow, WorkflowID, WorkflowKindList, WorkflowList, WorkflowMetrics, WorkflowRun, WorkflowRunList, WorkflowRunOrderByDirection, WorkflowRunOrderByField, WorkflowRunShape, WorkflowRunStatus, WorkflowRunStatusList, WorkflowRunsCancelRequest, WorkflowRunsMetrics, WorkflowUpdateRequest, WorkflowVersion, WorkflowWorkersCount } from './data-contracts';
|
|
1
|
+
import { APIErrors, APIMeta, AcceptInviteRequest, BulkCreateEventRequest, CancelEventRequest, CreateAPITokenRequest, CreateAPITokenResponse, CreateCronWorkflowTriggerRequest, CreateEventRequest, CreateSNSIntegrationRequest, CreateTenantAlertEmailGroupRequest, CreateTenantInviteRequest, CreateTenantRequest, CronWorkflows, CronWorkflowsList, CronWorkflowsOrderByField, Event, EventData, EventKey, EventKeyList, EventList, EventOrderByDirection, EventOrderByField, EventSearch, Events, FeatureFlagEvaluationResult, FeatureFlagId, ListAPIMetaIntegration, ListAPITokensResponse, ListSNSIntegrations, ListSlackWebhooks, OtelSpanList, RateLimitList, RateLimitOrderByDirection, RateLimitOrderByField, RejectInviteRequest, ReplayEventRequest, ReplayWorkflowRunsRequest, ReplayWorkflowRunsResponse, RerunStepRunRequest, SNSIntegration, ScheduleWorkflowRunRequest, ScheduledRunStatus, ScheduledWorkflows, ScheduledWorkflowsBulkDeleteRequest, ScheduledWorkflowsBulkDeleteResponse, ScheduledWorkflowsBulkUpdateRequest, ScheduledWorkflowsBulkUpdateResponse, ScheduledWorkflowsList, ScheduledWorkflowsOrderByField, StepRun, StepRunArchiveList, StepRunEventList, TaskStats, Tenant, TenantAlertEmailGroup, TenantAlertEmailGroupList, TenantAlertingSettings, TenantInvite, TenantInviteList, TenantMember, TenantMemberList, TenantQueueMetrics, TenantResourcePolicy, TenantStepRunQueueMetrics, TriggerRunResult, TriggerWorkflowRunRequest, UpdateCronWorkflowTriggerRequest, UpdateScheduledWorkflowRunRequest, UpdateTenantAlertEmailGroupRequest, UpdateTenantInviteRequest, UpdateTenantMemberRequest, UpdateTenantRequest, UpdateWorkerRequest, User, UserChangePasswordRequest, UserLoginRequest, UserRegisterRequest, UserTenantMembershipsList, V1AdditionalMetadataOperator, V1BranchDurableTaskRequest, V1BranchDurableTaskResponse, V1CELDebugRequest, V1CELDebugResponse, V1CancelTaskRequest, V1CancelledTasks, V1CreateFilterRequest, V1CreateServerlessEndpointRequest, V1CreateWebhookRequest, V1DagChildren, V1DurableEventLogList, V1Event, V1EventList, V1Filter, V1FilterList, V1LogLineLevel, V1LogLineList, V1LogLineOrderByDirection, V1LogsPointMetrics, V1ReplayTaskRequest, V1ReplayedTasks, V1RestoreTaskResponse, V1RunningFilter, V1ServerlessEndpoint, V1ServerlessEndpointList, V1StreamPayloadRef, V1TaskEventList, V1TaskPointMetrics, V1TaskRunMetrics, V1TaskStatus, V1TaskSummary, V1TaskSummaryList, V1TaskTimingList, V1TriggerWorkflowRunRequest, V1UpdateFilterRequest, V1UpdateServerlessEndpointRequest, V1UpdateWebhookRequest, V1Webhook, V1WebhookList, V1WebhookResponse, V1WebhookSourceName, V1WorkflowRunCount, V1WorkflowRunDetails, V1WorkflowRunDisplayNameList, V1WorkflowRunExternalIdList, WebhookWorkerCreateRequest, WebhookWorkerCreated, WebhookWorkerListResponse, WebhookWorkerRequestListResponse, Worker, WorkerList, WorkerStatus, Workflow, WorkflowID, WorkflowKindList, WorkflowList, WorkflowMetrics, WorkflowRun, WorkflowRunList, WorkflowRunOrderByDirection, WorkflowRunOrderByField, WorkflowRunShape, WorkflowRunStatus, WorkflowRunStatusList, WorkflowRunsCancelRequest, WorkflowRunsMetrics, WorkflowUpdateRequest, WorkflowVersion, WorkflowWorkersCount } from './data-contracts';
|
|
2
2
|
import { HttpClient, RequestParams } from './http-client';
|
|
3
3
|
export declare class Api<SecurityDataType = unknown> extends HttpClient<SecurityDataType> {
|
|
4
4
|
/**
|
|
@@ -777,6 +777,67 @@ export declare class Api<SecurityDataType = unknown> extends HttpClient<Security
|
|
|
777
777
|
* @secure
|
|
778
778
|
*/
|
|
779
779
|
v1WebhookUpdate: (tenant: string, v1Webhook: string, data: V1UpdateWebhookRequest, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1Webhook, any, {}>>;
|
|
780
|
+
/**
|
|
781
|
+
* @description Lists the serverless endpoints of a tenant.
|
|
782
|
+
*
|
|
783
|
+
* @tags Serverless
|
|
784
|
+
* @name V1ServerlessEndpointList
|
|
785
|
+
* @summary List serverless endpoints
|
|
786
|
+
* @request GET:/api/v1/stable/tenants/{tenant}/serverless/endpoints
|
|
787
|
+
* @secure
|
|
788
|
+
*/
|
|
789
|
+
v1ServerlessEndpointList: (tenant: string, query?: {
|
|
790
|
+
/**
|
|
791
|
+
* The number to skip
|
|
792
|
+
* @format int64
|
|
793
|
+
*/
|
|
794
|
+
offset?: number;
|
|
795
|
+
/**
|
|
796
|
+
* The number to limit by
|
|
797
|
+
* @format int64
|
|
798
|
+
*/
|
|
799
|
+
limit?: number;
|
|
800
|
+
}, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1ServerlessEndpointList, any, {}>>;
|
|
801
|
+
/**
|
|
802
|
+
* @description Create a serverless endpoint
|
|
803
|
+
*
|
|
804
|
+
* @tags Serverless
|
|
805
|
+
* @name V1ServerlessEndpointCreate
|
|
806
|
+
* @summary Create a serverless endpoint
|
|
807
|
+
* @request POST:/api/v1/stable/tenants/{tenant}/serverless/endpoints
|
|
808
|
+
* @secure
|
|
809
|
+
*/
|
|
810
|
+
v1ServerlessEndpointCreate: (tenant: string, data: V1CreateServerlessEndpointRequest, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1ServerlessEndpoint, any, {}>>;
|
|
811
|
+
/**
|
|
812
|
+
* @description Get a serverless endpoint by its id
|
|
813
|
+
*
|
|
814
|
+
* @tags Serverless
|
|
815
|
+
* @name V1ServerlessEndpointGet
|
|
816
|
+
* @summary Get a serverless endpoint
|
|
817
|
+
* @request GET:/api/v1/stable/serverless/endpoints/{v1-serverless-endpoint}
|
|
818
|
+
* @secure
|
|
819
|
+
*/
|
|
820
|
+
v1ServerlessEndpointGet: (v1ServerlessEndpoint: string, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1ServerlessEndpoint, any, {}>>;
|
|
821
|
+
/**
|
|
822
|
+
* @description Update a serverless endpoint
|
|
823
|
+
*
|
|
824
|
+
* @tags Serverless
|
|
825
|
+
* @name V1ServerlessEndpointUpdate
|
|
826
|
+
* @summary Update a serverless endpoint
|
|
827
|
+
* @request PATCH:/api/v1/stable/serverless/endpoints/{v1-serverless-endpoint}
|
|
828
|
+
* @secure
|
|
829
|
+
*/
|
|
830
|
+
v1ServerlessEndpointUpdate: (v1ServerlessEndpoint: string, data: V1UpdateServerlessEndpointRequest, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1ServerlessEndpoint, any, {}>>;
|
|
831
|
+
/**
|
|
832
|
+
* @description Delete a serverless endpoint
|
|
833
|
+
*
|
|
834
|
+
* @tags Serverless
|
|
835
|
+
* @name V1ServerlessEndpointDelete
|
|
836
|
+
* @summary Delete a serverless endpoint
|
|
837
|
+
* @request DELETE:/api/v1/stable/serverless/endpoints/{v1-serverless-endpoint}
|
|
838
|
+
* @secure
|
|
839
|
+
*/
|
|
840
|
+
v1ServerlessEndpointDelete: (v1ServerlessEndpoint: string, params?: RequestParams) => Promise<import("axios").AxiosResponse<V1ServerlessEndpoint, any, {}>>;
|
|
780
841
|
/**
|
|
781
842
|
* @description Evaluate a CEL expression against provided input data.
|
|
782
843
|
*
|
|
@@ -405,6 +405,56 @@ class Api extends http_client_1.HttpClient {
|
|
|
405
405
|
* @secure
|
|
406
406
|
*/
|
|
407
407
|
this.v1WebhookUpdate = (tenant, v1Webhook, data, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/tenants/${tenant}/webhooks/${v1Webhook}`, method: 'PATCH', body: data, secure: true, type: http_client_1.ContentType.Json, format: 'json' }, params));
|
|
408
|
+
/**
|
|
409
|
+
* @description Lists the serverless endpoints of a tenant.
|
|
410
|
+
*
|
|
411
|
+
* @tags Serverless
|
|
412
|
+
* @name V1ServerlessEndpointList
|
|
413
|
+
* @summary List serverless endpoints
|
|
414
|
+
* @request GET:/api/v1/stable/tenants/{tenant}/serverless/endpoints
|
|
415
|
+
* @secure
|
|
416
|
+
*/
|
|
417
|
+
this.v1ServerlessEndpointList = (tenant, query, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/tenants/${tenant}/serverless/endpoints`, method: 'GET', query: query, secure: true, format: 'json' }, params));
|
|
418
|
+
/**
|
|
419
|
+
* @description Create a serverless endpoint
|
|
420
|
+
*
|
|
421
|
+
* @tags Serverless
|
|
422
|
+
* @name V1ServerlessEndpointCreate
|
|
423
|
+
* @summary Create a serverless endpoint
|
|
424
|
+
* @request POST:/api/v1/stable/tenants/{tenant}/serverless/endpoints
|
|
425
|
+
* @secure
|
|
426
|
+
*/
|
|
427
|
+
this.v1ServerlessEndpointCreate = (tenant, data, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/tenants/${tenant}/serverless/endpoints`, method: 'POST', body: data, secure: true, type: http_client_1.ContentType.Json, format: 'json' }, params));
|
|
428
|
+
/**
|
|
429
|
+
* @description Get a serverless endpoint by its id
|
|
430
|
+
*
|
|
431
|
+
* @tags Serverless
|
|
432
|
+
* @name V1ServerlessEndpointGet
|
|
433
|
+
* @summary Get a serverless endpoint
|
|
434
|
+
* @request GET:/api/v1/stable/serverless/endpoints/{v1-serverless-endpoint}
|
|
435
|
+
* @secure
|
|
436
|
+
*/
|
|
437
|
+
this.v1ServerlessEndpointGet = (v1ServerlessEndpoint, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/serverless/endpoints/${v1ServerlessEndpoint}`, method: 'GET', secure: true, format: 'json' }, params));
|
|
438
|
+
/**
|
|
439
|
+
* @description Update a serverless endpoint
|
|
440
|
+
*
|
|
441
|
+
* @tags Serverless
|
|
442
|
+
* @name V1ServerlessEndpointUpdate
|
|
443
|
+
* @summary Update a serverless endpoint
|
|
444
|
+
* @request PATCH:/api/v1/stable/serverless/endpoints/{v1-serverless-endpoint}
|
|
445
|
+
* @secure
|
|
446
|
+
*/
|
|
447
|
+
this.v1ServerlessEndpointUpdate = (v1ServerlessEndpoint, data, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/serverless/endpoints/${v1ServerlessEndpoint}`, method: 'PATCH', body: data, secure: true, type: http_client_1.ContentType.Json, format: 'json' }, params));
|
|
448
|
+
/**
|
|
449
|
+
* @description Delete a serverless endpoint
|
|
450
|
+
*
|
|
451
|
+
* @tags Serverless
|
|
452
|
+
* @name V1ServerlessEndpointDelete
|
|
453
|
+
* @summary Delete a serverless endpoint
|
|
454
|
+
* @request DELETE:/api/v1/stable/serverless/endpoints/{v1-serverless-endpoint}
|
|
455
|
+
* @secure
|
|
456
|
+
*/
|
|
457
|
+
this.v1ServerlessEndpointDelete = (v1ServerlessEndpoint, params = {}) => this.request(Object.assign({ path: `/api/v1/stable/serverless/endpoints/${v1ServerlessEndpoint}`, method: 'DELETE', secure: true, format: 'json' }, params));
|
|
408
458
|
/**
|
|
409
459
|
* @description Evaluate a CEL expression against provided input data.
|
|
410
460
|
*
|
|
@@ -191,6 +191,11 @@ export declare enum V1CELDebugResponseStatus {
|
|
|
191
191
|
SUCCESS = "SUCCESS",
|
|
192
192
|
ERROR = "ERROR"
|
|
193
193
|
}
|
|
194
|
+
/** The kind of serverless endpoint. GENERIC_HTTP is any HTTPS endpoint that implements the serverless endpoint contract; CLOUDFLARE_WORKERS applies the Cloudflare Workers runtime constraints on top of it. */
|
|
195
|
+
export declare enum V1ServerlessEndpointKind {
|
|
196
|
+
GENERIC_HTTP = "GENERIC_HTTP",
|
|
197
|
+
CLOUDFLARE_WORKERS = "CLOUDFLARE_WORKERS"
|
|
198
|
+
}
|
|
194
199
|
export declare enum V1WebhookHMACEncoding {
|
|
195
200
|
HEX = "HEX",
|
|
196
201
|
BASE64 = "BASE64",
|
|
@@ -1129,6 +1134,130 @@ export interface V1UpdateWebhookRequest {
|
|
|
1129
1134
|
/** Whether to return the triggered event as the response payload when this webhook is triggered */
|
|
1130
1135
|
returnEventAsResponsePayload?: boolean;
|
|
1131
1136
|
}
|
|
1137
|
+
/** The health of the endpoint as last observed by the serverless operator. Written on state transitions only, so changedAt is the time the endpoint last flipped between healthy and unhealthy. */
|
|
1138
|
+
export interface V1ServerlessEndpointStatus {
|
|
1139
|
+
/** Whether the last healthcheck succeeded. Absent until the operator has polled the endpoint at least once. */
|
|
1140
|
+
healthy?: boolean;
|
|
1141
|
+
/** The error from the last failed healthcheck, if the endpoint is unhealthy. */
|
|
1142
|
+
error?: string;
|
|
1143
|
+
/**
|
|
1144
|
+
* When the healthy flag last changed.
|
|
1145
|
+
* @format date-time
|
|
1146
|
+
*/
|
|
1147
|
+
changedAt?: string;
|
|
1148
|
+
/** The action ids the operator registered for this endpoint from its last healthcheck, as the endpoint declared them. Several endpoints of a tenant may register the same action; each then serves it. */
|
|
1149
|
+
registeredActions: string[];
|
|
1150
|
+
}
|
|
1151
|
+
export interface V1ServerlessEndpoint {
|
|
1152
|
+
metadata: APIResourceMeta;
|
|
1153
|
+
/**
|
|
1154
|
+
* The ID of the tenant that owns this endpoint.
|
|
1155
|
+
* @format uuid
|
|
1156
|
+
*/
|
|
1157
|
+
tenantId: string;
|
|
1158
|
+
/** The name of the endpoint. Unique within the tenant. */
|
|
1159
|
+
name: string;
|
|
1160
|
+
/** The kind of serverless endpoint. GENERIC_HTTP is any HTTPS endpoint that implements the serverless endpoint contract; CLOUDFLARE_WORKERS applies the Cloudflare Workers runtime constraints on top of it. */
|
|
1161
|
+
kind: V1ServerlessEndpointKind;
|
|
1162
|
+
/** The HTTPS URL (port 443) polled periodically to discover the workflows this endpoint serves. */
|
|
1163
|
+
healthcheckUrl: string;
|
|
1164
|
+
/** The HTTPS URL (port 443) that assigned tasks are delivered to. */
|
|
1165
|
+
triggerUrl: string;
|
|
1166
|
+
/**
|
|
1167
|
+
* The per-request timeout backstop for trigger requests, in seconds.
|
|
1168
|
+
* @format int32
|
|
1169
|
+
*/
|
|
1170
|
+
requestTimeoutSeconds: number;
|
|
1171
|
+
/**
|
|
1172
|
+
* How often the healthcheck URL is polled, in seconds.
|
|
1173
|
+
* @format int32
|
|
1174
|
+
*/
|
|
1175
|
+
pollIntervalSeconds: number;
|
|
1176
|
+
/**
|
|
1177
|
+
* How long a trigger request may block waiting for a durable result before the operator falls back to the websocket durable protocol, in milliseconds.
|
|
1178
|
+
* @format int32
|
|
1179
|
+
*/
|
|
1180
|
+
inlineWaitBudgetMs: number;
|
|
1181
|
+
/** Worker labels applied to the connection-backed worker the operator creates for this endpoint. */
|
|
1182
|
+
labels: Record<string, any>;
|
|
1183
|
+
/** Whether the operator polls and dispatches to this endpoint. */
|
|
1184
|
+
enabled: boolean;
|
|
1185
|
+
/** The health of the endpoint as last observed by the serverless operator. Written on state transitions only, so changedAt is the time the endpoint last flipped between healthy and unhealthy. */
|
|
1186
|
+
status: V1ServerlessEndpointStatus;
|
|
1187
|
+
}
|
|
1188
|
+
export interface V1ServerlessEndpointList {
|
|
1189
|
+
pagination?: PaginationResponse;
|
|
1190
|
+
rows?: V1ServerlessEndpoint[];
|
|
1191
|
+
}
|
|
1192
|
+
export interface V1CreateServerlessEndpointRequest {
|
|
1193
|
+
/** The name of the endpoint. Unique within the tenant. */
|
|
1194
|
+
name: string;
|
|
1195
|
+
/** The kind of serverless endpoint. GENERIC_HTTP is any HTTPS endpoint that implements the serverless endpoint contract; CLOUDFLARE_WORKERS applies the Cloudflare Workers runtime constraints on top of it. */
|
|
1196
|
+
kind?: V1ServerlessEndpointKind;
|
|
1197
|
+
/** The HTTPS URL (port 443) polled periodically to discover the workflows this endpoint serves. */
|
|
1198
|
+
healthcheckUrl: string;
|
|
1199
|
+
/** The HTTPS URL (port 443) that assigned tasks are delivered to. */
|
|
1200
|
+
triggerUrl: string;
|
|
1201
|
+
/**
|
|
1202
|
+
* The secret used to HMAC-sign requests delivered to the endpoint. At least 32 characters. Write-only: it is stored encrypted and never returned in responses.
|
|
1203
|
+
* @minLength 32
|
|
1204
|
+
*/
|
|
1205
|
+
signingSecret: string;
|
|
1206
|
+
/**
|
|
1207
|
+
* The per-request timeout backstop for trigger requests, in seconds. Defaults to 60.
|
|
1208
|
+
* @format int32
|
|
1209
|
+
*/
|
|
1210
|
+
requestTimeoutSeconds?: number;
|
|
1211
|
+
/**
|
|
1212
|
+
* How often the healthcheck URL is polled, in seconds. Defaults to 30.
|
|
1213
|
+
* @format int32
|
|
1214
|
+
*/
|
|
1215
|
+
pollIntervalSeconds?: number;
|
|
1216
|
+
/**
|
|
1217
|
+
* The inline wait budget for durable results, in milliseconds. Defaults to 5000.
|
|
1218
|
+
* @format int32
|
|
1219
|
+
*/
|
|
1220
|
+
inlineWaitBudgetMs?: number;
|
|
1221
|
+
/** Worker labels applied to the worker the operator creates for this endpoint. */
|
|
1222
|
+
labels?: Record<string, any>;
|
|
1223
|
+
/** Whether the operator polls and dispatches to this endpoint. Defaults to true. */
|
|
1224
|
+
enabled?: boolean;
|
|
1225
|
+
}
|
|
1226
|
+
/** Fields to update on a serverless endpoint. Omitted fields are left unchanged. */
|
|
1227
|
+
export interface V1UpdateServerlessEndpointRequest {
|
|
1228
|
+
/** The name of the endpoint. Unique within the tenant. */
|
|
1229
|
+
name?: string;
|
|
1230
|
+
/** The kind of serverless endpoint. GENERIC_HTTP is any HTTPS endpoint that implements the serverless endpoint contract; CLOUDFLARE_WORKERS applies the Cloudflare Workers runtime constraints on top of it. */
|
|
1231
|
+
kind?: V1ServerlessEndpointKind;
|
|
1232
|
+
/** The HTTPS URL (port 443) polled periodically to discover the workflows this endpoint serves. */
|
|
1233
|
+
healthcheckUrl?: string;
|
|
1234
|
+
/** The HTTPS URL (port 443) that assigned tasks are delivered to. */
|
|
1235
|
+
triggerUrl?: string;
|
|
1236
|
+
/**
|
|
1237
|
+
* A new secret used to HMAC-sign requests delivered to the endpoint. At least 32 characters. Provide a value to rotate the secret; it is never returned in responses.
|
|
1238
|
+
* @minLength 32
|
|
1239
|
+
*/
|
|
1240
|
+
signingSecret?: string;
|
|
1241
|
+
/**
|
|
1242
|
+
* The per-request timeout backstop for trigger requests, in seconds.
|
|
1243
|
+
* @format int32
|
|
1244
|
+
*/
|
|
1245
|
+
requestTimeoutSeconds?: number;
|
|
1246
|
+
/**
|
|
1247
|
+
* How often the healthcheck URL is polled, in seconds.
|
|
1248
|
+
* @format int32
|
|
1249
|
+
*/
|
|
1250
|
+
pollIntervalSeconds?: number;
|
|
1251
|
+
/**
|
|
1252
|
+
* The inline wait budget for durable results, in milliseconds.
|
|
1253
|
+
* @format int32
|
|
1254
|
+
*/
|
|
1255
|
+
inlineWaitBudgetMs?: number;
|
|
1256
|
+
/** Worker labels applied to the worker the operator creates for this endpoint. Replaces the existing labels. */
|
|
1257
|
+
labels?: Record<string, any>;
|
|
1258
|
+
/** Whether the operator polls and dispatches to this endpoint. */
|
|
1259
|
+
enabled?: boolean;
|
|
1260
|
+
}
|
|
1132
1261
|
export interface V1CELDebugRequest {
|
|
1133
1262
|
/** The CEL expression to evaluate */
|
|
1134
1263
|
expression: string;
|
|
@@ -1661,6 +1790,8 @@ export interface Workflow {
|
|
|
1661
1790
|
jobs?: Job[];
|
|
1662
1791
|
/** The tenant id of the workflow. */
|
|
1663
1792
|
tenantId: string;
|
|
1793
|
+
/** The event and cron triggers declared on the latest workflow version. */
|
|
1794
|
+
triggers?: WorkflowTriggers;
|
|
1664
1795
|
}
|
|
1665
1796
|
export interface WorkflowVersionMeta {
|
|
1666
1797
|
metadata: APIResourceMeta;
|
|
@@ -1704,6 +1835,21 @@ export interface Job {
|
|
|
1704
1835
|
/** The timeout of the job. */
|
|
1705
1836
|
timeout?: string;
|
|
1706
1837
|
}
|
|
1838
|
+
export interface WorkflowTriggerEventRef {
|
|
1839
|
+
parent_id?: string;
|
|
1840
|
+
event_key?: string;
|
|
1841
|
+
}
|
|
1842
|
+
export interface WorkflowTriggerCronRef {
|
|
1843
|
+
parent_id?: string;
|
|
1844
|
+
cron?: string;
|
|
1845
|
+
}
|
|
1846
|
+
export interface WorkflowTriggers {
|
|
1847
|
+
metadata?: APIResourceMeta;
|
|
1848
|
+
workflow_version_id?: string;
|
|
1849
|
+
tenant_id?: string;
|
|
1850
|
+
events?: WorkflowTriggerEventRef[];
|
|
1851
|
+
crons?: WorkflowTriggerCronRef[];
|
|
1852
|
+
}
|
|
1707
1853
|
export interface WorkflowList {
|
|
1708
1854
|
metadata?: APIResourceMeta;
|
|
1709
1855
|
rows?: Workflow[];
|
|
@@ -1904,21 +2050,6 @@ export interface WorkflowConcurrency {
|
|
|
1904
2050
|
/** An action which gets the concurrency group for the WorkflowRun. */
|
|
1905
2051
|
getConcurrencyGroup: string;
|
|
1906
2052
|
}
|
|
1907
|
-
export interface WorkflowTriggerEventRef {
|
|
1908
|
-
parent_id?: string;
|
|
1909
|
-
event_key?: string;
|
|
1910
|
-
}
|
|
1911
|
-
export interface WorkflowTriggerCronRef {
|
|
1912
|
-
parent_id?: string;
|
|
1913
|
-
cron?: string;
|
|
1914
|
-
}
|
|
1915
|
-
export interface WorkflowTriggers {
|
|
1916
|
-
metadata?: APIResourceMeta;
|
|
1917
|
-
workflow_version_id?: string;
|
|
1918
|
-
tenant_id?: string;
|
|
1919
|
-
events?: WorkflowTriggerEventRef[];
|
|
1920
|
-
crons?: WorkflowTriggerCronRef[];
|
|
1921
|
-
}
|
|
1922
2053
|
export interface ConcurrencySetting {
|
|
1923
2054
|
/**
|
|
1924
2055
|
* The maximum number of concurrent workflow runs.
|
|
@@ -11,7 +11,8 @@
|
|
|
11
11
|
* ---------------------------------------------------------------
|
|
12
12
|
*/
|
|
13
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
-
exports.
|
|
14
|
+
exports.V1WorkflowType = exports.V1TaskEventType = exports.V1LogLineLevel = exports.V1LogLineOrderByDirection = exports.V1AdditionalMetadataOperator = exports.V1RunningFilter = exports.V1DurableEventLogKind = exports.V1DurableWaitConditionKind = exports.OtelSpanKind = exports.OtelStatusCode = exports.TenantVersion = exports.TenantEnvironment = exports.V1WebhookSourceName = exports.V1WebhookAuthType = exports.V1WebhookHMACAlgorithm = exports.V1WebhookHMACEncoding = exports.V1ServerlessEndpointKind = exports.V1CELDebugResponseStatus = exports.TenantResource = exports.TenantMemberRole = exports.WorkflowRunStatus = exports.EventOrderByField = exports.EventOrderByDirection = exports.RateLimitOrderByField = exports.RateLimitOrderByDirection = exports.WorkflowPauseScheduledCronRunQueueBehavior = exports.ScheduledWorkflowsMethod = exports.ScheduledWorkflowsOrderByField = exports.WorkflowRunOrderByDirection = exports.ScheduledRunStatus = exports.CronWorkflowsMethod = exports.CronWorkflowsOrderByField = exports.ConcurrencyLimitStrategy = exports.ConcurrencyScope = exports.StepRunStatus = exports.JobRunStatus = exports.StepRunEventReason = exports.StepRunEventSeverity = exports.WorkflowKind = exports.WorkflowRunOrderByField = exports.WorkerStatus = exports.WorkerType = exports.WorkerRuntimeSDKs = exports.WebhookWorkerRequestMethod = exports.FeatureFlagId = exports.PullRequestState = exports.LogLineLevel = exports.LogLineOrderByField = exports.LogLineOrderByDirection = exports.V1TaskRunStatus = void 0;
|
|
15
|
+
exports.V1TaskStatus = void 0;
|
|
15
16
|
var V1TaskRunStatus;
|
|
16
17
|
(function (V1TaskRunStatus) {
|
|
17
18
|
V1TaskRunStatus["PENDING"] = "PENDING";
|
|
@@ -238,6 +239,12 @@ var V1CELDebugResponseStatus;
|
|
|
238
239
|
V1CELDebugResponseStatus["SUCCESS"] = "SUCCESS";
|
|
239
240
|
V1CELDebugResponseStatus["ERROR"] = "ERROR";
|
|
240
241
|
})(V1CELDebugResponseStatus || (exports.V1CELDebugResponseStatus = V1CELDebugResponseStatus = {}));
|
|
242
|
+
/** The kind of serverless endpoint. GENERIC_HTTP is any HTTPS endpoint that implements the serverless endpoint contract; CLOUDFLARE_WORKERS applies the Cloudflare Workers runtime constraints on top of it. */
|
|
243
|
+
var V1ServerlessEndpointKind;
|
|
244
|
+
(function (V1ServerlessEndpointKind) {
|
|
245
|
+
V1ServerlessEndpointKind["GENERIC_HTTP"] = "GENERIC_HTTP";
|
|
246
|
+
V1ServerlessEndpointKind["CLOUDFLARE_WORKERS"] = "CLOUDFLARE_WORKERS";
|
|
247
|
+
})(V1ServerlessEndpointKind || (exports.V1ServerlessEndpointKind = V1ServerlessEndpointKind = {}));
|
|
241
248
|
var V1WebhookHMACEncoding;
|
|
242
249
|
(function (V1WebhookHMACEncoding) {
|
|
243
250
|
V1WebhookHMACEncoding["HEX"] = "HEX";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { V1StreamsClient } from '../../protoc/v1/streams';
|
|
2
|
+
import type { Transport } from '../transport/transport';
|
|
3
|
+
/**
|
|
4
|
+
* The v1 `V1Streams` client, every RPC of the generated `V1StreamsClient` interface, served
|
|
5
|
+
* by a Connect client on the given transport. `Subscribe` is a server stream, which the unary
|
|
6
|
+
* transport does not serve: calling it throws.
|
|
7
|
+
*/
|
|
8
|
+
export declare function createV1StreamsRpc(transport: Transport): V1StreamsClient;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createV1StreamsRpc = createV1StreamsRpc;
|
|
4
|
+
const streams_1 = require("../../protoc/v1/streams");
|
|
5
|
+
const streams_pb_1 = require("../../protoc-es/v1/streams_pb");
|
|
6
|
+
const ts_proto_client_1 = require("../transport/ts-proto-client");
|
|
7
|
+
/**
|
|
8
|
+
* The v1 `V1Streams` client, every RPC of the generated `V1StreamsClient` interface, served
|
|
9
|
+
* by a Connect client on the given transport. `Subscribe` is a server stream, which the unary
|
|
10
|
+
* transport does not serve: calling it throws.
|
|
11
|
+
*/
|
|
12
|
+
function createV1StreamsRpc(transport) {
|
|
13
|
+
return (0, ts_proto_client_1.createTsProtoClient)(streams_1.V1StreamsDefinition, streams_pb_1.V1Streams, transport);
|
|
14
|
+
}
|
|
@@ -82,7 +82,24 @@ function createFetchTransport(options) {
|
|
|
82
82
|
baseUrl: resolveServerUrl(options),
|
|
83
83
|
useBinaryFormat: true,
|
|
84
84
|
interceptors: [(0, transport_1.createAuthInterceptor)(options.token)],
|
|
85
|
-
fetch: limitMessageSizes(send, limits),
|
|
85
|
+
fetch: limitMessageSizes(withoutRedirects(send), limits),
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Wraps a `fetch` so a redirect fails the call instead of being followed. connect-web asks
|
|
90
|
+
* for this with `redirect: 'error'`, which Cloudflare Workers reject outright ("Invalid
|
|
91
|
+
* redirect value"), so the request goes out with `redirect: 'manual'` and a redirect
|
|
92
|
+
* response (a 3xx status, or the opaque redirect a browser hands back) is turned into the
|
|
93
|
+
* error connect-web would have raised. The engine never redirects; one means `serverUrl`
|
|
94
|
+
* points at something in front of it.
|
|
95
|
+
*/
|
|
96
|
+
function withoutRedirects(send) {
|
|
97
|
+
return (input, init) => __awaiter(this, void 0, void 0, function* () {
|
|
98
|
+
const response = yield send(input, Object.assign(Object.assign({}, init), { redirect: 'manual' }));
|
|
99
|
+
if (response.type === 'opaqueredirect' || (response.status >= 300 && response.status < 400)) {
|
|
100
|
+
throw new connect_1.ConnectError(`the server answered with a redirect (${response.status || 'opaque'}); serverUrl must point at the engine itself`, connect_1.Code.Unavailable);
|
|
101
|
+
}
|
|
102
|
+
return response;
|
|
86
103
|
});
|
|
87
104
|
}
|
|
88
105
|
/**
|
package/core/client.d.ts
CHANGED
|
@@ -55,11 +55,12 @@ export declare class HatchetCore {
|
|
|
55
55
|
readonly rateLimits: RateLimitsClient;
|
|
56
56
|
/** Writes task run log lines. */
|
|
57
57
|
readonly logs: LogsClient;
|
|
58
|
-
/** Publishes task run stream chunks. */
|
|
58
|
+
/** Publishes task run stream chunks and durable stream topics. */
|
|
59
59
|
readonly streams: StreamsClient;
|
|
60
60
|
private readonly workflowsRpc;
|
|
61
61
|
private readonly adminRpc;
|
|
62
62
|
private readonly eventsRpc;
|
|
63
|
+
private readonly streamsRpc;
|
|
63
64
|
constructor(config: CoreClientConfig);
|
|
64
65
|
/** The same as `new HatchetCore(config)`, mirroring the Node client's `init`. */
|
|
65
66
|
static init(config: CoreClientConfig): HatchetCore;
|
package/core/client.js
CHANGED
|
@@ -20,6 +20,7 @@ const fetch_transport_1 = require("../clients/transport/fetch-transport");
|
|
|
20
20
|
const rpc_1 = require("../clients/admin/rpc");
|
|
21
21
|
const trigger_request_1 = require("../clients/admin/trigger-request");
|
|
22
22
|
const rpc_2 = require("../clients/event/rpc");
|
|
23
|
+
const rpc_3 = require("../clients/streams/rpc");
|
|
23
24
|
const workflows_1 = require("../protoc/workflows");
|
|
24
25
|
const token_1 = require("../util/config-loader/token");
|
|
25
26
|
const batch_1 = require("../util/batch");
|
|
@@ -81,13 +82,14 @@ class HatchetCore {
|
|
|
81
82
|
this.workflowsRpc = (0, rpc_1.createWorkflowsRpc)(this.transport);
|
|
82
83
|
this.adminRpc = (0, rpc_1.createV1AdminRpc)(this.transport);
|
|
83
84
|
this.eventsRpc = (0, rpc_2.createEventsRpc)(this.transport);
|
|
85
|
+
this.streamsRpc = (0, rpc_3.createV1StreamsRpc)(this.transport);
|
|
84
86
|
const shared = { logger: this.logger, namespace, retrier: config.retrier };
|
|
85
87
|
this.events = new events_1.EventsClient(Object.assign({ rpc: this.eventsRpc }, shared));
|
|
86
88
|
this.runs = new runs_1.RunsClient(this.adminRpc);
|
|
87
89
|
this.workflows = new workflows_2.WorkflowsClient(Object.assign({ rpc: this.adminRpc }, shared));
|
|
88
90
|
this.rateLimits = new rate_limits_1.RateLimitsClient(Object.assign({ rpc: this.workflowsRpc }, shared));
|
|
89
91
|
this.logs = new logs_1.LogsClient(this.eventsRpc);
|
|
90
|
-
this.streams = new streams_1.StreamsClient(this.eventsRpc);
|
|
92
|
+
this.streams = new streams_1.StreamsClient({ events: this.eventsRpc, streams: this.streamsRpc });
|
|
91
93
|
}
|
|
92
94
|
/** The same as `new HatchetCore(config)`, mirroring the Node client's `init`. */
|
|
93
95
|
static init(config) {
|
|
@@ -1,11 +1,76 @@
|
|
|
1
1
|
import type { EventsServiceClient, PutStreamEventResponse } from '../../protoc/events/events';
|
|
2
|
-
|
|
2
|
+
import type { V1StreamsClient } from '../../protoc/v1/streams';
|
|
3
|
+
import type { StreamCallOptions, StreamTopicMetadata } from '../types';
|
|
4
|
+
/**
|
|
5
|
+
* The largest payload one `publish` carries: the engine's limit for a payload sent inline
|
|
6
|
+
* (`MaxStreamMessagePayloadBytes`). The Node client uploads larger payloads over its REST
|
|
7
|
+
* client first; this client has none, so it rejects them.
|
|
8
|
+
*/
|
|
9
|
+
export declare const MAX_STREAM_MESSAGE_BYTES: number;
|
|
10
|
+
export interface StreamsClientDeps {
|
|
11
|
+
events: EventsServiceClient;
|
|
12
|
+
streams: V1StreamsClient;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* How many (namespace, topic) producers the client remembers. A topic past the cap starts
|
|
16
|
+
* over with a new producer id, which the engine orders after the old one, so correctness
|
|
17
|
+
* does not depend on the cap; it only bounds memory for clients that publish to many
|
|
18
|
+
* short-lived topics.
|
|
19
|
+
*/
|
|
20
|
+
export declare const MAX_TRACKED_TOPICS = 1024;
|
|
21
|
+
/**
|
|
22
|
+
* Task run streams and durable stream topics.
|
|
23
|
+
*
|
|
24
|
+
* `put` publishes a chunk on a task run's stream, the way `ctx.putStream` does from a worker.
|
|
25
|
+
* `publish`, `reset` and `topicMetadata` are the Node client's durable topic calls
|
|
26
|
+
* (`hatchet.streams`), with the same names and options. `events()` is not here: it is a
|
|
27
|
+
* server stream, which the unary transport does not carry. Read a topic with the Node client
|
|
28
|
+
* (`hatchet.streams.events(topic)`), or from a serverless task over the operator socket once
|
|
29
|
+
* the operator relays the subscription.
|
|
30
|
+
*/
|
|
3
31
|
export declare class StreamsClient {
|
|
4
|
-
|
|
5
|
-
|
|
32
|
+
/** Per (namespace, topic); the sequence number only advances after a publish succeeds. */
|
|
33
|
+
private readonly producers;
|
|
34
|
+
/**
|
|
35
|
+
* Serializes publishes per (namespace, topic) so two never share a sequence number. The
|
|
36
|
+
* stored promise always resolves, so one failure does not block later calls.
|
|
37
|
+
*/
|
|
38
|
+
private readonly publishChains;
|
|
39
|
+
private readonly events;
|
|
40
|
+
private readonly streams;
|
|
41
|
+
/**
|
|
42
|
+
* Takes the events and durable streams services, or only the events service, which
|
|
43
|
+
* serves `put` and leaves the durable stream calls unavailable.
|
|
44
|
+
*/
|
|
45
|
+
constructor(deps: StreamsClientDeps | EventsServiceClient);
|
|
46
|
+
private durable;
|
|
6
47
|
/**
|
|
7
48
|
* Publishes one chunk on a task run's stream. `index` orders chunks that are published
|
|
8
49
|
* concurrently. Resolves once the engine has the chunk.
|
|
9
50
|
*/
|
|
10
51
|
put(taskRunExternalId: string, data: string | Uint8Array, index?: number): Promise<PutStreamEventResponse>;
|
|
52
|
+
/**
|
|
53
|
+
* Publishes a message to a durable topic and resolves once it is stored. A client's
|
|
54
|
+
* messages to a topic are delivered in the order `publish` was called. A payload over
|
|
55
|
+
* `MAX_STREAM_MESSAGE_BYTES` rejects with a `HatchetError` before anything is sent.
|
|
56
|
+
* @param topic - the topic to publish to
|
|
57
|
+
* @param message - the message payload
|
|
58
|
+
* @param options - optional namespace override and abort signal
|
|
59
|
+
*/
|
|
60
|
+
publish(topic: string, message: Uint8Array | string, options?: StreamCallOptions): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Describes a topic's retained messages. Rejects with a `ConnectError` of code `NotFound`
|
|
63
|
+
* for a topic nothing was published to.
|
|
64
|
+
* @param topic - the topic to describe
|
|
65
|
+
* @param options - optional namespace override and abort signal
|
|
66
|
+
*/
|
|
67
|
+
topicMetadata(topic: string, options?: Pick<StreamCallOptions, 'namespace' | 'signal'>): Promise<StreamTopicMetadata>;
|
|
68
|
+
/**
|
|
69
|
+
* Makes `events()` calls without a cursor start after the topic's latest message. Readers
|
|
70
|
+
* already iterating, and any call with a cursor, are unaffected.
|
|
71
|
+
* @param topic - the topic to reset
|
|
72
|
+
* @param options - optional namespace override and abort signal
|
|
73
|
+
*/
|
|
74
|
+
reset(topic: string, options?: Pick<StreamCallOptions, 'namespace' | 'signal'>): Promise<void>;
|
|
75
|
+
private publishOrdered;
|
|
11
76
|
}
|
package/core/features/streams.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
7
|
-
|
|
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.
|
|
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
|
|
4
|
-
* on a fetch transport, and it is configured from an
|
|
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
|
-
|
|
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
|
|
5
|
-
* on a fetch transport, and it is configured from an
|
|
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
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
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.
|
|
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",
|
|
@@ -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`);
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { StreamCallOptions, StreamTopicMetadata } from '../../../core/types';
|
|
1
2
|
import { HatchetClient } from '../client';
|
|
2
3
|
export type StreamEvent = {
|
|
3
4
|
/** the message payload */
|
|
@@ -7,23 +8,7 @@ export type StreamEvent = {
|
|
|
7
8
|
/** when the message was stored */
|
|
8
9
|
createdAt?: Date;
|
|
9
10
|
};
|
|
10
|
-
|
|
11
|
-
export type StreamTopicMetadata = {
|
|
12
|
-
namespace: string;
|
|
13
|
-
topic: string;
|
|
14
|
-
tenantId: string;
|
|
15
|
-
messageCount: number;
|
|
16
|
-
/** resumes events() after the newest retained message; undefined when none is retained */
|
|
17
|
-
latestCursor?: string;
|
|
18
|
-
/** when the newest retained message was stored; undefined when none is retained */
|
|
19
|
-
lastPublishedAt?: Date;
|
|
20
|
-
};
|
|
21
|
-
export type StreamCallOptions = {
|
|
22
|
-
namespace?: string;
|
|
23
|
-
cursor?: string;
|
|
24
|
-
/** ends an events() iteration cleanly, without throwing */
|
|
25
|
-
signal?: AbortSignal;
|
|
26
|
-
};
|
|
11
|
+
export type { StreamCallOptions, StreamTopicMetadata } from '../../../core/types';
|
|
27
12
|
/**
|
|
28
13
|
* StreamsClient publishes to and reads from durable topics. Unlike
|
|
29
14
|
* `runs.subscribeToStream`, topics are stored, independent of any run, and
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DURABLE_WAIT_MARKED = "[e2e] durable wait marked";
|
|
@@ -0,0 +1,49 @@
|
|
|
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
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.DURABLE_WAIT_MARKED = void 0;
|
|
13
|
+
const hatchet_client_1 = require("../hatchet-client");
|
|
14
|
+
const workflow_1 = require("./workflow");
|
|
15
|
+
exports.DURABLE_WAIT_MARKED = '[e2e] durable wait marked';
|
|
16
|
+
// Worker for the graceful termination e2e test. The test must not terminate
|
|
17
|
+
// this worker before the SDK has recorded the run as waiting, and nothing
|
|
18
|
+
// observable outside the process marks that moment: the engine writes the
|
|
19
|
+
// WAIT_FOR entry before it acks, and the SDK only calls markWaiting once the
|
|
20
|
+
// ack arrives. The eviction manager is created lazily on the worker's
|
|
21
|
+
// internal state, so it is wrapped on assignment to print a line the test can
|
|
22
|
+
// wait for.
|
|
23
|
+
function main() {
|
|
24
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
25
|
+
const worker = yield hatchet_client_1.hatchet.worker('graceful-eviction-worker', {
|
|
26
|
+
workflows: [workflow_1.evictableSleepForGracefulTermination],
|
|
27
|
+
});
|
|
28
|
+
let manager;
|
|
29
|
+
Object.defineProperty(worker._internal, 'evictionManager', {
|
|
30
|
+
configurable: true,
|
|
31
|
+
enumerable: true,
|
|
32
|
+
get: () => manager,
|
|
33
|
+
set: (next) => {
|
|
34
|
+
manager = next;
|
|
35
|
+
if (!next)
|
|
36
|
+
return;
|
|
37
|
+
const markWaiting = next.markWaiting.bind(next);
|
|
38
|
+
next.markWaiting = (key, waitKind, resourceId) => {
|
|
39
|
+
markWaiting(key, waitKind, resourceId);
|
|
40
|
+
console.log(`${exports.DURABLE_WAIT_MARKED} key=${key} kind=${waitKind} resource=${resourceId}`);
|
|
41
|
+
};
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
yield worker.start();
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (require.main === module) {
|
|
48
|
+
main();
|
|
49
|
+
}
|
package/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const HATCHET_VERSION = "1.
|
|
1
|
+
export declare const HATCHET_VERSION = "1.39.0";
|
package/version.js
CHANGED