@temporalio/common 0.21.0 → 1.0.0-rc.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 (49) hide show
  1. package/README.md +3 -3
  2. package/lib/converter/data-converter.d.ts +8 -4
  3. package/lib/converter/data-converter.js +3 -4
  4. package/lib/converter/data-converter.js.map +1 -1
  5. package/lib/converter/json-payload-converter.d.ts +10 -0
  6. package/lib/converter/json-payload-converter.js +39 -0
  7. package/lib/converter/json-payload-converter.js.map +1 -0
  8. package/lib/converter/patch-protobuf-root.d.ts +1 -8
  9. package/lib/converter/patch-protobuf-root.js +2 -39
  10. package/lib/converter/patch-protobuf-root.js.map +1 -1
  11. package/lib/converter/payload-codec.d.ts +0 -7
  12. package/lib/converter/payload-codec.js +0 -8
  13. package/lib/converter/payload-codec.js.map +1 -1
  14. package/lib/converter/payload-converter.d.ts +13 -44
  15. package/lib/converter/payload-converter.js +8 -85
  16. package/lib/converter/payload-converter.js.map +1 -1
  17. package/lib/converter/payload-converters.d.ts +48 -13
  18. package/lib/converter/payload-converters.js +74 -36
  19. package/lib/converter/payload-converters.js.map +1 -1
  20. package/lib/converter/protobuf-payload-converters.d.ts +1 -2
  21. package/lib/converter/protobuf-payload-converters.js +7 -5
  22. package/lib/converter/protobuf-payload-converters.js.map +1 -1
  23. package/lib/converter/search-attribute-payload-converter.d.ts +12 -0
  24. package/lib/converter/search-attribute-payload-converter.js +64 -0
  25. package/lib/converter/search-attribute-payload-converter.js.map +1 -0
  26. package/lib/converter/types.d.ts +1 -2
  27. package/lib/converter/types.js.map +1 -1
  28. package/lib/failure.d.ts +1 -1
  29. package/lib/failure.js +16 -5
  30. package/lib/failure.js.map +1 -1
  31. package/lib/index.d.ts +1 -0
  32. package/lib/index.js +1 -0
  33. package/lib/index.js.map +1 -1
  34. package/lib/protobufs.d.ts +1 -1
  35. package/lib/protobufs.js +1 -1
  36. package/package.json +4 -4
  37. package/src/converter/data-converter.ts +12 -7
  38. package/src/converter/json-payload-converter.ts +37 -0
  39. package/src/converter/patch-protobuf-root.ts +1 -49
  40. package/src/converter/payload-codec.ts +0 -8
  41. package/src/converter/payload-converter.ts +17 -99
  42. package/src/converter/payload-converters.ts +99 -41
  43. package/src/converter/protobuf-payload-converters.ts +8 -4
  44. package/src/converter/search-attribute-payload-converter.ts +71 -0
  45. package/src/converter/types.ts +1 -2
  46. package/src/failure.ts +17 -7
  47. package/src/index.ts +1 -0
  48. package/src/protobufs.ts +1 -1
  49. package/tsconfig.tsbuildinfo +1 -1
