@temporalio/common 0.19.0-rc.0 → 0.19.2

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 (97) hide show
  1. package/README.md +5 -11
  2. package/lib/converter/data-converter.d.ts +35 -62
  3. package/lib/converter/data-converter.js +6 -100
  4. package/lib/converter/data-converter.js.map +1 -1
  5. package/lib/{encoding.d.ts → converter/encoding.d.ts} +0 -0
  6. package/lib/{encoding.js → converter/encoding.js} +0 -0
  7. package/lib/converter/encoding.js.map +1 -0
  8. package/lib/converter/patch-protobuf-root.d.ts +8 -0
  9. package/lib/converter/patch-protobuf-root.js +43 -0
  10. package/lib/converter/patch-protobuf-root.js.map +1 -0
  11. package/lib/converter/payload-codec.d.ts +27 -0
  12. package/lib/converter/payload-codec.js +11 -0
  13. package/lib/converter/payload-codec.js.map +1 -0
  14. package/lib/converter/payload-converter.d.ts +65 -62
  15. package/lib/converter/payload-converter.js +123 -68
  16. package/lib/converter/payload-converter.js.map +1 -1
  17. package/lib/converter/payload-converters.d.ts +31 -0
  18. package/lib/converter/payload-converters.js +85 -0
  19. package/lib/converter/payload-converters.js.map +1 -0
  20. package/lib/converter/protobuf-payload-converters.d.ts +53 -0
  21. package/lib/converter/protobuf-payload-converters.js +159 -0
  22. package/lib/converter/protobuf-payload-converters.js.map +1 -0
  23. package/lib/converter/types.d.ts +4 -2
  24. package/lib/converter/types.js +3 -2
  25. package/lib/converter/types.js.map +1 -1
  26. package/lib/failure.d.ts +7 -7
  27. package/lib/failure.js +30 -32
  28. package/lib/failure.js.map +1 -1
  29. package/lib/index.d.ts +11 -11
  30. package/lib/index.js +14 -16
  31. package/lib/index.js.map +1 -1
  32. package/lib/protobufs.d.ts +13 -0
  33. package/lib/protobufs.js +31 -0
  34. package/lib/protobufs.js.map +1 -0
  35. package/package.json +11 -8
  36. package/src/converter/data-converter.ts +39 -175
  37. package/src/{encoding.ts → converter/encoding.ts} +0 -0
  38. package/src/converter/patch-protobuf-root.ts +49 -0
  39. package/src/converter/payload-codec.ts +30 -0
  40. package/src/converter/payload-converter.ts +137 -102
  41. package/src/converter/payload-converters.ts +89 -0
  42. package/src/converter/protobuf-payload-converters.ts +192 -0
  43. package/src/converter/types.ts +6 -3
  44. package/src/failure.ts +35 -39
  45. package/src/index.ts +11 -11
  46. package/src/protobufs.ts +15 -0
  47. package/tsconfig.json +2 -2
  48. package/tsconfig.tsbuildinfo +1 -1
  49. package/lib/activity-options.d.ts +0 -81
  50. package/lib/activity-options.js +0 -14
  51. package/lib/activity-options.js.map +0 -1
  52. package/lib/encoding.js.map +0 -1
  53. package/lib/errors.d.ts +0 -45
  54. package/lib/errors.js +0 -76
  55. package/lib/errors.js.map +0 -1
  56. package/lib/interceptors.d.ts +0 -18
  57. package/lib/interceptors.js +0 -24
  58. package/lib/interceptors.js.map +0 -1
  59. package/lib/interfaces.d.ts +0 -31
  60. package/lib/interfaces.js +0 -3
  61. package/lib/interfaces.js.map +0 -1
  62. package/lib/otel.d.ts +0 -26
  63. package/lib/otel.js +0 -82
  64. package/lib/otel.js.map +0 -1
  65. package/lib/retry-policy.d.ts +0 -43
  66. package/lib/retry-policy.js +0 -36
  67. package/lib/retry-policy.js.map +0 -1
  68. package/lib/time.d.ts +0 -17
  69. package/lib/time.js +0 -77
  70. package/lib/time.js.map +0 -1
  71. package/lib/tls-config.d.ts +0 -32
  72. package/lib/tls-config.js +0 -11
  73. package/lib/tls-config.js.map +0 -1
  74. package/lib/type-helpers.d.ts +0 -12
  75. package/lib/type-helpers.js +0 -17
  76. package/lib/type-helpers.js.map +0 -1
  77. package/lib/utils.d.ts +0 -4
  78. package/lib/utils.js +0 -11
  79. package/lib/utils.js.map +0 -1
  80. package/lib/workflow-handle.d.ts +0 -27
  81. package/lib/workflow-handle.js +0 -3
  82. package/lib/workflow-handle.js.map +0 -1
  83. package/lib/workflow-options.d.ts +0 -92
  84. package/lib/workflow-options.js +0 -26
  85. package/lib/workflow-options.js.map +0 -1
  86. package/src/activity-options.ts +0 -97
  87. package/src/errors.ts +0 -60
  88. package/src/interceptors.ts +0 -32
  89. package/src/interfaces.ts +0 -37
  90. package/src/otel.ts +0 -61
  91. package/src/retry-policy.ts +0 -73
  92. package/src/time.ts +0 -76
  93. package/src/tls-config.ts +0 -35
  94. package/src/type-helpers.ts +0 -26
  95. package/src/utils.ts +0 -6
  96. package/src/workflow-handle.ts +0 -30
  97. package/src/workflow-options.ts +0 -128
