@workglow/tasks 0.2.2 → 0.2.4
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/dist/browser.js +421 -76
- package/dist/browser.js.map +9 -6
- package/dist/bun.d.ts +1 -0
- package/dist/bun.d.ts.map +1 -1
- package/dist/bun.js +540 -68
- package/dist/bun.js.map +11 -7
- package/dist/common.d.ts +3 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/node.d.ts +1 -0
- package/dist/node.d.ts.map +1 -1
- package/dist/node.js +540 -68
- package/dist/node.js.map +11 -7
- package/dist/task/FetchUrlTask.d.ts +13 -0
- package/dist/task/FetchUrlTask.d.ts.map +1 -1
- package/dist/task/image/imageCodecLimits.d.ts +80 -0
- package/dist/task/image/imageCodecLimits.d.ts.map +1 -0
- package/dist/task/image/imageRasterCodecBrowser.d.ts.map +1 -1
- package/dist/task/image/imageRasterCodecNode.d.ts.map +1 -1
- package/dist/util/SafeFetch.d.ts +51 -0
- package/dist/util/SafeFetch.d.ts.map +1 -0
- package/dist/util/SafeFetch.server.d.ts +22 -0
- package/dist/util/SafeFetch.server.d.ts.map +1 -0
- package/dist/util/UrlClassifier.d.ts +64 -0
- package/dist/util/UrlClassifier.d.ts.map +1 -0
- package/package.json +13 -9
|
@@ -123,7 +123,20 @@ export declare class FetchUrlTask<Input extends FetchUrlTaskInput = FetchUrlTask
|
|
|
123
123
|
static title: string;
|
|
124
124
|
static description: string;
|
|
125
125
|
static hasDynamicSchemas: boolean;
|
|
126
|
+
static hasDynamicEntitlements: boolean;
|
|
126
127
|
static entitlements(): TaskEntitlements;
|
|
128
|
+
/**
|
|
129
|
+
* Dynamic entitlement check: when the configured URL targets a private or
|
|
130
|
+
* loopback host the task additionally requires `network:private`, scoped
|
|
131
|
+
* via the URL's origin so grants can be resource-limited (e.g. a dev-mode
|
|
132
|
+
* grant for `http://localhost:*`). The graph runner evaluates this before
|
|
133
|
+
* `execute()` runs, so a denied private URL never issues a network call.
|
|
134
|
+
*
|
|
135
|
+
* Root-task input may not yet be applied when entitlements are evaluated.
|
|
136
|
+
* If the URL is not available at this point, fail closed and require the
|
|
137
|
+
* private-network entitlement rather than under-declaring it.
|
|
138
|
+
*/
|
|
139
|
+
entitlements(): TaskEntitlements;
|
|
127
140
|
static configSchema(): DataPortSchema;
|
|
128
141
|
static inputSchema(): {
|
|
129
142
|
readonly type: "object";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FetchUrlTask.d.ts","sourceRoot":"","sources":["../../src/task/FetchUrlTask.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAEL,kBAAkB,EAClB,GAAG,EAGJ,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EACV,eAAe,EAEf,UAAU,EACV,gBAAgB,EACjB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,cAAc,
|
|
1
|
+
{"version":3,"file":"FetchUrlTask.d.ts","sourceRoot":"","sources":["../../src/task/FetchUrlTask.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Maximum number of decoded pixels (width * height) accepted by the image raster codec.
|
|
8
|
+
*
|
|
9
|
+
* Caps worst-case RGBA allocation at ~400 MiB (100 MP * 4 bytes/pixel). Legitimate
|
|
10
|
+
* photographic content rarely exceeds ~50 MP; synthetic pipelines that need more
|
|
11
|
+
* should bypass the codec and operate on ImageBinary directly.
|
|
12
|
+
*
|
|
13
|
+
* Defends against header-declared pixel bombs where a small compressed payload
|
|
14
|
+
* claims billions of pixels to force a downstream OOM.
|
|
15
|
+
*/
|
|
16
|
+
export declare const MAX_DECODED_PIXELS = 100000000;
|
|
17
|
+
/**
|
|
18
|
+
* Maximum raw (base64-decoded) byte size of an incoming data URI on the Node codec.
|
|
19
|
+
*
|
|
20
|
+
* This is a coarse pre-filter before format-specific decoding. The Node codec
|
|
21
|
+
* additionally enforces {@link MAX_DECODED_PIXELS} via sharp's header-level
|
|
22
|
+
* `limitInputPixels`, so 64 MiB is a comfortable ceiling on the server side.
|
|
23
|
+
*/
|
|
24
|
+
export declare const MAX_INPUT_BYTES_NODE: number;
|
|
25
|
+
/**
|
|
26
|
+
* Maximum raw byte size of an incoming data URI on the browser codec.
|
|
27
|
+
*
|
|
28
|
+
* The browser codec uses a stricter ceiling than {@link MAX_INPUT_BYTES_NODE}
|
|
29
|
+
* because `createImageBitmap` eagerly decompresses before we can observe the
|
|
30
|
+
* bitmap's dimensions. Bounding the compressed input is the primary defense;
|
|
31
|
+
* the post-bitmap `assertWithinPixelBudget` check only avoids the subsequent
|
|
32
|
+
* canvas + ImageData allocations.
|
|
33
|
+
*/
|
|
34
|
+
export declare const MAX_INPUT_BYTES_BROWSER: number;
|
|
35
|
+
/**
|
|
36
|
+
* Mime types rejected at decode time because rasterization would silently lose
|
|
37
|
+
* information (vector data, animation frames). Callers that need these formats
|
|
38
|
+
* must convert to PNG/JPEG/WebP externally before invoking the codec.
|
|
39
|
+
*
|
|
40
|
+
* Known limitations:
|
|
41
|
+
* - APNG declared as `image/png` cannot be distinguished by mime type alone;
|
|
42
|
+
* sharp will decode only the first frame. True APNG rejection requires
|
|
43
|
+
* post-decode metadata inspection (`pages > 1`).
|
|
44
|
+
* - Animated WebP declared as `image/webp` has the same limitation.
|
|
45
|
+
*/
|
|
46
|
+
export declare const REJECTED_DECODE_MIME_TYPES: ReadonlySet<string>;
|
|
47
|
+
/** Output formats the codec is willing to produce. Everything else throws at encode. */
|
|
48
|
+
export declare const SUPPORTED_OUTPUT_MIME_TYPES: readonly ["image/jpeg", "image/png", "image/webp"];
|
|
49
|
+
export type SupportedOutputMimeType = (typeof SUPPORTED_OUTPUT_MIME_TYPES)[number];
|
|
50
|
+
/**
|
|
51
|
+
* Throws if the decoded image would exceed {@link MAX_DECODED_PIXELS}, or if
|
|
52
|
+
* the dimensions are non-finite or non-positive.
|
|
53
|
+
*/
|
|
54
|
+
export declare function assertWithinPixelBudget(width: number, height: number): void;
|
|
55
|
+
/** Throws if `byteLength` exceeds `limit`. */
|
|
56
|
+
export declare function assertWithinByteBudget(byteLength: number, limit: number): void;
|
|
57
|
+
/**
|
|
58
|
+
* Throws unless `value` is a string that starts with `data:`. Defense in depth
|
|
59
|
+
* at the codec boundary — prevents the browser codec's `fetch(value)` from ever
|
|
60
|
+
* reaching the network (`http:`, `file:`, etc.) even if an upstream validator
|
|
61
|
+
* is removed or bypassed.
|
|
62
|
+
*/
|
|
63
|
+
export declare function assertIsDataUri(value: string): void;
|
|
64
|
+
/**
|
|
65
|
+
* Extracts the mime type from a data URI for pre-decode validation. Returns
|
|
66
|
+
* the lowercased mime type, or `undefined` if not parseable.
|
|
67
|
+
*
|
|
68
|
+
* Intentionally looser than `parseDataUri` in `@workglow/util/media`: this lets
|
|
69
|
+
* us report "unsupported svg+xml" before failing on an otherwise-malformed data
|
|
70
|
+
* URI, so the caller gets the most actionable error.
|
|
71
|
+
*/
|
|
72
|
+
export declare function extractDataUriMimeType(dataUri: string): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* Normalizes and validates an output mime type. Throws for unsupported or
|
|
75
|
+
* lossy types (e.g. `image/svg+xml`, `image/gif`) instead of silently falling
|
|
76
|
+
* through to PNG. Replaces the per-file `normalizeMimeType` helpers that used
|
|
77
|
+
* to mask format mismatches.
|
|
78
|
+
*/
|
|
79
|
+
export declare function normalizeOutputMimeType(mimeType: string): SupportedOutputMimeType;
|
|
80
|
+
//# sourceMappingURL=imageCodecLimits.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imageCodecLimits.d.ts","sourceRoot":"","sources":["../../../src/task/image/imageCodecLimits.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,YAAc,CAAC;AAE9C;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,QAAmB,CAAC;AAErD;;;;;;;;GAQG;AACH,eAAO,MAAM,uBAAuB,QAAkB,CAAC;AAEvD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,0BAA0B,EAAE,WAAW,CAAC,MAAM,CAKzD,CAAC;AAEH,wFAAwF;AACxF,eAAO,MAAM,2BAA2B,YAAI,YAAY,EAAE,WAAW,EAAE,YAAY,CAAU,CAAC;AAC9F,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnF;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAW3E;AAED,8CAA8C;AAC9C,wBAAgB,sBAAsB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAI9E;AA2BD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAKnD;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1E;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,uBAAuB,CAejF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageRasterCodecBrowser.d.ts","sourceRoot":"","sources":["../../../src/task/image/imageRasterCodecBrowser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"imageRasterCodecBrowser.d.ts","sourceRoot":"","sources":["../../../src/task/image/imageRasterCodecBrowser.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAaH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAiInE,wBAAgB,6BAA6B,IAAI,gBAAgB,CAEhE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"imageRasterCodecNode.d.ts","sourceRoot":"","sources":["../../../src/task/image/imageRasterCodecNode.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"imageRasterCodecNode.d.ts","sourceRoot":"","sources":["../../../src/task/image/imageRasterCodecNode.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAeH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAqHnE,wBAAgB,0BAA0B,IAAI,gBAAgB,CAE7D"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* SSRF-aware fetch wrapper.
|
|
7
|
+
*
|
|
8
|
+
* The browser default performs a static URL classification only and delegates
|
|
9
|
+
* to `globalThis.fetch`. The Node/Bun entrypoints register a server-side
|
|
10
|
+
* implementation (see `SafeFetch.server.ts`) that additionally resolves DNS,
|
|
11
|
+
* classifies every resolved address, and pins the connection to a specific
|
|
12
|
+
* IP via an undici Agent — this closes the DNS-rebinding gap.
|
|
13
|
+
*
|
|
14
|
+
* Callers pass `allowPrivate` to opt into private/loopback targets. The task
|
|
15
|
+
* layer sets this flag based on whether the task has been granted the
|
|
16
|
+
* `network:private` entitlement (via its dynamic `entitlements()`).
|
|
17
|
+
*/
|
|
18
|
+
export interface SafeFetchOptions extends RequestInit {
|
|
19
|
+
/**
|
|
20
|
+
* When true, requests to private/loopback/link-local/metadata hosts are
|
|
21
|
+
* permitted. When false (default), such requests throw PermanentJobError
|
|
22
|
+
* both at URL-classification time and (in the server impl) at DNS-resolution
|
|
23
|
+
* time — defeating DNS rebinding.
|
|
24
|
+
*/
|
|
25
|
+
readonly allowPrivate?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export type SafeFetchFn = (url: string, options: SafeFetchOptions) => Promise<Response>;
|
|
28
|
+
/**
|
|
29
|
+
* Register a platform-specific SafeFetch implementation. The Node/Bun
|
|
30
|
+
* entrypoints call this at module load time to install the DNS-resolving,
|
|
31
|
+
* connection-pinning implementation from `SafeFetch.server.ts`.
|
|
32
|
+
*
|
|
33
|
+
* Returns the previously registered implementation so callers can safely
|
|
34
|
+
* restore it after a temporary override.
|
|
35
|
+
*/
|
|
36
|
+
export declare function registerSafeFetch(fn: SafeFetchFn): SafeFetchFn;
|
|
37
|
+
/**
|
|
38
|
+
* Returns the currently registered SafeFetch implementation.
|
|
39
|
+
*/
|
|
40
|
+
export declare function getSafeFetchImpl(): SafeFetchFn;
|
|
41
|
+
/**
|
|
42
|
+
* Restores the default browser-safe implementation.
|
|
43
|
+
*/
|
|
44
|
+
export declare function resetSafeFetch(): void;
|
|
45
|
+
/**
|
|
46
|
+
* SSRF-aware fetch. See {@link SafeFetchOptions} for the `allowPrivate` flag.
|
|
47
|
+
* Throws `PermanentJobError` if the URL targets a private host without
|
|
48
|
+
* permission, or (server impl) if DNS resolves to a private IP.
|
|
49
|
+
*/
|
|
50
|
+
export declare function safeFetch(url: string, options?: SafeFetchOptions): Promise<Response>;
|
|
51
|
+
//# sourceMappingURL=SafeFetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeFetch.d.ts","sourceRoot":"","sources":["../../src/util/SafeFetch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AASH,MAAM,WAAW,gBAAiB,SAAQ,WAAW;IACnD;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;CACjC;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAgFxF;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,WAAW,GAAG,WAAW,CAI9D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,WAAW,CAE9C;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAErC;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAExF"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* Server-side SafeFetch implementation.
|
|
7
|
+
*
|
|
8
|
+
* Combines:
|
|
9
|
+
* 1. Static URL classification (shared with the browser impl).
|
|
10
|
+
* 2. DNS pre-resolution of every A/AAAA record for the hostname.
|
|
11
|
+
* 3. Rejection if any resolved address is private/link-local/metadata
|
|
12
|
+
* (unless `allowPrivate` is set).
|
|
13
|
+
* 4. Connection pinning via an undici Agent whose `connect.lookup` hook
|
|
14
|
+
* returns the pre-resolved IP — this prevents a second DNS lookup at
|
|
15
|
+
* connect time and defeats DNS rebinding (TOCTOU).
|
|
16
|
+
*
|
|
17
|
+
* Registered at module load from `packages/tasks/src/node.ts` and
|
|
18
|
+
* `packages/tasks/src/bun.ts` via `registerSafeFetch`.
|
|
19
|
+
*/
|
|
20
|
+
import { type SafeFetchFn } from "./SafeFetch";
|
|
21
|
+
export declare const serverSafeFetch: SafeFetchFn;
|
|
22
|
+
//# sourceMappingURL=SafeFetch.server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SafeFetch.server.d.ts","sourceRoot":"","sources":["../../src/util/SafeFetch.server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAMH,OAAO,EAAqB,KAAK,WAAW,EAAyB,MAAM,aAAa,CAAC;AAgHzF,eAAO,MAAM,eAAe,EAAE,WA+D7B,CAAC"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Steven Roussey <sroussey@gmail.com>
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*
|
|
6
|
+
* URL classifier used by {@link safeFetch} and {@link FetchUrlTask} to decide
|
|
7
|
+
* whether a URL targets a private/internal network host.
|
|
8
|
+
*
|
|
9
|
+
* The classifier is browser-safe (no Node built-ins) and performs only static
|
|
10
|
+
* analysis of the URL string — it does NOT perform DNS resolution. DNS-aware
|
|
11
|
+
* checking + connection pinning happens in `SafeFetch.server.ts` on Node/Bun.
|
|
12
|
+
*/
|
|
13
|
+
export type UrlClassificationKind = "public" | "private" | "invalid";
|
|
14
|
+
export interface UrlClassification {
|
|
15
|
+
readonly kind: UrlClassificationKind;
|
|
16
|
+
/** Human-readable reason, present when kind is "private" or "invalid". */
|
|
17
|
+
readonly reason?: string;
|
|
18
|
+
/** Normalized hostname (lowercase, trailing dots stripped, IPv6 brackets stripped). */
|
|
19
|
+
readonly host?: string;
|
|
20
|
+
/** Canonical dotted-quad IPv4 / RFC5952 IPv6 if the host is a literal IP. */
|
|
21
|
+
readonly literalIp?: string;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Accepts an IPv4 literal in any of the legacy forms accepted by inet_aton
|
|
25
|
+
* (decimal, hex `0x..`, octal `0..`, and 1/2/3/4-part notation) and returns
|
|
26
|
+
* its canonical dotted-quad form. Returns undefined if the host is not a
|
|
27
|
+
* valid IPv4 literal in any supported form.
|
|
28
|
+
*
|
|
29
|
+
* Examples:
|
|
30
|
+
* "127.0.0.1" → "127.0.0.1"
|
|
31
|
+
* "2130706433" → "127.0.0.1"
|
|
32
|
+
* "0x7f000001" → "127.0.0.1"
|
|
33
|
+
* "0177.0.0.1" → "127.0.0.1"
|
|
34
|
+
* "0x7f.1" → "127.0.0.1"
|
|
35
|
+
*/
|
|
36
|
+
export declare function tryNormalizeIPv4(host: string): string | undefined;
|
|
37
|
+
/**
|
|
38
|
+
* Classifies a literal IP address (v4 or v6) as public or private.
|
|
39
|
+
* Returns undefined if the address is not a valid IP literal.
|
|
40
|
+
*/
|
|
41
|
+
export declare function classifyIpLiteral(host: string): {
|
|
42
|
+
kind: "public" | "private";
|
|
43
|
+
reason?: string;
|
|
44
|
+
canonical: string;
|
|
45
|
+
} | undefined;
|
|
46
|
+
/**
|
|
47
|
+
* Statically classify a URL as public, private, or invalid.
|
|
48
|
+
*
|
|
49
|
+
* This is a pure string-level check — it does NOT perform DNS resolution.
|
|
50
|
+
* For DNS-aware protection against rebinding, use {@link safeFetch}.
|
|
51
|
+
*/
|
|
52
|
+
export declare function classifyUrl(urlStr: string): UrlClassification;
|
|
53
|
+
/**
|
|
54
|
+
* Returns the entitlement resource pattern for a URL, used when declaring
|
|
55
|
+
* a scoped `network:private` entitlement. The pattern covers any path/query
|
|
56
|
+
* under the same protocol+host(+port).
|
|
57
|
+
*
|
|
58
|
+
* Examples:
|
|
59
|
+
* http://localhost:3000/api → "http://localhost:3000/*"
|
|
60
|
+
* https://192.168.1.1/admin → "https://192.168.1.1/*"
|
|
61
|
+
* http://[::1]:8080/ → "http://[::1]:8080/*"
|
|
62
|
+
*/
|
|
63
|
+
export declare function urlResourcePattern(urlStr: string): string;
|
|
64
|
+
//# sourceMappingURL=UrlClassifier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"UrlClassifier.d.ts","sourceRoot":"","sources":["../../src/util/UrlClassifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAQH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;AAErE,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;IACrC,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,uFAAuF;IACvF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,6EAA6E;IAC7E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAwED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAqDjE;AAMD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,GACX;IAAE,IAAI,EAAE,QAAQ,GAAG,SAAS,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CA2ChF;AAoCD;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CA4C7D;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAYzD"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@workglow/tasks",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.2.
|
|
4
|
+
"version": "0.2.4",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "https://github.com/workglow-dev/workglow.git",
|
|
@@ -50,12 +50,16 @@
|
|
|
50
50
|
"publishConfig": {
|
|
51
51
|
"access": "public"
|
|
52
52
|
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"ipaddr.js": "^2.2.0",
|
|
55
|
+
"undici": "^8.0.2"
|
|
56
|
+
},
|
|
53
57
|
"peerDependencies": {
|
|
54
58
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
55
|
-
"@workglow/task-graph": "0.2.
|
|
56
|
-
"@workglow/util": "0.2.
|
|
57
|
-
"@workglow/job-queue": "0.2.
|
|
58
|
-
"@workglow/storage": "0.2.
|
|
59
|
+
"@workglow/task-graph": "0.2.4",
|
|
60
|
+
"@workglow/util": "0.2.4",
|
|
61
|
+
"@workglow/job-queue": "0.2.4",
|
|
62
|
+
"@workglow/storage": "0.2.4"
|
|
59
63
|
},
|
|
60
64
|
"peerDependenciesMeta": {
|
|
61
65
|
"@modelcontextprotocol/sdk": {
|
|
@@ -77,10 +81,10 @@
|
|
|
77
81
|
"devDependencies": {
|
|
78
82
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
79
83
|
"@types/papaparse": "^5.5.2",
|
|
80
|
-
"@workglow/job-queue": "0.2.
|
|
81
|
-
"@workglow/storage": "0.2.
|
|
82
|
-
"@workglow/task-graph": "0.2.
|
|
83
|
-
"@workglow/util": "0.2.
|
|
84
|
+
"@workglow/job-queue": "0.2.4",
|
|
85
|
+
"@workglow/storage": "0.2.4",
|
|
86
|
+
"@workglow/task-graph": "0.2.4",
|
|
87
|
+
"@workglow/util": "0.2.4"
|
|
84
88
|
},
|
|
85
89
|
"optionalDependencies": {
|
|
86
90
|
"papaparse": "^5.5.3",
|