@@ -1,49 +1 @@
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
- }
1
+ export { patchProtobufRoot } from '@temporalio/proto/lib/patch-protobuf-root';
@@ -20,11 +20,3 @@ export interface PayloadCodec {
20
20
  */
21
21
  decode(payloads: Payload[]): Promise<Payload[]>;
22
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,24 +1,22 @@
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';
1
+ import { Payload } from './types';
9
2
 
10
3
  /**
11
- * Used by the framework to serialize/deserialize parameters and return values.
4
+ * Used by the framework to serialize/deserialize data like parameters and return values.
12
5
  *
13
- * This is called inside the [Workflow isolate](https://docs.temporal.io/docs/typescript/determinism).
6
+ * This is called inside the [Workflow isolate](https://docs.temporal.io/typescript/determinism).
14
7
  * To write async code or use Node APIs (or use packages that use Node APIs), use a {@link PayloadCodec}.
15
8
  */
16
9
  export interface PayloadConverter {
17
10
  /**
18
11
  * 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.
12
+ *
13
+ * @param value The value to convert. Example values include the Workflow args sent from the Client and the values returned by a Workflow or Activity.
14
+ *
15
+ * @returns The {@link Payload}.
16
+ *
17
+ * Should throw {@link ValueError} if unable to convert.
20
18
  */
21
- toPayload<T>(value: T): Payload | undefined;
19
+ toPayload<T>(value: T): Payload;
22
20
 
23
21
  /**
24
22
  * Converts a {@link Payload} back to a value.
@@ -26,69 +24,13 @@ export interface PayloadConverter {
26
24
  fromPayload<T>(payload: Payload): T;
27
25
  }
28
26
 
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
- }
39
-
40
- /**
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.
43
- *
44
- * @throws UnsupportedJsonTypeError
45
- */
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
- }
55
-
56
- /**
57
- * Run {@link PayloadConverterWithEncoding.fromPayload} based on the {@link encodingTypes | encoding type} of the {@link Payload}.
58
- */
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);
69
- }
70
- }
71
-
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}`);
81
- }
82
- return payload;
83
- }
84
-
85
27
  /**
86
28
  * Implements conversion of a list of values.
87
29
  *
88
30
  * @param converter
89
31
  * @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
32
+ * @return list of {@link Payload}s
33
+ * @throws {@link ValueError} if conversion of the value passed as parameter failed for any
92
34
  * reason.
93
35
  */
94
36
  export function toPayloads(converter: PayloadConverter, ...values: unknown[]): Payload[] | undefined {
@@ -96,17 +38,17 @@ export function toPayloads(converter: PayloadConverter, ...values: unknown[]): P
96
38
  return undefined;
97
39
  }
98
40
 
99
- return values.map((value) => toPayload(converter, value));
41
+ return values.map((value) => converter.toPayload(value));
100
42
  }
101
43
 
102
44
  /**
103
45
  * Run {@link PayloadConverter.toPayload} on each value in the map.
104
46
  *
105
- * @throws {@link PayloadConverterError} if conversion of any value in the map fails
47
+ * @throws {@link ValueError} if conversion of any value in the map fails
106
48
  */
107
49
  export function mapToPayloads<K extends string>(converter: PayloadConverter, map: Record<K, any>): Record<K, Payload> {
108
50
  return Object.fromEntries(
109
- Object.entries(map).map(([k, v]): [K, Payload] => [k as K, toPayload(converter, v)])
51
+ Object.entries(map).map(([k, v]): [K, Payload] => [k as K, converter.toPayload(v)])
110
52
  ) as Record<K, Payload>;
111
53
  }
112
54
 
@@ -142,8 +84,8 @@ export function arrayFromPayloads(converter: PayloadConverter, payloads?: Payloa
142
84
  export function mapFromPayloads<K extends string>(
143
85
  converter: PayloadConverter,
144
86
  map?: Record<K, Payload> | null | undefined
145
- ): Record<K, unknown> | undefined {
146
- if (map === undefined || map === null) return undefined;
87
+ ): Record<K, unknown> | undefined | null {
88
+ if (map == null) return map;
147
89
  return Object.fromEntries(
148
90
  Object.entries(map).map(([k, payload]): [K, unknown] => {
149
91
  const value = converter.fromPayload(payload as Payload);
@@ -151,27 +93,3 @@ export function mapFromPayloads<K extends string>(
151
93
  })
152
94
  ) as Record<K, unknown>;
153
95
  }
154
-
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());
166
- }
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();
@@ -1,67 +1,98 @@
1
- import { errorMessage, UnsupportedJsonTypeError, ValueError } from '@temporalio/internal-workflow-common';
1
+ import { PayloadConverterError, ValueError } from '@temporalio/internal-workflow-common';
2
+ import { JsonPayloadConverter } from './json-payload-converter';
2
3
  import { PayloadConverter } from './payload-converter';
3
- import { encodingKeys, EncodingType, encodingTypes, METADATA_ENCODING_KEY, Payload, str, u8 } from './types';
4
+ import { SearchAttributePayloadConverter } from './search-attribute-payload-converter';
5
+ import { encodingKeys, encodingTypes, METADATA_ENCODING_KEY, Payload, str } from './types';
4
6
 
5
- export interface PayloadConverterWithEncoding extends PayloadConverter {
6
- readonly encodingType: EncodingType;
7
+ export interface PayloadConverterWithEncoding {
8
+ /**
9
+ * Converts a value to a {@link Payload}.
10
+ *
11
+ * @param value The value to convert. Example values include the Workflow args sent from the Client and the values returned by a Workflow or Activity.
12
+ * @returns The {@link Payload}, or `undefined` if unable to convert.
13
+ */
14
+ toPayload<T>(value: T): Payload | undefined;
15
+
16
+ /**
17
+ * Converts a {@link Payload} back to a value.
18
+ */
19
+ fromPayload<T>(payload: Payload): T;
20
+
21
+ readonly encodingType: string;
7
22
  }
8
23
 
9
24
  /**
10
- * Converts between JS undefined and NULL Payload
25
+ * Tries to convert values to {@link Payload}s using the {@link PayloadConverterWithEncoding}s provided to the constructor, in the order provided.
26
+ *
27
+ * Converts Payloads to values based on the `Payload.metadata.encoding` field, which matches the {@link PayloadConverterWithEncoding.encodingType}
28
+ * of the converter that created the Payload.
11
29
  */
12
- export class UndefinedPayloadConverter implements PayloadConverterWithEncoding {
13
- public encodingType = encodingTypes.METADATA_ENCODING_NULL;
30
+ export class CompositePayloadConverter implements PayloadConverter {
31
+ readonly converters: PayloadConverterWithEncoding[];
32
+ readonly converterByEncoding: Map<string, PayloadConverterWithEncoding> = new Map();
14
33
 
15
- public toPayload(value: unknown): Payload | undefined {
16
- if (value !== undefined) return undefined; // Can't encode
17
- return {
18
- metadata: {
19
- [METADATA_ENCODING_KEY]: encodingKeys.METADATA_ENCODING_NULL,
20
- },
21
- };
34
+ constructor(...converters: PayloadConverterWithEncoding[]) {
35
+ if (converters.length === 0) {
36
+ throw new PayloadConverterError('Must provide at least one PayloadConverterWithEncoding');
37
+ }
38
+
39
+ this.converters = converters;
40
+ for (const converter of converters) {
41
+ this.converterByEncoding.set(converter.encodingType, converter);
42
+ }
22
43
  }
23
44
 
24
- public fromPayload<T>(_content: Payload): T {
25
- return undefined as any; // Just return undefined
45
+ /**
46
+ * Tries to run `.toPayload(value)` on each converter in the order provided at construction.
47
+ * Returns the first successful result, throws {@link ValueError} if there is no converter that can handle the value.
48
+ */
49
+ public toPayload<T>(value: T): Payload {
50
+ for (const converter of this.converters) {
51
+ const result = converter.toPayload(value);
52
+ if (result !== undefined) {
53
+ return result;
54
+ }
55
+ }
56
+
57
+ throw new ValueError(`Unable to convert ${value} to payload`);
58
+ }
59
+
60
+ /**
61
+ * Run {@link PayloadConverterWithEncoding.fromPayload} based on the {@link encodingTypes | encoding type} of the {@link Payload}.
62
+ */
63
+ public fromPayload<T>(payload: Payload): T {
64
+ if (payload.metadata === undefined || payload.metadata === null) {
65
+ throw new ValueError('Missing payload metadata');
66
+ }
67
+ const encoding = str(payload.metadata[METADATA_ENCODING_KEY]);
68
+ const converter = this.converterByEncoding.get(encoding);
69
+ if (converter === undefined) {
70
+ throw new ValueError(`Unknown encoding: ${encoding}`);
71
+ }
72
+ return converter.fromPayload(payload);
26
73
  }
27
74
  }
28
75
 
29
76
  /**
30
- * Converts between non-undefined values and serialized JSON Payload
31
- *
32
- * @throws UnsupportedJsonTypeError
77
+ * Converts between JS undefined and NULL Payload
33
78
  */
34
- export class JsonPayloadConverter implements PayloadConverterWithEncoding {
35
- public encodingType = encodingTypes.METADATA_ENCODING_JSON;
79
+ export class UndefinedPayloadConverter implements PayloadConverterWithEncoding {
80
+ public encodingType = encodingTypes.METADATA_ENCODING_NULL;
36
81
 
37
82
  public toPayload(value: unknown): Payload | undefined {
38
- if (value === undefined) return undefined;
39
-
40
- let json;
41
- try {
42
- json = JSON.stringify(value);
43
- } catch (e) {
44
- throw new UnsupportedJsonTypeError(
45
- `Can't run JSON.stringify on this value: ${value}. Either convert it (or its properties) to JSON-serializable values (see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#description ), or use a custom data converter: https://docs.temporal.io/docs/typescript/data-converters . JSON.stringify error message: ${errorMessage(
46
- e
47
- )}`,
48
- e as Error
49
- );
83
+ if (value !== undefined) {
84
+ return undefined;
50
85
  }
51
86
 
52
87
  return {
53
88
  metadata: {
54
- [METADATA_ENCODING_KEY]: encodingKeys.METADATA_ENCODING_JSON,
89
+ [METADATA_ENCODING_KEY]: encodingKeys.METADATA_ENCODING_NULL,
55
90
  },
56
- data: u8(json),
57
91
  };
58
92
  }
59
93
 
60
- public fromPayload<T>(content: Payload): T {
61
- if (content.data === undefined || content.data === null) {
62
- throw new ValueError('Got payload with no data');
63
- }
64
- return JSON.parse(str(content.data));
94
+ public fromPayload<T>(_content: Payload): T {
95
+ return undefined as any; // Just return undefined
65
96
  }
66
97
  }
67
98
 
@@ -73,7 +104,10 @@ export class BinaryPayloadConverter implements PayloadConverterWithEncoding {
73
104
 
74
105
  public toPayload(value: unknown): Payload | undefined {
75
106
  // TODO: support any DataView or ArrayBuffer?
76
- if (!(value instanceof Uint8Array)) return undefined;
107
+ if (!(value instanceof Uint8Array)) {
108
+ return undefined;
109
+ }
110
+
77
111
  return {
78
112
  metadata: {
79
113
  [METADATA_ENCODING_KEY]: encodingKeys.METADATA_ENCODING_RAW,
@@ -87,3 +121,27 @@ export class BinaryPayloadConverter implements PayloadConverterWithEncoding {
87
121
  return content.data as any;
88
122
  }
89
123
  }
124
+
125
+ export const searchAttributePayloadConverter = new SearchAttributePayloadConverter();
126
+
127
+ export class DefaultPayloadConverter extends CompositePayloadConverter {
128
+ // Match the order used in other SDKs, but exclude Protobuf converters so that the code, including
129
+ // `proto3-json-serializer`, doesn't take space in Workflow bundles that don't use Protobufs. To use Protobufs, use
130
+ // {@link DefaultPayloadConverterWithProtobufs}.
131
+ //
132
+ // Go SDK:
133
+ // https://github.com/temporalio/sdk-go/blob/5e5645f0c550dcf717c095ae32c76a7087d2e985/converter/default_data_converter.go#L28
134
+ constructor() {
135
+ super(new UndefinedPayloadConverter(), new BinaryPayloadConverter(), new JsonPayloadConverter());
136
+ }
137
+ }
138
+
139
+ /**
140
+ * The default {@link PayloadConverter} used by the SDK.
141
+ * 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).
142
+ *
143
+ * To also support Protobufs, create a custom payload converter with {@link DefaultPayloadConverter}:
144
+ *
145
+ * `const myConverter = new DefaultPayloadConverter({ protobufRoot })`
146
+ */
147
+ export const defaultPayloadConverter = new DefaultPayloadConverter();
@@ -8,10 +8,10 @@ import {
8
8
  } from '@temporalio/internal-workflow-common';
9
9
  import * as protoJsonSerializer from 'proto3-json-serializer';
10
10
  import type { Message, Namespace, Root, Type } from 'protobufjs';
11
- import { CompositePayloadConverter } from './payload-converter';
11
+ import { JsonPayloadConverter } from './json-payload-converter';
12
12
  import {
13
13
  BinaryPayloadConverter,
14
- JsonPayloadConverter,
14
+ CompositePayloadConverter,
15
15
  PayloadConverterWithEncoding,
16
16
  UndefinedPayloadConverter,
17
17
  } from './payload-converters';
@@ -96,7 +96,9 @@ export class ProtobufBinaryPayloadConverter extends ProtobufPayloadConverter {
96
96
  }
97
97
 
98
98
  public toPayload(value: unknown): Payload | undefined {
99
- if (!isProtobufMessage(value)) return undefined;
99
+ if (!isProtobufMessage(value)) {
100
+ return undefined;
101
+ }
100
102
 
101
103
  return this.constructPayload({
102
104
  messageTypeName: getNamespacedTypeName(value.$type),
@@ -124,7 +126,9 @@ export class ProtobufJsonPayloadConverter extends ProtobufPayloadConverter {
124
126
  }
125
127
 
126
128
  public toPayload(value: unknown): Payload | undefined {
127
- if (!isProtobufMessage(value)) return undefined;
129
+ if (!isProtobufMessage(value)) {
130
+ return undefined;
131
+ }
128
132
 
129
133
  const jsonValue = protoJsonSerializer.toProto3JSON(value);
130
134
 
@@ -0,0 +1,71 @@
1
+ import { IllegalStateError, ValueError } from '@temporalio/internal-workflow-common';
2
+ import { PayloadConverter } from './payload-converter';
3
+ import { JsonPayloadConverter } from './json-payload-converter';
4
+ import { Payload, str } from './types';
5
+
6
+ const jsonConverter = new JsonPayloadConverter();
7
+ const validNonDateTypes = ['string', 'number', 'boolean'];
8
+
9
+ /**
10
+ * Converts Search Attribute values using JsonPayloadConverter
11
+ */
12
+ export class SearchAttributePayloadConverter implements PayloadConverter {
13
+ public toPayload(values: unknown): Payload {
14
+ if (!(values instanceof Array)) {
15
+ throw new ValueError(`SearchAttribute value must be an array`);
16
+ }
17
+
18
+ if (values.length > 0) {
19
+ const firstValue = values[0];
20
+ const firstType = typeof firstValue;
21
+ if (firstType === 'object') {
22
+ for (const idx in values) {
23
+ const value = values[idx];
24
+ if (!(value instanceof Date)) {
25
+ throw new ValueError(
26
+ `SearchAttribute values must arrays of strings, numbers, booleans, or Dates. The value ${value} at index ${idx} is of type ${typeof value}`
27
+ );
28
+ }
29
+ }
30
+ } else {
31
+ if (!validNonDateTypes.includes(firstType)) {
32
+ throw new ValueError(`SearchAttribute array values must be: string | number | boolean | Date`);
33
+ }
34
+
35
+ for (const idx in values) {
36
+ const value = values[idx];
37
+ if (typeof value !== firstType) {
38
+ throw new ValueError(
39
+ `All SearchAttribute array values must be of the same type. The first value ${firstValue} of type ${firstType} doesn't match value ${value} of type ${typeof value} at index ${idx}`
40
+ );
41
+ }
42
+ }
43
+ }
44
+ }
45
+
46
+ // JSON.stringify takes care of converting Dates to ISO strings
47
+ const ret = jsonConverter.toPayload(values);
48
+ if (ret === undefined) {
49
+ throw new IllegalStateError('Could not convert search attributes to payloads');
50
+ }
51
+ return ret;
52
+ }
53
+
54
+ /**
55
+ * Datetime Search Attribute values are converted to `Date`s
56
+ */
57
+ public fromPayload<T>(payload: Payload): T {
58
+ if (payload.metadata === undefined || payload.metadata === null) {
59
+ throw new ValueError('Missing payload metadata');
60
+ }
61
+
62
+ const value = jsonConverter.fromPayload(payload);
63
+ let arrayWrappedValue = value instanceof Array ? value : [value];
64
+
65
+ const searchAttributeType = str(payload.metadata.type);
66
+ if (searchAttributeType === 'Datetime') {
67
+ arrayWrappedValue = arrayWrappedValue.map((dateString) => new Date(dateString));
68
+ }
69
+ return arrayWrappedValue as unknown as T;
70
+ }
71
+ }
@@ -1,7 +1,6 @@
1
- import type { coresdk } from '@temporalio/proto/lib/coresdk';
2
1
  import { TextDecoder, TextEncoder } from './encoding';