@@ -1,189 +1,53 @@
1
- import { ValueError } from '../errors';
2
- import { str, METADATA_ENCODING_KEY, Payload } from './types';
3
- import {
4
- PayloadConverter,
5
- UndefinedPayloadConverter,
6
- BinaryPayloadConverter,
7
- JsonPayloadConverter,
8
- } from './payload-converter';
1
+ import { defaultPayloadCodec, PayloadCodec } from './payload-codec';
2
+ import { defaultPayloadConverter, PayloadConverter } from './payload-converter';
9
3
 
10
4
  /**
11
- * Used by the framework to serialize/deserialize method parameters that need to be sent over the
12
- * wire.
5
+ * When your data (arguments and return values) is sent over the wire and stored by Temporal Server, it is encoded in
6
+ * binary in a {@link Payload} Protobuf message.
13
7
  *
14
- * Implement this in order to customize worker data serialization or use the default data converter which supports `Uint8Array` and JSON serializables.
8
+ * The default `DataConverter` supports `undefined`, `Uint8Array`, and JSON serializables (so if
9
+ * [`JSON.stringify(yourArgOrRetval)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description)
10
+ * works, the default data converter will work). Protobufs are supported via [this
11
+ * API](https://docs.temporal.io/docs/typescript/data-converters#protobufs).
12
+ *
13
+ * Use a custom `DataConverter` to control the contents of your {@link Payload}s. Common reasons for using a custom
14
+ * `DataConverter` are:
15
+ * - Converting values that are not supported by the default `DataConverter` (for example, `JSON.stringify()` doesn't
16
+ * handle `BigInt`s, so if you want to return `{ total: 1000n }` from a Workflow, Signal, or Activity, you need your
17
+ * own `DataConverter`).
18
+ * - Encrypting values that may contain private information that you don't want stored in plaintext in Temporal Server's
19
+ * database.
20
+ * - Compressing values to reduce disk or network usage.
21
+ *
22
+ * To use your custom `DataConverter`, provide it to the {@link WorkflowClient}, {@link Worker}, and
23
+ * {@link bundleWorkflowCode} (if you use it):
24
+ * - `new WorkflowClient({ ..., dataConverter })`
25
+ * - `Worker.create({ ..., dataConverter })`
26
+ * - `bundleWorkflowCode({ ..., payloadConverterPath })`
15
27
  */
