@devp0nt/error0 1.0.0-next.50 → 1.0.0-next.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/cjs/index.cjs +15 -15
  2. package/dist/cjs/index.cjs.map +1 -1
  3. package/dist/cjs/index.d.cts +11 -2
  4. package/dist/cjs/plugins/{cause-serialize.cjs → cause.cjs} +34 -12
  5. package/dist/cjs/plugins/cause.cjs.map +1 -0
  6. package/dist/cjs/plugins/cause.d.cts +15 -0
  7. package/dist/cjs/plugins/code.cjs +10 -2
  8. package/dist/cjs/plugins/code.cjs.map +1 -1
  9. package/dist/cjs/plugins/code.d.cts +2 -1
  10. package/dist/cjs/plugins/expected.cjs +19 -6
  11. package/dist/cjs/plugins/expected.cjs.map +1 -1
  12. package/dist/cjs/plugins/expected.d.cts +4 -3
  13. package/dist/cjs/plugins/meta.cjs +3 -3
  14. package/dist/cjs/plugins/meta.cjs.map +1 -1
  15. package/dist/cjs/plugins/meta.d.cts +2 -2
  16. package/dist/cjs/plugins/stack-merge.cjs +3 -3
  17. package/dist/cjs/plugins/stack-merge.cjs.map +1 -1
  18. package/dist/cjs/plugins/stack-merge.d.cts +2 -2
  19. package/dist/cjs/plugins/status.cjs +7 -1
  20. package/dist/cjs/plugins/status.cjs.map +1 -1
  21. package/dist/cjs/plugins/status.d.cts +2 -1
  22. package/dist/cjs/plugins/tags.cjs +3 -3
  23. package/dist/cjs/plugins/tags.cjs.map +1 -1
  24. package/dist/cjs/plugins/tags.d.cts +2 -2
  25. package/dist/esm/index.d.ts +11 -2
  26. package/dist/esm/index.js +15 -15
  27. package/dist/esm/index.js.map +1 -1
  28. package/dist/esm/plugins/cause.d.ts +15 -0
  29. package/dist/esm/plugins/cause.js +39 -0
  30. package/dist/esm/plugins/cause.js.map +1 -0
  31. package/dist/esm/plugins/code.d.ts +2 -1
  32. package/dist/esm/plugins/code.js +10 -2
  33. package/dist/esm/plugins/code.js.map +1 -1
  34. package/dist/esm/plugins/expected.d.ts +4 -3
  35. package/dist/esm/plugins/expected.js +19 -6
  36. package/dist/esm/plugins/expected.js.map +1 -1
  37. package/dist/esm/plugins/meta.d.ts +2 -2
  38. package/dist/esm/plugins/meta.js +3 -3
  39. package/dist/esm/plugins/meta.js.map +1 -1
  40. package/dist/esm/plugins/stack-merge.d.ts +2 -2
  41. package/dist/esm/plugins/stack-merge.js +3 -3
  42. package/dist/esm/plugins/stack-merge.js.map +1 -1
  43. package/dist/esm/plugins/status.d.ts +2 -1
  44. package/dist/esm/plugins/status.js +7 -1
  45. package/dist/esm/plugins/status.js.map +1 -1
  46. package/dist/esm/plugins/tags.d.ts +2 -2
  47. package/dist/esm/plugins/tags.js +3 -3
  48. package/dist/esm/plugins/tags.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/index.test.ts +9 -2
  51. package/src/index.ts +31 -16
  52. package/src/plugins/{cause-serialize.test.ts → cause.test.ts} +56 -3
  53. package/src/plugins/cause.ts +45 -0
  54. package/src/plugins/code.ts +10 -2
  55. package/src/plugins/expected.test.ts +22 -3
  56. package/src/plugins/expected.ts +23 -6
  57. package/src/plugins/meta.ts +3 -3
  58. package/src/plugins/stack-merge.test.ts +0 -7
  59. package/src/plugins/stack-merge.ts +4 -4
  60. package/src/plugins/status.ts +8 -2
  61. package/src/plugins/tags.ts +4 -4
  62. package/dist/cjs/plugins/cause-serialize.cjs.map +0 -1
  63. package/dist/cjs/plugins/cause-serialize.d.cts +0 -7
  64. package/dist/esm/plugins/cause-serialize.d.ts +0 -7
  65. package/dist/esm/plugins/cause-serialize.js +0 -17
  66. package/dist/esm/plugins/cause-serialize.js.map +0 -1
  67. package/src/plugins/cause-serialize.ts +0 -15
@@ -0,0 +1,39 @@
1
+ import { Error0 } from "../index.js";
2
+ const causePlugin = ({
3
+ isPublic = false,
4
+ variants = void 0
5
+ } = {}) => Error0.plugin().cause({
6
+ serialize: ({ cause, isPublic: _isPublic, is, serialize }) => {
7
+ if (!isPublic && _isPublic) {
8
+ return void 0;
9
+ }
10
+ if (variants) {
11
+ for (const variant of Object.values(variants)) {
12
+ if (cause instanceof variant) {
13
+ return variant.serialize(cause);
14
+ }
15
+ }
16
+ }
17
+ if (is(cause)) {
18
+ return serialize(cause);
19
+ }
20
+ return void 0;
21
+ },
22
+ deserialize: ({ cause, fromSerialized, isSerialized }) => {
23
+ if (variants) {
24
+ for (const variant of Object.values(variants)) {
25
+ if (variant.isSerialized(cause)) {
26
+ return variant.from(cause);
27
+ }
28
+ }
29
+ }
30
+ if (isSerialized(cause)) {
31
+ return fromSerialized(cause);
32
+ }
33
+ return cause;
34
+ }
35
+ });
36
+ export {
37
+ causePlugin
38
+ };
39
+ //# sourceMappingURL=cause.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/plugins/cause.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\ntype Variant = {\n new (...args: any[]): unknown\n [Symbol.hasInstance]: (value: any) => boolean\n isSerialized: (serializedCause: any) => boolean\n serialize: (error: any) => unknown\n from: (error: any) => unknown\n}\n\nexport const causePlugin = <TVariants extends Record<string, Variant> = Record<never, Variant>>({\n isPublic = false,\n variants = undefined,\n}: { isPublic?: boolean; variants?: TVariants } = {}) =>\n Error0.plugin().cause({\n serialize: ({ cause, isPublic: _isPublic, is, serialize }) => {\n if (!isPublic && _isPublic) {\n return undefined\n }\n if (variants) {\n for (const variant of Object.values(variants)) {\n if (cause instanceof variant) {\n return variant.serialize(cause)\n }\n }\n }\n if (is(cause)) {\n return serialize(cause)\n }\n return undefined\n },\n deserialize: ({ cause, fromSerialized, isSerialized }) => {\n if (variants) {\n for (const variant of Object.values(variants)) {\n if (variant.isSerialized(cause)) {\n return variant.from(cause)\n }\n }\n }\n if (isSerialized(cause)) {\n return fromSerialized(cause)\n }\n return cause\n },\n })\n"],"mappings":"AAAA,SAAS,cAAc;AAUhB,MAAM,cAAc,CAAqE;AAAA,EAC9F,WAAW;AAAA,EACX,WAAW;AACb,IAAkD,CAAC,MACjD,OAAO,OAAO,EAAE,MAAM;AAAA,EACpB,WAAW,CAAC,EAAE,OAAO,UAAU,WAAW,IAAI,UAAU,MAAM;AAC5D,QAAI,CAAC,YAAY,WAAW;AAC1B,aAAO;AAAA,IACT;AACA,QAAI,UAAU;AACZ,iBAAW,WAAW,OAAO,OAAO,QAAQ,GAAG;AAC7C,YAAI,iBAAiB,SAAS;AAC5B,iBAAO,QAAQ,UAAU,KAAK;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AACA,QAAI,GAAG,KAAK,GAAG;AACb,aAAO,UAAU,KAAK;AAAA,IACxB;AACA,WAAO;AAAA,EACT;AAAA,EACA,aAAa,CAAC,EAAE,OAAO,gBAAgB,aAAa,MAAM;AACxD,QAAI,UAAU;AACZ,iBAAW,WAAW,OAAO,OAAO,QAAQ,GAAG;AAC7C,YAAI,QAAQ,aAAa,KAAK,GAAG;AAC/B,iBAAO,QAAQ,KAAK,KAAK;AAAA,QAC3B;AAAA,MACF;AAAA,IACF;AACA,QAAI,aAAa,KAAK,GAAG;AACvB,aAAO,eAAe,KAAK;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AACF,CAAC;","names":[]}
@@ -1,7 +1,8 @@
1
1
  import { PluginError0, ErrorPluginPropOptions, Error0 } from '../index.js';