3
2
 
4
- export type Payload = coresdk.common.IPayload;
3
+ export { Payload } from '@temporalio/internal-workflow-common';
5
4
 
6
5
  /**
7
6
  * Transform an *ascii* string into a Uint8Array
package/src/failure.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { checkExtends, hasOwnProperties, isRecord } from '@temporalio/internal-workflow-common';
2
- import type { temporal } from '@temporalio/proto/lib/coresdk';
3
- import { arrayFromPayloads, fromPayloadsAtIndex, PayloadConverter, toPayloads } from './converter/payload-converter';
2
+ import type { temporal } from '@temporalio/proto';
3
+ import { PayloadConverter, arrayFromPayloads, fromPayloadsAtIndex, toPayloads } from './converter/payload-converter';
4
4
 
5
5
  export const FAILURE_SOURCE = 'TypeScriptSDK';
6
6
  export type ProtoFailure = temporal.api.failure.v1.IFailure;
@@ -225,9 +225,9 @@ const CUTOFF_STACK_PATTERNS = [
225
225
  /** Activity execution */
226
226
  /\s+at Activity\.execute \(.*[\\/]worker[\\/](?:src|lib)[\\/]activity\.[jt]s:\d+:\d+\)/,
227
227
  /** Workflow activation */
228
- /\s+at Activator\.\S+NextHandler \(webpack-internal:\/\/\/.*\/internals\.[jt]s:\d+:\d+\)/,
228
+ /\s+at Activator\.\S+NextHandler \(.*[\\/]workflow[\\/](?:src|lib)[\\/]internals\.[jt]s:\d+:\d+\)/,
229
229
  /** Workflow run anything in context */
