@temporalio/common 1.3.0 → 1.4.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 (116) hide show
  1. package/lib/activity-options.d.ts +138 -0
  2. package/lib/activity-options.js +15 -0
  3. package/lib/activity-options.js.map +1 -0
  4. package/lib/converter/data-converter.d.ts +20 -1
  5. package/lib/converter/data-converter.js +14 -3
  6. package/lib/converter/data-converter.js.map +1 -1
  7. package/lib/converter/failure-converter.d.ts +75 -0
  8. package/lib/converter/failure-converter.js +239 -0
  9. package/lib/converter/failure-converter.js.map +1 -0
  10. package/lib/converter/payload-codec.d.ts +1 -1
  11. package/lib/converter/payload-converter.d.ts +85 -1
  12. package/lib/converter/payload-converter.js +210 -1
  13. package/lib/converter/payload-converter.js.map +1 -1
  14. package/lib/converter/protobuf-payload-converters.d.ts +3 -3
  15. package/lib/converter/protobuf-payload-converters.js +20 -19
  16. package/lib/converter/protobuf-payload-converters.js.map +1 -1
  17. package/lib/converter/types.d.ts +0 -6
  18. package/lib/converter/types.js +7 -18
  19. package/lib/converter/types.js.map +1 -1
  20. package/lib/deprecated-time.d.ts +52 -0
  21. package/lib/deprecated-time.js +106 -0
  22. package/lib/deprecated-time.js.map +1 -0
  23. package/lib/{converter/encoding.d.ts → encoding.d.ts} +8 -0
  24. package/lib/{converter/encoding.js → encoding.js} +15 -1
  25. package/lib/encoding.js.map +1 -0
  26. package/lib/errors.d.ts +47 -0
  27. package/lib/errors.js +68 -0
  28. package/lib/errors.js.map +1 -0
  29. package/lib/failure.d.ts +0 -27
  30. package/lib/failure.js +9 -205
  31. package/lib/failure.js.map +1 -1
  32. package/lib/index.d.ts +25 -8
  33. package/lib/index.js +43 -7
  34. package/lib/index.js.map +1 -1
  35. package/lib/interceptors.d.ts +18 -0
  36. package/lib/interceptors.js +24 -0
  37. package/lib/interceptors.js.map +1 -0
  38. package/lib/interfaces.d.ts +52 -0
  39. package/lib/interfaces.js +3 -0
  40. package/lib/interfaces.js.map +1 -0
  41. package/lib/internal-non-workflow/codec-helpers.d.ts +82 -0
  42. package/lib/internal-non-workflow/codec-helpers.js +295 -0
  43. package/lib/internal-non-workflow/codec-helpers.js.map +1 -0
  44. package/lib/internal-non-workflow/codec-types.d.ts +22 -0
  45. package/lib/internal-non-workflow/codec-types.js +3 -0
  46. package/lib/internal-non-workflow/codec-types.js.map +1 -0
  47. package/lib/internal-non-workflow/data-converter-helpers.d.ts +11 -0
  48. package/lib/internal-non-workflow/data-converter-helpers.js +66 -0
  49. package/lib/internal-non-workflow/data-converter-helpers.js.map +1 -0
  50. package/lib/internal-non-workflow/index.d.ts +10 -0
  51. package/lib/internal-non-workflow/index.js +27 -0
  52. package/lib/internal-non-workflow/index.js.map +1 -0
  53. package/lib/internal-non-workflow/tls-config.d.ts +32 -0
  54. package/lib/internal-non-workflow/tls-config.js +11 -0
  55. package/lib/internal-non-workflow/tls-config.js.map +1 -0
  56. package/lib/internal-non-workflow/utils.d.ts +4 -0
  57. package/lib/internal-non-workflow/utils.js +11 -0
  58. package/lib/internal-non-workflow/utils.js.map +1 -0
  59. package/lib/otel.d.ts +1 -1
  60. package/lib/otel.js +2 -2
  61. package/lib/otel.js.map +1 -1
  62. package/lib/retry-policy.d.ts +48 -0
  63. package/lib/retry-policy.js +62 -0
  64. package/lib/retry-policy.js.map +1 -0
  65. package/lib/time.d.ts +18 -0
  66. package/lib/time.js +79 -0
  67. package/lib/time.js.map +1 -0
  68. package/lib/type-helpers.d.ts +21 -0
  69. package/lib/type-helpers.js +46 -0
  70. package/lib/type-helpers.js.map +1 -0
  71. package/lib/workflow-handle.d.ts +27 -0
  72. package/lib/workflow-handle.js +3 -0
  73. package/lib/workflow-handle.js.map +1 -0
  74. package/lib/workflow-options.d.ts +118 -0
  75. package/lib/workflow-options.js +53 -0
  76. package/lib/workflow-options.js.map +1 -0
  77. package/package.json +5 -4
  78. package/src/activity-options.ts +159 -0
  79. package/src/converter/data-converter.ts +24 -3
  80. package/src/converter/failure-converter.ts +355 -0
  81. package/src/converter/payload-codec.ts +1 -1
  82. package/src/converter/payload-converter.ts +246 -1
  83. package/src/converter/protobuf-payload-converters.ts +14 -25
  84. package/src/converter/types.ts +6 -19
  85. package/src/deprecated-time.ts +80 -0
  86. package/src/{converter/encoding.ts → encoding.ts} +14 -0
  87. package/src/errors.ts +55 -0
  88. package/src/failure.ts +1 -251
  89. package/src/index.ts +34 -8
  90. package/src/interceptors.ts +32 -0
  91. package/src/interfaces.ts +64 -0
  92. package/src/internal-non-workflow/codec-helpers.ts +348 -0
  93. package/src/internal-non-workflow/codec-types.ts +34 -0
  94. package/src/internal-non-workflow/data-converter-helpers.ts +81 -0
  95. package/src/internal-non-workflow/index.ts +10 -0
  96. package/src/internal-non-workflow/tls-config.ts +35 -0
  97. package/src/internal-non-workflow/utils.ts +6 -0
  98. package/src/otel.ts +2 -2
  99. package/src/retry-policy.ts +101 -0
  100. package/src/time.ts +79 -0
  101. package/src/type-helpers.ts +64 -0
  102. package/src/workflow-handle.ts +30 -0
  103. package/src/workflow-options.ts +156 -0
  104. package/lib/converter/encoding.js.map +0 -1
  105. package/lib/converter/json-payload-converter.d.ts +0 -10
  106. package/lib/converter/json-payload-converter.js +0 -39
  107. package/lib/converter/json-payload-converter.js.map +0 -1
  108. package/lib/converter/payload-converters.d.ts +0 -67
  109. package/lib/converter/payload-converters.js +0 -124
  110. package/lib/converter/payload-converters.js.map +0 -1
  111. package/lib/converter/search-attribute-payload-converter.d.ts +0 -12
  112. package/lib/converter/search-attribute-payload-converter.js +0 -64
  113. package/lib/converter/search-attribute-payload-converter.js.map +0 -1
  114. package/src/converter/json-payload-converter.ts +0 -37
  115. package/src/converter/payload-converters.ts +0 -148
  116. package/src/converter/search-attribute-payload-converter.ts +0 -71