16
28
  export interface DataConverter {
17
- toPayload<T>(value: T): Promise<Payload>;
18
-
19
- fromPayload<T>(payload: Payload): Promise<T>;
20
- /**
21
- * Implements conversion of a list of values.
22
- *
23
- * @param values JS values to convert to Payloads.
24
- * @return converted value
25
- * @throws DataConverterError if conversion of the value passed as parameter failed for any
26
- * reason.
27
- */
28
- toPayloads(...values: unknown[]): Promise<Payload[] | undefined>;
29
-
30
- /**
31
- * Implements conversion of an array of values of different types. Useful for deserializing
32
- * arguments of function invocations.
33
- *
34
- * @param index index of the value in the payloads
35
- * @param content serialized value to convert to JS values.
36
- * @return converted JS value
37
- * @throws DataConverterError if conversion of the data passed as parameter failed for any
38
- * reason.
39
- */
40
- fromPayloads<T>(index: number, content?: Payload[] | null): Promise<T>;
41
-
42
29
  /**
43
- * Sync conversion of single payload, used in the Workflow runtime
30
+ * Path of a file that has a `payloadConverter` named export.
31
+ * `payloadConverter` should be an instance of a class that implements {@link PayloadConverter}.
32
+ * If no path is provided, {@link defaultPayloadConverter} is used.
44
33
  */
45
- toPayloadSync<T>(value: T): Payload;
34
+ payloadConverterPath?: string;
46
35
 
47
36
  /**
48
- * Sync conversion from a single payload, used in the Workflow runtime
37
+ * A {@link PayloadCodec} instance. The default codec is a no-op.
49
38
  */
50
- fromPayloadSync<T>(payload: Payload): T;
51
- /**
52
- * Sync conversion of all arguments, used in the Workflow runtime
53
- *
54
- * Implements conversion of a list of values.
55
- *
56
- * @param values JS values to convert to Payloads.
57
- * @return converted value
58
- * @throws DataConverterError if conversion of the value passed as parameter failed for any
59
- * reason.
60
- */
61
- toPayloadsSync(...values: unknown[]): Payload[] | undefined;
62
-
63
- /**
64
- * Sync version of {@link fromPayloads}
65
- */
66
- fromPayloadsSync<T>(index: number, content?: Payload[] | null): T;
39
+ payloadCodec?: PayloadCodec;
67
40
  }
68
41
 