230
- /\s+at Script\.runInContext/,
230
+ /\s+at Script\.runInContext \((?:node:vm|vm\.js):\d+:\d+\)/,
231
231
  ];
232
232
 
233
233
  /**
@@ -337,13 +337,22 @@ export function errorToFailure(err: unknown, payloadConverter: PayloadConverter)
337
337
  };
338
338
  }
339
339
 
340
- const recommendation = ` [A non-Error value was thrown from your code. We recommend throwing Error objects so that we can provide a stack trace.]`;
340
+ const recommendation = ` [A non-Error value was thrown from your code. We recommend throwing Error objects so that we can provide a stack trace]`;
341
341
 
342
342
  if (typeof err === 'string') {
343
343
  return { ...base, message: err + recommendation };
344
344
  }
345
+ if (typeof err === 'object') {
346
+ let message = '';
347
+ try {
348
+ message = JSON.stringify(err);
349
+ } catch (_err) {
350
+ message = String(err);
351
+ }
352
+ return { ...base, message: message + recommendation };
353
+ }
345
354
 
346
- return { ...base, message: JSON.stringify(err) + recommendation };
355
+ return { ...base, message: String(err) + recommendation };
347
356
  }
348
357
 
349
358
  /**
@@ -357,7 +366,8 @@ export function ensureTemporalFailure(err: unknown): TemporalFailure {
357
366
  if (err instanceof TemporalFailure) {
358
367
  return err;
359
368
  } else if (err instanceof Error) {
360
- const failure = new ApplicationFailure(err.message, err.name, false);
369
+ const name = err.constructor?.name ?? err.name;
370
+ const failure = new ApplicationFailure(err.message, name, false);
361
371
  failure.stack = err.stack;
362
372
  return failure;
363
373
  } else {
package/src/index.ts CHANGED
@@ -13,5 +13,6 @@ export * from './converter/data-converter';
13
13
  export * from './converter/payload-codec';
14
14
  export * from './converter/payload-converter';
15
15
  export * from './converter/payload-converters';
16
+ export * from './converter/json-payload-converter';
16
17
  export * from './converter/types';
17
18
  export * from './failure';
package/src/protobufs.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Entry point for classes and utilities related to using
3
- * [Protobufs](https://docs.temporal.io/docs/typescript/data-converters#protobufs) for serialization.
3
+ * [Protobufs](https://docs.temporal.io/typescript/data-converters#protobufs) for serialization.
4
4
  *
5
5
  * Import from `@temporalio/common/lib/protobufs`, for example:
6
6
  *