@@ -0,0 +1,348 @@
1
+ import { Payload } from '../interfaces';
2
+ import { arrayFromPayloads, fromPayloadsAtIndex, toPayloads } from '../converter/payload-converter';
3
+ import { PayloadConverterError } from '../errors';
4
+ import { PayloadCodec } from '../converter/payload-codec';
5
+ import { ProtoFailure, TemporalFailure } from '../failure';
6
+ import { LoadedDataConverter } from '../converter/data-converter';
7
+ import { DecodedPayload, DecodedProtoFailure, EncodedPayload, EncodedProtoFailure } from './codec-types';
8
+
9
+ /**
10
+ * Decode through each codec, starting with the last codec.
11
+ */
12
+ export async function decode(codecs: PayloadCodec[], payloads: Payload[]): Promise<DecodedPayload[]> {
13
+ for (let i = codecs.length - 1; i >= 0; i--) {
14
+ payloads = await codecs[i].decode(payloads);
15
+ }
16
+ return payloads as DecodedPayload[];
17
+ }
18
+
19
+ /**
20
+ * Encode through each codec, starting with the first codec.
21
+ */
22
+ export async function encode(codecs: PayloadCodec[], payloads: Payload[]): Promise<EncodedPayload[]> {
23
+ for (let i = 0; i < codecs.length; i++) {
24
+ payloads = await codecs[i].encode(payloads);
25
+ }
26
+ return payloads as EncodedPayload[];
27
+ }
28
+
29
+ /** Run {@link PayloadCodec.encode} on `payloads` */
30
+ export async function encodeOptional(
31
+ codecs: PayloadCodec[],
32
+ payloads: Payload[] | null | undefined
33
+ ): Promise<EncodedPayload[] | null | undefined> {
34
+ if (payloads == null) return payloads;
35
+ return await encode(codecs, payloads);
36
+ }
37
+
38
+ /** Run {@link PayloadCodec.decode} on `payloads` */
39
+ export async function decodeOptional(
40
+ codecs: PayloadCodec[],
41
+ payloads: Payload[] | null | undefined
42
+ ): Promise<DecodedPayload[] | null | undefined> {
43
+ if (payloads == null) return payloads;
44
+ return await decode(codecs, payloads);
45
+ }
46
+
47
+ async function encodeSingle(codecs: PayloadCodec[], payload: Payload): Promise<EncodedPayload> {
48
+ const encodedPayloads = await encode(codecs, [payload]);
49
+ return encodedPayloads[0] as EncodedPayload;
50
+ }
51
+
52
+ async function decodeSingle(codecs: PayloadCodec[], payload: Payload): Promise<DecodedPayload> {
53
+ const [decodedPayload] = await decode(codecs, [payload]);
54
+ return decodedPayload;
55
+ }
56
+
57
+ /** Run {@link PayloadCodec.encode} on a single Payload */
58
+ export async function encodeOptionalSingle(
59
+ codecs: PayloadCodec[],
60
+ payload: Payload | null | undefined
61
+ ): Promise<EncodedPayload | null | undefined> {
62
+ if (payload == null) return payload;
63
+ return await encodeSingle(codecs, payload);
64
+ }
65
+
66
+ /** Run {@link PayloadCodec.decode} on a single Payload */
67
+ export async function decodeOptionalSingle(
68
+ codecs: PayloadCodec[],
69
+ payload: Payload | null | undefined
70
+ ): Promise<DecodedPayload | null | undefined> {
71
+ if (payload == null) return payload;
72
+ return await decodeSingle(codecs, payload);
73
+ }
74
+
75
+ /**
76
+ * Run {@link PayloadConverter.toPayload} on value, and then encode it.
77
+ */
78
+ export async function encodeToPayload(converter: LoadedDataConverter, value: unknown): Promise<Payload> {
79
+ const { payloadConverter, payloadCodecs } = converter;
80
+ return await encodeSingle(payloadCodecs, payloadConverter.toPayload(value));
81
+ }
82
+
83
+ /**
84
+ * Decode `payloads` and then return {@link arrayFromPayloads}`.
85
+ */
86
+ export async function decodeArrayFromPayloads(
87
+ converter: LoadedDataConverter,
88
+ payloads?: Payload[] | null
89
+ ): Promise<unknown[]> {
90
+ const { payloadConverter, payloadCodecs } = converter;
91
+ return arrayFromPayloads(payloadConverter, await decodeOptional(payloadCodecs, payloads));
92
+ }
93
+
94
+ /**
95
+ * Decode `payloads` and then return {@link fromPayloadsAtIndex}.
96
+ */
97
+ export async function decodeFromPayloadsAtIndex<T>(
98
+ converter: LoadedDataConverter,
99
+ index: number,
100
+ payloads?: Payload[] | null
101
+ ): Promise<T> {
102
+ const { payloadConverter, payloadCodecs } = converter;
103
+ return await fromPayloadsAtIndex(payloadConverter, index, await decodeOptional(payloadCodecs, payloads));
104
+ }
105
+
106
+ /**
107
+ * Run {@link decodeFailure} and then return {@link failureToError}.
108
+ */
109
+ export async function decodeOptionalFailureToOptionalError(
110
+ converter: LoadedDataConverter,
111
+ failure: ProtoFailure | undefined | null
112
+ ): Promise<TemporalFailure | undefined> {
113
+ const { failureConverter, payloadCodecs } = converter;
114
+ return failure ? failureConverter.failureToError(await decodeFailure(payloadCodecs, failure)) : undefined;
115
+ }
116
+
117
+ export async function decodeOptionalMap(
118
+ codecs: PayloadCodec[],
119
+ payloads: Record<string, Payload> | null | undefined
120
+ ): Promise<Record<string, DecodedPayload> | null | undefined> {
121
+ if (payloads == null) return payloads;
122
+ return Object.fromEntries(
123
+ await Promise.all(Object.entries(payloads).map(async ([k, v]) => [k, await decode(codecs, [v])]))
124
+ );
125
+ }
126
+
127
+ /**
128
+ * Run {@link PayloadConverter.toPayload} on values, and then encode them.
129
+ */
130
+ export async function encodeToPayloads(
131
+ converter: LoadedDataConverter,
132
+ ...values: unknown[]
133
+ ): Promise<Payload[] | undefined> {
134
+ const { payloadConverter, payloadCodecs } = converter;
135
+ if (values.length === 0) {
136
+ return undefined;
137
+ }
138
+ const payloads = toPayloads(payloadConverter, ...values);
139
+ return payloads ? await encode(payloadCodecs, payloads) : undefined;
140
+ }
141
+
142
+ /**
143
+ * Run {@link PayloadCodec.decode} and then {@link PayloadConverter.fromPayload} on values in `map`.
144
+ */
145
+ export async function decodeMapFromPayloads<K extends string>(
146
+ converter: LoadedDataConverter,
147
+ map: Record<K, Payload> | null | undefined
148
+ ): Promise<Record<K, unknown> | undefined> {
149
+ if (!map) return undefined;
150
+ const { payloadConverter, payloadCodecs } = converter;
151
+ return Object.fromEntries(
152
+ await Promise.all(
153
+ Object.entries(map).map(async ([k, payload]): Promise<[K, unknown]> => {
154
+ const [decodedPayload] = await decode(payloadCodecs, [payload as Payload]);
155
+ const value = payloadConverter.fromPayload(decodedPayload);
156
+ return [k as K, value];
157
+ })
158
+ )
159
+ ) as Record<K, unknown>;
160
+ }
161
+
162
+ /** Run {@link PayloadCodec.encode} on all values in `map` */
163
+ export async function encodeMap<K extends string>(
164
+ codecs: PayloadCodec[],
165
+ map: Record<K, Payload> | null | undefined
166
+ ): Promise<Record<K, EncodedPayload> | null | undefined> {
167
+ if (map === null) return null;
168
+ if (map === undefined) return undefined;
169
+ return Object.fromEntries(
170
+ await Promise.all(
171
+ Object.entries(map).map(async ([k, payload]): Promise<[K, EncodedPayload]> => {
172
+ return [k as K, await encodeSingle(codecs, payload as Payload)];
173
+ })
174
+ )
175
+ ) as Record<K, EncodedPayload>;
176
+ }
177
+
178
+ /**
179
+ * Run {@link PayloadConverter.toPayload} and then {@link PayloadCodec.encode} on values in `map`.
180
+ */
181
+ export async function encodeMapToPayloads<K extends string>(
182
+ converter: LoadedDataConverter,
183
+ map: Record<K, unknown>
184
+ ): Promise<Record<K, Payload>> {
185
+ const { payloadConverter, payloadCodecs } = converter;
186
+ return Object.fromEntries(
187
+ await Promise.all(
188
+ Object.entries(map).map(async ([k, v]): Promise<[K, Payload]> => {
189
+ const payload = payloadConverter.toPayload(v);
190
+ if (payload === undefined) throw new PayloadConverterError(`Failed to encode entry: ${k}: ${v}`);
191
+ const [encodedPayload] = await encode(payloadCodecs, [payload]);
192
+ return [k as K, encodedPayload];
193
+ })
194
+ )
195
+ ) as Record<K, Payload>;
196
+ }
197
+
198
+ /**
199
+ * Run {@link errorToFailure} on `error`, and then {@link encodeFailure}.
200
+ */
201
+ export async function encodeErrorToFailure(dataConverter: LoadedDataConverter, error: unknown): Promise<ProtoFailure> {
202
+ const { failureConverter, payloadCodecs } = dataConverter;
203
+ return await encodeFailure(payloadCodecs, failureConverter.errorToFailure(error));
204
+ }
205
+
206
+ /**
207
+ * Return a new {@link ProtoFailure} with `codec.encode()` run on all the {@link Payload}s.
208
+ */
209
+ export async function encodeFailure(codecs: PayloadCodec[], failure: ProtoFailure): Promise<EncodedProtoFailure> {
210
+ return {
211
+ ...failure,
212
+ encodedAttributes: failure.encodedAttributes ? (await encode(codecs, [failure.encodedAttributes]))[0] : undefined,
213
+ cause: failure.cause ? await encodeFailure(codecs, failure.cause) : null,
214
+ applicationFailureInfo: failure.applicationFailureInfo
215
+ ? {
216
+ ...failure.applicationFailureInfo,
217
+ details: failure.applicationFailureInfo.details
218
+ ? {
219
+ payloads: await encode(codecs, failure.applicationFailureInfo.details.payloads ?? []),
220
+ }
221
+ : undefined,
222
+ }
223
+ : undefined,
224
+ timeoutFailureInfo: failure.timeoutFailureInfo
225
+ ? {
226
+ ...failure.timeoutFailureInfo,
227
+ lastHeartbeatDetails: failure.timeoutFailureInfo.lastHeartbeatDetails
228
+ ? {
229
+ payloads: await encode(codecs, failure.timeoutFailureInfo.lastHeartbeatDetails.payloads ?? []),
230
+ }
231
+ : undefined,
232
+ }
233
+ : undefined,
234
+ canceledFailureInfo: failure.canceledFailureInfo
235
+ ? {
236
+ ...failure.canceledFailureInfo,
237
+ details: failure.canceledFailureInfo.details
238
+ ? {
239
+ payloads: await encode(codecs, failure.canceledFailureInfo.details.payloads ?? []),
240
+ }
241
+ : undefined,
242
+ }
243
+ : undefined,
244
+ resetWorkflowFailureInfo: failure.resetWorkflowFailureInfo
245
+ ? {
246
+ ...failure.resetWorkflowFailureInfo,
247
+ lastHeartbeatDetails: failure.resetWorkflowFailureInfo.lastHeartbeatDetails
248
+ ? {
249
+ payloads: await encode(codecs, failure.resetWorkflowFailureInfo.lastHeartbeatDetails.payloads ?? []),
250
+ }
251
+ : undefined,
252
+ }
253
+ : undefined,
254
+ };
255
+ }
256
+
257
+ /**
258
+ * Return a new {@link ProtoFailure} with `codec.decode()` run on all the {@link Payload}s.
259
+ */
260
+ export async function decodeFailure(codecs: PayloadCodec[], failure: ProtoFailure): Promise<DecodedProtoFailure> {
261
+ return {
262
+ ...failure,
263
+ encodedAttributes: failure.encodedAttributes ? (await decode(codecs, [failure.encodedAttributes]))[0] : undefined,
264
+ cause: failure.cause ? await decodeFailure(codecs, failure.cause) : null,
265
+ applicationFailureInfo: failure.applicationFailureInfo
266
+ ? {
267
+ ...failure.applicationFailureInfo,
268
+ details: failure.applicationFailureInfo.details
269
+ ? {
270
+ payloads: await decode(codecs, failure.applicationFailureInfo.details.payloads ?? []),
271
+ }
272
+ : undefined,
273
+ }
274
+ : undefined,
275
+ timeoutFailureInfo: failure.timeoutFailureInfo
276
+ ? {
277
+ ...failure.timeoutFailureInfo,
278
+ lastHeartbeatDetails: failure.timeoutFailureInfo.lastHeartbeatDetails
279
+ ? {
280
+ payloads: await decode(codecs, failure.timeoutFailureInfo.lastHeartbeatDetails.payloads ?? []),
281
+ }
282
+ : undefined,
283
+ }
284
+ : undefined,
285
+ canceledFailureInfo: failure.canceledFailureInfo
286
+ ? {
287
+ ...failure.canceledFailureInfo,
288
+ details: failure.canceledFailureInfo.details
289
+ ? {
290
+ payloads: await decode(codecs, failure.canceledFailureInfo.details.payloads ?? []),
291
+ }
292
+ : undefined,
293
+ }
294
+ : undefined,
295
+ resetWorkflowFailureInfo: failure.resetWorkflowFailureInfo
296
+ ? {
297
+ ...failure.resetWorkflowFailureInfo,
298
+ lastHeartbeatDetails: failure.resetWorkflowFailureInfo.lastHeartbeatDetails
299
+ ? {
300
+ payloads: await decode(codecs, failure.resetWorkflowFailureInfo.lastHeartbeatDetails.payloads ?? []),
301
+ }
302
+ : undefined,
303
+ }
304
+ : undefined,
305
+ };
306
+ }
307
+
308
+ /**
309
+ * Return a new {@link ProtoFailure} with `codec.encode()` run on all the {@link Payload}s.
310
+ */
311
+ export async function encodeOptionalFailure(
312
+ codecs: PayloadCodec[],
313
+ failure: ProtoFailure | null | undefined
314
+ ): Promise<EncodedProtoFailure | null | undefined> {
315
+ if (failure == null) return failure;
316
+ return await encodeFailure(codecs, failure);
317
+ }
318
+
319
+ /**
320
+ * Return a new {@link ProtoFailure} with `codec.encode()` run on all the {@link Payload}s.
321
+ */
322
+ export async function decodeOptionalFailure(
323
+ codecs: PayloadCodec[],
324
+ failure: ProtoFailure | null | undefined
325
+ ): Promise<DecodedProtoFailure | null | undefined> {
326
+ if (failure == null) return failure;
327
+ return await decodeFailure(codecs, failure);
328
+ }
329
+
330
+ /**
331
+ * Mark all values in the map as encoded.
332
+ * Use this for headers, which we don't encode.
333
+ */
334
+ export function noopEncodeMap<K extends string>(
335
+ map: Record<K, Payload> | null | undefined
336
+ ): Record<K, EncodedPayload> | null | undefined {
337
+ return map as Record<K, EncodedPayload> | null | undefined;
338
+ }
339
+
340
+ /**
341
+ * Mark all values in the map as decoded.
342
+ * Use this for headers, which we don't encode.
343
+ */
344
+ export function noopDecodeMap<K extends string>(
345
+ map: Record<K, Payload> | null | undefined
346
+ ): Record<K, DecodedPayload> | null | undefined {
347
+ return map as Record<K, DecodedPayload> | null | undefined;
348
+ }
@@ -0,0 +1,34 @@
1
+ import type { Payload } from '../interfaces';
2
+ import type { ProtoFailure } from '../failure';
3
+
4
+ export interface EncodedPayload extends Payload {
5
+ encoded: true;
6
+ }
7
+
8
+ export interface DecodedPayload extends Payload {
9
+ decoded: true;
10
+ }
11
+
12
+ /** Replace `Payload`s with `EncodedPayload`s */
13
+ export type Encoded<T> = ReplaceNested<T, Payload, EncodedPayload>;
14
+
15
+ /** Replace `Payload`s with `DecodedPayload`s */
16
+ export type Decoded<T> = ReplaceNested<T, Payload, DecodedPayload>;
17
+
18
+ export type EncodedProtoFailure = Encoded<ProtoFailure>;
19
+ export type DecodedProtoFailure = Decoded<ProtoFailure>;
20
+
21
+ /** An object T with any nested values of type ToReplace replaced with ReplaceWith */
22
+ export type ReplaceNested<T, ToReplace, ReplaceWith> = T extends (...args: any[]) => any
23
+ ? T
24
+ : [keyof T] extends [never]
25
+ ? T
26
+ : T extends { [k: string]: ToReplace }
27
+ ? {
28
+ [P in keyof T]: ReplaceNested<T[P], ToReplace, ReplaceWith>;
29
+ }
30
+ : T extends ToReplace
31
+ ? ReplaceWith | Exclude<T, ToReplace>
32
+ : {
33
+ [P in keyof T]: ReplaceNested<T[P], ToReplace, ReplaceWith>;
34
+ };
@@ -0,0 +1,81 @@
1
+ import { PayloadConverter } from '../converter/payload-converter';
2
+ import { DataConverter, defaultFailureConverter, LoadedDataConverter } from '../converter/data-converter';
3
+ import { FailureConverter } from '../converter/failure-converter';
4
+ import { defaultPayloadConverter } from '../converter/payload-converter';
5
+ import { errorCode, hasOwnProperty, isRecord } from '../type-helpers';
6
+ import { ValueError } from '../errors';
7
+
8
+ const isValidPayloadConverter = (converter: unknown): converter is PayloadConverter =>
9
+ typeof converter === 'object' &&
10
+ converter !== null &&
11
+ ['toPayload', 'fromPayload'].every((method) => typeof (converter as Record<string, unknown>)[method] === 'function');
12
+
13
+ const isValidFailureConverter = (converter: unknown): converter is FailureConverter =>
14
+ typeof converter === 'object' &&
15
+ converter !== null &&
16
+ ['errorToFailure', 'failureToError'].every(
17
+ (method) => typeof (converter as Record<string, unknown>)[method] === 'function'
18
+ );
19
+
20
+ function requireConverter<T>(path: string, type: string, validator: (converter: unknown) => converter is T): T {
21
+ let module;
22
+ try {
23
+ module = require(path); // eslint-disable-line @typescript-eslint/no-var-requires
24
+ } catch (error) {
25
+ if (errorCode(error) === 'MODULE_NOT_FOUND') {
26
+ throw new ValueError(`Could not find a file at the specified ${type}Path: '${path}'.`);
27
+ }
28
+ throw error;
29
+ }
30
+
31
+ if (isRecord(module) && hasOwnProperty(module, type)) {
32
+ const converter = module[type];
33
+ if (validator(converter)) {
34
+ return converter;
35
+ } else {
36
+ throw new ValueError(
37
+ `payloadConverter export at ${path} must be an object with toPayload and fromPayload methods`
38
+ );
39
+ }
40
+ } else {
41
+ throw new ValueError(`Module ${path} does not have a \`payloadConverter\` named export`);
42
+ }
43
+ }
44
+
45
+ /**
46
+ * If {@link DataConverter.payloadConverterPath} is specified, `require()` it and validate that the module has a `payloadConverter` named export.
47
+ * If not, use {@link defaultPayloadConverter}.
48
+ * If {@link DataConverter.payloadCodecs} is unspecified, use an empty array.
49
+ */
50
+ export function loadDataConverter(dataConverter?: DataConverter): LoadedDataConverter {
51
+ let payloadConverter: PayloadConverter = defaultPayloadConverter;
52
+ if (dataConverter?.payloadConverterPath) {
53
+ payloadConverter = requireConverter(
54
+ dataConverter.payloadConverterPath,
55
+ 'payloadConverter',
56
+ isValidPayloadConverter
57
+ );
58
+ }
59
+ let failureConverter: FailureConverter = defaultFailureConverter;
60
+ if (dataConverter?.failureConverterPath) {
61
+ failureConverter = requireConverter(
62
+ dataConverter.failureConverterPath,
63
+ 'failureConverter',
64
+ isValidFailureConverter
65
+ );
66
+ }
67
+ return {
68
+ payloadConverter,
69
+ failureConverter,
70
+ payloadCodecs: dataConverter?.payloadCodecs ?? [],
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Returns true if the converter is already "loaded"
76
+ */
77
+ export function isLoadedDataConverter(
78
+ dataConverter?: DataConverter | LoadedDataConverter
79
+ ): dataConverter is LoadedDataConverter {
80
+ return isRecord(dataConverter) && hasOwnProperty(dataConverter, 'payloadConverter');
81
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Internal SDK library: users should usually use other packages instead. Not included in Workflow bundle.
3
+ *
4
+ * @module
5
+ */
6
+ export * from './codec-helpers';
7
+ export * from './codec-types';
8
+ export * from './data-converter-helpers';
9
+ export * from './tls-config';
10
+ export * from './utils';
@@ -0,0 +1,35 @@
1
+ /** TLS configuration options. */
2
+ export interface TLSConfig {
3
+ /**
4
+ * Overrides the target name used for SSL host name checking.
5
+ * If this attribute is not specified, the name used for SSL host name checking will be the host from {@link ServerOptions.url}.
6
+ * This _should_ be used for testing only.
7
+ */
8
+ serverNameOverride?: string;
9
+ /**
10
+ * Root CA certificate used by the server. If not set, and the server's
11
+ * cert is issued by someone the operating system trusts, verification will still work (ex: Cloud offering).
12
+ */
13
+ serverRootCACertificate?: Buffer;
14
+ /** Sets the client certificate and key for connecting with mTLS */
15
+ clientCertPair?: {
16
+ /** The certificate for this client */
17
+ crt: Buffer;
18
+ /** The private key for this client */
19
+ key: Buffer;
20
+ };
21
+ }
22
+
23
+ /**
24
+ * TLS configuration.
25
+ * Pass a falsy value to use a non-encrypted connection or `true` or `{}` to
26
+ * connect with TLS without any customization.
27
+ */
28
+ export type TLSConfigOption = TLSConfig | boolean | null;
29
+
30
+ /**
31
+ * Normalize {@link TLSConfigOption} by turning false and null to undefined and true to and empty object
32
+ */
33
+ export function normalizeTlsConfig(tls?: TLSConfigOption): TLSConfig | undefined {
34
+ return typeof tls === 'object' ? (tls === null ? undefined : tls) : tls ? {} : undefined;
35
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Helper to prevent undefined and null values overriding defaults when merging maps
3
+ */
4
+ export function filterNullAndUndefined<T extends Record<string, any>>(obj: T): T {
5
+ return Object.fromEntries(Object.entries(obj).filter(([_k, v]) => v != null)) as any;
6
+ }
package/src/otel.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as otel from '@opentelemetry/api';
2
- import { Headers } from '@temporalio/internal-workflow-common';
3
- import { defaultPayloadConverter } from './converter/payload-converters';
2
+ import { Headers } from './interceptors';
3
+ import { defaultPayloadConverter } from './converter/payload-converter';
4
4
 
5
5
  /** Default trace header for opentelemetry interceptors */
6
6
  export const TRACE_HEADER = '_tracer-data';
@@ -0,0 +1,101 @@
1
+ import type { temporal } from '@temporalio/proto';
2
+ import { ValueError } from './errors';
3
+ import { msOptionalToNumber, msOptionalToTs, msToNumber, msToTs, optionalTsToMs } from './time';
4
+
5
+ /**
6
+ * Options for retrying Workflows and Activities
7
+ */
8
+ export interface RetryPolicy {
9
+ /**
10
+ * Coefficient used to calculate the next retry interval.
11
+ * The next retry interval is previous interval multiplied by this coefficient.
12
+ * @minimum 1
13
+ * @default 2
14
+ */
15
+ backoffCoefficient?: number;
16
+ /**
17
+ * Interval of the first retry.
18
+ * If coefficient is 1 then it is used for all retries
19
+ * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
20
+ * @default 1 second
21
+ */
22
+ initialInterval?: string | number;
23
+ /**
24
+ * Maximum number of attempts. When exceeded, retries stop (even if {@link ActivityOptions.scheduleToCloseTimeout}
25
+ * hasn't been reached).
26
+ *
27
+ * @default Infinity
28
+ */
29
+ maximumAttempts?: number;
30
+ /**
31
+ * Maximum interval between retries.
32
+ * Exponential backoff leads to interval increase.
33
+ * This value is the cap of the increase.
34
+ *
35
+ * @default 100x of {@link initialInterval}
36
+ * @format number of milliseconds or {@link https://www.npmjs.com/package/ms | ms-formatted string}
37
+ */
38
+ maximumInterval?: string | number;
39
+
40
+ /**
41
+ * List of application failures types to not retry.
42
+ */
43
+ nonRetryableErrorTypes?: string[];
44
+ }
45
+
46
+ /**
47
+ * Turn a TS RetryPolicy into a proto compatible RetryPolicy
48
+ */
49
+ export function compileRetryPolicy(retryPolicy: RetryPolicy): temporal.api.common.v1.IRetryPolicy {
50
+ if (retryPolicy.backoffCoefficient != null && retryPolicy.backoffCoefficient <= 0) {
51
+ throw new ValueError('RetryPolicy.backoffCoefficient must be greater than 0');
52
+ }
53
+ if (retryPolicy.maximumAttempts != null) {
54
+ if (retryPolicy.maximumAttempts === Number.POSITIVE_INFINITY) {
55
+ // drop field (Infinity is the default)
56
+ const { maximumAttempts: _, ...without } = retryPolicy;
57
+ retryPolicy = without;
58
+ } else if (retryPolicy.maximumAttempts <= 0) {
59
+ throw new ValueError('RetryPolicy.maximumAttempts must be a positive integer');
60
+ } else if (!Number.isInteger(retryPolicy.maximumAttempts)) {
61
+ throw new ValueError('RetryPolicy.maximumAttempts must be an integer');
62
+ }
63
+ }
64
+ const maximumInterval = msOptionalToNumber(retryPolicy.maximumInterval);
65
+ const initialInterval = msToNumber(retryPolicy.initialInterval ?? 1000);
66
+ if (maximumInterval === 0) {
67
+ throw new ValueError('RetryPolicy.maximumInterval cannot be 0');
68
+ }
69
+ if (initialInterval === 0) {
70
+ throw new ValueError('RetryPolicy.initialInterval cannot be 0');
71
+ }
72
+ if (maximumInterval != null && maximumInterval < initialInterval) {
73
+ throw new ValueError('RetryPolicy.maximumInterval cannot be less than its initialInterval');
74
+ }
75
+ return {
76
+ maximumAttempts: retryPolicy.maximumAttempts,
77
+ initialInterval: msToTs(initialInterval),
78
+ maximumInterval: msOptionalToTs(maximumInterval),
79
+ backoffCoefficient: retryPolicy.backoffCoefficient,
80
+ nonRetryableErrorTypes: retryPolicy.nonRetryableErrorTypes,
81
+ };
82
+ }
83
+
84
+ /**
85
+ * Turn a proto compatible RetryPolicy into a TS RetryPolicy
86
+ */
87
+ export function decompileRetryPolicy(
88
+ retryPolicy?: temporal.api.common.v1.IRetryPolicy | null
89
+ ): RetryPolicy | undefined {
90
+ if (!retryPolicy) {
91
+ return undefined;
92
+ }
93
+
94
+ return {
95
+ backoffCoefficient: retryPolicy.backoffCoefficient ?? undefined,
96
+ maximumAttempts: retryPolicy.maximumAttempts ?? undefined,
97
+ maximumInterval: optionalTsToMs(retryPolicy.maximumInterval),
98
+ initialInterval: optionalTsToMs(retryPolicy.initialInterval),
99
+ nonRetryableErrorTypes: retryPolicy.nonRetryableErrorTypes ?? undefined,
100
+ };
101
+ }