@apify/actor-utils 0.1.0 → 0.1.3-beta.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/README.md +22 -17
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/src/qc-logger/assert.d.ts +17 -0
- package/dist/src/qc-logger/assert.d.ts.map +1 -0
- package/dist/src/qc-logger/assert.js +23 -0
- package/dist/src/qc-logger/assert.js.map +1 -0
- package/dist/src/qc-logger/checkpoint.d.ts +40 -0
- package/dist/src/qc-logger/checkpoint.d.ts.map +1 -0
- package/dist/src/qc-logger/checkpoint.js +45 -0
- package/dist/src/qc-logger/checkpoint.js.map +1 -0
- package/dist/src/qc-logger/index.d.ts +6 -0
- package/dist/src/qc-logger/index.d.ts.map +1 -0
- package/dist/src/qc-logger/index.js +5 -0
- package/dist/src/qc-logger/index.js.map +1 -0
- package/dist/src/qc-logger/is.d.ts +116 -0
- package/dist/src/qc-logger/is.d.ts.map +1 -0
- package/dist/src/qc-logger/is.js +26 -0
- package/dist/src/qc-logger/is.js.map +1 -0
- package/dist/src/qc-logger/structured-logger.d.ts +9 -0
- package/dist/src/qc-logger/structured-logger.d.ts.map +1 -0
- package/dist/src/qc-logger/structured-logger.js +38 -0
- package/dist/src/qc-logger/structured-logger.js.map +1 -0
- package/dist/src/safePushData.d.ts +46 -0
- package/dist/src/safePushData.d.ts.map +1 -0
- package/dist/src/safePushData.js +285 -0
- package/dist/src/safePushData.js.map +1 -0
- package/dist/src/type-utils/index.d.ts +3 -0
- package/dist/src/type-utils/index.d.ts.map +1 -0
- package/dist/src/type-utils/index.js +2 -0
- package/dist/src/type-utils/index.js.map +1 -0
- package/dist/src/type-utils/types.d.ts +23 -0
- package/dist/src/type-utils/types.d.ts.map +1 -0
- package/dist/src/type-utils/types.js +2 -0
- package/dist/src/type-utils/types.js.map +1 -0
- package/dist/src/type-utils/unreachable.d.ts +30 -0
- package/dist/src/type-utils/unreachable.d.ts.map +1 -0
- package/dist/src/type-utils/unreachable.js +32 -0
- package/dist/src/type-utils/unreachable.js.map +1 -0
- package/package.json +70 -59
package/README.md
CHANGED
|
@@ -47,25 +47,30 @@ every AJV error per item:
|
|
|
47
47
|
### Placeholder defaults
|
|
48
48
|
|
|
49
49
|
When a constraint fires on a path we placeholder'd ourselves, the wrapper
|
|
50
|
-
picks a value that should satisfy it
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
|
55
|
-
|
|
|
56
|
-
| `type:
|
|
57
|
-
| `type: array`
|
|
58
|
-
| `type: object`
|
|
59
|
-
| `type: null`
|
|
60
|
-
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
50
|
+
picks a value that should satisfy it. We deliberately only fill in the four
|
|
51
|
+
**empty** values below — they're unambiguously empty and can't be mistaken
|
|
52
|
+
for real data:
|
|
53
|
+
|
|
54
|
+
| AJV keyword | Placeholder value |
|
|
55
|
+
| -------------- | ----------------- |
|
|
56
|
+
| `type: string` | `''` |
|
|
57
|
+
| `type: array` | `[]` |
|
|
58
|
+
| `type: object` | `{}` |
|
|
59
|
+
| `type: null` | `null` |
|
|
60
|
+
| Anything else | Item is dropped. |
|
|
61
|
+
|
|
62
|
+
When a field allows **multiple types** (e.g. `['string', 'null']`), the
|
|
63
|
+
wrapper always picks `null` — it's the cleanest placeholder because it
|
|
64
|
+
commits to no concrete value at all.
|
|
65
|
+
|
|
66
|
+
Everything else (`enum`, `format`, `minLength`, numeric bounds, `type:
|
|
67
|
+
integer` / `number` / `boolean`, …) is **not** placeholdered: a made-up
|
|
68
|
+
email, a first-enum-value, or a fabricated number would silently poison the
|
|
69
|
+
customer's dataset with plausible-looking junk, so the item is dropped
|
|
70
|
+
instead.
|
|
66
71
|
|
|
67
72
|
The retry loop chases one layer of errors per round
|
|
68
|
-
(`required` → `type` →
|
|
73
|
+
(`required` → `type` → push) until either the push succeeds
|
|
69
74
|
or `maxAttempts` (default 5) is hit.
|
|
70
75
|
|
|
71
76
|
## Options
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAC9E,YAAY,EACR,eAAe,EACf,WAAW,EACX,kBAAkB,EAClB,mBAAmB,EACnB,MAAM,GACT,MAAM,uBAAuB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Ctx } from './structured-logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Glorified assertion that also logs at `error` level. Throws a plain `Error`
|
|
4
|
+
* by default; pass e.g. Crawlee's `NonRetryableError` or `CriticalError` to
|
|
5
|
+
* control what the failure means to the crawler.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const someEnvVar = process.env.SOME_ENV_VAR; // string | undefined
|
|
10
|
+
* assert(typeof someEnvVar === "string", "some-env-var");
|
|
11
|
+
* // someEnvVar is now guaranteed to be a `string`, unless the assertion fails.
|
|
12
|
+
* assert(someEnvVar, "some-env-var");
|
|
13
|
+
* // someEnvVar is now guaranteed to be a truthy `string` (non-empty), unless the assertion fails.
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function assert(cond: unknown, key: string, ctx?: Ctx, ErrorCtor?: new (message: string) => Error): asserts cond;
|
|
17
|
+
//# sourceMappingURL=assert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.d.ts","sourceRoot":"","sources":["../../../src/qc-logger/assert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAuB,MAAM,wBAAwB,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,wBAAgB,MAAM,CAClB,IAAI,EAAE,OAAO,EACb,GAAG,EAAE,MAAM,EACX,GAAG,CAAC,EAAE,GAAG,EACT,SAAS,GAAE,KAAK,OAAO,EAAE,MAAM,KAAK,KAAa,GAClD,OAAO,CAAC,IAAI,CAKd"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { emit, formatMessage } from './structured-logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Glorified assertion that also logs at `error` level. Throws a plain `Error`
|
|
4
|
+
* by default; pass e.g. Crawlee's `NonRetryableError` or `CriticalError` to
|
|
5
|
+
* control what the failure means to the crawler.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* ```ts
|
|
9
|
+
* const someEnvVar = process.env.SOME_ENV_VAR; // string | undefined
|
|
10
|
+
* assert(typeof someEnvVar === "string", "some-env-var");
|
|
11
|
+
* // someEnvVar is now guaranteed to be a `string`, unless the assertion fails.
|
|
12
|
+
* assert(someEnvVar, "some-env-var");
|
|
13
|
+
* // someEnvVar is now guaranteed to be a truthy `string` (non-empty), unless the assertion fails.
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export function assert(cond, key, ctx, ErrorCtor = Error) {
|
|
17
|
+
if (cond)
|
|
18
|
+
return;
|
|
19
|
+
const error = new ErrorCtor(formatMessage('assert', key));
|
|
20
|
+
emit('error', 'assert', key, { ...ctx, name: error.name, stack: error.stack });
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=assert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assert.js","sourceRoot":"","sources":["../../../src/qc-logger/assert.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,IAAI,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvE;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,MAAM,CAClB,IAAa,EACb,GAAW,EACX,GAAS,EACT,YAA4C,KAAK;IAEjD,IAAI,IAAI;QAAE,OAAO;IACjB,MAAM,KAAK,GAAG,IAAI,SAAS,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC;IAC1D,IAAI,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/E,MAAM,KAAK,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Ctx } from './structured-logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Logs an `info`-level checkpoint marking that a point in the run was reached.
|
|
4
|
+
* Unlike the `is*` predicates or {@link assert}, this has no condition — it
|
|
5
|
+
* always emits — so it's meant for tracing progress through a run.
|
|
6
|
+
*
|
|
7
|
+
* @param key - Identifies the checkpoint; emitted as `qc:checkpoint:<key>`.
|
|
8
|
+
* @param ctx - Optional extra fields to attach to the log line.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* checkpoint("started");
|
|
13
|
+
* // logs `qc:checkpoint:started`
|
|
14
|
+
*
|
|
15
|
+
* await doWork();
|
|
16
|
+
* checkpoint("work-done", { itemsProcessed: 42 });
|
|
17
|
+
* // logs `qc:checkpoint:work-done` with { itemsProcessed: 42 }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function checkpoint(key: string, ctx?: Ctx): void;
|
|
21
|
+
/**
|
|
22
|
+
* Conditionally logs an `info`-level checkpoint — only when `cond` is truthy.
|
|
23
|
+
* A convenience wrapper over {@link checkpoint} for guarding a marker behind a
|
|
24
|
+
* condition without an explicit `if` at the call site.
|
|
25
|
+
*
|
|
26
|
+
* @param cond - The condition; the checkpoint is emitted only when it's truthy.
|
|
27
|
+
* @param key - Identifies the checkpoint; emitted as `qc:checkpoint:<key>`.
|
|
28
|
+
* @param ctx - Optional extra fields to attach to the log line.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```ts
|
|
32
|
+
* checkpointIf(items.length === 0, "empty-batch");
|
|
33
|
+
* // logs `qc:checkpoint:empty-batch` only when the batch is empty
|
|
34
|
+
*
|
|
35
|
+
* checkpointIf(retries > 3, "many-retries", { retries });
|
|
36
|
+
* // logs `qc:checkpoint:many-retries` with { retries } only past the threshold
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export declare function checkpointIf(cond: unknown, key: string, ctx?: Ctx): void;
|
|
40
|
+
//# sourceMappingURL=checkpoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../../src/qc-logger/checkpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAQ,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAEvD;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAExE"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { emit } from './structured-logger.js';
|
|
2
|
+
/**
|
|
3
|
+
* Logs an `info`-level checkpoint marking that a point in the run was reached.
|
|
4
|
+
* Unlike the `is*` predicates or {@link assert}, this has no condition — it
|
|
5
|
+
* always emits — so it's meant for tracing progress through a run.
|
|
6
|
+
*
|
|
7
|
+
* @param key - Identifies the checkpoint; emitted as `qc:checkpoint:<key>`.
|
|
8
|
+
* @param ctx - Optional extra fields to attach to the log line.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* checkpoint("started");
|
|
13
|
+
* // logs `qc:checkpoint:started`
|
|
14
|
+
*
|
|
15
|
+
* await doWork();
|
|
16
|
+
* checkpoint("work-done", { itemsProcessed: 42 });
|
|
17
|
+
* // logs `qc:checkpoint:work-done` with { itemsProcessed: 42 }
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function checkpoint(key, ctx) {
|
|
21
|
+
emit('info', 'checkpoint', key, ctx);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Conditionally logs an `info`-level checkpoint — only when `cond` is truthy.
|
|
25
|
+
* A convenience wrapper over {@link checkpoint} for guarding a marker behind a
|
|
26
|
+
* condition without an explicit `if` at the call site.
|
|
27
|
+
*
|
|
28
|
+
* @param cond - The condition; the checkpoint is emitted only when it's truthy.
|
|
29
|
+
* @param key - Identifies the checkpoint; emitted as `qc:checkpoint:<key>`.
|
|
30
|
+
* @param ctx - Optional extra fields to attach to the log line.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* checkpointIf(items.length === 0, "empty-batch");
|
|
35
|
+
* // logs `qc:checkpoint:empty-batch` only when the batch is empty
|
|
36
|
+
*
|
|
37
|
+
* checkpointIf(retries > 3, "many-retries", { retries });
|
|
38
|
+
* // logs `qc:checkpoint:many-retries` with { retries } only past the threshold
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function checkpointIf(cond, key, ctx) {
|
|
42
|
+
if (cond)
|
|
43
|
+
checkpoint(key, ctx);
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=checkpoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint.js","sourceRoot":"","sources":["../../../src/qc-logger/checkpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW,EAAE,GAAS;IAC7C,IAAI,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;AACzC,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,YAAY,CAAC,IAAa,EAAE,GAAW,EAAE,GAAS;IAC9D,IAAI,IAAI;QAAE,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { checkpoint, checkpointIf } from './checkpoint.js';
|
|
2
|
+
export { assert } from './assert.js';
|
|
3
|
+
export { isFalsy, isTruthy, isNullish, isDefined } from './is.js';
|
|
4
|
+
export { emit, formatMessage } from './structured-logger.js';
|
|
5
|
+
export type { Ctx } from './structured-logger.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/qc-logger/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EAAE,GAAG,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/qc-logger/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAClE,OAAO,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import type { Defined, Falsy, Nullish, Truthy } from '../type-utils/types.js';
|
|
2
|
+
import { type Ctx } from './structured-logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Checks for falsy values and logs a `warning` when they are.
|
|
5
|
+
*
|
|
6
|
+
* Sample usage:
|
|
7
|
+
* ```ts
|
|
8
|
+
* if (isFalsy(someValue, "my-key-here")) {
|
|
9
|
+
* // someValue is falsy, warning gets logged `qc:is:falsy:my-key-here`
|
|
10
|
+
* return; // do my early return
|
|
11
|
+
* }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* The overloads narrow the return type based on what's statically known about
|
|
15
|
+
* `value`: a {@link Truthy} input returns the literal `false`, a {@link Falsy}
|
|
16
|
+
* input returns the literal `true`, and only genuinely uncertain values get the
|
|
17
|
+
* `value is Falsy & T` type guard. This means a redundant call — e.g.
|
|
18
|
+
* `isFalsy` on something the compiler already knows is truthy — produces a
|
|
19
|
+
* branch whose condition is a constant.
|
|
20
|
+
*
|
|
21
|
+
* Enable the `@typescript-eslint/no-unnecessary-condition` rule to have that
|
|
22
|
+
* surfaced as a lint error instead of a silent dead branch. The rule ships with
|
|
23
|
+
* both [typescript-eslint](https://typescript-eslint.io/rules/no-unnecessary-condition/)
|
|
24
|
+
* and [oxlint](https://oxc.rs/docs/guide/usage/linter/rules/typescript/no-unnecessary-condition.html)
|
|
25
|
+
* (note: it requires type-aware linting).
|
|
26
|
+
*/
|
|
27
|
+
export declare function isFalsy<T>(value: Truthy<T>, key: string, ctx?: Ctx): false;
|
|
28
|
+
export declare function isFalsy(value: Falsy, key: string, ctx?: Ctx): true;
|
|
29
|
+
export declare function isFalsy<T>(value: T, key: string, ctx?: Ctx): value is Falsy & T;
|
|
30
|
+
/**
|
|
31
|
+
* Checks for truthy values and logs a `warning` when they are — the
|
|
32
|
+
* inverse of {@link isFalsy}.
|
|
33
|
+
*
|
|
34
|
+
* Sample usage:
|
|
35
|
+
* ```ts
|
|
36
|
+
* if (isTruthy(someValue, "my-key-here")) {
|
|
37
|
+
* // someValue is truthy, warning gets logged `qc:is:truthy:my-key-here`
|
|
38
|
+
* return someValue; // do my early return
|
|
39
|
+
* }
|
|
40
|
+
* // fallback behavior here
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* Mirroring {@link isFalsy}, the overloads narrow the return type based on what's
|
|
44
|
+
* statically known about `value`: a {@link Falsy} input returns the literal
|
|
45
|
+
* `false`, a {@link Truthy} input returns the literal `true`, and only genuinely
|
|
46
|
+
* uncertain values get the `value is Truthy<T>` type guard. A redundant call —
|
|
47
|
+
* e.g. `isTruthy` on something the compiler already knows is falsy — produces a
|
|
48
|
+
* branch whose condition is a constant.
|
|
49
|
+
*
|
|
50
|
+
* Enable the `@typescript-eslint/no-unnecessary-condition` rule to have that
|
|
51
|
+
* surfaced as a lint error instead of a silent dead branch. The rule ships with
|
|
52
|
+
* both [typescript-eslint](https://typescript-eslint.io/rules/no-unnecessary-condition/)
|
|
53
|
+
* and [oxlint](https://oxc.rs/docs/guide/usage/linter/rules/typescript/no-unnecessary-condition.html)
|
|
54
|
+
* (note: it requires type-aware linting).
|
|
55
|
+
*/
|
|
56
|
+
export declare function isTruthy(value: Falsy, key: string, ctx?: Ctx): false;
|
|
57
|
+
export declare function isTruthy<T>(value: Truthy<T>, key: string, ctx?: Ctx): true;
|
|
58
|
+
export declare function isTruthy<T>(value: T, key: string, ctx?: Ctx): value is Truthy<T>;
|
|
59
|
+
/**
|
|
60
|
+
* Checks for `null | undefined` values and logs a `warning` when they are.
|
|
61
|
+
* Unlike {@link isFalsy}, `0`, `false`, and `""` are not considered a match.
|
|
62
|
+
*
|
|
63
|
+
* Sample usage:
|
|
64
|
+
* ```ts
|
|
65
|
+
* if (isNullish(someValue, "my-key-here")) {
|
|
66
|
+
* // someValue is null or undefined, warning gets logged `qc:is:nullish:my-key-here`
|
|
67
|
+
* return; // do my early return
|
|
68
|
+
* }
|
|
69
|
+
* // keep on truckin'
|
|
70
|
+
* ```
|
|
71
|
+
*
|
|
72
|
+
* Like {@link isFalsy}, the overloads narrow the return type based on what's
|
|
73
|
+
* statically known about `value`: a {@link Defined} input returns the literal
|
|
74
|
+
* `false`, a {@link Nullish} input returns the literal `true`, and only
|
|
75
|
+
* genuinely uncertain values get the `value is Nullish & T` type guard. A
|
|
76
|
+
* redundant call — e.g. `isNullish` on something the compiler already knows is
|
|
77
|
+
* defined — produces a branch whose condition is a constant.
|
|
78
|
+
*
|
|
79
|
+
* Enable the `@typescript-eslint/no-unnecessary-condition` rule to have that
|
|
80
|
+
* surfaced as a lint error instead of a silent dead branch. The rule ships with
|
|
81
|
+
* both [typescript-eslint](https://typescript-eslint.io/rules/no-unnecessary-condition/)
|
|
82
|
+
* and [oxlint](https://oxc.rs/docs/guide/usage/linter/rules/typescript/no-unnecessary-condition.html)
|
|
83
|
+
* (note: it requires type-aware linting).
|
|
84
|
+
*/
|
|
85
|
+
export declare function isNullish<T>(value: Defined<T>, key: string, ctx?: Ctx): false;
|
|
86
|
+
export declare function isNullish(value: Nullish, key: string, ctx?: Ctx): true;
|
|
87
|
+
export declare function isNullish<T>(value: T, key: string, ctx?: Ctx): value is Nullish & T;
|
|
88
|
+
/**
|
|
89
|
+
* Checks that a value is neither `null` nor `undefined` and logs a
|
|
90
|
+
* `warning` when that's the case — the inverse of {@link isNullish}.
|
|
91
|
+
*
|
|
92
|
+
* Sample usage:
|
|
93
|
+
* ```ts
|
|
94
|
+
* if (isDefined(someValue, "my-key-here")) {
|
|
95
|
+
* // someValue is neither null nor undefined, warning gets logged `qc:is:defined:my-key-here`
|
|
96
|
+
* return; // do my early return
|
|
97
|
+
* }
|
|
98
|
+
* ```
|
|
99
|
+
*
|
|
100
|
+
* Like {@link isFalsy}, the overloads narrow the return type based on what's
|
|
101
|
+
* statically known about `value`: a {@link Nullish} input returns the literal
|
|
102
|
+
* `false`, a {@link Defined} input returns the literal `true`, and only
|
|
103
|
+
* genuinely uncertain values get the `value is Defined<T>` type guard. A
|
|
104
|
+
* redundant call — e.g. `isDefined` on something the compiler already knows is
|
|
105
|
+
* defined — produces a branch whose condition is a constant.
|
|
106
|
+
*
|
|
107
|
+
* Enable the `@typescript-eslint/no-unnecessary-condition` rule to have that
|
|
108
|
+
* surfaced as a lint error instead of a silent dead branch. The rule ships with
|
|
109
|
+
* both [typescript-eslint](https://typescript-eslint.io/rules/no-unnecessary-condition/)
|
|
110
|
+
* and [oxlint](https://oxc.rs/docs/guide/usage/linter/rules/typescript/no-unnecessary-condition.html)
|
|
111
|
+
* (note: it requires type-aware linting).
|
|
112
|
+
*/
|
|
113
|
+
export declare function isDefined(value: Nullish, key: string, ctx?: Ctx): false;
|
|
114
|
+
export declare function isDefined<T>(value: Defined<T>, key: string, ctx?: Ctx): true;
|
|
115
|
+
export declare function isDefined<T>(value: T, key: string, ctx?: Ctx): value is Defined<T>;
|
|
116
|
+
//# sourceMappingURL=is.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is.d.ts","sourceRoot":"","sources":["../../../src/qc-logger/is.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAC9E,OAAO,EAAE,KAAK,GAAG,EAAQ,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC;AAC5E,wBAAgB,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;AACpE,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,IAAI,KAAK,GAAG,CAAC,CAAC;AAOjF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC;AACtE,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;AAC5E,wBAAgB,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC;AAOlF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC;AAC/E,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;AACxE,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,IAAI,OAAO,GAAG,CAAC,CAAC;AAOrF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC;AACzE,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC;AAC9E,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { emit } from './structured-logger.js';
|
|
2
|
+
export function isFalsy(value, key, ctx) {
|
|
3
|
+
const result = !value;
|
|
4
|
+
if (result)
|
|
5
|
+
emit('warning', 'is:falsy', key, ctx);
|
|
6
|
+
return result;
|
|
7
|
+
}
|
|
8
|
+
export function isTruthy(value, key, ctx) {
|
|
9
|
+
const result = Boolean(value);
|
|
10
|
+
if (result)
|
|
11
|
+
emit('warning', 'is:truthy', key, ctx);
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
export function isNullish(value, key, ctx) {
|
|
15
|
+
const result = value === undefined || value === null;
|
|
16
|
+
if (result)
|
|
17
|
+
emit('warning', 'is:nullish', key, ctx);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
export function isDefined(value, key, ctx) {
|
|
21
|
+
const result = value !== undefined && value !== null;
|
|
22
|
+
if (result)
|
|
23
|
+
emit('warning', 'is:defined', key, ctx);
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=is.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is.js","sourceRoot":"","sources":["../../../src/qc-logger/is.ts"],"names":[],"mappings":"AACA,OAAO,EAAY,IAAI,EAAE,MAAM,wBAAwB,CAAC;AA6BxD,MAAM,UAAU,OAAO,CAAI,KAAQ,EAAE,GAAW,EAAE,GAAS;IACvD,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC;IACtB,IAAI,MAAM;QAAE,IAAI,CAAC,SAAS,EAAE,UAAU,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IAClD,OAAO,MAAM,CAAC;AAClB,CAAC;AA+BD,MAAM,UAAU,QAAQ,CAAI,KAAQ,EAAE,GAAW,EAAE,GAAS;IACxD,MAAM,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,IAAI,MAAM;QAAE,IAAI,CAAC,SAAS,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACnD,OAAO,MAAM,CAAC;AAClB,CAAC;AA+BD,MAAM,UAAU,SAAS,CAAI,KAAQ,EAAE,GAAW,EAAE,GAAS;IACzD,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC;IACrD,IAAI,MAAM;QAAE,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC;AAClB,CAAC;AA8BD,MAAM,UAAU,SAAS,CAAI,KAAQ,EAAE,GAAW,EAAE,GAAS;IACzD,MAAM,MAAM,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC;IACrD,IAAI,MAAM;QAAE,IAAI,CAAC,SAAS,EAAE,YAAY,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;IACpD,OAAO,MAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type Ctx = Record<string, unknown>;
|
|
2
|
+
/**
|
|
3
|
+
* Builds the canonical log line (`qc:<verb>:<key>`) without emitting it.
|
|
4
|
+
* Exposed so callers (e.g. `assert`) can reuse the exact same message when
|
|
5
|
+
* constructing an error to throw.
|
|
6
|
+
*/
|
|
7
|
+
export declare function formatMessage(qcVerb: string, rawKey: string): string;
|
|
8
|
+
export declare function emit(level: 'debug' | 'info' | 'warning' | 'error', qcVerb: string, rawKey: string, ctx?: Ctx): string;
|
|
9
|
+
//# sourceMappingURL=structured-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-logger.d.ts","sourceRoot":"","sources":["../../../src/qc-logger/structured-logger.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAiB1C;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED,wBAAgB,IAAI,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,CAcrH"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import log from '@apify/log';
|
|
2
|
+
/**
|
|
3
|
+
* Keys are part of the log line's parse structure (`qc:<verb>:<key>`)
|
|
4
|
+
* Turns any string into a valid qc key.
|
|
5
|
+
*
|
|
6
|
+
* If a key is completely invalid, it is replaced with "invalid-key".
|
|
7
|
+
*/
|
|
8
|
+
function normalizeKey(key) {
|
|
9
|
+
return (String(key)
|
|
10
|
+
.toLowerCase()
|
|
11
|
+
.replace(/[^a-z0-9-]+/g, '-')
|
|
12
|
+
.replace(/^-|-$/g, '') || 'invalid-key');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Builds the canonical log line (`qc:<verb>:<key>`) without emitting it.
|
|
16
|
+
* Exposed so callers (e.g. `assert`) can reuse the exact same message when
|
|
17
|
+
* constructing an error to throw.
|
|
18
|
+
*/
|
|
19
|
+
export function formatMessage(qcVerb, rawKey) {
|
|
20
|
+
return `qc:${qcVerb}:${normalizeKey(rawKey)}`;
|
|
21
|
+
}
|
|
22
|
+
export function emit(level, qcVerb, rawKey, ctx) {
|
|
23
|
+
let message;
|
|
24
|
+
try {
|
|
25
|
+
const qcKey = normalizeKey(rawKey);
|
|
26
|
+
message = formatMessage(qcVerb, rawKey);
|
|
27
|
+
// Caller ctx is spread first so it can never clobber the canonical fields.
|
|
28
|
+
// Run/actor identity is not attached here — Mezmo enriches lines with it.
|
|
29
|
+
log[level](message, { ...ctx, level, qcKey, qcVerb });
|
|
30
|
+
return message;
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Telemetry must never break a run.
|
|
34
|
+
message ??= `qc:unknown:qc-error-generating-key`;
|
|
35
|
+
return message;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=structured-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"structured-logger.js","sourceRoot":"","sources":["../../../src/qc-logger/structured-logger.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,YAAY,CAAC;AAI7B;;;;;GAKG;AACH,SAAS,YAAY,CAAC,GAAW;IAC7B,OAAO,CACH,MAAM,CAAC,GAAG,CAAC;SACN,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,aAAa,CAC9C,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc,EAAE,MAAc;IACxD,OAAO,MAAM,MAAM,IAAI,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,IAAI,CAAC,KAA6C,EAAE,MAAc,EAAE,MAAc,EAAE,GAAS;IACzG,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACnC,OAAO,GAAG,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACxC,2EAA2E;QAC3E,0EAA0E;QAC1E,GAAG,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,EAAE,GAAG,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QACtD,OAAO,OAAO,CAAC;IACnB,CAAC;IAAC,MAAM,CAAC;QACL,oCAAoC;QACpC,OAAO,KAAK,oCAAoC,CAAC;QACjD,OAAO,OAAO,CAAC;IACnB,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
declare const SCHEMA_ERROR_TYPE = "schema-validation-error";
|
|
2
|
+
export interface ValidationError {
|
|
3
|
+
instancePath: string;
|
|
4
|
+
schemaPath?: string;
|
|
5
|
+
keyword: string;
|
|
6
|
+
params?: Record<string, unknown>;
|
|
7
|
+
message?: string;
|
|
8
|
+
}
|
|
9
|
+
interface InvalidItem {
|
|
10
|
+
itemPosition: number;
|
|
11
|
+
validationErrors: ValidationError[];
|
|
12
|
+
}
|
|
13
|
+
interface SchemaValidationError {
|
|
14
|
+
type: typeof SCHEMA_ERROR_TYPE;
|
|
15
|
+
statusCode: 400;
|
|
16
|
+
message: string;
|
|
17
|
+
data: {
|
|
18
|
+
invalidItems: InvalidItem[];
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare function isSchemaValidationError(err: unknown): err is SchemaValidationError;
|
|
22
|
+
export interface DroppedItem<T> {
|
|
23
|
+
item: T;
|
|
24
|
+
errors: ValidationError[];
|
|
25
|
+
}
|
|
26
|
+
export interface SafePushDataResult<T> {
|
|
27
|
+
pushed: number;
|
|
28
|
+
dropped: DroppedItem<T>[];
|
|
29
|
+
attempts: number;
|
|
30
|
+
}
|
|
31
|
+
export interface SafePushDataOptions {
|
|
32
|
+
maxAttempts?: number;
|
|
33
|
+
}
|
|
34
|
+
export type PushFn<T> = (items: T[]) => Promise<unknown>;
|
|
35
|
+
/**
|
|
36
|
+
* Push `input` via `pushFn`, surviving Apify dataset schema-validation
|
|
37
|
+
* failures by cleaning offending items and retrying.
|
|
38
|
+
*
|
|
39
|
+
* `pushFn` is mandatory and intentionally not bundled — a CI check forbids
|
|
40
|
+
* direct `.pushData()` calls in this library, so the binding lives at the
|
|
41
|
+
* call site: `(b) => Actor.pushData(b)` or
|
|
42
|
+
* `(b) => client.dataset(id).pushItems(b)`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function safePushData<T>(pushFn: PushFn<T>, input: T | T[], options?: SafePushDataOptions): Promise<SafePushDataResult<T>>;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=safePushData.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safePushData.d.ts","sourceRoot":"","sources":["../../src/safePushData.ts"],"names":[],"mappings":"AAWA,QAAA,MAAM,iBAAiB,4BAA4B,CAAC;AAKpD,MAAM,WAAW,eAAe;IAC5B,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,WAAW;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,eAAe,EAAE,CAAC;CACvC;AAKD,UAAU,qBAAqB;IAC3B,IAAI,EAAE,OAAO,iBAAiB,CAAC;IAC/B,UAAU,EAAE,GAAG,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE;QAAE,YAAY,EAAE,WAAW,EAAE,CAAA;KAAE,CAAC;CACzC;AAED,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,GAAG,IAAI,qBAAqB,CAMlF;AAED,MAAM,WAAW,WAAW,CAAC,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC;IACR,MAAM,EAAE,eAAe,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,kBAAkB,CAAC,CAAC;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEzD;;;;;;;;GAQG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAChC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,EACjB,KAAK,EAAE,CAAC,GAAG,CAAC,EAAE,EACd,OAAO,GAAE,mBAAwB,GAClC,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAehC"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
// safePushData: parse the Apify dataset schema-validation error, repair the
|
|
2
|
+
// offending items (strip bad fields, placeholder missing required ones), and
|
|
3
|
+
// retry the push.
|
|
4
|
+
//
|
|
5
|
+
// NOTE: instead of recursively healing the data one error-round at a time, we
|
|
6
|
+
// could parse the Actor's `dataset_schema.json` up front and fix every item in
|
|
7
|
+
// a single pass (we'd know each field's expected type / constraints without
|
|
8
|
+
// waiting for the API to report them). That would avoid the multi-round retry
|
|
9
|
+
// loop, but requires heavier code (locating + loading the schema, resolving
|
|
10
|
+
// $refs, walking the schema tree). Something to consider in the future.
|
|
11
|
+
const SCHEMA_ERROR_TYPE = 'schema-validation-error';
|
|
12
|
+
export function isSchemaValidationError(err) {
|
|
13
|
+
if (!err || typeof err !== 'object')
|
|
14
|
+
return false;
|
|
15
|
+
const e = err;
|
|
16
|
+
if (e.type !== SCHEMA_ERROR_TYPE)
|
|
17
|
+
return false;
|
|
18
|
+
if (e.statusCode !== 400)
|
|
19
|
+
return false;
|
|
20
|
+
return Array.isArray(e.data?.invalidItems);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Push `input` via `pushFn`, surviving Apify dataset schema-validation
|
|
24
|
+
* failures by cleaning offending items and retrying.
|
|
25
|
+
*
|
|
26
|
+
* `pushFn` is mandatory and intentionally not bundled — a CI check forbids
|
|
27
|
+
* direct `.pushData()` calls in this library, so the binding lives at the
|
|
28
|
+
* call site: `(b) => Actor.pushData(b)` or
|
|
29
|
+
* `(b) => client.dataset(id).pushItems(b)`.
|
|
30
|
+
*/
|
|
31
|
+
export async function safePushData(pushFn, input, options = {}) {
|
|
32
|
+
const items = Array.isArray(input) ? input : [input];
|
|
33
|
+
// Happy path: assume validation will succeed (the overwhelmingly common
|
|
34
|
+
// case). No working copies, no maps, no per-item wrapper objects — just
|
|
35
|
+
// hand the caller's array to pushFn and return on success.
|
|
36
|
+
try {
|
|
37
|
+
await pushFn(items);
|
|
38
|
+
return { pushed: items.length, dropped: [], attempts: 1 };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
if (!isSchemaValidationError(err))
|
|
42
|
+
throw err;
|
|
43
|
+
// Clamp to >=1: the initial push above always counts as one attempt,
|
|
44
|
+
// so 0/negative would make the reported `attempts` lie about it.
|
|
45
|
+
return cleanAndRetry(pushFn, items, err, Math.max(1, options.maxAttempts ?? 5));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async function cleanAndRetry(pushFn, originalItems, initialError, maxAttempts) {
|
|
49
|
+
// working[i] is what we'll send on the next push. We mutate this array
|
|
50
|
+
// in place (splicing drops, replacing cleaned entries); the caller's
|
|
51
|
+
// `originalItems` is never touched.
|
|
52
|
+
const working = originalItems.slice();
|
|
53
|
+
// Parallel to `working`. Holds the original (untouched) reference so a
|
|
54
|
+
// dropped report shows what the caller actually passed in, even if the
|
|
55
|
+
// item was partially cleaned before being dropped on a later round.
|
|
56
|
+
const originalAt = originalItems.slice();
|
|
57
|
+
// Parallel to `working`. Tracks which paths inside each item are
|
|
58
|
+
// placeholders we set (vs. real user data). Needed so we can chase
|
|
59
|
+
// follow-up type/minLength/enum errors on the placeholder field
|
|
60
|
+
// without looping forever; for user-supplied fields the existing
|
|
61
|
+
// "delete the field" behaviour stays in effect.
|
|
62
|
+
const placeholderPaths = originalItems.map(() => new Set());
|
|
63
|
+
// Parallel to `working`. The validation errors that were last reported
|
|
64
|
+
// for this position — kept so a give-up drop (maxAttempts exceeded) can
|
|
65
|
+
// still report *why*, not just that it gave up.
|
|
66
|
+
const lastErrorsAt = originalItems.map(() => []);
|
|
67
|
+
const dropped = [];
|
|
68
|
+
let attempts = 1;
|
|
69
|
+
let lastError = initialError;
|
|
70
|
+
while (true) {
|
|
71
|
+
// Process this round's errors. Highest position first so the splices
|
|
72
|
+
// below don't shift positions we still need to look at.
|
|
73
|
+
const invalids = lastError.data.invalidItems.slice().sort((a, b) => b.itemPosition - a.itemPosition);
|
|
74
|
+
for (const invalid of invalids) {
|
|
75
|
+
const i = invalid.itemPosition;
|
|
76
|
+
// Guard against a malformed/unexpected error payload (e.g. a
|
|
77
|
+
// position outside the batch we actually sent) instead of
|
|
78
|
+
// crashing on `working[i]` being undefined.
|
|
79
|
+
if (i < 0 || i >= working.length) {
|
|
80
|
+
console.log(`safePushData: ignoring out-of-range itemPosition ${i} in validation error response.`);
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
const cleaned = cleanItemFields(working[i], invalid.validationErrors, placeholderPaths[i]);
|
|
84
|
+
if (cleaned === null) {
|
|
85
|
+
dropped.push({ item: originalAt[i], errors: invalid.validationErrors });
|
|
86
|
+
working.splice(i, 1);
|
|
87
|
+
originalAt.splice(i, 1);
|
|
88
|
+
placeholderPaths.splice(i, 1);
|
|
89
|
+
lastErrorsAt.splice(i, 1);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
working[i] = cleaned;
|
|
93
|
+
lastErrorsAt[i] = invalid.validationErrors;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
console.log(`safePushData: schema validation failed on attempt ${attempts}: ` +
|
|
97
|
+
`${lastError.data.invalidItems.length} invalid item(s); ` +
|
|
98
|
+
`retrying with ${working.length} item(s).`);
|
|
99
|
+
if (working.length === 0) {
|
|
100
|
+
return { pushed: originalItems.length - dropped.length, dropped, attempts };
|
|
101
|
+
}
|
|
102
|
+
attempts++;
|
|
103
|
+
if (attempts > maxAttempts) {
|
|
104
|
+
console.log(`safePushData: gave up after ${maxAttempts} attempts with ${working.length} item(s) still failing.`);
|
|
105
|
+
for (let i = 0; i < working.length; i++) {
|
|
106
|
+
dropped.push({ item: originalAt[i], errors: lastErrorsAt[i] });
|
|
107
|
+
}
|
|
108
|
+
return { pushed: originalItems.length - dropped.length, dropped, attempts: maxAttempts };
|
|
109
|
+
}
|
|
110
|
+
try {
|
|
111
|
+
await pushFn(working);
|
|
112
|
+
return { pushed: originalItems.length - dropped.length, dropped, attempts };
|
|
113
|
+
}
|
|
114
|
+
catch (err) {
|
|
115
|
+
if (!isSchemaValidationError(err))
|
|
116
|
+
throw err;
|
|
117
|
+
lastError = err;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Try to repair a single item given its AJV errors. Returns null when the
|
|
122
|
+
// item can't be salvaged.
|
|
123
|
+
//
|
|
124
|
+
// Mutates `placeholderPaths` to record any fields we filled in ourselves,
|
|
125
|
+
// so the caller can keep iterating on them across rounds.
|
|
126
|
+
function cleanItemFields(item, validationErrors, placeholderPaths) {
|
|
127
|
+
// structuredClone so we never mutate the caller's data.
|
|
128
|
+
const cloned = structuredClone(item);
|
|
129
|
+
for (const err of validationErrors) {
|
|
130
|
+
const instancePath = err.instancePath || '';
|
|
131
|
+
const path = parseJsonPointer(instancePath);
|
|
132
|
+
// Root-level errors describe the item as a whole.
|
|
133
|
+
if (path.length === 0) {
|
|
134
|
+
// Missing required field: insert a placeholder and remember we
|
|
135
|
+
// did so. The next round will see a `type` error on this path
|
|
136
|
+
// and we'll upgrade null to a type-appropriate value.
|
|
137
|
+
if (err.keyword === 'required' && typeof err.params?.missingProperty === 'string') {
|
|
138
|
+
const prop = err.params.missingProperty;
|
|
139
|
+
cloned[prop] = null;
|
|
140
|
+
placeholderPaths.add(`/${prop}`);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
// Strip an unknown property reported at the root.
|
|
144
|
+
if (err.keyword === 'additionalProperties' && typeof err.params?.additionalProperty === 'string') {
|
|
145
|
+
delete cloned[err.params.additionalProperty];
|
|
146
|
+
continue;
|
|
147
|
+
}
|
|
148
|
+
// type/format/etc. at the root means the item itself is the wrong shape.
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
// Errors on a path we placeholder'd: try to satisfy the constraint
|
|
152
|
+
// rather than delete the field (deleting would re-trigger required).
|
|
153
|
+
if (placeholderPaths.has(instancePath)) {
|
|
154
|
+
const fix = placeholderFor(err);
|
|
155
|
+
if (fix.ok) {
|
|
156
|
+
setAtPath(cloned, path, fix.value);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
// Constraint we don't know how to satisfy on a placeholder field
|
|
160
|
+
// (e.g. pattern, custom format). Give up on this item.
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
// additionalProperties errors point at the *parent* object; the
|
|
164
|
+
// offending key is in params, not in instancePath.
|
|
165
|
+
if (err.keyword === 'additionalProperties' && typeof err.params?.additionalProperty === 'string') {
|
|
166
|
+
deleteAtPath(cloned, [...path, err.params.additionalProperty]);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
// User-supplied field with a violation we don't try to coerce.
|
|
170
|
+
// Strip it; if the schema declares it required, the next push will
|
|
171
|
+
// re-add a placeholder.
|
|
172
|
+
deleteAtPath(cloned, path);
|
|
173
|
+
}
|
|
174
|
+
return cloned;
|
|
175
|
+
}
|
|
176
|
+
// Pick a value that will satisfy `err.keyword` on a placeholder field.
|
|
177
|
+
// Returns ok:false when we don't have a sensible default; the caller drops
|
|
178
|
+
// the item in that case.
|
|
179
|
+
//
|
|
180
|
+
// We deliberately only placeholder the four "empty" values — `''`, `[]`, `{}`,
|
|
181
|
+
// and `null`. These are unambiguously empty and can't be mistaken for real
|
|
182
|
+
// data. We do NOT fabricate values for `enum`, `format`, `minLength`, numeric
|
|
183
|
+
// bounds, etc.: a made-up email, a first-enum-value, or a `'_'.repeat(N)`
|
|
184
|
+
// string all silently poison the customer's dataset with plausible-looking
|
|
185
|
+
// junk. Better to drop the item than to lie about its contents. As a result
|
|
186
|
+
// the only keyword we handle is `type` (only for those four target types) —
|
|
187
|
+
// everything else falls through to ok:false and the item is dropped.
|
|
188
|
+
function placeholderFor(err) {
|
|
189
|
+
const params = err.params ?? {};
|
|
190
|
+
if (err.keyword !== 'type')
|
|
191
|
+
return { ok: false };
|
|
192
|
+
// params.type is the expected type as a string, or an array of strings
|
|
193
|
+
// when the field allows multiple types (e.g. `['string', 'null']`).
|
|
194
|
+
const types = Array.isArray(params.type) ? params.type : [params.type];
|
|
195
|
+
// Union type that permits null: prefer null. It's the cleanest possible
|
|
196
|
+
// placeholder — it commits to no concrete value at all — so whenever the
|
|
197
|
+
// schema allows it, that's what we use.
|
|
198
|
+
if (types.length > 1 && types.includes('null')) {
|
|
199
|
+
return { ok: true, value: null };
|
|
200
|
+
}
|
|
201
|
+
// Otherwise take the first allowed type we have an "empty" default for.
|
|
202
|
+
// integer / number / boolean are intentionally absent: 0 / false read as
|
|
203
|
+
// real data, so a field of only those types is dropped instead.
|
|
204
|
+
for (const t of types) {
|
|
205
|
+
switch (t) {
|
|
206
|
+
case 'null':
|
|
207
|
+
return { ok: true, value: null };
|
|
208
|
+
case 'string':
|
|
209
|
+
return { ok: true, value: '' };
|
|
210
|
+
case 'array':
|
|
211
|
+
return { ok: true, value: [] };
|
|
212
|
+
case 'object':
|
|
213
|
+
return { ok: true, value: {} };
|
|
214
|
+
default:
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return { ok: false };
|
|
219
|
+
}
|
|
220
|
+
// Parse a JSON Pointer (RFC 6901) into decoded segments.
|
|
221
|
+
// "" -> []; "/foo/bar" -> ["foo","bar"]; "/tags/0" -> ["tags","0"].
|
|
222
|
+
function parseJsonPointer(pointer) {
|
|
223
|
+
if (!pointer)
|
|
224
|
+
return [];
|
|
225
|
+
return pointer
|
|
226
|
+
.split('/')
|
|
227
|
+
.slice(1)
|
|
228
|
+
.map((seg) => seg.replace(/~1/g, '/').replace(/~0/g, '~'));
|
|
229
|
+
}
|
|
230
|
+
// Delete the value at `path` inside `obj`. Arrays splice (so later
|
|
231
|
+
// `/tags/N` errors in the same round line up with their original indices).
|
|
232
|
+
function deleteAtPath(obj, path) {
|
|
233
|
+
if (path.length === 0)
|
|
234
|
+
return false;
|
|
235
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
236
|
+
let cursor = obj;
|
|
237
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
238
|
+
const key = path[i];
|
|
239
|
+
if (cursor == null || typeof cursor !== 'object')
|
|
240
|
+
return false;
|
|
241
|
+
cursor = Array.isArray(cursor) ? cursor[Number(key)] : cursor[key];
|
|
242
|
+
}
|
|
243
|
+
if (cursor == null || typeof cursor !== 'object')
|
|
244
|
+
return false;
|
|
245
|
+
const last = path[path.length - 1];
|
|
246
|
+
if (Array.isArray(cursor)) {
|
|
247
|
+
const idx = Number(last);
|
|
248
|
+
if (!Number.isInteger(idx) || idx < 0 || idx >= cursor.length)
|
|
249
|
+
return false;
|
|
250
|
+
cursor.splice(idx, 1);
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
if (Object.prototype.hasOwnProperty.call(cursor, last)) {
|
|
254
|
+
delete cursor[last];
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
// Set the value at `path` inside `obj`. Creates nothing — the path must
|
|
260
|
+
// already exist (placeholder fields are created at the root, not nested).
|
|
261
|
+
function setAtPath(obj, path, value) {
|
|
262
|
+
if (path.length === 0)
|
|
263
|
+
return false;
|
|
264
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
265
|
+
let cursor = obj;
|
|
266
|
+
for (let i = 0; i < path.length - 1; i++) {
|
|
267
|
+
const key = path[i];
|
|
268
|
+
if (cursor == null || typeof cursor !== 'object')
|
|
269
|
+
return false;
|
|
270
|
+
cursor = Array.isArray(cursor) ? cursor[Number(key)] : cursor[key];
|
|
271
|
+
}
|
|
272
|
+
if (cursor == null || typeof cursor !== 'object')
|
|
273
|
+
return false;
|
|
274
|
+
const last = path[path.length - 1];
|
|
275
|
+
if (Array.isArray(cursor)) {
|
|
276
|
+
const idx = Number(last);
|
|
277
|
+
if (!Number.isInteger(idx) || idx < 0)
|
|
278
|
+
return false;
|
|
279
|
+
cursor[idx] = value;
|
|
280
|
+
return true;
|
|
281
|
+
}
|
|
282
|
+
cursor[last] = value;
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=safePushData.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"safePushData.js","sourceRoot":"","sources":["../../src/safePushData.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/type-utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/type-utils/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type Falsy = false | 0 | '' | null | undefined;
|
|
2
|
+
export type Nullish = null | undefined;
|
|
3
|
+
/**
|
|
4
|
+
* Narrows `T` to only its truthy members by stripping every {@link Falsy}
|
|
5
|
+
* value (`false`, `0`, `''`, `null`, `undefined`).
|
|
6
|
+
*
|
|
7
|
+
* Unlike `Exclude<T, Falsy>`, this checks each falsy literal individually so a
|
|
8
|
+
* broad type such as `boolean` or `number` is preserved rather than collapsed:
|
|
9
|
+
* `boolean` only loses `false` if `false` is the whole type, not when it's part
|
|
10
|
+
* of `boolean`. Object types short-circuit first, so `''`/`0` don't accidentally
|
|
11
|
+
* match structural (`{}`) types.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* type A = Truthy<string | undefined>; // string
|
|
16
|
+
* type B = Truthy<0 | 1 | 2>; // 1 | 2
|
|
17
|
+
* type C = Truthy<'' | 'hello'>; // 'hello'
|
|
18
|
+
* type D = Truthy<false>; // never
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export type Truthy<T> = T extends object ? T : false extends T ? never : 0 extends T ? never : '' extends T ? never : null extends T ? never : undefined extends T ? never : T;
|
|
22
|
+
export type Defined<T> = Exclude<T, Nullish>;
|
|
23
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/type-utils/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,KAAK,GAAG,KAAK,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,GAAG,SAAS,CAAC;AACtD,MAAM,MAAM,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC;AAEvC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,IAEhB,CAAC,SAAS,MAAM,GACV,CAAC,GACD,KAAK,SAAS,CAAC,GACb,KAAK,GACL,CAAC,SAAS,CAAC,GACT,KAAK,GACL,EAAE,SAAS,CAAC,GACV,KAAK,GACL,IAAI,SAAS,CAAC,GACZ,KAAK,GACL,SAAS,SAAS,CAAC,GACjB,KAAK,GACL,CAAC,CAAC;AAEtB,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/type-utils/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asserts that a code path is unreachable, enabling exhaustiveness checks.
|
|
3
|
+
*
|
|
4
|
+
* Pass a value of type `never` to this function to let the TypeScript compiler
|
|
5
|
+
* verify that all cases of a union have been handled. If a new variant is added
|
|
6
|
+
* to the union but not handled, the call becomes a compile-time error. At
|
|
7
|
+
* runtime, reaching this function throws an `Error`.
|
|
8
|
+
*
|
|
9
|
+
* @param x - The value that should be of type `never` at this point.
|
|
10
|
+
* @throws {Error} Always throws, since this code should never be reached.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* type Shape = 'circle' | 'square';
|
|
15
|
+
*
|
|
16
|
+
* function area(shape: Shape): number {
|
|
17
|
+
* switch (shape) {
|
|
18
|
+
* case 'circle':
|
|
19
|
+
* return Math.PI;
|
|
20
|
+
* case 'square':
|
|
21
|
+
* return 1;
|
|
22
|
+
* default:
|
|
23
|
+
* // Compile-time error here if a new Shape variant is unhandled.
|
|
24
|
+
* return unreachable(shape);
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function unreachable(x: never): never;
|
|
30
|
+
//# sourceMappingURL=unreachable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unreachable.d.ts","sourceRoot":"","sources":["../../../src/type-utils/unreachable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,GAAG,KAAK,CAE3C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asserts that a code path is unreachable, enabling exhaustiveness checks.
|
|
3
|
+
*
|
|
4
|
+
* Pass a value of type `never` to this function to let the TypeScript compiler
|
|
5
|
+
* verify that all cases of a union have been handled. If a new variant is added
|
|
6
|
+
* to the union but not handled, the call becomes a compile-time error. At
|
|
7
|
+
* runtime, reaching this function throws an `Error`.
|
|
8
|
+
*
|
|
9
|
+
* @param x - The value that should be of type `never` at this point.
|
|
10
|
+
* @throws {Error} Always throws, since this code should never be reached.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```ts
|
|
14
|
+
* type Shape = 'circle' | 'square';
|
|
15
|
+
*
|
|
16
|
+
* function area(shape: Shape): number {
|
|
17
|
+
* switch (shape) {
|
|
18
|
+
* case 'circle':
|
|
19
|
+
* return Math.PI;
|
|
20
|
+
* case 'square':
|
|
21
|
+
* return 1;
|
|
22
|
+
* default:
|
|
23
|
+
* // Compile-time error here if a new Shape variant is unhandled.
|
|
24
|
+
* return unreachable(shape);
|
|
25
|
+
* }
|
|
26
|
+
* }
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export function unreachable(x) {
|
|
30
|
+
throw new Error(`unreachable: ${x}`);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=unreachable.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unreachable.js","sourceRoot":"","sources":["../../../src/type-utils/unreachable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,WAAW,CAAC,CAAQ;IAChC,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;AACzC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,63 +1,74 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
"name": "@apify/actor-utils",
|
|
3
|
+
"version": "0.1.3-beta.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Wrapper around Actor.pushData that survives dataset schema-validation failures by stripping offending fields and retrying. Callers pass the actual push function as pushFn.",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "https://github.com/apify/apify-actor-utils.git"
|
|
9
|
+
},
|
|
10
|
+
"engines": {
|
|
11
|
+
"node": ">=22.6.0"
|
|
12
|
+
},
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"main": "./dist/index.js",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
9
19
|
},
|
|
10
|
-
"
|
|
11
|
-
|
|
20
|
+
"./qc-logger": {
|
|
21
|
+
"types": "./dist/src/qc-logger/index.d.ts",
|
|
22
|
+
"default": "./dist/src/qc-logger/index.js"
|
|
12
23
|
},
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
"
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
24
|
+
"./type-utils": {
|
|
25
|
+
"types": "./dist/src/type-utils/index.d.ts",
|
|
26
|
+
"default": "./dist/src/type-utils/index.js"
|
|
27
|
+
}
|
|
28
|
+
},
|
|
29
|
+
"files": [
|
|
30
|
+
"dist/index.js",
|
|
31
|
+
"dist/index.js.map",
|
|
32
|
+
"dist/index.d.ts",
|
|
33
|
+
"dist/index.d.ts.map",
|
|
34
|
+
"dist/src"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "tsc",
|
|
38
|
+
"typecheck": "tsc --noEmit",
|
|
39
|
+
"lint": "eslint",
|
|
40
|
+
"lint:fix": "eslint --fix",
|
|
41
|
+
"format": "prettier --write .",
|
|
42
|
+
"format:check": "prettier --check .",
|
|
43
|
+
"test": "tsc && node --test dist/test/*.test.js",
|
|
44
|
+
"check:pushdata": "node scripts/check-pushdata.mjs",
|
|
45
|
+
"check-unused": "knip",
|
|
46
|
+
"ci": "npm run typecheck && npm run lint && npm run format:check && npm run check:pushdata && npm test",
|
|
47
|
+
"probe": "node scripts/probe-errors.mjs",
|
|
48
|
+
"prepare": "husky .husky || true"
|
|
49
|
+
},
|
|
50
|
+
"lint-staged": {
|
|
51
|
+
"*.js": "eslint",
|
|
52
|
+
"*.ts": "eslint",
|
|
53
|
+
"*.mjs": "eslint"
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@apify/eslint-config": "^1.2.0",
|
|
57
|
+
"@apify/tsconfig": "^0.1.2",
|
|
58
|
+
"@types/node": "^25.9.1",
|
|
59
|
+
"apify-client": "^2.10.0",
|
|
60
|
+
"eslint": "^9.39.4",
|
|
61
|
+
"eslint-config-prettier": "^10.1.8",
|
|
62
|
+
"globals": "^17.7.0",
|
|
63
|
+
"husky": "^9.1.7",
|
|
64
|
+
"knip": "^5.88.1",
|
|
65
|
+
"lint-staged": "^15.5.2",
|
|
66
|
+
"prettier": "^3.9.4",
|
|
67
|
+
"typescript": "^6.0.3",
|
|
68
|
+
"typescript-eslint": "^8.62.1"
|
|
69
|
+
},
|
|
70
|
+
"license": "ISC",
|
|
71
|
+
"peerDependencies": {
|
|
72
|
+
"@apify/log": "^2.5.44"
|
|
73
|
+
}
|
|
63
74
|
}
|