@outputai/core 0.8.1-next.e92f632.0 → 0.8.2-dev.e78f6b4.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/package.json +9 -10
- package/src/bus.js +1 -1
- package/src/consts.js +5 -2
- package/src/helpers/component.js +12 -0
- package/src/helpers/component.spec.js +54 -0
- package/src/helpers/fetch.js +105 -0
- package/src/helpers/fetch.spec.js +203 -0
- package/src/helpers/function.js +15 -0
- package/src/helpers/function.spec.js +48 -0
- package/src/helpers/object.js +98 -0
- package/src/helpers/object.spec.js +377 -0
- package/src/helpers/promise.js +29 -0
- package/src/helpers/promise.spec.js +35 -0
- package/src/helpers/string.js +30 -0
- package/src/helpers/string.spec.js +64 -0
- package/src/interface/evaluator.js +14 -12
- package/src/interface/evaluator.spec.js +10 -6
- package/src/interface/index.d.ts +7 -6
- package/src/interface/index.js +2 -0
- package/src/interface/logger.d.ts +53 -0
- package/src/interface/logger.js +68 -0
- package/src/interface/logger.spec.js +138 -0
- package/src/interface/step.js +15 -12
- package/src/interface/step.spec.js +10 -6
- package/src/interface/webhook.d.ts +21 -2
- package/src/interface/workflow.js +85 -78
- package/src/interface/workflow.spec.js +11 -4
- package/src/internal_activities/index.js +38 -35
- package/src/internal_activities/index.spec.js +27 -4
- package/src/logger/development.js +2 -2
- package/src/logger/development.spec.js +19 -2
- package/src/logger/production.js +1 -1
- package/src/logger/production.spec.js +24 -5
- package/src/sdk/README.md +47 -0
- package/src/sdk/helpers/component_metadata.d.ts +17 -0
- package/src/sdk/helpers/component_metadata.js +6 -0
- package/src/sdk/helpers/component_metadata.spec.js +30 -0
- package/src/sdk/helpers/index.d.ts +12 -0
- package/src/sdk/helpers/index.js +3 -0
- package/src/sdk/helpers/objects.d.ts +51 -0
- package/src/sdk/helpers/objects.js +8 -0
- package/src/sdk/helpers/objects.spec.js +16 -0
- package/src/sdk/helpers/path.d.ts +11 -0
- package/src/sdk/helpers/path.js +32 -0
- package/src/{utils/resolve_invocation_dir.spec.js → sdk/helpers/path.spec.js} +9 -9
- package/src/sdk/runtime/context.d.ts +30 -0
- package/src/sdk/runtime/context.js +15 -0
- package/src/{activity_integration → sdk/runtime}/context.spec.js +5 -5
- package/src/sdk/runtime/events.d.ts +15 -0
- package/src/sdk/runtime/events.js +18 -0
- package/src/{activity_integration → sdk/runtime}/events.spec.js +8 -9
- package/src/sdk/runtime/index.d.ts +12 -0
- package/src/sdk/runtime/index.js +3 -0
- package/src/sdk/runtime/tracing.d.ts +46 -0
- package/src/sdk/runtime/tracing.js +11 -0
- package/src/tracing/processors/s3/redis_client.spec.js +0 -6
- package/src/tracing/processors/s3/s3_client.spec.js +0 -6
- package/src/tracing/trace_engine.js +1 -1
- package/src/worker/catalog_workflow/catalog_job.js +1 -1
- package/src/worker/catalog_workflow/index.spec.js +8 -11
- package/src/worker/configs.js +14 -1
- package/src/worker/configs.spec.js +34 -1
- package/src/worker/connection_monitor.js +3 -14
- package/src/worker/connection_monitor.spec.js +4 -21
- package/src/worker/global_functions.js +14 -0
- package/src/worker/global_functions.spec.js +55 -0
- package/src/worker/index.js +11 -3
- package/src/worker/index.spec.js +29 -1
- package/src/worker/interceptors/activity.js +2 -2
- package/src/worker/interceptors/workflow.js +3 -3
- package/src/worker/interceptors/workflow.spec.js +1 -1
- package/src/worker/loader/matchers.js +1 -1
- package/src/worker/loader/tools.js +1 -1
- package/src/worker/loader/tools.spec.js +1 -1
- package/src/worker/log_hooks.js +14 -0
- package/src/worker/log_hooks.spec.js +83 -2
- package/src/worker/sinks.js +7 -1
- package/src/worker/sinks.spec.js +203 -0
- package/src/activity_integration/context.d.ts +0 -23
- package/src/activity_integration/context.js +0 -18
- package/src/activity_integration/event_id_integration.spec.js +0 -52
- package/src/activity_integration/events.d.ts +0 -10
- package/src/activity_integration/events.js +0 -15
- package/src/activity_integration/index.d.ts +0 -9
- package/src/activity_integration/index.js +0 -3
- package/src/activity_integration/tracing.d.ts +0 -40
- package/src/activity_integration/tracing.js +0 -48
- package/src/utils/index.d.ts +0 -180
- package/src/utils/index.js +0 -2
- package/src/utils/resolve_invocation_dir.js +0 -34
- package/src/utils/utils.js +0 -334
- package/src/utils/utils.spec.js +0 -723
- /package/src/{internal_utils → helpers}/aggregations.js +0 -0
- /package/src/{internal_utils → helpers}/aggregations.spec.js +0 -0
- /package/src/{internal_utils → helpers}/errors.js +0 -0
- /package/src/{internal_utils → helpers}/errors.spec.js +0 -0
- /package/src/{internal_utils → helpers}/temporal_context.js +0 -0
- /package/src/{internal_utils → helpers}/temporal_context.spec.ts +0 -0
- /package/src/{internal_utils → helpers}/trace_info.js +0 -0
- /package/src/{internal_utils → helpers}/trace_info.spec.js +0 -0
- /package/src/{internal_utils → helpers}/workflow_context.js +0 -0
- /package/src/{internal_utils → helpers}/workflow_context.spec.js +0 -0
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import type { Attribute } from '#trace_attribute';
|
|
2
|
-
|
|
3
|
-
export { Attribute } from '#trace_attribute';
|
|
4
|
-
/**
|
|
5
|
-
* Creates a new event.
|
|
6
|
-
*
|
|
7
|
-
* @param args
|
|
8
|
-
* @param args.id - A unique id for the Event.
|
|
9
|
-
* @param args.kind - The kind of Event, like HTTP, DiskWrite, DBOp, etc.
|
|
10
|
-
* @param args.name - The human-friendly name of the Event: query, request, create.
|
|
11
|
-
* @param args.details - Arbitrary data to add to this event, it will be used as the "input" field.
|
|
12
|
-
*/
|
|
13
|
-
export declare function addEventStart( args: { id: string; kind: string; name: string; details: unknown } ): void;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Concludes an event.
|
|
17
|
-
*
|
|
18
|
-
* @param args
|
|
19
|
-
* @param args.id - The id of the event to conclude.
|
|
20
|
-
* @param args.details - Arbitrary data to add to this event, it will be used as the "output" field.
|
|
21
|
-
*/
|
|
22
|
-
export declare function addEventEnd( args: { id: string; details: unknown } ): void;
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Concludes an event with an error.
|
|
26
|
-
*
|
|
27
|
-
* @param args
|
|
28
|
-
* @param args.id - The id of the event to conclude.
|
|
29
|
-
* @param args.details - Arbitrary data to add to this event, it will be used as the "error" field.
|
|
30
|
-
*/
|
|
31
|
-
export declare function addEventError( args: { id: string; details: unknown } ): void;
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Adds an attribute to an event.
|
|
35
|
-
*
|
|
36
|
-
* @param args
|
|
37
|
-
* @param args.eventId - The id of the event to attach the attribute to.
|
|
38
|
-
* @param args.attribute - The attribute to attach to the event.
|
|
39
|
-
*/
|
|
40
|
-
export declare function addEventAttribute( args: { eventId: string; attribute: Attribute.Instance } ): void;
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import { addEventActionWithContext, EventAction } from '#tracing';
|
|
2
|
-
|
|
3
|
-
export { Attribute } from '#trace_attribute';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Creates a new event.
|
|
7
|
-
*
|
|
8
|
-
* @param {object} args
|
|
9
|
-
* @param {string} args.id - A unique id for the Event.
|
|
10
|
-
* @param {string} args.kind - The kind of Event, like HTTP, DiskWrite, DBOp, etc.
|
|
11
|
-
* @param {string} args.name - The human-friendly name of the Event: query, request, create.
|
|
12
|
-
* @param {object} args.details - Arbitrary data to add to this event, it will be used as the "input" field.
|
|
13
|
-
* @returns {void}
|
|
14
|
-
*/
|
|
15
|
-
export const addEventStart = ( { id, kind, name, details } ) =>
|
|
16
|
-
addEventActionWithContext( EventAction.START, { kind, name, details, id } );
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Concludes an event.
|
|
20
|
-
*
|
|
21
|
-
* @param {object} args
|
|
22
|
-
* @param {string} args.id - The id of the event to conclude.
|
|
23
|
-
* @param {object} args.details - Arbitrary data to add to this event, it will be used as the "output" field.
|
|
24
|
-
* @returns {void}
|
|
25
|
-
*/
|
|
26
|
-
export const addEventEnd = ( { id, details } ) => addEventActionWithContext( EventAction.END, { id, details } );
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Concludes an event with an error.
|
|
30
|
-
*
|
|
31
|
-
* @param {object} args
|
|
32
|
-
* @param {string} args.id - The id of the event to conclude.
|
|
33
|
-
* @param {object} args.details - Arbitrary data to add to this event, it will be used as the "error" field.
|
|
34
|
-
* @returns {void}
|
|
35
|
-
*/
|
|
36
|
-
export const addEventError = ( { id, details } ) => addEventActionWithContext( EventAction.ERROR, { id, details } );
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Adds an attribute to an event.
|
|
40
|
-
*
|
|
41
|
-
* @param {object} args
|
|
42
|
-
* @param {string} args.eventId - The id of the event to attach the attribute to.
|
|
43
|
-
* @param {string} args.name - The attribute name
|
|
44
|
-
* @param {unknown} args.value - The attribute value
|
|
45
|
-
* @returns {void}
|
|
46
|
-
*/
|
|
47
|
-
export const addEventAttribute = ( { eventId, attribute } ) =>
|
|
48
|
-
addEventActionWithContext( EventAction.ADD_ATTR, { id: eventId, details: attribute } );
|
package/src/utils/index.d.ts
DELETED
|
@@ -1,180 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* > [!WARNING]
|
|
3
|
-
* > **Internal use only.** Not part of the public API; may change without notice.
|
|
4
|
-
*
|
|
5
|
-
* @packageDocumentation
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Return the first immediate directory of the file invoking the code that called this function.
|
|
10
|
-
*
|
|
11
|
-
* Excludes `@outputai/core`, node, and other internal paths.
|
|
12
|
-
*/
|
|
13
|
-
export function resolveInvocationDir(): string;
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Node safe clone implementation that doesn't use global structuredClone().
|
|
17
|
-
*
|
|
18
|
-
* Returns a cloned version of the object.
|
|
19
|
-
*
|
|
20
|
-
* Only clones static properties. Getters become static properties.
|
|
21
|
-
*
|
|
22
|
-
* @param object
|
|
23
|
-
*/
|
|
24
|
-
export function clone( object: object ): object;
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Receives an error as argument and throws it.
|
|
28
|
-
*
|
|
29
|
-
* @param error
|
|
30
|
-
* @throws {Error}
|
|
31
|
-
*/
|
|
32
|
-
export function throws( error: Error ): void;
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* Attach given value to an object with the METADATA_ACCESS_SYMBOL symbol as key.
|
|
36
|
-
*
|
|
37
|
-
* @param target
|
|
38
|
-
* @param value
|
|
39
|
-
* @returns
|
|
40
|
-
*/
|
|
41
|
-
export function setMetadata( target: object, value: object ): void;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Read metadata previously attached via setMetadata.
|
|
45
|
-
*
|
|
46
|
-
* @param target - The function or object to read metadata from.
|
|
47
|
-
* @returns The metadata object, or null if none is attached.
|
|
48
|
-
*/
|
|
49
|
-
export function getMetadata( target: Function ): { name: string; description?: string; type?: string } | null;
|
|
50
|
-
|
|
51
|
-
/** Represents a {Response} serialized to plain object */
|
|
52
|
-
export type SerializedFetchResponse = {
|
|
53
|
-
/** The response url */
|
|
54
|
-
url: string,
|
|
55
|
-
|
|
56
|
-
/** The response status code */
|
|
57
|
-
status: number,
|
|
58
|
-
|
|
59
|
-
/** The response status text */
|
|
60
|
-
statusText: string,
|
|
61
|
-
|
|
62
|
-
/** Flag indicating if the request succeeded */
|
|
63
|
-
ok: boolean,
|
|
64
|
-
|
|
65
|
-
/** Object with response headers */
|
|
66
|
-
headers: Record<string, string>,
|
|
67
|
-
|
|
68
|
-
/** Response body, either JSON, text or arrayBuffer converter to base64 */
|
|
69
|
-
body: object | string
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* Consumes an HTTP `Response` and serializes it to a plain object.
|
|
74
|
-
*
|
|
75
|
-
* @param response - The response to serialize.
|
|
76
|
-
* @returns SerializedFetchResponse
|
|
77
|
-
*/
|
|
78
|
-
export function serializeFetchResponse( response: Response ): SerializedFetchResponse;
|
|
79
|
-
|
|
80
|
-
export type SerializedBodyAndContentType = {
|
|
81
|
-
/** The body as a string when possible; otherwise the original value */
|
|
82
|
-
body: string | unknown,
|
|
83
|
-
/** The inferred `Content-Type` header value, if any */
|
|
84
|
-
contentType: string | undefined
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Serializes a payload for use as a fetch POST body and infers its `Content-Type`.
|
|
89
|
-
*
|
|
90
|
-
* @param body - The payload to serialize.
|
|
91
|
-
* @returns The serialized body and inferred `Content-Type`.
|
|
92
|
-
*/
|
|
93
|
-
export function serializeBodyAndInferContentType( body: unknown ): SerializedBodyAndContentType;
|
|
94
|
-
|
|
95
|
-
/**
|
|
96
|
-
* Returns true if the value is a plain object:
|
|
97
|
-
* - `{}`
|
|
98
|
-
* - `new Object()`
|
|
99
|
-
* - `Object.create(null)`
|
|
100
|
-
*
|
|
101
|
-
* @param object - The value to check.
|
|
102
|
-
* @returns Whether the value is a plain object.
|
|
103
|
-
*/
|
|
104
|
-
export function isPlainObject( object: unknown ): boolean;
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Returns a copy of an array with its content shuffled.
|
|
108
|
-
*
|
|
109
|
-
* @param arr - The array to shuffle
|
|
110
|
-
* @returns A shuffled array copy
|
|
111
|
-
*/
|
|
112
|
-
export function shuffleArray( arr: unknown[] ): unknown[];
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Creates a new object by merging object `b` onto object `a`, biased toward `b`:
|
|
116
|
-
* - Fields in `b` overwrite fields in `a`.
|
|
117
|
-
* - Fields in `b` that don't exist in `a` are created.
|
|
118
|
-
* - Fields in `a` that don't exist in `b` are left unchanged.
|
|
119
|
-
*
|
|
120
|
-
* @param a - The base object.
|
|
121
|
-
* @param b - The overriding object.
|
|
122
|
-
* @throws {Error} If either `a` or `b` is not a plain object.
|
|
123
|
-
* @returns A new merged object.
|
|
124
|
-
*/
|
|
125
|
-
export function deepMerge( a: object, b: object | null | undefined ): object;
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Creates a new object by merging object `b` onto object `a`, biased toward `b`:
|
|
129
|
-
* - Fields in `b` that don't exist in `a` are created.
|
|
130
|
-
* - Fields in `a` that don't exist in `b` are left unchanged.
|
|
131
|
-
* - Fields in `a` and `b` are passed as arguments to the resolve function (a,b) and its return assigns the new value.
|
|
132
|
-
*
|
|
133
|
-
* @param a - The base object.
|
|
134
|
-
* @param b - The overriding object.
|
|
135
|
-
* @param resolver - The resolver function.
|
|
136
|
-
* @throws {Error} If either `a` or `b` is not a plain object.
|
|
137
|
-
* @returns A new merged object.
|
|
138
|
-
*/
|
|
139
|
-
export function deepMergeWithResolver( a: object, b: object | null | undefined, resolver: function ): object;
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Shortens a UUID to a url-safe base64-like string (custom 64-char alphabet).
|
|
143
|
-
* Temporal-friendly: no Buffer or crypto; safe to use inside workflows.
|
|
144
|
-
*
|
|
145
|
-
* @param uuid - Standard UUID (e.g. `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`).
|
|
146
|
-
* @returns Short string using A–Z, a–z, 0–9, `_`, `-` (typically 21–22 chars).
|
|
147
|
-
*/
|
|
148
|
-
export function toUrlSafeBase64( uuid: string ): string;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Similar to native Promise.allSettled, but rejects with `{ isTimeout: true }`
|
|
152
|
-
* if the execution exceeds the given timeout.
|
|
153
|
-
*
|
|
154
|
-
* @param promises - Values or promises to wait for.
|
|
155
|
-
* @param timeoutMs - Maximum wait time in milliseconds.
|
|
156
|
-
* @returns Native Promise.allSettled-style results.
|
|
157
|
-
*/
|
|
158
|
-
export function allSettledWithTimeout<T>(
|
|
159
|
-
promises: Array<T | PromiseLike<T>>,
|
|
160
|
-
timeoutMs: number
|
|
161
|
-
): Promise<PromiseSettledResult<Awaited<T>>[]>;
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Promise wrapper that can be resolved externally.
|
|
165
|
-
*/
|
|
166
|
-
export class CancellablePromise {
|
|
167
|
-
/** The internal promise */
|
|
168
|
-
readonly promise: Promise<void>;
|
|
169
|
-
/** Whether the promise is already resolved or not */
|
|
170
|
-
readonly completed: boolean;
|
|
171
|
-
/** Resolves the promise */
|
|
172
|
-
complete(): void;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
/**
|
|
176
|
-
* Returns a function that invokes the wrapped function once.
|
|
177
|
-
*/
|
|
178
|
-
export function runOnce<Args extends unknown[], Return>(
|
|
179
|
-
fn: ( ...args: Args ) => Return
|
|
180
|
-
): ( ...args: Args ) => Return;
|
package/src/utils/index.js
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import * as stackTraceParser from 'stacktrace-parser';
|
|
2
|
-
|
|
3
|
-
// OS separator, but in a deterministic way, allowing this to work in Temporal's sandbox
|
|
4
|
-
// This avoids importing from node:path
|
|
5
|
-
const SEP = new Error().stack.includes( '/' ) ? '/' : '\\';
|
|
6
|
-
|
|
7
|
-
const transformSeparators = path => path.replaceAll( '/', SEP );
|
|
8
|
-
const defaultIgnorePaths = [
|
|
9
|
-
'/@outputai/core/',
|
|
10
|
-
'/@outputai/llm/',
|
|
11
|
-
'/@outputai/evals/',
|
|
12
|
-
'/sdk/core/',
|
|
13
|
-
'/sdk/llm/',
|
|
14
|
-
'/sdk/evals/',
|
|
15
|
-
'node:internal/',
|
|
16
|
-
'evalmachine.',
|
|
17
|
-
'webpack/bootstrap'
|
|
18
|
-
];
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Return the directory of the file invoking the code that called this function
|
|
22
|
-
* Excludes some internal paths and the sdk itself
|
|
23
|
-
*/
|
|
24
|
-
export default ( additionalIgnorePaths = [] ) => {
|
|
25
|
-
const stack = new Error().stack;
|
|
26
|
-
const lines = stackTraceParser.parse( stack );
|
|
27
|
-
const ignorePaths = [ ...additionalIgnorePaths, ...defaultIgnorePaths ].map( transformSeparators );
|
|
28
|
-
|
|
29
|
-
const frame = lines.find( l => !ignorePaths.some( p => l.file.includes( p ) ) );
|
|
30
|
-
if ( !frame ) {
|
|
31
|
-
throw new Error( `Invocation dir resolution via stack trace failed. Stack: ${stack}` );
|
|
32
|
-
}
|
|
33
|
-
return frame.file.replace( 'file://', '' ).split( SEP ).slice( 0, -1 ).join( SEP );
|
|
34
|
-
};
|
package/src/utils/utils.js
DELETED
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
import { METADATA_ACCESS_SYMBOL } from '#consts';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Node safe clone implementation that doesn't use global structuredClone()
|
|
5
|
-
* @param {object} v
|
|
6
|
-
* @returns {object}
|
|
7
|
-
*/
|
|
8
|
-
export const clone = v => {
|
|
9
|
-
try {
|
|
10
|
-
return JSON.parse( JSON.stringify( v ) );
|
|
11
|
-
} catch {
|
|
12
|
-
return v;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Detect a JS plain object.
|
|
18
|
-
*
|
|
19
|
-
* @param {unknown} v
|
|
20
|
-
* @returns {boolean}
|
|
21
|
-
*/
|
|
22
|
-
export const isPlainObject = v =>
|
|
23
|
-
typeof v === 'object' &&
|
|
24
|
-
!Array.isArray( v ) &&
|
|
25
|
-
v !== null &&
|
|
26
|
-
[ Object.prototype, null ].includes( Object.getPrototypeOf( v ) );
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Throw given error
|
|
30
|
-
* @param {Error} e
|
|
31
|
-
* @throws {e}
|
|
32
|
-
*/
|
|
33
|
-
export const throws = e => {
|
|
34
|
-
throw e;
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Add metadata "values" property to a given object
|
|
39
|
-
* @param {object} target
|
|
40
|
-
* @param {object} values
|
|
41
|
-
* @returns
|
|
42
|
-
*/
|
|
43
|
-
export const setMetadata = ( target, values ) =>
|
|
44
|
-
Object.defineProperty( target, METADATA_ACCESS_SYMBOL, { value: values, writable: false, enumerable: false, configurable: false } );
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Read metadata previously attached via setMetadata
|
|
48
|
-
* @param {Function} target
|
|
49
|
-
* @returns {object|null}
|
|
50
|
-
*/
|
|
51
|
-
export const getMetadata = target => target[METADATA_ACCESS_SYMBOL] ?? null;
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* Returns true if string value is stringbool and true
|
|
55
|
-
* @param {string} v
|
|
56
|
-
* @returns
|
|
57
|
-
*/
|
|
58
|
-
export const isStringboolTrue = v => [ '1', 'true', 'on' ].includes( v );
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Consume Fetch's HTTP Response and return a serialized version of it;
|
|
62
|
-
*
|
|
63
|
-
* @param {Response} response
|
|
64
|
-
* @returns {object} Serialized response
|
|
65
|
-
*/
|
|
66
|
-
export const serializeFetchResponse = async response => {
|
|
67
|
-
const headers = Object.fromEntries( response.headers );
|
|
68
|
-
const contentType = headers['content-type'] || '';
|
|
69
|
-
|
|
70
|
-
const body = await ( async () => {
|
|
71
|
-
if ( contentType.includes( 'application/json' ) ) {
|
|
72
|
-
return response.json();
|
|
73
|
-
}
|
|
74
|
-
if ( contentType.startsWith( 'text/' ) ) {
|
|
75
|
-
return response.text();
|
|
76
|
-
}
|
|
77
|
-
return response.arrayBuffer().then( buf => Buffer.from( buf ).toString( 'base64' ) );
|
|
78
|
-
} )();
|
|
79
|
-
|
|
80
|
-
return {
|
|
81
|
-
url: response.url,
|
|
82
|
-
status: response.status,
|
|
83
|
-
statusText: response.statusText,
|
|
84
|
-
ok: response.ok,
|
|
85
|
-
headers,
|
|
86
|
-
body
|
|
87
|
-
};
|
|
88
|
-
};
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Duck-typing to detect a Node Readable (Stream) without importing anything
|
|
92
|
-
*
|
|
93
|
-
* @param {unknown} v
|
|
94
|
-
* @returns {boolean}
|
|
95
|
-
*/
|
|
96
|
-
const isReadable = v =>
|
|
97
|
-
typeof v === 'object' &&
|
|
98
|
-
typeof v?.read === 'function' &&
|
|
99
|
-
typeof v?.on === 'function' &&
|
|
100
|
-
typeof v?.pipe === 'function' &&
|
|
101
|
-
v?.readable !== false;
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* Based on the type of a payload, serialized it to be send as the body of a fetch POST request and also infer its Content Type.
|
|
105
|
-
*
|
|
106
|
-
* Non serializable types versus Content-Type reference (for Node)
|
|
107
|
-
*
|
|
108
|
-
* |Type|Is self-describing)|Inferred type by fetch|Defined mime type|
|
|
109
|
-
* |-|-|-|-}
|
|
110
|
-
* |Blob|yes|`blob.type`||
|
|
111
|
-
* |File|yes|`file.type`||
|
|
112
|
-
* |FormData|yes|"multipart/form-data; boundary=..."||
|
|
113
|
-
* |URLSearchParams|yes|"application/x-www-form-urlencoded;charset=UTF-8"||
|
|
114
|
-
* |ArrayBuffer|no||"application/octet-stream"|
|
|
115
|
-
* |TypedArray (Uint8Array,Uint16Array)||"application/octet-stream"||
|
|
116
|
-
* |DataView|no||"application/octet-stream"|
|
|
117
|
-
* |ReadableStream, Readable, AsyncIterator|no||Can't, because stream must be read|
|
|
118
|
-
*
|
|
119
|
-
* If payload is none of the above types, test it:
|
|
120
|
-
* If the it is an object, serialize using JSON.stringify and set content-type to `application/json`;
|
|
121
|
-
* Else, it is a JS primitive, serialize using JSON.stringify and set content-type to `text/plain`;
|
|
122
|
-
*
|
|
123
|
-
* This implementation is overkill for temporal workflows since the only types available there will be:
|
|
124
|
-
* - URLSearchParams
|
|
125
|
-
* - ArrayBuffer
|
|
126
|
-
* - TypedArrays
|
|
127
|
-
* - DataView
|
|
128
|
-
* - asyncGenerator
|
|
129
|
-
* The others are non deterministic and are not available at runtime, but this function was build to be flexible
|
|
130
|
-
*
|
|
131
|
-
* @see {@link https://fetch.spec.whatwg.org/#bodyinit}
|
|
132
|
-
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch}
|
|
133
|
-
*
|
|
134
|
-
* @param {unknown} payload
|
|
135
|
-
* @returns {object} An object with the serialized body and inferred content-type
|
|
136
|
-
*/
|
|
137
|
-
export const serializeBodyAndInferContentType = payload => {
|
|
138
|
-
const dataTypes = [ Blob, File, URLSearchParams, FormData ];
|
|
139
|
-
|
|
140
|
-
// empty body
|
|
141
|
-
if ( [ null, undefined ].includes( payload ) ) {
|
|
142
|
-
return { body: undefined, contentType: undefined };
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Buffer types, covers ArrayBuffer, TypedArrays and DataView
|
|
146
|
-
if ( payload instanceof ArrayBuffer || ArrayBuffer.isView( payload ) ) {
|
|
147
|
-
return { body: payload, contentType: 'application/octet-stream' };
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// These data types auto assigned mime types
|
|
151
|
-
if ( dataTypes.some( t => payload instanceof t ) ) {
|
|
152
|
-
return { body: payload, contentType: undefined };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// ReadableStream, Readable and Async Iterator mimes cant be determined without reading it
|
|
156
|
-
if ( payload instanceof ReadableStream || typeof payload[Symbol.asyncIterator] === 'function' || isReadable( payload ) ) {
|
|
157
|
-
return { body: payload, contentType: undefined };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
if ( typeof payload === 'object' ) {
|
|
161
|
-
return { body: JSON.stringify( payload ), contentType: 'application/json; charset=UTF-8' };
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return { body: String( payload ), contentType: 'text/plain; charset=UTF-8' };
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Receives an array and returns a copy of it with the elements shuffled
|
|
169
|
-
*
|
|
170
|
-
* @param {array} arr
|
|
171
|
-
* @returns {array}
|
|
172
|
-
*/
|
|
173
|
-
export const shuffleArray = arr => arr
|
|
174
|
-
.map( v => ( { v, sort: Math.random() } ) )
|
|
175
|
-
.sort( ( a, b ) => a.sort - b.sort )
|
|
176
|
-
.map( ( { v } ) => v );
|
|
177
|
-
|
|
178
|
-
/**
|
|
179
|
-
* Creates a new object merging object "b" onto object "a", using a resolver function to define the value to keep.
|
|
180
|
-
* - Object "b" fields that also exists on "a" will have their value defined by the "resolver" function
|
|
181
|
-
* - Object "b" fields that don't exist on object "a" will be added;
|
|
182
|
-
* - Object "a" fields that don't exist on object "b" will be preserved;
|
|
183
|
-
*
|
|
184
|
-
* If "b" isn't an object, a new object equal to "a" is returned
|
|
185
|
-
*
|
|
186
|
-
* @param {object} a - The base object
|
|
187
|
-
* @param {object} b - The target object
|
|
188
|
-
* @param {function} resolver - A function that return the value to be kept. First argument is value a, second is value b
|
|
189
|
-
* @returns {object} A new object
|
|
190
|
-
*/
|
|
191
|
-
export const deepMergeWithResolver = ( a, b, resolver ) => {
|
|
192
|
-
if ( !isPlainObject( a ) ) {
|
|
193
|
-
throw new Error( 'Parameter "a" is not an object.' );
|
|
194
|
-
}
|
|
195
|
-
if ( !isPlainObject( b ) ) {
|
|
196
|
-
return clone( a );
|
|
197
|
-
}
|
|
198
|
-
return Object.entries( b ).reduce( ( obj, [ k, v ] ) =>
|
|
199
|
-
Object.assign( obj, {
|
|
200
|
-
[k]: ( () => {
|
|
201
|
-
if ( isPlainObject( v ) && isPlainObject( a[k] ) ) {
|
|
202
|
-
return deepMergeWithResolver( a[k], v, resolver );
|
|
203
|
-
}
|
|
204
|
-
if ( Object.hasOwn( a, k ) ) {
|
|
205
|
-
return resolver( a[k], v );
|
|
206
|
-
}
|
|
207
|
-
return v;
|
|
208
|
-
} )()
|
|
209
|
-
} )
|
|
210
|
-
, clone( a ) );
|
|
211
|
-
};
|
|
212
|
-
|
|
213
|
-
/**
|
|
214
|
-
* Creates a new object merging object "b" onto object "a" biased to "b":
|
|
215
|
-
* - Object "b" will overwrite fields on object "a";
|
|
216
|
-
* - Object "b" fields that don't exist on object "a" will be added;
|
|
217
|
-
* - Object "a" fields that don't exist on object "b" will be preserved;
|
|
218
|
-
*
|
|
219
|
-
* If "b" isn't an object, a new object equal to "a" is returned
|
|
220
|
-
*
|
|
221
|
-
* @param {object} a - The base object
|
|
222
|
-
* @param {object} b - The target object
|
|
223
|
-
* @returns {object} A new object
|
|
224
|
-
*/
|
|
225
|
-
export const deepMerge = ( a, b ) => deepMergeWithResolver( a, b, ( _, b ) => b );
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Shortens a UUID by re-encoding it to base62.
|
|
229
|
-
*
|
|
230
|
-
* This is a Temporal friendly, without crypto or Buffer.
|
|
231
|
-
* @param {string} uuid
|
|
232
|
-
* @returns {string}
|
|
233
|
-
*/
|
|
234
|
-
export const toUrlSafeBase64 = uuid => {
|
|
235
|
-
const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-';
|
|
236
|
-
const alphabetLen = alphabet.length;
|
|
237
|
-
const base = BigInt( alphabetLen );
|
|
238
|
-
const hex = uuid.replace( /-/g, '' );
|
|
239
|
-
|
|
240
|
-
const toDigits = n => n <= 0n ? [] : toDigits( n / base ).concat( alphabet[Number( n % base )] );
|
|
241
|
-
return toDigits( BigInt( '0x' + hex ) ).join( '' );
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
/**
|
|
245
|
-
* Similar to native Promise.allSettled but throws an Error if the execution exceeds a given time.
|
|
246
|
-
*
|
|
247
|
-
* The error thrown will have attribute `.isTimeout` as `true`.
|
|
248
|
-
*
|
|
249
|
-
* @template T
|
|
250
|
-
* @param {Array<T | PromiseLike<T>>} promises
|
|
251
|
-
* @param {number} timeoutMs
|
|
252
|
-
* @returns {Promise<PromiseSettledResult<Awaited<T>>[]>}
|
|
253
|
-
* @throws {Error & { isTimeout: true }}
|
|
254
|
-
*/
|
|
255
|
-
export const allSettledWithTimeout = ( () => {
|
|
256
|
-
class TimeoutError extends Error {
|
|
257
|
-
isTimeout = true;
|
|
258
|
-
constructor() {
|
|
259
|
-
super( 'Timed out before completing all promises' );
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return async ( promises, timeoutMs ) => {
|
|
264
|
-
if ( promises.length === 0 ) {
|
|
265
|
-
return [];
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const state = { timeoutMonitor: null };
|
|
269
|
-
|
|
270
|
-
try {
|
|
271
|
-
return await Promise.race( [
|
|
272
|
-
Promise.allSettled( promises ),
|
|
273
|
-
new Promise( ( _, reject ) => {
|
|
274
|
-
state.timeoutMonitor = setTimeout( () => reject( new TimeoutError() ), timeoutMs );
|
|
275
|
-
} )
|
|
276
|
-
] );
|
|
277
|
-
} finally {
|
|
278
|
-
clearTimeout( state.timeoutMonitor );
|
|
279
|
-
}
|
|
280
|
-
};
|
|
281
|
-
} )();
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Builds a promise that can be resolved from the outside.
|
|
285
|
-
*/
|
|
286
|
-
export class CancellablePromise {
|
|
287
|
-
#promise = null;
|
|
288
|
-
#complete = null;
|
|
289
|
-
#completed = false;
|
|
290
|
-
|
|
291
|
-
constructor() {
|
|
292
|
-
this.#promise = new Promise( resolve => {
|
|
293
|
-
this.#complete = () => {
|
|
294
|
-
resolve();
|
|
295
|
-
this.#completed = true;
|
|
296
|
-
};
|
|
297
|
-
} );
|
|
298
|
-
}
|
|
299
|
-
/** Retrieves the promise */
|
|
300
|
-
get promise() {
|
|
301
|
-
return this.#promise;
|
|
302
|
-
}
|
|
303
|
-
/** Returns whether the promise is resolved or not */
|
|
304
|
-
get completed() {
|
|
305
|
-
return this.#completed;
|
|
306
|
-
}
|
|
307
|
-
/** Resolves the promise */
|
|
308
|
-
complete() {
|
|
309
|
-
this.#complete();
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* Returns a function that invokes the fn argument when called once, further calls do nothing.
|
|
315
|
-
* @param {Function} fn
|
|
316
|
-
* @returns {Function}
|
|
317
|
-
*/
|
|
318
|
-
export const runOnce = fn => {
|
|
319
|
-
const state = { executed: false, result: undefined };
|
|
320
|
-
return ( ...args ) => {
|
|
321
|
-
if ( !state.executed ) {
|
|
322
|
-
state.executed = true;
|
|
323
|
-
return state.result = fn( ...args );
|
|
324
|
-
}
|
|
325
|
-
return state.result;
|
|
326
|
-
};
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
/**
|
|
330
|
-
* Escape regexp characters in a string
|
|
331
|
-
* @param {*} value
|
|
332
|
-
* @returns
|
|
333
|
-
*/
|
|
334
|
-
export const rxEscape = v => v.replace( /[.*+?^${}()|[\]\\]/g, '\\$&' );
|