2
2
 
3
- declare const codePlugin: <TCode extends string>({ codes }?: {
3
+ declare const codePlugin: <TCode extends string>({ codes, isPublic, }?: {
4
4
  codes?: TCode[];
5
+ isPublic?: boolean;
5
6
  }) => PluginError0<Record<never, never> & Record<"code", ErrorPluginPropOptions<TCode, TCode, Error0, TCode | undefined>>, Record<never, never>>;
6
7
 
7
8
  export { codePlugin };
@@ -1,10 +1,18 @@
1
1
  import { Error0 } from "../index.js";
2
- const codePlugin = ({ codes } = {}) => {
2
+ const codePlugin = ({
3
+ codes,
4
+ isPublic = false
5
+ } = {}) => {
3
6
  const isCode = (value) => typeof value === "string" && (!codes || codes.includes(value));
4
7
  return Error0.plugin().prop("code", {
5
8
  init: (code) => code,
6
9
  resolve: ({ flow }) => flow.find(Boolean),
7
- serialize: ({ resolved, isPublic }) => resolved,
10
+ serialize: ({ resolved, isPublic: _isPublic }) => {
11
+ if (!isPublic && _isPublic) {
12
+ return void 0;
13
+ }
14
+ return resolved;
15
+ },
8
16
  deserialize: ({ value, record }) => isCode(value) ? value : void 0
9
17
  });
10
18
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/plugins/code.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const codePlugin = <TCode extends string>({ codes }: { codes?: TCode[] } = {}) => {\n const isCode = (value: unknown): value is TCode =>\n typeof value === 'string' && (!codes || codes.includes(value as TCode))\n return Error0.plugin().prop('code', {\n init: (code: TCode) => code,\n resolve: ({ flow }) => flow.find(Boolean),\n serialize: ({ resolved, isPublic }) => resolved,\n deserialize: ({ value, record }) => (isCode(value) ? value : undefined),\n })\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,aAAa,CAAuB,EAAE,MAAM,IAAyB,CAAC,MAAM;AACvF,QAAM,SAAS,CAAC,UACd,OAAO,UAAU,aAAa,CAAC,SAAS,MAAM,SAAS,KAAc;AACvE,SAAO,OAAO,OAAO,EAAE,KAAK,QAAQ;AAAA,IAClC,MAAM,CAAC,SAAgB;AAAA,IACvB,SAAS,CAAC,EAAE,KAAK,MAAM,KAAK,KAAK,OAAO;AAAA,IACxC,WAAW,CAAC,EAAE,UAAU,SAAS,MAAM;AAAA,IACvC,aAAa,CAAC,EAAE,OAAO,OAAO,MAAO,OAAO,KAAK,IAAI,QAAQ;AAAA,EAC/D,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../src/plugins/code.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const codePlugin = <TCode extends string>({\n codes,\n isPublic = false,\n}: { codes?: TCode[]; isPublic?: boolean } = {}) => {\n const isCode = (value: unknown): value is TCode =>\n typeof value === 'string' && (!codes || codes.includes(value as TCode))\n return Error0.plugin().prop('code', {\n init: (code: TCode) => code,\n resolve: ({ flow }) => flow.find(Boolean),\n serialize: ({ resolved, isPublic: _isPublic }) => {\n if (!isPublic && _isPublic) {\n return undefined\n }\n return resolved\n },\n deserialize: ({ value, record }) => (isCode(value) ? value : undefined),\n })\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,aAAa,CAAuB;AAAA,EAC/C;AAAA,EACA,WAAW;AACb,IAA6C,CAAC,MAAM;AAClD,QAAM,SAAS,CAAC,UACd,OAAO,UAAU,aAAa,CAAC,SAAS,MAAM,SAAS,KAAc;AACvE,SAAO,OAAO,OAAO,EAAE,KAAK,QAAQ;AAAA,IAClC,MAAM,CAAC,SAAgB;AAAA,IACvB,SAAS,CAAC,EAAE,KAAK,MAAM,KAAK,KAAK,OAAO;AAAA,IACxC,WAAW,CAAC,EAAE,UAAU,UAAU,UAAU,MAAM;AAChD,UAAI,CAAC,YAAY,WAAW;AAC1B,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IACA,aAAa,CAAC,EAAE,OAAO,OAAO,MAAO,OAAO,KAAK,IAAI,QAAQ;AAAA,EAC/D,CAAC;AACH;","names":[]}
@@ -1,7 +1,8 @@
1
- import { PluginError0, ErrorPluginPropOptions, Error0 } from '../index.js';
1
+ import { Error0, PluginError0, ErrorPluginPropOptions } from '../index.js';
2
2
 
3
- declare const expectedPlugin: ({ hideWhenPublic }?: {
4
- hideWhenPublic?: boolean;
3
+ declare const expectedPlugin: <TError extends Error0>({ isPublic, override, }?: {
4
+ isPublic?: boolean;
5
+ override?: (error: TError) => boolean | undefined;
5
6
  }) => PluginError0<Record<never, never> & Record<"expected", ErrorPluginPropOptions<boolean, boolean, Error0, boolean>>, Record<never, never> & Record<"isExpected", (error: Error0 & {
6
7
  expected: boolean;
7
8
  } & {} & {
@@ -1,5 +1,15 @@
1
1
  import { Error0 } from "../index.js";
2
- const isExpected = (flow) => {
2
+ const isExpected = ({
3
+ flow,
4
+ error,
5
+ override
6
+ }) => {
7
+ if (override) {
8
+ const overridden = override(error);
9
+ if (overridden !== void 0) {
10
+ return overridden;
11
+ }
12
+ }
3
13
  let expected = false;
4
14
  for (const value of flow) {
5
15
  if (value === false) {
@@ -11,18 +21,21 @@ const isExpected = (flow) => {
11
21
  }
12
22
  return expected;
13
23
  };
14
- const expectedPlugin = ({ hideWhenPublic = true } = {}) => Error0.plugin().prop("expected", {
24
+ const expectedPlugin = ({
25
+ isPublic = false,
26
+ override
27
+ } = {}) => Error0.plugin().prop("expected", {
15
28
  init: (input) => input,
16
- resolve: ({ flow }) => isExpected(flow),
17
- serialize: ({ resolved, isPublic }) => {
18
- if (hideWhenPublic && isPublic) {
29
+ resolve: ({ flow, error }) => isExpected({ flow, error, override }),
30
+ serialize: ({ resolved, isPublic: _isPublic }) => {
31
+ if (isPublic && _isPublic) {
19
32
  return void 0;
20
33
  }
21
34
  return resolved;
22
35
  },
23
36
  deserialize: ({ value }) => typeof value === "boolean" ? value : void 0
24
37
  }).method("isExpected", (error) => {
25
- return isExpected(error.flow("expected"));
38
+ return isExpected({ flow: error.flow("expected"), error, override });
26
39
  });
27
40
  export {
28
41
  expectedPlugin
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/plugins/expected.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nconst isExpected = (flow: unknown[]) => {\n let expected = false\n for (const value of flow) {\n if (value === false) {\n return false\n }\n if (value === true) {\n expected = true\n }\n }\n return expected\n}\n\nexport const expectedPlugin = ({ hideWhenPublic = true }: { hideWhenPublic?: boolean } = {}) =>\n Error0.plugin()\n .prop('expected', {\n init: (input: boolean) => input,\n resolve: ({ flow }) => isExpected(flow),\n serialize: ({ resolved, isPublic }) => {\n if (hideWhenPublic && isPublic) {\n return undefined\n }\n return resolved\n },\n deserialize: ({ value }) => (typeof value === 'boolean' ? value : undefined),\n })\n .method('isExpected', (error) => {\n return isExpected(error.flow('expected'))\n })\n"],"mappings":"AAAA,SAAS,cAAc;AAEvB,MAAM,aAAa,CAAC,SAAoB;AACtC,MAAI,WAAW;AACf,aAAW,SAAS,MAAM;AACxB,QAAI,UAAU,OAAO;AACnB,aAAO;AAAA,IACT;AACA,QAAI,UAAU,MAAM;AAClB,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAEO,MAAM,iBAAiB,CAAC,EAAE,iBAAiB,KAAK,IAAkC,CAAC,MACxF,OAAO,OAAO,EACX,KAAK,YAAY;AAAA,EAChB,MAAM,CAAC,UAAmB;AAAA,EAC1B,SAAS,CAAC,EAAE,KAAK,MAAM,WAAW,IAAI;AAAA,EACtC,WAAW,CAAC,EAAE,UAAU,SAAS,MAAM;AACrC,QAAI,kBAAkB,UAAU;AAC9B,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EACA,aAAa,CAAC,EAAE,MAAM,MAAO,OAAO,UAAU,YAAY,QAAQ;AACpE,CAAC,EACA,OAAO,cAAc,CAAC,UAAU;AAC/B,SAAO,WAAW,MAAM,KAAK,UAAU,CAAC;AAC1C,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/plugins/expected.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nconst isExpected = ({\n flow,\n error,\n override,\n}: {\n flow: unknown[]\n error: Error0\n override?: (error: any) => boolean | undefined\n}) => {\n if (override) {\n const overridden = override(error)\n if (overridden !== undefined) {\n return overridden\n }\n }\n let expected = false\n for (const value of flow) {\n if (value === false) {\n return false\n }\n if (value === true) {\n expected = true\n }\n }\n return expected\n}\n\nexport const expectedPlugin = <TError extends Error0>({\n isPublic = false,\n override,\n}: { isPublic?: boolean; override?: (error: TError) => boolean | undefined } = {}) =>\n Error0.plugin()\n .prop('expected', {\n init: (input: boolean) => input,\n resolve: ({ flow, error }) => isExpected({ flow, error, override }),\n serialize: ({ resolved, isPublic: _isPublic }) => {\n if (isPublic && _isPublic) {\n return undefined\n }\n return resolved\n },\n deserialize: ({ value }) => (typeof value === 'boolean' ? value : undefined),\n })\n .method('isExpected', (error) => {\n return isExpected({ flow: error.flow('expected'), error, override })\n })\n"],"mappings":"AAAA,SAAS,cAAc;AAEvB,MAAM,aAAa,CAAC;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AACF,MAIM;AACJ,MAAI,UAAU;AACZ,UAAM,aAAa,SAAS,KAAK;AACjC,QAAI,eAAe,QAAW;AAC5B,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,WAAW;AACf,aAAW,SAAS,MAAM;AACxB,QAAI,UAAU,OAAO;AACnB,aAAO;AAAA,IACT;AACA,QAAI,UAAU,MAAM;AAClB,iBAAW;AAAA,IACb;AAAA,EACF;AACA,SAAO;AACT;AAEO,MAAM,iBAAiB,CAAwB;AAAA,EACpD,WAAW;AAAA,EACX;AACF,IAA+E,CAAC,MAC9E,OAAO,OAAO,EACX,KAAK,YAAY;AAAA,EAChB,MAAM,CAAC,UAAmB;AAAA,EAC1B,SAAS,CAAC,EAAE,MAAM,MAAM,MAAM,WAAW,EAAE,MAAM,OAAO,SAAS,CAAC;AAAA,EAClE,WAAW,CAAC,EAAE,UAAU,UAAU,UAAU,MAAM;AAChD,QAAI,YAAY,WAAW;AACzB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EACA,aAAa,CAAC,EAAE,MAAM,MAAO,OAAO,UAAU,YAAY,QAAQ;AACpE,CAAC,EACA,OAAO,cAAc,CAAC,UAAU;AAC/B,SAAO,WAAW,EAAE,MAAM,MAAM,KAAK,UAAU,GAAG,OAAO,SAAS,CAAC;AACrE,CAAC;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { PluginError0, ErrorPluginPropOptions, Error0 } from '../index.js';
2
2
 
3
- declare const metaPlugin: ({ hideWhenPublic }?: {
4
- hideWhenPublic?: boolean;
3
+ declare const metaPlugin: ({ isPublic }?: {
4
+ isPublic?: boolean;
5
5
  }) => PluginError0<Record<never, never> & Record<"meta", ErrorPluginPropOptions<Record<string, unknown>, Record<string, unknown>, Error0, Record<string, unknown> | undefined>>, Record<never, never>>;
6
6
 
7
7
  export { metaPlugin };
@@ -22,7 +22,7 @@ const toJsonSafe = (input) => {
22
22
  return void 0;
23
23
  };
24
24
  const isMetaRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
25
- const metaPlugin = ({ hideWhenPublic = true } = {}) => Error0.plugin().prop("meta", {
25
+ const metaPlugin = ({ isPublic = false } = {}) => Error0.plugin().prop("meta", {
26
26
  init: (input) => input,
27
27
  resolve: ({ flow }) => {
28
28
  const values = flow.filter(isMetaRecord);
@@ -35,8 +35,8 @@ const metaPlugin = ({ hideWhenPublic = true } = {}) => Error0.plugin().prop("met
35
35
  }
36
36
  return merged;
37
37
  },
38
- serialize: ({ resolved, isPublic }) => {
39
- if (hideWhenPublic && isPublic) {
38
+ serialize: ({ resolved, isPublic: _isPublic }) => {
39
+ if (!isPublic && _isPublic) {
40
40
  return void 0;
41
41
  }
42
42
  return toJsonSafe(resolved);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/plugins/meta.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\ntype Json = null | boolean | number | string | Json[] | { [key: string]: Json }\n\nconst toJsonSafe = (input: unknown): Json | undefined => {\n if (input === null) {\n return null\n }\n if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {\n return input\n }\n if (Array.isArray(input)) {\n return input.map((value) => toJsonSafe(value)) as Json[]\n }\n if (typeof input === 'object') {\n const output: Record<string, Json> = {}\n for (const [key, value] of Object.entries(input as Record<string, unknown>)) {\n const jsonValue = toJsonSafe(value)\n if (jsonValue !== undefined) {\n output[key] = jsonValue\n }\n }\n return output\n }\n return undefined\n}\n\nconst isMetaRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nexport const metaPlugin = ({ hideWhenPublic = true }: { hideWhenPublic?: boolean } = {}) =>\n Error0.plugin().prop('meta', {\n init: (input: Record<string, unknown>) => input,\n resolve: ({ flow }) => {\n const values = flow.filter(isMetaRecord)\n if (values.length === 0) {\n return undefined\n }\n\n // Merge cause meta into the current error; nearer errors win on conflicts.\n const merged: Record<string, unknown> = {}\n for (const value of [...values].reverse()) {\n Object.assign(merged, value)\n }\n return merged\n },\n serialize: ({ resolved, isPublic }) => {\n if (hideWhenPublic && isPublic) {\n return undefined\n }\n return toJsonSafe(resolved)\n },\n deserialize: ({ value }) => {\n if (!isMetaRecord(value)) {\n return undefined\n }\n return value\n },\n })\n"],"mappings":"AAAA,SAAS,cAAc;AAIvB,MAAM,aAAa,CAAC,UAAqC;AACvD,MAAI,UAAU,MAAM;AAClB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;AACxF,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,UAAU,WAAW,KAAK,CAAC;AAAA,EAC/C;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAA+B,CAAC;AACtC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC3E,YAAM,YAAY,WAAW,KAAK;AAClC,UAAI,cAAc,QAAW;AAC3B,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,MAAM,eAAe,CAAC,UACpB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAE9D,MAAM,aAAa,CAAC,EAAE,iBAAiB,KAAK,IAAkC,CAAC,MACpF,OAAO,OAAO,EAAE,KAAK,QAAQ;AAAA,EAC3B,MAAM,CAAC,UAAmC;AAAA,EAC1C,SAAS,CAAC,EAAE,KAAK,MAAM;AACrB,UAAM,SAAS,KAAK,OAAO,YAAY;AACvC,QAAI,OAAO,WAAW,GAAG;AACvB,aAAO;AAAA,IACT;AAGA,UAAM,SAAkC,CAAC;AACzC,eAAW,SAAS,CAAC,GAAG,MAAM,EAAE,QAAQ,GAAG;AACzC,aAAO,OAAO,QAAQ,KAAK;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AAAA,EACA,WAAW,CAAC,EAAE,UAAU,SAAS,MAAM;AACrC,QAAI,kBAAkB,UAAU;AAC9B,aAAO;AAAA,IACT;AACA,WAAO,WAAW,QAAQ;AAAA,EAC5B;AAAA,EACA,aAAa,CAAC,EAAE,MAAM,MAAM;AAC1B,QAAI,CAAC,aAAa,KAAK,GAAG;AACxB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/plugins/meta.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\ntype Json = null | boolean | number | string | Json[] | { [key: string]: Json }\n\nconst toJsonSafe = (input: unknown): Json | undefined => {\n if (input === null) {\n return null\n }\n if (typeof input === 'string' || typeof input === 'number' || typeof input === 'boolean') {\n return input\n }\n if (Array.isArray(input)) {\n return input.map((value) => toJsonSafe(value)) as Json[]\n }\n if (typeof input === 'object') {\n const output: Record<string, Json> = {}\n for (const [key, value] of Object.entries(input as Record<string, unknown>)) {\n const jsonValue = toJsonSafe(value)\n if (jsonValue !== undefined) {\n output[key] = jsonValue\n }\n }\n return output\n }\n return undefined\n}\n\nconst isMetaRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nexport const metaPlugin = ({ isPublic = false }: { isPublic?: boolean } = {}) =>\n Error0.plugin().prop('meta', {\n init: (input: Record<string, unknown>) => input,\n resolve: ({ flow }) => {\n const values = flow.filter(isMetaRecord)\n if (values.length === 0) {\n return undefined\n }\n\n // Merge cause meta into the current error; nearer errors win on conflicts.\n const merged: Record<string, unknown> = {}\n for (const value of [...values].reverse()) {\n Object.assign(merged, value)\n }\n return merged\n },\n serialize: ({ resolved, isPublic: _isPublic }) => {\n if (!isPublic && _isPublic) {\n return undefined\n }\n return toJsonSafe(resolved)\n },\n deserialize: ({ value }) => {\n if (!isMetaRecord(value)) {\n return undefined\n }\n return value\n },\n })\n"],"mappings":"AAAA,SAAS,cAAc;AAIvB,MAAM,aAAa,CAAC,UAAqC;AACvD,MAAI,UAAU,MAAM;AAClB,WAAO;AAAA,EACT;AACA,MAAI,OAAO,UAAU,YAAY,OAAO,UAAU,YAAY,OAAO,UAAU,WAAW;AACxF,WAAO;AAAA,EACT;AACA,MAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,WAAO,MAAM,IAAI,CAAC,UAAU,WAAW,KAAK,CAAC;AAAA,EAC/C;AACA,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,SAA+B,CAAC;AACtC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAgC,GAAG;AAC3E,YAAM,YAAY,WAAW,KAAK;AAClC,UAAI,cAAc,QAAW;AAC3B,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEA,MAAM,eAAe,CAAC,UACpB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAE9D,MAAM,aAAa,CAAC,EAAE,WAAW,MAAM,IAA4B,CAAC,MACzE,OAAO,OAAO,EAAE,KAAK,QAAQ;AAAA,EAC3B,MAAM,CAAC,UAAmC;AAAA,EAC1C,SAAS,CAAC,EAAE,KAAK,MAAM;AACrB,UAAM,SAAS,KAAK,OAAO,YAAY;AACvC,QAAI,OAAO,WAAW,GAAG;AACvB,aAAO;AAAA,IACT;AAGA,UAAM,SAAkC,CAAC;AACzC,eAAW,SAAS,CAAC,GAAG,MAAM,EAAE,QAAQ,GAAG;AACzC,aAAO,OAAO,QAAQ,KAAK;AAAA,IAC7B;AACA,WAAO;AAAA,EACT;AAAA,EACA,WAAW,CAAC,EAAE,UAAU,UAAU,UAAU,MAAM;AAChD,QAAI,CAAC,YAAY,WAAW;AAC1B,aAAO;AAAA,IACT;AACA,WAAO,WAAW,QAAQ;AAAA,EAC5B;AAAA,EACA,aAAa,CAAC,EAAE,MAAM,MAAM;AAC1B,QAAI,CAAC,aAAa,KAAK,GAAG;AACxB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AACF,CAAC;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { PluginError0 } from '../index.js';
2
2
 
3
- declare const stackMergePlugin: ({ hideWhenPublic, delimiter, }?: {
4
- hideWhenPublic?: boolean;
3
+ declare const stackMergePlugin: ({ isPublic, delimiter, }?: {
4
+ isPublic?: boolean;
5
5
  delimiter?: string;
6
6
  }) => PluginError0<Record<never, never>, Record<never, never>>;
7
7
 
@@ -1,10 +1,10 @@
1
1
  import { Error0 } from "../index.js";
2
2
  const stackMergePlugin = ({
3
- hideWhenPublic = true,
3
+ isPublic = false,
4
4
  delimiter = "\n"
5
5
  } = {}) => Error0.plugin().stack({
6
- serialize: ({ error, isPublic }) => {
7
- if (hideWhenPublic && isPublic) {
6
+ serialize: ({ error, isPublic: _isPublic }) => {
7
+ if (!isPublic && _isPublic) {
8
8
  return void 0;
9
9
  }
10
10
  return error.causes().map((cause) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/plugins/stack-merge.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const stackMergePlugin = ({\n hideWhenPublic = true,\n delimiter = '\\n',\n}: { hideWhenPublic?: boolean; delimiter?: string } = {}) =>\n Error0.plugin().stack({\n serialize: ({ error, isPublic }) => {\n if (hideWhenPublic && isPublic) {\n return undefined\n }\n return error\n .causes()\n .map((cause) => {\n return cause instanceof Error ? cause.stack : undefined\n })\n .filter((value): value is string => typeof value === 'string')\n .join(delimiter)\n },\n })\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,mBAAmB,CAAC;AAAA,EAC/B,iBAAiB;AAAA,EACjB,YAAY;AACd,IAAsD,CAAC,MACrD,OAAO,OAAO,EAAE,MAAM;AAAA,EACpB,WAAW,CAAC,EAAE,OAAO,SAAS,MAAM;AAClC,QAAI,kBAAkB,UAAU;AAC9B,aAAO;AAAA,IACT;AACA,WAAO,MACJ,OAAO,EACP,IAAI,CAAC,UAAU;AACd,aAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,IAChD,CAAC,EACA,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ,EAC5D,KAAK,SAAS;AAAA,EACnB;AACF,CAAC;","names":[]}
1
+ {"version":3,"sources":["../../../src/plugins/stack-merge.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const stackMergePlugin = ({\n isPublic = false,\n delimiter = '\\n',\n}: { isPublic?: boolean; delimiter?: string } = {}) =>\n Error0.plugin().stack({\n serialize: ({ error, isPublic: _isPublic }) => {\n if (!isPublic && _isPublic) {\n return undefined\n }\n return error\n .causes()\n .map((cause) => {\n return cause instanceof Error ? cause.stack : undefined\n })\n .filter((value): value is string => typeof value === 'string')\n .join(delimiter)\n },\n })\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,mBAAmB,CAAC;AAAA,EAC/B,WAAW;AAAA,EACX,YAAY;AACd,IAAgD,CAAC,MAC/C,OAAO,OAAO,EAAE,MAAM;AAAA,EACpB,WAAW,CAAC,EAAE,OAAO,UAAU,UAAU,MAAM;AAC7C,QAAI,CAAC,YAAY,WAAW;AAC1B,aAAO;AAAA,IACT;AACA,WAAO,MACJ,OAAO,EACP,IAAI,CAAC,UAAU;AACd,aAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,IAChD,CAAC,EACA,OAAO,CAAC,UAA2B,OAAO,UAAU,QAAQ,EAC5D,KAAK,SAAS;AAAA,EACnB;AACF,CAAC;","names":[]}
@@ -1,6 +1,7 @@
1
1
  import { PluginError0, ErrorPluginPropOptions, Error0 } from '../index.js';
2
2
 
3
- declare const statusPlugin: <TStatuses extends Record<string, number> = Record<never, number>>({ statuses, strict, }?: {
3
+ declare const statusPlugin: <TStatuses extends Record<string, number> = Record<never, number>>({ isPublic, statuses, strict, }?: {
4
+ isPublic?: boolean;
4
5
  statuses?: TStatuses;
5
6
  strict?: boolean;
6
7
  }) => PluginError0<Record<never, never> & Record<"status", ErrorPluginPropOptions<number | Extract<keyof TStatuses, string>, number | undefined, Error0, number | undefined>>, Record<never, never>>;
@@ -1,5 +1,6 @@
1
1
  import { Error0 } from "../index.js";
2
2
  const statusPlugin = ({
3
+ isPublic = false,
3
4
  statuses,
4
5
  strict = false
5
6
  } = {}) => {
@@ -20,7 +21,12 @@ const statusPlugin = ({
20
21
  return Error0.plugin().prop("status", {
21
22
  init: (status) => convertStatusValue(status),
22
23
  resolve: ({ flow }) => flow.find(Boolean),
23
- serialize: ({ resolved }) => resolved,
24
+ serialize: ({ resolved, isPublic: _isPublic }) => {
25
+ if (!isPublic && _isPublic) {
26
+ return void 0;
27
+ }
28
+ return resolved;
29
+ },
24
30
  deserialize: ({ value }) => typeof value === "number" ? value : void 0
25
31
  });
26
32
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/plugins/status.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const statusPlugin = <TStatuses extends Record<string, number> = Record<never, number>>({\n statuses,\n strict = false,\n}: { statuses?: TStatuses; strict?: boolean } = {}) => {\n const statusValues = statuses ? Object.values(statuses) : undefined\n const isStatusValue = (value: unknown): value is number =>\n typeof value === 'number' && (!statusValues || !strict || statusValues.includes(value))\n const normalizeStatusValue = (value: unknown): number | undefined => {\n return isStatusValue(value) ? value : undefined\n }\n const convertStatusValue = (value: number | string): number | undefined => {\n if (typeof value === 'number') {\n return normalizeStatusValue(value)\n }\n if (statuses && value in statuses) {\n return statuses[value as keyof TStatuses]\n }\n return undefined\n }\n\n return Error0.plugin().prop('status', {\n init: (status: number | Extract<keyof TStatuses, string>) => convertStatusValue(status),\n resolve: ({ flow }) => flow.find(Boolean),\n serialize: ({ resolved }) => resolved,\n deserialize: ({ value }) => (typeof value === 'number' ? value : undefined),\n })\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,eAAe,CAAmE;AAAA,EAC7F;AAAA,EACA,SAAS;AACX,IAAgD,CAAC,MAAM;AACrD,QAAM,eAAe,WAAW,OAAO,OAAO,QAAQ,IAAI;AAC1D,QAAM,gBAAgB,CAAC,UACrB,OAAO,UAAU,aAAa,CAAC,gBAAgB,CAAC,UAAU,aAAa,SAAS,KAAK;AACvF,QAAM,uBAAuB,CAAC,UAAuC;AACnE,WAAO,cAAc,KAAK,IAAI,QAAQ;AAAA,EACxC;AACA,QAAM,qBAAqB,CAAC,UAA+C;AACzE,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,qBAAqB,KAAK;AAAA,IACnC;AACA,QAAI,YAAY,SAAS,UAAU;AACjC,aAAO,SAAS,KAAwB;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,OAAO,EAAE,KAAK,UAAU;AAAA,IACpC,MAAM,CAAC,WAAsD,mBAAmB,MAAM;AAAA,IACtF,SAAS,CAAC,EAAE,KAAK,MAAM,KAAK,KAAK,OAAO;AAAA,IACxC,WAAW,CAAC,EAAE,SAAS,MAAM;AAAA,IAC7B,aAAa,CAAC,EAAE,MAAM,MAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,EACnE,CAAC;AACH;","names":[]}
1
+ {"version":3,"sources":["../../../src/plugins/status.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const statusPlugin = <TStatuses extends Record<string, number> = Record<never, number>>({\n isPublic = false,\n statuses,\n strict = false,\n}: { isPublic?: boolean; statuses?: TStatuses; strict?: boolean } = {}) => {\n const statusValues = statuses ? Object.values(statuses) : undefined\n const isStatusValue = (value: unknown): value is number =>\n typeof value === 'number' && (!statusValues || !strict || statusValues.includes(value))\n const normalizeStatusValue = (value: unknown): number | undefined => {\n return isStatusValue(value) ? value : undefined\n }\n const convertStatusValue = (value: number | string): number | undefined => {\n if (typeof value === 'number') {\n return normalizeStatusValue(value)\n }\n if (statuses && value in statuses) {\n return statuses[value as keyof TStatuses]\n }\n return undefined\n }\n\n return Error0.plugin().prop('status', {\n init: (status: number | Extract<keyof TStatuses, string>) => convertStatusValue(status),\n resolve: ({ flow }) => flow.find(Boolean),\n serialize: ({ resolved, isPublic: _isPublic }) => {\n if (!isPublic && _isPublic) {\n return undefined\n }\n return resolved\n },\n deserialize: ({ value }) => (typeof value === 'number' ? value : undefined),\n })\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,eAAe,CAAmE;AAAA,EAC7F,WAAW;AAAA,EACX;AAAA,EACA,SAAS;AACX,IAAoE,CAAC,MAAM;AACzE,QAAM,eAAe,WAAW,OAAO,OAAO,QAAQ,IAAI;AAC1D,QAAM,gBAAgB,CAAC,UACrB,OAAO,UAAU,aAAa,CAAC,gBAAgB,CAAC,UAAU,aAAa,SAAS,KAAK;AACvF,QAAM,uBAAuB,CAAC,UAAuC;AACnE,WAAO,cAAc,KAAK,IAAI,QAAQ;AAAA,EACxC;AACA,QAAM,qBAAqB,CAAC,UAA+C;AACzE,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,qBAAqB,KAAK;AAAA,IACnC;AACA,QAAI,YAAY,SAAS,UAAU;AACjC,aAAO,SAAS,KAAwB;AAAA,IAC1C;AACA,WAAO;AAAA,EACT;AAEA,SAAO,OAAO,OAAO,EAAE,KAAK,UAAU;AAAA,IACpC,MAAM,CAAC,WAAsD,mBAAmB,MAAM;AAAA,IACtF,SAAS,CAAC,EAAE,KAAK,MAAM,KAAK,KAAK,OAAO;AAAA,IACxC,WAAW,CAAC,EAAE,UAAU,UAAU,UAAU,MAAM;AAChD,UAAI,CAAC,YAAY,WAAW;AAC1B,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,MAAO,OAAO,UAAU,WAAW,QAAQ;AAAA,EACnE,CAAC;AACH;","names":[]}
@@ -1,7 +1,7 @@
1
1
  import { PluginError0, ErrorPluginPropOptions, Error0 } from '../index.js';
2
2
 
3
- declare const tagsPlugin: <TTag extends string>({ hideWhenPublic, tags, strict, }?: {
4
- hideWhenPublic?: boolean;
3
+ declare const tagsPlugin: <TTag extends string>({ isPublic, tags, strict, }?: {
4
+ isPublic?: boolean;
5
5
  tags?: TTag[] | readonly TTag[];
6
6
  strict?: boolean;
7
7
  }) => PluginError0<Record<never, never> & Record<"tags", ErrorPluginPropOptions<string[], string[], Error0, string[] | undefined>>, Record<never, never> & Record<"hasTag", {
@@ -1,6 +1,6 @@
1
1
  import { Error0 } from "../index.js";
2
2
  const tagsPlugin = ({
3
- hideWhenPublic = true,
3
+ isPublic = false,
4
4
  tags,
5
5
  strict = true
6
6
  } = {}) => {
@@ -29,8 +29,8 @@ const tagsPlugin = ({
29
29
  }
30
30
  return merged.length > 0 ? Array.from(new Set(merged)) : void 0;
31
31
  },
32
- serialize: ({ resolved, isPublic }) => {
33
- if (hideWhenPublic && isPublic) {
32
+ serialize: ({ resolved, isPublic: _isPublic }) => {
33
+ if (!isPublic && _isPublic) {
34
34
  return void 0;
35
35
  }
36
36
  return resolved;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/plugins/tags.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const tagsPlugin = <TTag extends string>({\n hideWhenPublic = true,\n tags,\n strict = true,\n}: { hideWhenPublic?: boolean; tags?: TTag[] | readonly TTag[]; strict?: boolean } = {}) => {\n function hasTag(error: Error0, tag: TTag): boolean\n function hasTag(error: Error0, tag: TTag[], policy: 'every' | 'some'): boolean\n function hasTag(error: Error0, tag: TTag | TTag[], policy?: 'every' | 'some'): boolean {\n const tags = (error as any).tags as string[] | undefined\n if (!tags) {\n return false\n }\n if (Array.isArray(tag)) {\n if (policy === 'every') {\n return tag.every((item) => tags.includes(item))\n }\n return tag.some((item) => tags.includes(item))\n }\n return tags.includes(tag)\n }\n const isTag = (value: unknown): value is TTag =>\n typeof value === 'string' && (!tags || !strict || tags.includes(value as TTag))\n return Error0.plugin()\n .prop('tags', {\n init: (input: string[]) => input,\n resolve: ({ flow }) => {\n const merged: string[] = []\n for (const value of flow) {\n if (Array.isArray(value)) {\n merged.push(...value)\n }\n }\n return merged.length > 0 ? Array.from(new Set(merged)) : undefined\n },\n serialize: ({ resolved, isPublic }) => {\n if (hideWhenPublic && isPublic) {\n return undefined\n }\n return resolved\n },\n deserialize: ({ value }) => {\n if (!Array.isArray(value)) {\n return undefined\n }\n return value.filter((item) => isTag(item))\n },\n })\n .method('hasTag', hasTag)\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,aAAa,CAAsB;AAAA,EAC9C,iBAAiB;AAAA,EACjB;AAAA,EACA,SAAS;AACX,IAAqF,CAAC,MAAM;AAG1F,WAAS,OAAO,OAAe,KAAoB,QAAoC;AACrF,UAAMA,QAAQ,MAAc;AAC5B,QAAI,CAACA,OAAM;AACT,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,UAAI,WAAW,SAAS;AACtB,eAAO,IAAI,MAAM,CAAC,SAASA,MAAK,SAAS,IAAI,CAAC;AAAA,MAChD;AACA,aAAO,IAAI,KAAK,CAAC,SAASA,MAAK,SAAS,IAAI,CAAC;AAAA,IAC/C;AACA,WAAOA,MAAK,SAAS,GAAG;AAAA,EAC1B;AACA,QAAM,QAAQ,CAAC,UACb,OAAO,UAAU,aAAa,CAAC,QAAQ,CAAC,UAAU,KAAK,SAAS,KAAa;AAC/E,SAAO,OAAO,OAAO,EAClB,KAAK,QAAQ;AAAA,IACZ,MAAM,CAAC,UAAoB;AAAA,IAC3B,SAAS,CAAC,EAAE,KAAK,MAAM;AACrB,YAAM,SAAmB,CAAC;AAC1B,iBAAW,SAAS,MAAM;AACxB,YAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAO,KAAK,GAAG,KAAK;AAAA,QACtB;AAAA,MACF;AACA,aAAO,OAAO,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI;AAAA,IAC3D;AAAA,IACA,WAAW,CAAC,EAAE,UAAU,SAAS,MAAM;AACrC,UAAI,kBAAkB,UAAU;AAC9B,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,MAAM;AAC1B,UAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,eAAO;AAAA,MACT;AACA,aAAO,MAAM,OAAO,CAAC,SAAS,MAAM,IAAI,CAAC;AAAA,IAC3C;AAAA,EACF,CAAC,EACA,OAAO,UAAU,MAAM;AAC5B;","names":["tags"]}
1
+ {"version":3,"sources":["../../../src/plugins/tags.ts"],"sourcesContent":["import { Error0 } from '../index.js'\n\nexport const tagsPlugin = <TTag extends string>({\n isPublic = false,\n tags,\n strict = true,\n}: { isPublic?: boolean; tags?: TTag[] | readonly TTag[]; strict?: boolean } = {}) => {\n function hasTag(error: Error0, tag: TTag): boolean\n function hasTag(error: Error0, tag: TTag[], policy: 'every' | 'some'): boolean\n function hasTag(error: Error0, tag: TTag | TTag[], policy?: 'every' | 'some'): boolean {\n const tags = (error as any).tags as string[] | undefined\n if (!tags) {\n return false\n }\n if (Array.isArray(tag)) {\n if (policy === 'every') {\n return tag.every((item) => tags.includes(item))\n }\n return tag.some((item) => tags.includes(item))\n }\n return tags.includes(tag)\n }\n const isTag = (value: unknown): value is TTag =>\n typeof value === 'string' && (!tags || !strict || tags.includes(value as TTag))\n return Error0.plugin()\n .prop('tags', {\n init: (input: string[]) => input,\n resolve: ({ flow }) => {\n const merged: string[] = []\n for (const value of flow) {\n if (Array.isArray(value)) {\n merged.push(...value)\n }\n }\n return merged.length > 0 ? Array.from(new Set(merged)) : undefined\n },\n serialize: ({ resolved, isPublic: _isPublic }) => {\n if (!isPublic && _isPublic) {\n return undefined\n }\n return resolved\n },\n deserialize: ({ value }) => {\n if (!Array.isArray(value)) {\n return undefined\n }\n return value.filter((item) => isTag(item))\n },\n })\n .method('hasTag', hasTag)\n}\n"],"mappings":"AAAA,SAAS,cAAc;AAEhB,MAAM,aAAa,CAAsB;AAAA,EAC9C,WAAW;AAAA,EACX;AAAA,EACA,SAAS;AACX,IAA+E,CAAC,MAAM;AAGpF,WAAS,OAAO,OAAe,KAAoB,QAAoC;AACrF,UAAMA,QAAQ,MAAc;AAC5B,QAAI,CAACA,OAAM;AACT,aAAO;AAAA,IACT;AACA,QAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,UAAI,WAAW,SAAS;AACtB,eAAO,IAAI,MAAM,CAAC,SAASA,MAAK,SAAS,IAAI,CAAC;AAAA,MAChD;AACA,aAAO,IAAI,KAAK,CAAC,SAASA,MAAK,SAAS,IAAI,CAAC;AAAA,IAC/C;AACA,WAAOA,MAAK,SAAS,GAAG;AAAA,EAC1B;AACA,QAAM,QAAQ,CAAC,UACb,OAAO,UAAU,aAAa,CAAC,QAAQ,CAAC,UAAU,KAAK,SAAS,KAAa;AAC/E,SAAO,OAAO,OAAO,EAClB,KAAK,QAAQ;AAAA,IACZ,MAAM,CAAC,UAAoB;AAAA,IAC3B,SAAS,CAAC,EAAE,KAAK,MAAM;AACrB,YAAM,SAAmB,CAAC;AAC1B,iBAAW,SAAS,MAAM;AACxB,YAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,iBAAO,KAAK,GAAG,KAAK;AAAA,QACtB;AAAA,MACF;AACA,aAAO,OAAO,SAAS,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,CAAC,IAAI;AAAA,IAC3D;AAAA,IACA,WAAW,CAAC,EAAE,UAAU,UAAU,UAAU,MAAM;AAChD,UAAI,CAAC,YAAY,WAAW;AAC1B,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAAA,IACA,aAAa,CAAC,EAAE,MAAM,MAAM;AAC1B,UAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,eAAO;AAAA,MACT;AACA,aAAO,MAAM,OAAO,CAAC,SAAS,MAAM,IAAI,CAAC;AAAA,IAC3C;AAAA,EACF,CAAC,EACA,OAAO,UAAU,MAAM;AAC5B;","names":["tags"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@devp0nt/error0",
3
- "version": "1.0.0-next.50",
3
+ "version": "1.0.0-next.51",
4
4
  "license": "MIT",
5
5
  "author": {
6
6
  "name": "Sergei Dmitriev",
package/src/index.test.ts CHANGED
@@ -203,13 +203,20 @@ describe('Error0', () => {
203
203
  expect('code' in json).toBe(false)
204
204
  })
205
205
 
206
- it('serialize keeps stack by default without stack plugin', () => {
206
+ it('serialize keeps stack by default without stack plugin when not public', () => {
207
207
  const AppError = Error0.use(statusPlugin)
208
208
  const error = new AppError('test', { status: 500 })
209
- const json = AppError.serialize(error)
209
+ const json = AppError.serialize(error, false)
210
210
  expect(json.stack).toBe(error.stack)
211
211
  })
212
212
 
213
+ it('serialize does not keep stack when public', () => {
214
+ const AppError = Error0.use(statusPlugin)
215
+ const error = new AppError('test', { status: 500 })
216
+ const json = AppError.serialize(error, true)
217
+ expect('stack' in json).toBe(false)
218
+ })
219
+
213
220
  it('stack plugin can customize stack serialization without defining prop plugin', () => {
214
221
  const AppError = Error0.use('stack', { serialize: ({ value }) => (value ? `custom:${value}` : undefined) })
215
222
  const error = new AppError('test')
package/src/index.ts CHANGED
@@ -79,11 +79,22 @@ export type ErrorPluginStackSerialize<TError extends Error0> = (options: {
79
79
  }) => unknown
80
80
  export type ErrorPluginStack<TError extends Error0 = Error0> = { serialize: ErrorPluginStackSerialize<TError> }
81
81
  export type ErrorPluginCauseSerialize<TError extends Error0> = (options: {
82
- value: unknown
82
+ cause: unknown
83
83
  error: TError
84
84
  isPublic: boolean
85
+ is: (cause: unknown) => boolean
86
+ serialize: (cause: unknown) => Record<string, unknown>
85
87
  }) => unknown
86
- export type ErrorPluginCause<TError extends Error0 = Error0> = { serialize: ErrorPluginCauseSerialize<TError> }
88
+ export type ErrorPluginCauseDeserialize = (options: {
89
+ cause: unknown
90
+ error: Record<string, unknown>
91
+ isSerialized: (serializedCause: unknown) => boolean
92
+ fromSerialized: (serializedCause: unknown) => Error0
93
+ }) => unknown
94
+ export type ErrorPluginCause<TError extends Error0 = Error0> = {
95
+ serialize: ErrorPluginCauseSerialize<TError>
96
+ deserialize: ErrorPluginCauseDeserialize
97
+ }
87
98
  export type ErrorPluginMessageSerialize<TError extends Error0> = (options: {
88
99
  value: string
89
100
  error: TError
@@ -897,8 +908,6 @@ export class Error0 extends Error {
897
908
  console.error(`Error0: failed to deserialize property ${key}`, errorRecord)
898
909
  }
899
910
  }
900
- // we do not serialize causes
901
- // ;(recreated as unknown as { cause?: unknown }).cause = errorRecord.cause
902
911
  if ('stack' in errorRecord) {
903
912
  try {
904
913
  if (typeof errorRecord.stack === 'string') {
@@ -910,13 +919,14 @@ export class Error0 extends Error {
910
919
  }
911
920
  }
912
921
  const causePlugin = plugin.cause
913
- if (causePlugin?.serialize && 'cause' in errorRecord) {
922
+ if (causePlugin && 'cause' in errorRecord) {
914
923
  try {
915
- if (this.isSerialized(errorRecord.cause)) {
916
- ;(recreated as { cause?: unknown }).cause = this._fromSerialized(errorRecord.cause)
917
- } else {
918
- ;(recreated as { cause?: unknown }).cause = errorRecord.cause
919
- }
924
+ ;(recreated as { cause?: unknown }).cause = causePlugin.deserialize({
925
+ cause: errorRecord.cause,
926
+ error: errorRecord,
927
+ isSerialized: (serializedCause) => this.isSerialized(serializedCause),
928
+ fromSerialized: (serializedCause) => this._fromSerialized(serializedCause),
929
+ })
920
930
  } catch {
921
931
  // eslint-disable-next-line no-console
922
932
  console.error('Error0: failed to deserialize cause', errorRecord)
@@ -1098,8 +1108,13 @@ export class Error0 extends Error {
1098
1108
  if (typeof key === 'undefined') {
1099
1109
  throw new Error('Error0.use("cause", value) requires cause plugin value')
1100
1110
  }
1101
- if (typeof key !== 'object' || key === null || typeof (key as { serialize?: unknown }).serialize !== 'function') {
1102
- throw new Error('Error0.use("cause", value) expects { serialize: function }')
1111
+ if (
1112
+ typeof key !== 'object' ||
1113
+ key === null ||
1114
+ typeof (key as { serialize?: unknown }).serialize !== 'function' ||
1115
+ typeof (key as { deserialize?: unknown }).deserialize !== 'function'
1116
+ ) {
1117
+ throw new Error('Error0.use("cause", value) expects { serialize: function, deserialize: function }')
1103
1118
  }
1104
1119
  return this._useWithPlugin({
1105
1120
  cause: key as ErrorPluginCause,
@@ -1166,8 +1181,6 @@ export class Error0 extends Error {
1166
1181
  }
1167
1182
  const json: Record<string, unknown> = {
1168
1183
  name: error0.name,
1169
- // we do not serialize causes, it is enough that we have floated props and adapt helper
1170
- // cause: error0.cause,
1171
1184
  }
1172
1185
  if (serializedMessage !== undefined) {
1173
1186
  json.message = serializedMessage
@@ -1206,7 +1219,7 @@ export class Error0 extends Error {
1206
1219
  if (stackPlugin) {
1207
1220
  serializedStack = stackPlugin.serialize({ value: error0.stack, error: error0, isPublic })
1208
1221
  } else {
1209
- serializedStack = error0.stack
1222
+ serializedStack = isPublic ? undefined : error0.stack
1210
1223
  }
1211
1224
  if (serializedStack !== undefined) {
1212
1225
  json.stack = serializedStack
@@ -1219,9 +1232,11 @@ export class Error0 extends Error {
1219
1232
  if (causePlugin?.serialize) {
1220
1233
  try {
1221
1234
  const serializedCause = causePlugin.serialize({
1222
- value: (error0 as { cause?: unknown }).cause,
1235
+ cause: (error0 as { cause?: unknown }).cause,
1223
1236
  error: error0,
1224
1237
  isPublic,
1238
+ is: (cause) => this.is(cause),
1239
+ serialize: (cause) => this.serialize(cause, isPublic),
1225
1240
  })
1226
1241
  if (serializedCause !== undefined) {
1227
1242
  json.cause = serializedCause
@@ -1,8 +1,8 @@
1
1
  import { describe, expect, it } from 'bun:test'
2
2
  import { Error0 } from '../index.js'
3
- import { causeSerializePlugin } from './cause-serialize.js'
3
+ import { causePlugin } from './cause.js'
4
4
 
5
- describe('causeSerializePlugin', () => {
5
+ describe('causePlugin', () => {
6
6
  const statusPlugin = Error0.plugin().use('prop', 'status', {
7
7
  init: (input: number) => input,
8
8
  resolve: ({ flow }) => flow.find((value) => typeof value === 'number'),
@@ -23,7 +23,7 @@ describe('causeSerializePlugin', () => {
23
23
  it('serializes and deserializes nested Error0 causes', () => {
24
24
  const AppError = Error0.use(statusPlugin)
25
25
  .use(codePlugin)
26
- .use(causeSerializePlugin({ hideWhenPublic: false }))
26
+ .use(causePlugin({ isPublic: true }))
27
27
  const deepCauseError = new AppError('deep cause')
28
28
  const causeError = new AppError('cause', { status: 409, code: 'NOT_FOUND', cause: deepCauseError })
29
29
  const error = new AppError('root', { status: 500, cause: causeError })
@@ -50,4 +50,57 @@ describe('causeSerializePlugin', () => {
50
50
  expect((recreated.cause as any).cause.code).toBe(undefined)
51
51
  expect((recreated.cause as any).cause.cause).toBeUndefined()
52
52
  })
53
+
54
+ it('supports variants', () => {
55
+ class DbError extends Error {
56
+ query: string
57
+ constructor(message: string, options: { cause?: unknown; query: string }) {
58
+ super(message, { cause: options.cause })
59
+ this.query = options.query
60
+ this.name = 'DbError'
61
+ }
62
+ static serialize(error: DbError): Record<string, unknown> {
63
+ return {
64
+ message: error.message,
65
+ query: error.query,
66
+ }
67
+ }
68
+ static from(error: unknown): DbError {
69
+ if (error instanceof DbError) {
70
+ return error
71
+ }
72
+ const object = typeof error === 'object' && error !== null ? (error as Record<string, unknown>) : {}
73
+ const message =
74
+ typeof object.message === 'string' ? object.message : typeof error === 'string' ? error : 'Unknown error'
75
+ const query = typeof object.query === 'string' ? object.query : 'NOT_FOUND'
76
+ return new DbError(message, { cause: error, query })
77
+ }
78
+ static isSerialized(serializedCause: unknown): boolean {
79
+ return (
80
+ typeof serializedCause === 'object' &&
81
+ serializedCause !== null &&
82
+ 'query' in serializedCause &&
83
+ typeof serializedCause.query === 'string'
84
+ )
85
+ }
86
+ }
87
+ const AppError = Error0.use(statusPlugin)
88
+ .use(codePlugin)
89
+ .use(
90
+ causePlugin({
91
+ variants: {
92
+ DbError,
93
+ },
94
+ }),
95
+ )
96
+ const dbError = new DbError('test', { query: 'SELECT * FROM users' })
97
+ const error = new AppError('root', { status: 500, cause: dbError })
98
+ const json = AppError.serialize(error, false)
99
+ expect(json.cause).toBeDefined()
100
+ expect((json.cause as any).query).toBe('SELECT * FROM users')
101
+ const recreated = AppError.from(json)
102
+ expect(recreated).toBeInstanceOf(AppError)
103
+ expect(recreated.cause).toBeInstanceOf(DbError)
104
+ expect((recreated.cause as any).query).toBe('SELECT * FROM users')
105
+ })
53
106
  })
@@ -0,0 +1,45 @@
1
+ import { Error0 } from '../index.js'
2
+
3
+ type Variant = {
4
+ new (...args: any[]): unknown
5
+ [Symbol.hasInstance]: (value: any) => boolean
6
+ isSerialized: (serializedCause: any) => boolean
7
+ serialize: (error: any) => unknown
8
+ from: (error: any) => unknown
9
+ }
10
+
11
+ export const causePlugin = <TVariants extends Record<string, Variant> = Record<never, Variant>>({
12
+ isPublic = false,
13
+ variants = undefined,
14
+ }: { isPublic?: boolean; variants?: TVariants } = {}) =>
15
+ Error0.plugin().cause({
16
+ serialize: ({ cause, isPublic: _isPublic, is, serialize }) => {
17
+ if (!isPublic && _isPublic) {
18
+ return undefined
19
+ }
20
+ if (variants) {
21
+ for (const variant of Object.values(variants)) {
22
+ if (cause instanceof variant) {
23
+ return variant.serialize(cause)
24
+ }
25
+ }
26
+ }
27
+ if (is(cause)) {
28
+ return serialize(cause)
29
+ }
30
+ return undefined
31
+ },
32
+ deserialize: ({ cause, fromSerialized, isSerialized }) => {
33
+ if (variants) {
34
+ for (const variant of Object.values(variants)) {
35
+ if (variant.isSerialized(cause)) {
36
+ return variant.from(cause)
37
+ }
38
+ }
39
+ }
40
+ if (isSerialized(cause)) {
41
+ return fromSerialized(cause)
42
+ }
43
+ return cause
44
+ },
45
+ })
@@ -1,12 +1,20 @@
1
1
  import { Error0 } from '../index.js'
2
2
 
3
- export const codePlugin = <TCode extends string>({ codes }: { codes?: TCode[] } = {}) => {
3
+ export const codePlugin = <TCode extends string>({
4
+ codes,
5
+ isPublic = false,
6
+ }: { codes?: TCode[]; isPublic?: boolean } = {}) => {
4
7
  const isCode = (value: unknown): value is TCode =>
5
8
  typeof value === 'string' && (!codes || codes.includes(value as TCode))
6
9
  return Error0.plugin().prop('code', {
7
10
  init: (code: TCode) => code,
8
11
  resolve: ({ flow }) => flow.find(Boolean),
9
- serialize: ({ resolved, isPublic }) => resolved,
12
+ serialize: ({ resolved, isPublic: _isPublic }) => {
13
+ if (!isPublic && _isPublic) {
14
+ return undefined
15
+ }
16
+ return resolved
17
+ },
10
18
  deserialize: ({ value, record }) => (isCode(value) ? value : undefined),
11
19
  })
12
20
  }