@benzenejs/results 0.0.0-stage → 0.1.0-beta.2

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.
@@ -0,0 +1,49 @@
1
+ import { BenzeneError, IBenzeneResultOf, VoidResult } from '@benzenejs/abstractions';
2
+ import { ProblemDetails } from './ProblemDetails';
3
+ export declare const BenzeneResult: {
4
+ /** Port of the C# `Set` overloads. */
5
+ readonly set: <T = VoidResult>(status: string, payload?: T, isSuccessful?: boolean) => IBenzeneResultOf<T>;
6
+ /**
7
+ * Port of C# `Set(status, params BenzeneError[] errors)` and its `string[]` sibling: accepts
8
+ * either, so `setErrors(status, 'a message')` and
9
+ * `setErrors(status, { message: 'a message', field: 'Name', code: 'NotEmpty' })` both work.
10
+ */
11
+ readonly setErrors: <T = VoidResult>(status: string, ...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
12
+ /**
13
+ * Builds a failed result carrying a deliberately-authored problem document - the port of C#
14
+ * `BenzeneResult.Problem<T>(ProblemDetails)`.
15
+ *
16
+ * The status comes from the document's `benzeneStatus`, which is required: a problem document
17
+ * with no status cannot be classified by anything downstream. The result's `errors` are projected
18
+ * from the document's own `errors`, and the result is always unsuccessful - this factory exists
19
+ * to fail deliberately with a richer document than the status-derived one, most often to set an
20
+ * application-owned `type` (wire-contracts.md §1.3).
21
+ */
22
+ readonly problem: <T = VoidResult>(problem: ProblemDetails) => IBenzeneResultOf<T>;
23
+ /**
24
+ * Builds a failed result for a problem document a CLIENT received off the wire - the port of C#
25
+ * `BenzeneResult.AttachReceivedProblem<T>` (internal there, reached from
26
+ * `Benzene.Clients.Common.ClientResultExtensions`; exported here because the clients live in another
27
+ * package). The status is the one the client decided - the document's `benzeneStatus` where it has one
28
+ * (wire-contracts §4.1), else the envelope/HTTP classification - and is taken as given here; `errors`
29
+ * are the ones rebuilt from the document
30
+ * (core-concepts §12 "Error fidelity", wire-contracts.md §1.3); and the document, when there is one,
31
+ * is attached so `ProblemTypes.from(result)` returns exactly what was received - an application's own
32
+ * problem `type` survives the hop.
33
+ */
34
+ readonly receivedProblem: <T = VoidResult>(status: string, errors: readonly BenzeneError[], problem?: ProblemDetails) => IBenzeneResultOf<T>;
35
+ readonly ok: <T = VoidResult>(payload?: T) => IBenzeneResultOf<T>;
36
+ readonly created: <T = VoidResult>(payload?: T) => IBenzeneResultOf<T>;
37
+ readonly accepted: <T = VoidResult>(payload?: T) => IBenzeneResultOf<T>;
38
+ readonly updated: <T = VoidResult>(payload?: T) => IBenzeneResultOf<T>;
39
+ readonly deleted: <T = VoidResult>(payload?: T) => IBenzeneResultOf<T>;
40
+ readonly ignored: <T = VoidResult>() => IBenzeneResultOf<T>;
41
+ readonly notFound: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
42
+ readonly badRequest: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
43
+ readonly unauthorized: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
44
+ readonly forbidden: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
45
+ readonly validationError: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
46
+ readonly serviceUnavailable: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
47
+ readonly tooManyRequests: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
48
+ readonly unexpectedError: <T = VoidResult>(...errors: (string | BenzeneError)[]) => IBenzeneResultOf<T>;
49
+ };
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BenzeneResult = void 0;
4
+ const abstractions_1 = require("@benzenejs/abstractions");
5
+ const BenzeneResultStatus_1 = require("./BenzeneResultStatus");
6
+ /**
7
+ * Factory for creating result instances.
8
+ * Port of Benzene.Results.BenzeneResult.
9
+ *
10
+ * The C# generic/non-generic overload pairs (`Ok()` / `Ok<T>(payload)`) collapse
11
+ * into single functions with an optional payload defaulting to `VoidResult`
12
+ * (the port of C# `Void`). The status-specific factories mirror the C# names.
13
+ */
14
+ class BenzeneResultInternal {
15
+ status;
16
+ payload;
17
+ errors;
18
+ isSuccessful;
19
+ constructor(status, payload, errors, isSuccessful) {
20
+ this.status = status;
21
+ this.payload = payload;
22
+ this.errors = errors;
23
+ this.isSuccessful = isSuccessful;
24
+ }
25
+ get payloadAsObject() {
26
+ return this.payload;
27
+ }
28
+ }
29
+ /**
30
+ * Widens the caller's errors to structured {@link BenzeneError}s. A plain string becomes
31
+ * `{ message }` - the shape a message-only failure has always had on the wire - so every existing
32
+ * call site that passes strings is unchanged, while a caller that has a `field` or `code` can now
33
+ * pass those through instead of losing them.
34
+ */
35
+ function toBenzeneErrors(errors) {
36
+ return errors.map((error) => (typeof error === 'string' ? { message: error } : error));
37
+ }
38
+ function create(status, payload, errors = [], isSuccessful) {
39
+ return new BenzeneResultInternal(status, payload, errors, isSuccessful ?? BenzeneResultStatus_1.BenzeneResultStatus.isSuccess(status));
40
+ }
41
+ const voidPayload = new abstractions_1.VoidResult();
42
+ exports.BenzeneResult = {
43
+ /** Port of the C# `Set` overloads. */
44
+ set(status, payload, isSuccessful) {
45
+ return create(status, (payload ?? voidPayload), [], isSuccessful);
46
+ },
47
+ /**
48
+ * Port of C# `Set(status, params BenzeneError[] errors)` and its `string[]` sibling: accepts
49
+ * either, so `setErrors(status, 'a message')` and
50
+ * `setErrors(status, { message: 'a message', field: 'Name', code: 'NotEmpty' })` both work.
51
+ */
52
+ setErrors(status, ...errors) {
53
+ return create(status, voidPayload, toBenzeneErrors(errors));
54
+ },
55
+ /**
56
+ * Builds a failed result carrying a deliberately-authored problem document - the port of C#
57
+ * `BenzeneResult.Problem<T>(ProblemDetails)`.
58
+ *
59
+ * The status comes from the document's `benzeneStatus`, which is required: a problem document
60
+ * with no status cannot be classified by anything downstream. The result's `errors` are projected
61
+ * from the document's own `errors`, and the result is always unsuccessful - this factory exists
62
+ * to fail deliberately with a richer document than the status-derived one, most often to set an
63
+ * application-owned `type` (wire-contracts.md §1.3).
64
+ */
65
+ problem(problem) {
66
+ if (problem.benzeneStatus === undefined || problem.benzeneStatus === '') {
67
+ throw new Error('problem.benzeneStatus is required to build a BenzeneResult.problem(...) - a problem ' +
68
+ 'document with no status cannot be classified by anything downstream. Set ' +
69
+ 'ProblemDetails.benzeneStatus before passing it here.');
70
+ }
71
+ const result = create(problem.benzeneStatus, voidPayload, [...(problem.errors ?? [])], false);
72
+ // The authored document travels alongside the result so the response mapper emits it verbatim
73
+ // rather than re-deriving one from the status - otherwise an application-owned `type` would be
74
+ // overwritten by the registry URI on the way out.
75
+ result.problem = problem;
76
+ return result;
77
+ },
78
+ /**
79
+ * Builds a failed result for a problem document a CLIENT received off the wire - the port of C#
80
+ * `BenzeneResult.AttachReceivedProblem<T>` (internal there, reached from
81
+ * `Benzene.Clients.Common.ClientResultExtensions`; exported here because the clients live in another
82
+ * package). The status is the one the client decided - the document's `benzeneStatus` where it has one
83
+ * (wire-contracts §4.1), else the envelope/HTTP classification - and is taken as given here; `errors`
84
+ * are the ones rebuilt from the document
85
+ * (core-concepts §12 "Error fidelity", wire-contracts.md §1.3); and the document, when there is one,
86
+ * is attached so `ProblemTypes.from(result)` returns exactly what was received - an application's own
87
+ * problem `type` survives the hop.
88
+ */
89
+ receivedProblem(status, errors, problem) {
90
+ const result = create(status, voidPayload, [...errors], false);
91
+ if (problem !== undefined) {
92
+ result.problem = problem;
93
+ }
94
+ return result;
95
+ },
96
+ ok(payload) {
97
+ return exports.BenzeneResult.set(BenzeneResultStatus_1.BenzeneResultStatus.ok, payload);
98
+ },
99
+ created(payload) {
100
+ return exports.BenzeneResult.set(BenzeneResultStatus_1.BenzeneResultStatus.created, payload);
101
+ },
102
+ accepted(payload) {
103
+ return exports.BenzeneResult.set(BenzeneResultStatus_1.BenzeneResultStatus.accepted, payload);
104
+ },
105
+ updated(payload) {
106
+ return exports.BenzeneResult.set(BenzeneResultStatus_1.BenzeneResultStatus.updated, payload);
107
+ },
108
+ deleted(payload) {
109
+ return exports.BenzeneResult.set(BenzeneResultStatus_1.BenzeneResultStatus.deleted, payload);
110
+ },
111
+ ignored() {
112
+ return exports.BenzeneResult.set(BenzeneResultStatus_1.BenzeneResultStatus.ignored);
113
+ },
114
+ notFound(...errors) {
115
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.notFound, ...errors);
116
+ },
117
+ badRequest(...errors) {
118
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.badRequest, ...errors);
119
+ },
120
+ unauthorized(...errors) {
121
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.unauthorized, ...errors);
122
+ },
123
+ forbidden(...errors) {
124
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.forbidden, ...errors);
125
+ },
126
+ validationError(...errors) {
127
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.validationError, ...errors);
128
+ },
129
+ serviceUnavailable(...errors) {
130
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.serviceUnavailable, ...errors);
131
+ },
132
+ tooManyRequests(...errors) {
133
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.tooManyRequests, ...errors);
134
+ },
135
+ unexpectedError(...errors) {
136
+ return exports.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.unexpectedError, ...errors);
137
+ },
138
+ };
@@ -0,0 +1,14 @@
1
+ import { IBenzeneResultOf, VoidResult } from '@benzenejs/abstractions';
2
+ /**
3
+ * Free-function ports of the `Benzene.Results.BenzeneResultExtensions` C# extension methods.
4
+ *
5
+ * Only the HTTP-status reverse mapping (`Convert(this HttpStatusCode)`) is ported here so far — the
6
+ * client-side mapping of an HTTP response code back to a Benzene result status
7
+ * (`wire-contracts.md` §4.1, the "reverse" table). The `As`/`AsTask` result-shape helpers are ported
8
+ * elsewhere as they are needed.
9
+ *
10
+ * TS bend: .NET keys the switch on the `System.Net.HttpStatusCode` enum; TypeScript has no such enum,
11
+ * so the port takes the numeric status code directly (`convertHttpStatusCode(204)`), which is how the
12
+ * conformance runner and HTTP clients already carry it. The mapping is byte-for-byte the same table.
13
+ */
14
+ export declare function convertHttpStatusCode(httpStatusCode: number): IBenzeneResultOf<VoidResult>;
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.convertHttpStatusCode = convertHttpStatusCode;
4
+ const BenzeneResult_1 = require("./BenzeneResult");
5
+ const BenzeneResultStatus_1 = require("./BenzeneResultStatus");
6
+ /**
7
+ * Free-function ports of the `Benzene.Results.BenzeneResultExtensions` C# extension methods.
8
+ *
9
+ * Only the HTTP-status reverse mapping (`Convert(this HttpStatusCode)`) is ported here so far — the
10
+ * client-side mapping of an HTTP response code back to a Benzene result status
11
+ * (`wire-contracts.md` §4.1, the "reverse" table). The `As`/`AsTask` result-shape helpers are ported
12
+ * elsewhere as they are needed.
13
+ *
14
+ * TS bend: .NET keys the switch on the `System.Net.HttpStatusCode` enum; TypeScript has no such enum,
15
+ * so the port takes the numeric status code directly (`convertHttpStatusCode(204)`), which is how the
16
+ * conformance runner and HTTP clients already carry it. The mapping is byte-for-byte the same table.
17
+ */
18
+ function convertHttpStatusCode(httpStatusCode) {
19
+ switch (httpStatusCode) {
20
+ case 202:
21
+ return BenzeneResult_1.BenzeneResult.accepted();
22
+ case 200:
23
+ return BenzeneResult_1.BenzeneResult.ok();
24
+ case 201:
25
+ return BenzeneResult_1.BenzeneResult.created();
26
+ case 204:
27
+ return BenzeneResult_1.BenzeneResult.deleted();
28
+ case 404:
29
+ return BenzeneResult_1.BenzeneResult.notFound();
30
+ case 400:
31
+ return BenzeneResult_1.BenzeneResult.badRequest();
32
+ case 409:
33
+ return BenzeneResult_1.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.conflict);
34
+ case 403:
35
+ return BenzeneResult_1.BenzeneResult.forbidden();
36
+ case 401:
37
+ return BenzeneResult_1.BenzeneResult.unauthorized();
38
+ case 422:
39
+ return BenzeneResult_1.BenzeneResult.validationError();
40
+ case 429:
41
+ return BenzeneResult_1.BenzeneResult.tooManyRequests();
42
+ case 408:
43
+ return BenzeneResult_1.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.timeout);
44
+ case 504:
45
+ return BenzeneResult_1.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.timeout);
46
+ case 501:
47
+ return BenzeneResult_1.BenzeneResult.setErrors(BenzeneResultStatus_1.BenzeneResultStatus.notImplemented);
48
+ case 502:
49
+ return BenzeneResult_1.BenzeneResult.serviceUnavailable();
50
+ case 503:
51
+ return BenzeneResult_1.BenzeneResult.serviceUnavailable();
52
+ default:
53
+ return BenzeneResult_1.BenzeneResult.unexpectedError();
54
+ }
55
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Well-known result statuses and their success/failure classification.
3
+ * Port of Benzene.Results.BenzeneResultStatus.
4
+ *
5
+ * The string VALUES are the normative **wire** status vocabulary from `docs/specification/wire-contracts.md`
6
+ * §3 - lowercase-kebab-case and case-sensitive (`ok`, `not-found`, `validation-error`), identical to the
7
+ * .NET constants. This is a cross-language contract: a Benzene service in any language writes these exact
8
+ * strings as the response envelope's `statusCode`, so a TypeScript service and a .NET service (or mesh
9
+ * aggregator) reading each other's responses classify statuses identically.
10
+ */
11
+ export declare const BenzeneResultStatus: {
12
+ readonly accepted: "accepted";
13
+ readonly ok: "ok";
14
+ readonly created: "created";
15
+ readonly updated: "updated";
16
+ readonly deleted: "deleted";
17
+ readonly ignored: "ignored";
18
+ readonly notFound: "not-found";
19
+ readonly badRequest: "bad-request";
20
+ readonly validationError: "validation-error";
21
+ readonly serviceUnavailable: "service-unavailable";
22
+ readonly notImplemented: "not-implemented";
23
+ readonly unexpectedError: "unexpected-error";
24
+ readonly conflict: "conflict";
25
+ readonly forbidden: "forbidden";
26
+ readonly unauthorized: "unauthorized";
27
+ readonly tooManyRequests: "too-many-requests";
28
+ readonly timeout: "timeout";
29
+ readonly isSuccess: (status: string | undefined) => boolean;
30
+ readonly isFailure: (status: string | undefined) => boolean;
31
+ readonly isKnown: (status: string | undefined) => boolean;
32
+ readonly isTransient: (status: string | undefined) => boolean;
33
+ };
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BenzeneResultStatus = void 0;
4
+ /**
5
+ * Well-known result statuses and their success/failure classification.
6
+ * Port of Benzene.Results.BenzeneResultStatus.
7
+ *
8
+ * The string VALUES are the normative **wire** status vocabulary from `docs/specification/wire-contracts.md`
9
+ * §3 - lowercase-kebab-case and case-sensitive (`ok`, `not-found`, `validation-error`), identical to the
10
+ * .NET constants. This is a cross-language contract: a Benzene service in any language writes these exact
11
+ * strings as the response envelope's `statusCode`, so a TypeScript service and a .NET service (or mesh
12
+ * aggregator) reading each other's responses classify statuses identically.
13
+ */
14
+ exports.BenzeneResultStatus = {
15
+ accepted: 'accepted',
16
+ ok: 'ok',
17
+ created: 'created',
18
+ updated: 'updated',
19
+ deleted: 'deleted',
20
+ ignored: 'ignored',
21
+ notFound: 'not-found',
22
+ badRequest: 'bad-request',
23
+ validationError: 'validation-error',
24
+ serviceUnavailable: 'service-unavailable',
25
+ notImplemented: 'not-implemented',
26
+ unexpectedError: 'unexpected-error',
27
+ conflict: 'conflict',
28
+ forbidden: 'forbidden',
29
+ unauthorized: 'unauthorized',
30
+ tooManyRequests: 'too-many-requests',
31
+ timeout: 'timeout',
32
+ isSuccess(status) {
33
+ return status !== undefined && successStatuses.has(status);
34
+ },
35
+ isFailure(status) {
36
+ return status !== undefined && failureStatuses.has(status);
37
+ },
38
+ isKnown(status) {
39
+ return exports.BenzeneResultStatus.isSuccess(status) || exports.BenzeneResultStatus.isFailure(status);
40
+ },
41
+ isTransient(status) {
42
+ return status !== undefined && transientStatuses.has(status);
43
+ },
44
+ };
45
+ const successStatuses = new Set(['ok', 'created', 'accepted', 'updated', 'deleted', 'ignored']);
46
+ const failureStatuses = new Set([
47
+ 'bad-request',
48
+ 'validation-error',
49
+ 'unauthorized',
50
+ 'forbidden',
51
+ 'not-found',
52
+ 'conflict',
53
+ 'too-many-requests',
54
+ 'timeout',
55
+ 'not-implemented',
56
+ 'service-unavailable',
57
+ 'unexpected-error',
58
+ ]);
59
+ const transientStatuses = new Set(['service-unavailable', 'too-many-requests', 'timeout']);
@@ -0,0 +1,52 @@
1
+ import { BenzeneError } from '@benzenejs/abstractions';
2
+ /**
3
+ * An [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem document — the body of a failed
4
+ * result (wire-contracts.md §1.3). Port of Benzene.Results.ProblemDetails.
5
+ *
6
+ * Deviation: C# declares nullable auto-properties with `[JsonIgnore(WhenWritingNull)]`; the port
7
+ * types them optional (`| undefined`) so an unset member is simply omitted by `JSON.stringify`
8
+ * rather than serialized as an explicit `null` the way System.Text.Json would.
9
+ */
10
+ export declare class ProblemDetails {
11
+ /**
12
+ * A URI reference identifying the problem *type*. Framework-produced failures use the registry
13
+ * URI for the status (`ProblemTypes`); applications should use their own absolute URI. Readers
14
+ * treat it as an **opaque identifier** — compare by string equality, never dereference.
15
+ */
16
+ type: string | undefined;
17
+ /** A short human summary of the *type*, fixed per type. Wording is never asserted by fixtures. */
18
+ title: string | undefined;
19
+ /**
20
+ * The **HTTP** response status code — HTTP bindings only, and a `number`, not the Benzene status.
21
+ * Must equal the actual HTTP response status when present, and must be **omitted** where no HTTP
22
+ * response exists (an envelope over a queue), which is why it is filled in by the HTTP-aware
23
+ * response mapper rather than by the transport-neutral `ProblemTypes.from`. Clients must not
24
+ * classify success/failure from this member — classification is envelope-first (§1.2).
25
+ */
26
+ status: number | undefined;
27
+ /**
28
+ * Human-readable detail for this occurrence — the result's error messages joined with `", "`.
29
+ * The compatibility member: every reader of the pre-RFC-9457 `ErrorPayload` shape used only this
30
+ * one and keeps working unchanged.
31
+ */
32
+ detail: string | undefined;
33
+ /** Optional, application-owned. The framework never fabricates a value. */
34
+ instance: string | undefined;
35
+ /**
36
+ * **Required on framework-produced documents.** The Benzene status string (§3), mirroring the
37
+ * envelope's `statusCode`. This is the transport-neutral discriminator — present on every
38
+ * transport, whereas {@link status} only exists on HTTP.
39
+ *
40
+ * It replaced a `status: string` member that carried the Benzene status and collided with RFC
41
+ * 9457's own `status` (defined as the integer HTTP code). The collision was resolved by rename,
42
+ * not by dropping the RFC alignment. The `benzene` marker is there because this member namespace
43
+ * is shared with RFC 9457 itself and with applications.
44
+ */
45
+ benzeneStatus: string | undefined;
46
+ /**
47
+ * The result's errors, when present — authoritative and ordered. Omitted from the wire when the
48
+ * result carries none; a reader without this member treats {@link detail} as a single opaque
49
+ * message.
50
+ */
51
+ errors: BenzeneError[] | undefined;
52
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProblemDetails = void 0;
4
+ /**
5
+ * An [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) problem document — the body of a failed
6
+ * result (wire-contracts.md §1.3). Port of Benzene.Results.ProblemDetails.
7
+ *
8
+ * Deviation: C# declares nullable auto-properties with `[JsonIgnore(WhenWritingNull)]`; the port
9
+ * types them optional (`| undefined`) so an unset member is simply omitted by `JSON.stringify`
10
+ * rather than serialized as an explicit `null` the way System.Text.Json would.
11
+ */
12
+ class ProblemDetails {
13
+ /**
14
+ * A URI reference identifying the problem *type*. Framework-produced failures use the registry
15
+ * URI for the status (`ProblemTypes`); applications should use their own absolute URI. Readers
16
+ * treat it as an **opaque identifier** — compare by string equality, never dereference.
17
+ */
18
+ type;
19
+ /** A short human summary of the *type*, fixed per type. Wording is never asserted by fixtures. */
20
+ title;
21
+ /**
22
+ * The **HTTP** response status code — HTTP bindings only, and a `number`, not the Benzene status.
23
+ * Must equal the actual HTTP response status when present, and must be **omitted** where no HTTP
24
+ * response exists (an envelope over a queue), which is why it is filled in by the HTTP-aware
25
+ * response mapper rather than by the transport-neutral `ProblemTypes.from`. Clients must not
26
+ * classify success/failure from this member — classification is envelope-first (§1.2).
27
+ */
28
+ status;
29
+ /**
30
+ * Human-readable detail for this occurrence — the result's error messages joined with `", "`.
31
+ * The compatibility member: every reader of the pre-RFC-9457 `ErrorPayload` shape used only this
32
+ * one and keeps working unchanged.
33
+ */
34
+ detail;
35
+ /** Optional, application-owned. The framework never fabricates a value. */
36
+ instance;
37
+ /**
38
+ * **Required on framework-produced documents.** The Benzene status string (§3), mirroring the
39
+ * envelope's `statusCode`. This is the transport-neutral discriminator — present on every
40
+ * transport, whereas {@link status} only exists on HTTP.
41
+ *
42
+ * It replaced a `status: string` member that carried the Benzene status and collided with RFC
43
+ * 9457's own `status` (defined as the integer HTTP code). The collision was resolved by rename,
44
+ * not by dropping the RFC alignment. The `benzene` marker is there because this member namespace
45
+ * is shared with RFC 9457 itself and with applications.
46
+ */
47
+ benzeneStatus;
48
+ /**
49
+ * The result's errors, when present — authoritative and ordered. Omitted from the wire when the
50
+ * result carries none; a reader without this member treats {@link detail} as a single opaque
51
+ * message.
52
+ */
53
+ errors;
54
+ }
55
+ exports.ProblemDetails = ProblemDetails;
@@ -0,0 +1,58 @@
1
+ import { IBenzeneResult } from '@benzenejs/abstractions';
2
+ import { ProblemDetails } from './ProblemDetails';
3
+ export declare const ProblemTypes: {
4
+ /** The {@link ProblemDetails.type} URI for `bad-request`. */
5
+ readonly badRequest: "https://benzene.app/problems/bad-request";
6
+ /** The {@link ProblemDetails.type} URI for `unauthorized`. */
7
+ readonly unauthorized: "https://benzene.app/problems/unauthorized";
8
+ /** The {@link ProblemDetails.type} URI for `forbidden`. */
9
+ readonly forbidden: "https://benzene.app/problems/forbidden";
10
+ /** The {@link ProblemDetails.type} URI for `not-found`. */
11
+ readonly notFound: "https://benzene.app/problems/not-found";
12
+ /** The {@link ProblemDetails.type} URI for `conflict`. */
13
+ readonly conflict: "https://benzene.app/problems/conflict";
14
+ /** The {@link ProblemDetails.type} URI for `validation-error`. */
15
+ readonly validationError: "https://benzene.app/problems/validation-error";
16
+ /** The {@link ProblemDetails.type} URI for `too-many-requests`. */
17
+ readonly tooManyRequests: "https://benzene.app/problems/too-many-requests";
18
+ /** The {@link ProblemDetails.type} URI for `unexpected-error`. */
19
+ readonly unexpectedError: "https://benzene.app/problems/unexpected-error";
20
+ /** The {@link ProblemDetails.type} URI for `not-implemented`. */
21
+ readonly notImplemented: "https://benzene.app/problems/not-implemented";
22
+ /** The {@link ProblemDetails.type} URI for `service-unavailable`. */
23
+ readonly serviceUnavailable: "https://benzene.app/problems/service-unavailable";
24
+ /** The {@link ProblemDetails.type} URI for `timeout`. */
25
+ readonly timeout: "https://benzene.app/problems/timeout";
26
+ /**
27
+ * The registry {@link ProblemDetails.type} URI for `status`, or `undefined` for an
28
+ * application-defined status the registry doesn't know (the application owns its own `type`, or
29
+ * omits one).
30
+ */
31
+ readonly typeFor: (status: string | undefined) => string | undefined;
32
+ /**
33
+ * The registry {@link ProblemDetails.title} for `status`, or `undefined` for an
34
+ * application-defined status the registry doesn't know.
35
+ */
36
+ readonly titleFor: (status: string | undefined) => string | undefined;
37
+ /**
38
+ * The HTTP status code the registry maps `status` to, or `500` for an application-defined status —
39
+ * the same "unknown status falls to the generic-error row" rule the {@link BenzeneResultStatus}-based
40
+ * HTTP mappings use elsewhere (e.g. `DefaultHttpStatusCodeMapper`).
41
+ */
42
+ readonly httpStatusFor: (status: string | undefined) => number;
43
+ /**
44
+ * Builds the problem document for a failed `result`: {@link ProblemDetails.type}/
45
+ * {@link ProblemDetails.title} from the registry (both `undefined` for an application-defined
46
+ * status), {@link ProblemDetails.detail} as the result's error messages joined with `", "`,
47
+ * {@link ProblemDetails.benzeneStatus} as the result's status, and {@link ProblemDetails.errors}
48
+ * as the result's structured errors when non-empty (else `undefined`, so the member is omitted
49
+ * from the wire). Deliberately never sets {@link ProblemDetails.status} — the numeric HTTP status
50
+ * is an HTTP-binding concern, filled in by the HTTP-aware response mapper, not this
51
+ * transport-neutral factory.
52
+ *
53
+ * A result built by `BenzeneResult.problem(...)` carries its authored document, which is returned
54
+ * verbatim: re-deriving one here would overwrite an application-owned `type` with the registry
55
+ * URI, which is the whole reason that factory exists (wire-contracts.md §1.3).
56
+ */
57
+ readonly from: (result: IBenzeneResult) => ProblemDetails;
58
+ };
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ProblemTypes = void 0;
4
+ const BenzeneResultStatus_1 = require("./BenzeneResultStatus");
5
+ const ProblemDetails_1 = require("./ProblemDetails");
6
+ /**
7
+ * The problem-type registry: `type` URI / `title` / HTTP status keyed by the existing
8
+ * {@link BenzeneResultStatus} failure vocabulary — no new taxonomy (see
9
+ * `docs/specification/wire-contracts.md` §3.1 in the cross-language Benzene spec repo).
10
+ * Port of Benzene.Results.ProblemTypes.
11
+ *
12
+ * A pure, static, spec-pinned table, matching {@link BenzeneResultStatus}'s own pattern: C#'s
13
+ * `static class` of `const string` members plus static methods collapses into a frozen object
14
+ * literal here.
15
+ */
16
+ const baseUri = 'https://benzene.app/problems/';
17
+ const unknownHttpStatus = 500;
18
+ // One row per failure status (docs/specification/wire-contracts.md §3.1). Success statuses have no
19
+ // problem type - problems exist only on failure - so they're deliberately absent here.
20
+ const registry = {
21
+ [BenzeneResultStatus_1.BenzeneResultStatus.badRequest]: { type: `${baseUri}bad-request`, title: 'Bad request', httpStatus: 400 },
22
+ [BenzeneResultStatus_1.BenzeneResultStatus.unauthorized]: { type: `${baseUri}unauthorized`, title: 'Unauthorized', httpStatus: 401 },
23
+ [BenzeneResultStatus_1.BenzeneResultStatus.forbidden]: { type: `${baseUri}forbidden`, title: 'Forbidden', httpStatus: 403 },
24
+ [BenzeneResultStatus_1.BenzeneResultStatus.notFound]: { type: `${baseUri}not-found`, title: 'Not found', httpStatus: 404 },
25
+ [BenzeneResultStatus_1.BenzeneResultStatus.conflict]: { type: `${baseUri}conflict`, title: 'Conflict', httpStatus: 409 },
26
+ [BenzeneResultStatus_1.BenzeneResultStatus.validationError]: { type: `${baseUri}validation-error`, title: 'Validation failed', httpStatus: 422 },
27
+ [BenzeneResultStatus_1.BenzeneResultStatus.tooManyRequests]: { type: `${baseUri}too-many-requests`, title: 'Too many requests', httpStatus: 429 },
28
+ [BenzeneResultStatus_1.BenzeneResultStatus.unexpectedError]: { type: `${baseUri}unexpected-error`, title: 'Unexpected error', httpStatus: 500 },
29
+ [BenzeneResultStatus_1.BenzeneResultStatus.notImplemented]: { type: `${baseUri}not-implemented`, title: 'Not implemented', httpStatus: 501 },
30
+ [BenzeneResultStatus_1.BenzeneResultStatus.serviceUnavailable]: { type: `${baseUri}service-unavailable`, title: 'Service unavailable', httpStatus: 503 },
31
+ [BenzeneResultStatus_1.BenzeneResultStatus.timeout]: { type: `${baseUri}timeout`, title: 'Timeout', httpStatus: 504 },
32
+ };
33
+ function rowFor(status) {
34
+ return status === undefined ? undefined : registry[status];
35
+ }
36
+ exports.ProblemTypes = {
37
+ /** The {@link ProblemDetails.type} URI for `bad-request`. */
38
+ badRequest: `${baseUri}bad-request`,
39
+ /** The {@link ProblemDetails.type} URI for `unauthorized`. */
40
+ unauthorized: `${baseUri}unauthorized`,
41
+ /** The {@link ProblemDetails.type} URI for `forbidden`. */
42
+ forbidden: `${baseUri}forbidden`,
43
+ /** The {@link ProblemDetails.type} URI for `not-found`. */
44
+ notFound: `${baseUri}not-found`,
45
+ /** The {@link ProblemDetails.type} URI for `conflict`. */
46
+ conflict: `${baseUri}conflict`,
47
+ /** The {@link ProblemDetails.type} URI for `validation-error`. */
48
+ validationError: `${baseUri}validation-error`,
49
+ /** The {@link ProblemDetails.type} URI for `too-many-requests`. */
50
+ tooManyRequests: `${baseUri}too-many-requests`,
51
+ /** The {@link ProblemDetails.type} URI for `unexpected-error`. */
52
+ unexpectedError: `${baseUri}unexpected-error`,
53
+ /** The {@link ProblemDetails.type} URI for `not-implemented`. */
54
+ notImplemented: `${baseUri}not-implemented`,
55
+ /** The {@link ProblemDetails.type} URI for `service-unavailable`. */
56
+ serviceUnavailable: `${baseUri}service-unavailable`,
57
+ /** The {@link ProblemDetails.type} URI for `timeout`. */
58
+ timeout: `${baseUri}timeout`,
59
+ /**
60
+ * The registry {@link ProblemDetails.type} URI for `status`, or `undefined` for an
61
+ * application-defined status the registry doesn't know (the application owns its own `type`, or
62
+ * omits one).
63
+ */
64
+ typeFor(status) {
65
+ return rowFor(status)?.type;
66
+ },
67
+ /**
68
+ * The registry {@link ProblemDetails.title} for `status`, or `undefined` for an
69
+ * application-defined status the registry doesn't know.
70
+ */
71
+ titleFor(status) {
72
+ return rowFor(status)?.title;
73
+ },
74
+ /**
75
+ * The HTTP status code the registry maps `status` to, or `500` for an application-defined status —
76
+ * the same "unknown status falls to the generic-error row" rule the {@link BenzeneResultStatus}-based
77
+ * HTTP mappings use elsewhere (e.g. `DefaultHttpStatusCodeMapper`).
78
+ */
79
+ httpStatusFor(status) {
80
+ return rowFor(status)?.httpStatus ?? unknownHttpStatus;
81
+ },
82
+ /**
83
+ * Builds the problem document for a failed `result`: {@link ProblemDetails.type}/
84
+ * {@link ProblemDetails.title} from the registry (both `undefined` for an application-defined
85
+ * status), {@link ProblemDetails.detail} as the result's error messages joined with `", "`,
86
+ * {@link ProblemDetails.benzeneStatus} as the result's status, and {@link ProblemDetails.errors}
87
+ * as the result's structured errors when non-empty (else `undefined`, so the member is omitted
88
+ * from the wire). Deliberately never sets {@link ProblemDetails.status} — the numeric HTTP status
89
+ * is an HTTP-binding concern, filled in by the HTTP-aware response mapper, not this
90
+ * transport-neutral factory.
91
+ *
92
+ * A result built by `BenzeneResult.problem(...)` carries its authored document, which is returned
93
+ * verbatim: re-deriving one here would overwrite an application-owned `type` with the registry
94
+ * URI, which is the whole reason that factory exists (wire-contracts.md §1.3).
95
+ */
96
+ from(result) {
97
+ const authored = result.problem;
98
+ if (authored !== undefined) {
99
+ return authored;
100
+ }
101
+ const errors = result.errors ?? [];
102
+ const detail = errors.map((error) => error.message).join(', ');
103
+ const problem = new ProblemDetails_1.ProblemDetails();
104
+ problem.type = exports.ProblemTypes.typeFor(result.status);
105
+ problem.title = exports.ProblemTypes.titleFor(result.status);
106
+ problem.detail = detail === '' ? undefined : detail;
107
+ problem.benzeneStatus = result.status;
108
+ problem.errors = errors.length > 0 ? [...errors] : undefined;
109
+ return problem;
110
+ },
111
+ };
@@ -0,0 +1,40 @@
1
+ import { IBenzeneResultOf } from '@benzenejs/abstractions';
2
+ /**
3
+ * transport-bindings.md §1 (spec 1.1): a send that fails in transport - no connection, a refused or reset
4
+ * request, the client's own deadline - before any reply arrives (or, for a one-way client, before the broker
5
+ * accepts the message) SHOULD yield a result rather than an exception: `timeout` when the deadline elapsed,
6
+ * otherwise `service-unavailable`, so a caller handles a dead peer as it handles every other failure. These
7
+ * functions are that rule, shared by every client in the port - reply-receiving and one-way alike.
8
+ *
9
+ * What counts as "the deadline elapsed", for the errors a Node client actually sees:
10
+ * - an aborted call (`AbortError`, or the `TimeoutError` an `AbortSignal.timeout(ms)` aborts with): in
11
+ * JavaScript an `AbortSignal` is how a caller bounds a `fetch` (it has no timeout option of its own), so an
12
+ * abort is the caller's own deadline;
13
+ * - an error whose name ends in `TimeoutError` (the AWS SDK's request/connection timeouts, kafkajs's
14
+ * `KafkaJSRequestTimeoutError`);
15
+ * - a timeout code: undici/Node's (`UND_ERR_CONNECT_TIMEOUT`, `UND_ERR_HEADERS_TIMEOUT`, `UND_ERR_BODY_TIMEOUT`,
16
+ * `ETIMEDOUT`, `ESOCKETTIMEDOUT`) or the Azure messaging SDKs' (`ServiceTimeout`, `OperationTimeoutError`);
17
+ * - a gRPC-shaped error (numeric `code` beside a string `details`, as the Pub/Sub client throws) whose code is
18
+ * 4, `DEADLINE_EXCEEDED`;
19
+ *
20
+ * each looked for on the error and its `cause` chain - `fetch` rejects with `TypeError('fetch failed')` and
21
+ * puts the socket error in `cause`.
22
+ *
23
+ * Everything else - `ECONNREFUSED`, `ECONNRESET`, a DNS failure, a TLS failure - is `service-unavailable`.
24
+ */
25
+ export declare function transportFailureStatus(error: unknown): string;
26
+ /**
27
+ * The failed result for a call that failed before any reply arrived: {@link transportFailureStatus}'s status,
28
+ * with one error carrying the failure's message (and its `cause`'s, which is where `fetch` puts the socket
29
+ * error), so the reason is not lost with the exception.
30
+ */
31
+ export declare function transportFailureResult<T>(error: unknown): IBenzeneResultOf<T>;
32
+ /**
33
+ * The result for a one-way send whose SDK call rejected. When the broker itself answered - an AWS SDK service
34
+ * exception (`$metadata.httpStatusCode`) or an Azure `RestError` (`statusCode`), 400 or above - the message
35
+ * was refused, not lost in transport, so that native status maps through the reverse HTTP table
36
+ * (wire-contracts §4.1: `403` → `forbidden`, `404` → `not-found`, `429` → `too-many-requests`, ...).
37
+ * Otherwise the send failed before the broker accepted it: {@link transportFailureResult}. Either way the
38
+ * one error carries the failure's message.
39
+ */
40
+ export declare function failedSendResult<T>(error: unknown): IBenzeneResultOf<T>;
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.transportFailureStatus = transportFailureStatus;
4
+ exports.transportFailureResult = transportFailureResult;
5
+ exports.failedSendResult = failedSendResult;
6
+ const BenzeneResult_1 = require("./BenzeneResult");
7
+ const BenzeneResultExtensions_1 = require("./BenzeneResultExtensions");
8
+ const BenzeneResultStatus_1 = require("./BenzeneResultStatus");
9
+ /**
10
+ * transport-bindings.md §1 (spec 1.1): a send that fails in transport - no connection, a refused or reset
11
+ * request, the client's own deadline - before any reply arrives (or, for a one-way client, before the broker
12
+ * accepts the message) SHOULD yield a result rather than an exception: `timeout` when the deadline elapsed,
13
+ * otherwise `service-unavailable`, so a caller handles a dead peer as it handles every other failure. These
14
+ * functions are that rule, shared by every client in the port - reply-receiving and one-way alike.
15
+ *
16
+ * What counts as "the deadline elapsed", for the errors a Node client actually sees:
17
+ * - an aborted call (`AbortError`, or the `TimeoutError` an `AbortSignal.timeout(ms)` aborts with): in
18
+ * JavaScript an `AbortSignal` is how a caller bounds a `fetch` (it has no timeout option of its own), so an
19
+ * abort is the caller's own deadline;
20
+ * - an error whose name ends in `TimeoutError` (the AWS SDK's request/connection timeouts, kafkajs's
21
+ * `KafkaJSRequestTimeoutError`);
22
+ * - a timeout code: undici/Node's (`UND_ERR_CONNECT_TIMEOUT`, `UND_ERR_HEADERS_TIMEOUT`, `UND_ERR_BODY_TIMEOUT`,
23
+ * `ETIMEDOUT`, `ESOCKETTIMEDOUT`) or the Azure messaging SDKs' (`ServiceTimeout`, `OperationTimeoutError`);
24
+ * - a gRPC-shaped error (numeric `code` beside a string `details`, as the Pub/Sub client throws) whose code is
25
+ * 4, `DEADLINE_EXCEEDED`;
26
+ *
27
+ * each looked for on the error and its `cause` chain - `fetch` rejects with `TypeError('fetch failed')` and
28
+ * puts the socket error in `cause`.
29
+ *
30
+ * Everything else - `ECONNREFUSED`, `ECONNRESET`, a DNS failure, a TLS failure - is `service-unavailable`.
31
+ */
32
+ function transportFailureStatus(error) {
33
+ for (const link of causeChain(error)) {
34
+ if (typeof link !== 'object' || link === null) {
35
+ continue;
36
+ }
37
+ const { name, code, details } = link;
38
+ if (name === 'AbortError' || (typeof name === 'string' && name.endsWith('TimeoutError'))) {
39
+ return BenzeneResultStatus_1.BenzeneResultStatus.timeout;
40
+ }
41
+ if (typeof code === 'string' && TimeoutCodes.has(code)) {
42
+ return BenzeneResultStatus_1.BenzeneResultStatus.timeout;
43
+ }
44
+ if (code === GrpcDeadlineExceeded && typeof details === 'string') {
45
+ return BenzeneResultStatus_1.BenzeneResultStatus.timeout;
46
+ }
47
+ }
48
+ return BenzeneResultStatus_1.BenzeneResultStatus.serviceUnavailable;
49
+ }
50
+ /**
51
+ * The failed result for a call that failed before any reply arrived: {@link transportFailureStatus}'s status,
52
+ * with one error carrying the failure's message (and its `cause`'s, which is where `fetch` puts the socket
53
+ * error), so the reason is not lost with the exception.
54
+ */
55
+ function transportFailureResult(error) {
56
+ return BenzeneResult_1.BenzeneResult.setErrors(transportFailureStatus(error), transportFailureMessage(error));
57
+ }
58
+ /**
59
+ * The result for a one-way send whose SDK call rejected. When the broker itself answered - an AWS SDK service
60
+ * exception (`$metadata.httpStatusCode`) or an Azure `RestError` (`statusCode`), 400 or above - the message
61
+ * was refused, not lost in transport, so that native status maps through the reverse HTTP table
62
+ * (wire-contracts §4.1: `403` → `forbidden`, `404` → `not-found`, `429` → `too-many-requests`, ...).
63
+ * Otherwise the send failed before the broker accepted it: {@link transportFailureResult}. Either way the
64
+ * one error carries the failure's message.
65
+ */
66
+ function failedSendResult(error) {
67
+ const brokerStatus = brokerHttpStatus(error);
68
+ return brokerStatus === undefined
69
+ ? transportFailureResult(error)
70
+ : BenzeneResult_1.BenzeneResult.setErrors((0, BenzeneResultExtensions_1.convertHttpStatusCode)(brokerStatus).status, transportFailureMessage(error));
71
+ }
72
+ /** The HTTP status a broker answered a rejected SDK call with, when it answered at all. */
73
+ function brokerHttpStatus(error) {
74
+ if (typeof error !== 'object' || error === null) {
75
+ return undefined;
76
+ }
77
+ const { $metadata, statusCode } = error;
78
+ const status = $metadata?.httpStatusCode ?? statusCode;
79
+ return typeof status === 'number' && status >= 400 ? status : undefined;
80
+ }
81
+ const TimeoutCodes = new Set([
82
+ 'UND_ERR_CONNECT_TIMEOUT',
83
+ 'UND_ERR_HEADERS_TIMEOUT',
84
+ 'UND_ERR_BODY_TIMEOUT',
85
+ 'ETIMEDOUT',
86
+ 'ESOCKETTIMEDOUT',
87
+ 'ServiceTimeout',
88
+ 'OperationTimeoutError',
89
+ ]);
90
+ /** gRPC's `DEADLINE_EXCEEDED`. */
91
+ const GrpcDeadlineExceeded = 4;
92
+ function transportFailureMessage(error) {
93
+ const messages = [];
94
+ for (const link of causeChain(error)) {
95
+ const message = link instanceof Error ? link.message : typeof link === 'string' ? link : undefined;
96
+ if (message !== undefined && message !== '' && !messages.includes(message)) {
97
+ messages.push(message);
98
+ }
99
+ }
100
+ return messages.length > 0 ? messages.join(': ') : 'The call failed before any reply arrived';
101
+ }
102
+ /** `error`, then each `cause` beneath it (bounded, so a cyclic chain cannot loop). */
103
+ function causeChain(error) {
104
+ const chain = [];
105
+ let current = error;
106
+ while (current !== undefined && current !== null && chain.length < 8 && !chain.includes(current)) {
107
+ chain.push(current);
108
+ current = typeof current === 'object' ? current.cause : undefined;
109
+ }
110
+ return chain;
111
+ }
@@ -0,0 +1,7 @@
1
+ export { BenzeneError } from '@benzenejs/abstractions';
2
+ export * from './BenzeneResult';
3
+ export * from './BenzeneResultExtensions';
4
+ export * from './BenzeneResultStatus';
5
+ export * from './ProblemDetails';
6
+ export * from './ProblemTypes';
7
+ export * from './TransportFailure';
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./BenzeneResult"), exports);
18
+ __exportStar(require("./BenzeneResultExtensions"), exports);
19
+ __exportStar(require("./BenzeneResultStatus"), exports);
20
+ __exportStar(require("./ProblemDetails"), exports);
21
+ __exportStar(require("./ProblemTypes"), exports);
22
+ __exportStar(require("./TransportFailure"), exports);
package/package.json CHANGED
@@ -1,6 +1,15 @@
1
1
  {
2
2
  "name": "@benzenejs/results",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0-beta.2",
4
+ "description": "TypeScript port of Benzene.Results",
5
+ "license": "MIT",
6
+ "type": "commonjs",
7
+ "main": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "dependencies": {
10
+ "@benzenejs/abstractions": "0.1.0-beta.2"
11
+ },
12
+ "files": [
13
+ "dist"
14
+ ]
15
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.