69
- export class CompositeDataConverter implements DataConverter {
70
- readonly converters: PayloadConverter[];
71
- readonly converterByEncoding: Map<string, PayloadConverter> = new Map();
72
-
73
- constructor(...converters: PayloadConverter[]) {
74
- this.converters = converters;
75
- for (const converter of converters) {
76
- this.converterByEncoding.set(converter.encodingType, converter);
77
- }
78
- }
79
-
80
- public async toPayload<T>(value: T): Promise<Payload> {
81
- for (const converter of this.converters) {
82
- const result = await converter.toData(value);
83
- if (result !== undefined) return result;
84
- }
85
- throw new ValueError(`Cannot serialize ${value}`);
86
- }
87
-
88
- public toPayloadSync<T>(value: T): Payload {
89
- for (const converter of this.converters) {
90
- const result = converter.toDataSync(value);
91
- if (result !== undefined) return result;
92
- }
93
- throw new ValueError(`Cannot serialize ${value}`);
94
- }
95
-
96
- public async fromPayload<T>(payload: Payload): Promise<T> {
97
- if (payload.metadata === undefined || payload.metadata === null) {
98
- throw new ValueError('Missing payload metadata');
99
- }
100
- const encoding = str(payload.metadata[METADATA_ENCODING_KEY]);
101
- const converter = this.converterByEncoding.get(encoding);
102
- if (converter === undefined) {
103
- throw new ValueError(`Unknown encoding: ${encoding}`);
104
- }
105
- return await converter.fromData(payload);
106
- }
107
-
108
- public fromPayloadSync<T>(payload: Payload): T {
109
- if (payload.metadata === undefined || payload.metadata === null) {
110
- throw new ValueError('Missing payload metadata');
111
- }
112
- const encoding = str(payload.metadata[METADATA_ENCODING_KEY]);
113
- const converter = this.converterByEncoding.get(encoding);
114
- if (converter === undefined) {
115
- throw new ValueError(`Unknown encoding: ${encoding}`);
116
- }
117
- return converter.fromDataSync(payload);
118
- }
119
-
120
- public async toPayloads(...values: unknown[]): Promise<Payload[] | undefined> {
121
- if (values.length === 0) {
122
- return undefined;
123
- }
124
- return await Promise.all(values.map((value) => this.toPayload(value)));
125
- }
126
-
127
- public toPayloadsSync(...values: unknown[]): Payload[] | undefined {
128
- if (values.length === 0) {
129
- return undefined;
130
- }
131
- return values.map((value) => this.toPayloadSync(value));
132
- }
133
-
134
- public async fromPayloads<T>(index: number, payloads?: Payload[] | null): Promise<T> {
135
- // To make adding arguments a backwards compatible change
136
- if (payloads === undefined || payloads === null || index >= payloads.length) {
137
- return undefined as any;
138
- }
139
- return await this.fromPayload(payloads[index]);
140
- }
141
-
142
- public fromPayloadsSync<T>(index: number, payloads?: Payload[] | null): T {
143
- // To make adding arguments a backwards compatible change
144
- if (payloads === undefined || payloads === null || index >= payloads.length) {
145
- return undefined as any;
146
- }
147
- return this.fromPayloadSync(payloads[index]);
148
- }
149
- }
150
-
151
- export async function arrayFromPayloads(converter: DataConverter, content?: Payload[] | null): Promise<unknown[]> {
152
- if (!content) {
153
- return [];
154
- }
155
- return await Promise.all(content.map((payload: Payload) => converter.fromPayload(payload)));
156
- }
157
-
158
- export async function mapToPayloads<K extends string>(
159
- converter: DataConverter,
160
- source: Record<K, any>
161
- ): Promise<Record<K, Payload>> {
162
- return Object.fromEntries(
163
- await Promise.all(
164
- Object.entries(source).map(async ([k, v]): Promise<[K, Payload]> => [k as K, await converter.toPayload(v)])
165
- )
166
- ) as Record<K, Payload>;
167
- }
168
-
169
- export function arrayFromPayloadsSync(converter: DataConverter, content?: Payload[] | null): unknown[] {
170
- if (!content) {
171
- return [];
172
- }
173
- return content.map((payload: Payload) => converter.fromPayloadSync(payload));
174
- }
175
-
176
- export function mapToPayloadsSync<K extends string>(
177
- converter: DataConverter,
178
- source: Record<K, any>
179
- ): Record<K, Payload> {
180
- return Object.fromEntries(
181
- Object.entries(source).map(([k, v]): [K, Payload] => [k as K, converter.toPayloadSync(v)])
182
- ) as Record<K, Payload>;
42
+ /**
43
+ * A {@link DataConverter} that has been loaded via {@link loadDataConverter}.
44
+ */
45
+ export interface LoadedDataConverter {
46
+ payloadConverter: PayloadConverter;
47
+ payloadCodec: PayloadCodec;
183
48
  }
184
49
 
185
- export const defaultDataConverter = new CompositeDataConverter(
186
- new UndefinedPayloadConverter(),
187
- new BinaryPayloadConverter(),
188
- new JsonPayloadConverter()
189
- );
50
+ export const defaultDataConverter: LoadedDataConverter = {
51
+ payloadConverter: defaultPayloadConverter,
52
+ payloadCodec: defaultPayloadCodec,
53
+ };
File without changes
@@ -0,0 +1,49 @@
1
+ import { isRecord } from '@temporalio/internal-workflow-common';
2
+
3
+ /**
4
+ * Create a version of `root` with non-nested namespaces to match the generated types.
5
+ * For more information, see:
6
+ * https://github.com/temporalio/sdk-typescript/blob/main/docs/protobuf-libraries.md#current-solution
7
+ * @param root Generated by `pbjs -t json-module -w commonjs -o json-module.js *.proto`
8
+ * @returns A new patched `root`
9
+ */
10
+ export function patchProtobufRoot<T extends Record<string, unknown>>(root: T): T {
11
+ return _patchProtobufRoot(root);
12
+ }
13
+
14
+ function _patchProtobufRoot<T extends Record<string, unknown>>(root: T, name?: string): T {
15
+ const newRoot = new (root.constructor as any)(isNamespace(root) ? name : {});
16
+ for (const key in root) {
17
+ newRoot[key] = root[key];
18
+ }
19
+
20
+ if (isRecord(root.nested)) {
21
+ for (const typeOrNamespace in root.nested) {
22
+ const value = root.nested[typeOrNamespace];
23
+ if (typeOrNamespace in root && !(isType(root[typeOrNamespace]) || isNamespace(root[typeOrNamespace]))) {
24
+ console.log(
25
+ `patchRoot warning: overriding property '${typeOrNamespace}' that is used by protobufjs with the '${typeOrNamespace}' protobuf namespace. This may result in protobufjs not working property.`
26
+ );
27
+ }
28
+
29
+ if (isNamespace(value)) {
30
+ newRoot[typeOrNamespace] = _patchProtobufRoot(value, typeOrNamespace);
31
+ } else if (isType(value)) {
32
+ newRoot[typeOrNamespace] = value;
33
+ }
34
+ }
35
+ }
36
+
37
+ return newRoot;
38
+ }
39
+
40
+ type Type = Record<string, unknown>;
41
+ type Namespace = { nested: Record<string, unknown> };
42
+
43
+ function isType(value: unknown): value is Type {
44
+ return isRecord(value) && value.constructor.name === 'Type';
45
+ }
46
+
47
+ function isNamespace(value: unknown): value is Namespace {
48
+ return isRecord(value) && value.constructor.name === 'Namespace';
49
+ }
@@ -0,0 +1,30 @@
1
+ import { Payload } from './types';
2
+
3
+ /**
4
+ * `PayloadCodec` is an optional step that happens between the wire and the {@link PayloadConverter}:
5
+ *
6
+ * Temporal Server <--> Wire <--> `PayloadCodec` <--> `PayloadConverter` <--> User code
7
+ *
8
+ * Implement this to transform an array of {@link Payload}s to/from the format sent over the wire and stored by Temporal Server.
9
+ * Common transformations are encryption and compression.
10
+ */
11
+ export interface PayloadCodec {
12
+ /**
13
+ * Encode an array of {@link Payload}s for sending over the wire.
14
+ * @param payloads May have length 0.
15
+ */
16
+ encode(payloads: Payload[]): Promise<Payload[]>;
17
+
18
+ /**
19
+ * Decode an array of {@link Payload}s received from the wire.
20
+ */
21
+ decode(payloads: Payload[]): Promise<Payload[]>;
22
+ }
23
+
24
+ /**
25
+ * No-op implementation of {@link PayloadCodec}.
26
+ */
27
+ export const defaultPayloadCodec = {
28
+ encode: async (payloads: Payload[]): Promise<Payload[]> => payloads,
29
+ decode: async (payloads: Payload[]): Promise<Payload[]> => payloads,
30
+ };
@@ -1,142 +1,177 @@
1
- import { ValueError } from '../errors';
2
- import { u8, str, Payload, encodingTypes, encodingKeys, METADATA_ENCODING_KEY } from './types';
1
+ import { PayloadConverterError, ValueError } from '@temporalio/internal-workflow-common';
2
+ import {
3
+ BinaryPayloadConverter,
4
+ JsonPayloadConverter,
5
+ PayloadConverterWithEncoding,
6
+ UndefinedPayloadConverter,
7
+ } from './payload-converters';
8
+ import { METADATA_ENCODING_KEY, Payload, str } from './types';
3
9
 
4
10
  /**
5
- * Used by the framework to serialize/deserialize method parameters that need to be sent over the
6
- * wire.
11
+ * Used by the framework to serialize/deserialize parameters and return values.
7
12
  *
8
- * @author fateev
13
+ * This is called inside the [Workflow isolate](https://docs.temporal.io/docs/typescript/determinism).
14
+ * To write async code or use Node APIs (or use packages that use Node APIs), use a {@link PayloadCodec}.
9
15
  */
10
16
  export interface PayloadConverter {
11
- encodingType: string;
12
-
13
17
  /**
14
- * TODO: Fix comment in https://github.com/temporalio/sdk-java/blob/85593dbfa99bddcdf54c7196d2b73eeb23e94e9e/temporal-sdk/src/main/java/io/temporal/common/converter/DataConverter.java#L46
15
- * Implements conversion of value to payload
16
- *
17
- * @param value JS value to convert.
18
- * @return converted value
19
- * @throws DataConverterException if conversion of the value passed as parameter failed for any
20
- * reason.
18
+ * Converts a value to a {@link Payload}.
19
+ * @param value The value to convert. Example values include the Workflow args sent by the client and the values returned by a Workflow or Activity.
21
20
  */
22
- toData(value: unknown): Promise<Payload | undefined>;
21
+ toPayload<T>(value: T): Payload | undefined;
23
22
 
24
23
  /**
25
- * Implements conversion of payload to value.
26
- *
27
- * @param content Serialized value to convert to a JS value.
28
- * @return converted JS value
29
- * @throws DataConverterException if conversion of the data passed as parameter failed for any
30
- * reason.
24
+ * Converts a {@link Payload} back to a value.
31
25
  */
32
- fromData<T>(content: Payload): Promise<T>;
26
+ fromPayload<T>(payload: Payload): T;
27
+ }
28
+
29
+ export class CompositePayloadConverter implements PayloadConverter {
30
+ readonly converters: PayloadConverterWithEncoding[];
31
+ readonly converterByEncoding: Map<string, PayloadConverterWithEncoding> = new Map();
32
+
33
+ constructor(...converters: PayloadConverterWithEncoding[]) {
34
+ this.converters = converters;
35
+ for (const converter of converters) {
36
+ this.converterByEncoding.set(converter.encodingType, converter);
37
+ }
38
+ }
33
39
 
34
40
  /**
35
- * Synchronous version of {@link toData}, used in the Workflow runtime because
36
- * the async version limits the functionality of the runtime.
37
- *
38
- * Implements conversion of value to payload
41
+ * Tries to run `.toPayload(value)` on each converter in the order provided at construction.
42
+ * Returns the first successful result, or `undefined` if there is no converter that can handle the value.
39
43
  *
40
- * @param value JS value to convert.
41
- * @return converted value
42
- * @throws DataConverterException if conversion of the value passed as parameter failed for any
43
- * reason.
44
+ * @throws UnsupportedJsonTypeError
44
45
  */
45
- toDataSync(value: unknown): Payload | undefined;
46
+ public toPayload<T>(value: T): Payload | undefined {
47
+ for (const converter of this.converters) {
48
+ const result = converter.toPayload(value);
49
+ if (result !== undefined) {
50
+ return result;
51
+ }
52
+ }
53
+ return undefined;
54
+ }
46
55
 
47
56
  /**
48
- * Synchronous version of {@link fromData}, used in the Workflow runtime because
49
- * the async version limits the functionality of the runtime.
50
- *
51
- * Implements conversion of payload to value.
52
- *
53
- * @param content Serialized value to convert to a JS value.
54
- * @return converted JS value
55
- * @throws DataConverterException if conversion of the data passed as parameter failed for any
56
- * reason.
57
+ * Run {@link PayloadConverterWithEncoding.fromPayload} based on the {@link encodingTypes | encoding type} of the {@link Payload}.
57
58
  */
58
- fromDataSync<T>(content: Payload): T;
59
- }
60
-
61
- export abstract class AsyncFacadePayloadConverter implements PayloadConverter {
62
- abstract encodingType: string;
63
- abstract toDataSync(value: unknown): Payload | undefined;
64
- abstract fromDataSync<T>(content: Payload): T;
65
-
66
- public async toData(value: unknown): Promise<Payload | undefined> {
67
- return this.toDataSync(value);
59
+ public fromPayload<T>(payload: Payload): T {
60
+ if (payload.metadata === undefined || payload.metadata === null) {
61
+ throw new ValueError('Missing payload metadata');
62
+ }
63
+ const encoding = str(payload.metadata[METADATA_ENCODING_KEY]);
64
+ const converter = this.converterByEncoding.get(encoding);
65
+ if (converter === undefined) {
66
+ throw new ValueError(`Unknown encoding: ${encoding}`);
67
+ }
68
+ return converter.fromPayload(payload);
68
69
  }
70
+ }
69
71
 
70
- public async fromData<T>(content: Payload): Promise<T> {
71
- return this.fromDataSync(content);
72
+ /**
73
+ * Tries to convert `value` to a {@link Payload}. Throws if conversion fails.
74
+ *
75
+ * @throws {@link PayloadConverterError}
76
+ */
77
+ export function toPayload(converter: PayloadConverter, value: unknown): Payload {
78
+ const payload = converter.toPayload(value);
79
+ if (payload === undefined) {
80
+ throw new PayloadConverterError(`Failed to convert value: ${value}`);
72
81
  }
82
+ return payload;
73
83
  }
74
84
 
75
85
  /**
76
- * Converts between JS undefined and NULL Payload
86
+ * Implements conversion of a list of values.
87
+ *
88
+ * @param converter
89
+ * @param values JS values to convert to Payloads
90
+ * @return converted values
91
+ * @throws PayloadConverterError if conversion of the value passed as parameter failed for any
92
+ * reason.
77
93
  */
78
- export class UndefinedPayloadConverter extends AsyncFacadePayloadConverter {
79
- public encodingType = encodingTypes.METADATA_ENCODING_NULL;
80
-
81
- public toDataSync(value: unknown): Payload | undefined {
82
- if (value !== undefined) return undefined; // Can't encode
83
- return {
84
- metadata: {
85
- [METADATA_ENCODING_KEY]: encodingKeys.METADATA_ENCODING_NULL,
86
- },
87
- };
94
+ export function toPayloads(converter: PayloadConverter, ...values: unknown[]): Payload[] | undefined {
95
+ if (values.length === 0) {
96
+ return undefined;
88
97
  }
89
98
 
90
- public fromDataSync<T>(_content: Payload): T {
91
- return undefined as any; // Just return undefined
92
- }
99
+ return values.map((value) => toPayload(converter, value));
93
100
  }
94
101
 
95
102
  /**
96
- * Converts between non-undefined values and serialized JSON Payload
103
+ * Run {@link PayloadConverter.toPayload} on each value in the map.
104
+ *
105
+ * @throws {@link PayloadConverterError} if conversion of any value in the map fails
97
106
  */
98
- export class JsonPayloadConverter extends AsyncFacadePayloadConverter {
99
- public encodingType = encodingTypes.METADATA_ENCODING_JSON;
100
-
101
- public toDataSync(value: unknown): Payload | undefined {
102
- if (value === undefined) return undefined; // Should be encoded with the UndefinedPayloadConverter
103
- return {
104
- metadata: {
105
- [METADATA_ENCODING_KEY]: encodingKeys.METADATA_ENCODING_JSON,
106
- },
107
- data: u8(JSON.stringify(value)),
108
- };
109
- }
107
+ export function mapToPayloads<K extends string>(converter: PayloadConverter, map: Record<K, any>): Record<K, Payload> {
108
+ return Object.fromEntries(
109
+ Object.entries(map).map(([k, v]): [K, Payload] => [k as K, toPayload(converter, v)])
110
+ ) as Record<K, Payload>;
111
+ }
110
112
 
111
- public fromDataSync<T>(content: Payload): T {
112
- if (content.data === undefined || content.data === null) {
113
- throw new ValueError('Got payload with no data');
114
- }
115
- return JSON.parse(str(content.data));
113
+ /**
114
+ * Implements conversion of an array of values of different types. Useful for deserializing
115
+ * arguments of function invocations.
116
+ *
117
+ * @param converter
118
+ * @param index index of the value in the payloads
119
+ * @param payloads serialized value to convert to JS values.
120
+ * @return converted JS value
121
+ * @throws {@link PayloadConverterError} if conversion of the data passed as parameter failed for any
122
+ * reason.
123
+ */
124
+ export function fromPayloadsAtIndex<T>(converter: PayloadConverter, index: number, payloads?: Payload[] | null): T {
125
+ // To make adding arguments a backwards compatible change
126
+ if (payloads === undefined || payloads === null || index >= payloads.length) {
127
+ return undefined as any;
116
128
  }
129
+ return converter.fromPayload(payloads[index]);
117
130
  }
118
131
 
119
132
  /**
120
- * Converts between binary data types and RAW Payload
133
+ * Run {@link PayloadConverter.fromPayload} on each value in the array.
121
134
  */
122
- export class BinaryPayloadConverter extends AsyncFacadePayloadConverter {
123
- public encodingType = encodingTypes.METADATA_ENCODING_RAW;
124
-
125
- public toDataSync(value: unknown): Payload | undefined {
126
- // TODO: support any DataView or ArrayBuffer?
127
- if (!(value instanceof Uint8Array)) {
128
- return undefined;
129
- }
130
- return {
131
- metadata: {
132
- [METADATA_ENCODING_KEY]: encodingKeys.METADATA_ENCODING_RAW,
133
- },
134
- data: value,
135
- };
135
+ export function arrayFromPayloads(converter: PayloadConverter, payloads?: Payload[] | null): unknown[] {
136
+ if (!payloads) {
137
+ return [];
136
138
  }
139
+ return payloads.map((payload: Payload) => converter.fromPayload(payload));
140
+ }
141
+
142
+ export function mapFromPayloads<K extends string>(
143
+ converter: PayloadConverter,
144
+ map?: Record<K, Payload> | null | undefined
145
+ ): Record<K, unknown> | undefined {
146
+ if (map === undefined || map === null) return undefined;
147
+ return Object.fromEntries(
148
+ Object.entries(map).map(([k, payload]): [K, unknown] => {
149
+ const value = converter.fromPayload(payload as Payload);
150
+ return [k as K, value];
151
+ })
152
+ ) as Record<K, unknown>;
153
+ }
137
154
 
138
- public fromDataSync<T>(content: Payload): T {
139
- // TODO: support any DataView or ArrayBuffer?
140
- return content.data as any;
155
+ export const searchAttributePayloadConverter = new JsonPayloadConverter();
156
+
157
+ export class DefaultPayloadConverter extends CompositePayloadConverter {
158
+ // Match the order used in other SDKs, but exclude Protobuf converters so that the code, including
159
+ // `proto3-json-serializer`, doesn't take space in Workflow bundles that don't use Protobufs. To use Protobufs, use
160
+ // {@link DefaultPayloadConverterWithProtobufs}.
161
+ //
162
+ // Go SDK:
163
+ // https://github.com/temporalio/sdk-go/blob/5e5645f0c550dcf717c095ae32c76a7087d2e985/converter/default_data_converter.go#L28
164
+ constructor() {
165
+ super(new UndefinedPayloadConverter(), new BinaryPayloadConverter(), new JsonPayloadConverter());
141
166
  }
142
167
  }
168
+
169
+ /**
170
+ * The default {@link PayloadConverter} used by the SDK.
171
+ * Supports `Uint8Array` and JSON serializables (so if [`JSON.stringify(yourArgOrRetval)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description) works, the default payload converter will work).
172
+ *
173
+ * To also support Protobufs, create a custom payload converter with {@link DefaultPayloadConverter}:
174
+ *
175
+ * `const myConverter = new DefaultPayloadConverter({ protobufRoot })`
176
+ */
177
+ export const defaultPayloadConverter = new DefaultPayloadConverter();