@entifix/rest 0.13.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/entity-rest/build-entity-rest-adapter-delete/build-entity-rest-adapter-delete.d.ts +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-delete/build-entity-rest-adapter-delete.d.ts.map +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-facets/build-entity-rest-adapter-facets.d.ts +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-facets/build-entity-rest-adapter-facets.d.ts.map +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-get/build-entity-rest-adapter-get.d.ts +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-get/build-entity-rest-adapter-get.d.ts.map +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-load/build-entity-rest-adapter-load.d.ts +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-load/build-entity-rest-adapter-load.d.ts.map +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-mixins/build-entity-base-url.d.ts +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-mixins/build-entity-base-url.d.ts.map +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-mixins/index.d.ts +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-save/build-entity-rest-adapter-save.d.ts +4 -8
- package/dist/adapters/entity-rest/build-entity-rest-adapter-save/build-entity-rest-adapter-save.d.ts.map +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-save/build-entity-rest-adapter-save.js +15 -94
- package/dist/adapters/entity-rest/build-entity-rest-adapter-save/build-entity-rest-adapter-save.js.map +1 -1
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/build-entity-rest-adapter-write.d.ts +10 -0
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/build-entity-rest-adapter-write.d.ts.map +1 -0
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/build-entity-rest-adapter-write.js +49 -0
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/build-entity-rest-adapter-write.js.map +1 -0
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/index.d.ts +2 -0
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/index.d.ts.map +1 -0
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/index.js +3 -0
- package/dist/adapters/entity-rest/build-entity-rest-adapter-write/index.js.map +1 -0
- package/dist/adapters/entity-rest/pending-save-keys.d.ts +13 -0
- package/dist/adapters/entity-rest/pending-save-keys.d.ts.map +1 -0
- package/dist/adapters/entity-rest/pending-save-keys.js +13 -0
- package/dist/adapters/entity-rest/pending-save-keys.js.map +1 -0
- package/dist/adapters/entity-rest/read-write-response.d.ts +13 -0
- package/dist/adapters/entity-rest/read-write-response.d.ts.map +1 -0
- package/dist/adapters/entity-rest/read-write-response.js +17 -0
- package/dist/adapters/entity-rest/read-write-response.js.map +1 -0
- package/dist/adapters/entity-rest/types.d.ts +5 -15
- package/dist/adapters/entity-rest/types.d.ts.map +1 -1
- package/dist/adapters/entity-rest/types.js.map +1 -1
- package/dist/adapters/entity-use-case/make-entity-rest-use-case-runner.d.ts +3 -1
- package/dist/adapters/entity-use-case/make-entity-rest-use-case-runner.d.ts.map +1 -1
- package/dist/adapters/entity-use-case/make-entity-rest-use-case-runner.js +9 -2
- package/dist/adapters/entity-use-case/make-entity-rest-use-case-runner.js.map +1 -1
- package/dist/adapters/flow-status/build-flow-status-reader/build-flow-status-reader.d.ts +19 -0
- package/dist/adapters/flow-status/build-flow-status-reader/build-flow-status-reader.d.ts.map +1 -0
- package/dist/adapters/flow-status/build-flow-status-reader/build-flow-status-reader.js +27 -0
- package/dist/adapters/flow-status/build-flow-status-reader/build-flow-status-reader.js.map +1 -0
- package/dist/adapters/flow-status/build-flow-status-reader/index.d.ts +2 -0
- package/dist/adapters/flow-status/build-flow-status-reader/index.d.ts.map +1 -0
- package/dist/adapters/flow-status/build-flow-status-reader/index.js +3 -0
- package/dist/adapters/flow-status/build-flow-status-reader/index.js.map +1 -0
- package/dist/adapters/is-not-found.d.ts +7 -0
- package/dist/adapters/is-not-found.d.ts.map +1 -0
- package/dist/adapters/is-not-found.js +8 -0
- package/dist/adapters/is-not-found.js.map +1 -0
- package/dist/clients/types.d.ts +1 -1
- package/dist/clients/types.d.ts.map +1 -1
- package/dist/clients/types.js.map +1 -1
- package/dist/configuration-client/configuration-client-rest-client.d.ts.map +1 -1
- package/dist/configuration-client/configuration-client-rest-client.js +5 -3
- package/dist/configuration-client/configuration-client-rest-client.js.map +1 -1
- package/dist/endpoint/participant-client.d.ts +3 -2
- package/dist/endpoint/participant-client.d.ts.map +1 -1
- package/dist/endpoint/participant-client.js +10 -16
- package/dist/endpoint/participant-client.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
- package/dist/adapters/transaction-status/build-transaction-status-reader/build-transaction-status-reader.d.ts +0 -4
- package/dist/adapters/transaction-status/build-transaction-status-reader/build-transaction-status-reader.d.ts.map +0 -1
- package/dist/adapters/transaction-status/build-transaction-status-reader/build-transaction-status-reader.js +0 -47
- package/dist/adapters/transaction-status/build-transaction-status-reader/build-transaction-status-reader.js.map +0 -1
- package/dist/adapters/transaction-status/build-transaction-status-reader/index.d.ts +0 -2
- package/dist/adapters/transaction-status/build-transaction-status-reader/index.d.ts.map +0 -1
- package/dist/adapters/transaction-status/build-transaction-status-reader/index.js +0 -3
- package/dist/adapters/transaction-status/build-transaction-status-reader/index.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/adapters/entity-use-case/make-entity-rest-use-case-runner.ts"],"sourcesContent":["import {\n type BulkOutcome,\n type Entity,\n type EntityConstructor,\n type EntityUseCaseRunner,\n extractMetaEntity,\n ProtocolFailure,\n toWireSelection,\n} from '@entifix/core';\nimport { Effect } from 'effect';\n\nimport { performHttpRequestThroughFetch } from '../../clients/fetch/index.js';\nimport { buildEntityRestAdapterMixins as adapterMixins } from '../entity-rest/build-entity-rest-adapter-mixins/index.js';\nimport type { BuildEntityRestOptions } from '../entity-rest/types.js';\n\n/**\n * Runs an entity's verbs against the service that serves them, at the path the\n * shell derives from each verb's key and binding — under the same base URL the\n * entity's other adapters use, so a same-origin proxy is followed the same way\n * ([ADR 0020](../../../../../../docs/adr/0020-endpoints-are-descriptors-and-the-shell-builds-an-httpapi.md)).\n *\n * A refusal arrives as the failure the service sent, decoded from its problem\n * body, so a screen shows the coded message rather than a generic error.\n */\nexport const makeEntityRestUseCaseRunner = <TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n { uriConfig, configuration }: BuildEntityRestOptions,\n): EntityUseCaseRunner => {\n const metaEntity = extractMetaEntity(entityConstructor);\n const name = metaEntity.key ?? metaEntity.name;\n const baseUrl = (id?: string) =>\n adapterMixins.buildEntityBaseUrl(configuration, { uriConfig }, name, id);\n\n return {\n run: (useCase, id) =>\n Effect.gen(function* () {\n const url = yield* baseUrl(\n useCase.binding === 'entity' && id != null ? String(id) : undefined,\n );\n yield* performHttpRequestThroughFetch({\n method: 'POST',\n url: `${url}/${useCase.key}`,\n });\n }),\n bulk: (useCase, selection) =>\n Effect.gen(function* () {\n const url = yield* baseUrl();\n // The wire form, never the selection itself: a `Set` serializes to\n // `{}`, so a selection sent raw would lose its ids.\n const response = yield* performHttpRequestThroughFetch<{\n readonly data?: unknown;\n }>({\n method: 'POST',\n url: `${url}/${useCase.key}`,\n headers: { 'Content-Type': 'application/json' },\n body: { selection: toWireSelection(selection) },\n });\n // A bulk answer is a `bulkOutcome` envelope, one outcome per record in\n // its `data`; anything else is a peer speaking something else.\n const outcomes = response.body?.data;\n if (!Array.isArray(outcomes)) {\n return yield* new ProtocolFailure({\n reason:\n 'a bulk answer carries its outcomes in a bulkOutcome envelope',\n });\n }\n return outcomes as readonly BulkOutcome[];\n }),\n };\n};\n"],"names":["extractMetaEntity","ProtocolFailure","toWireSelection","Effect","performHttpRequestThroughFetch","buildEntityRestAdapterMixins","adapterMixins","makeEntityRestUseCaseRunner","entityConstructor","uriConfig","configuration","metaEntity","name","key","baseUrl","id","buildEntityBaseUrl","run","useCase","gen","url","binding","String","undefined","method","
|
|
1
|
+
{"version":3,"sources":["../../../src/adapters/entity-use-case/make-entity-rest-use-case-runner.ts"],"sourcesContent":["import {\n type BulkOutcome,\n type Entity,\n type EntityConstructor,\n type EntityUseCaseRunner,\n extractMetaEntity,\n ProtocolFailure,\n toWireSelection,\n} from '@entifix/core';\nimport { Effect } from 'effect';\n\nimport { performHttpRequestThroughFetch } from '../../clients/fetch/index.js';\nimport { buildEntityRestAdapterMixins as adapterMixins } from '../entity-rest/build-entity-rest-adapter-mixins/index.js';\nimport { readWriteResponse } from '../entity-rest/read-write-response.js';\nimport type { BuildEntityRestOptions } from '../entity-rest/types.js';\n\n/**\n * Runs an entity's verbs against the service that serves them, at the path the\n * shell derives from each verb's key and binding — under the same base URL the\n * entity's other adapters use, so a same-origin proxy is followed the same way\n * ([ADR 0020](../../../../../../docs/adr/0020-endpoints-are-descriptors-and-the-shell-builds-an-httpapi.md)).\n *\n * A refusal arrives as the failure the service sent, decoded from its problem\n * body, so a screen shows the coded message rather than a generic error. A\n * verb that starts a flow answers `202 flowAccepted` and runs as pending; any\n * other success is settled with the `data` of what the service answered.\n */\nexport const makeEntityRestUseCaseRunner = <TEntity extends Entity>(\n entityConstructor: EntityConstructor<TEntity>,\n { uriConfig, configuration }: BuildEntityRestOptions,\n): EntityUseCaseRunner => {\n const metaEntity = extractMetaEntity(entityConstructor);\n const name = metaEntity.key ?? metaEntity.name;\n const baseUrl = (id?: string) =>\n adapterMixins.buildEntityBaseUrl(configuration, { uriConfig }, name, id);\n\n return {\n run: (useCase, id) =>\n Effect.gen(function* () {\n const url = yield* baseUrl(\n useCase.binding === 'entity' && id != null ? String(id) : undefined,\n );\n const response = yield* performHttpRequestThroughFetch<{\n readonly data?: unknown;\n }>({\n method: 'POST',\n url: `${url}/${useCase.key}`,\n });\n return yield* readWriteResponse(response, () =>\n Effect.succeed(response.body?.data),\n );\n }),\n bulk: (useCase, selection) =>\n Effect.gen(function* () {\n const url = yield* baseUrl();\n // The wire form, never the selection itself: a `Set` serializes to\n // `{}`, so a selection sent raw would lose its ids.\n const response = yield* performHttpRequestThroughFetch<{\n readonly data?: unknown;\n }>({\n method: 'POST',\n url: `${url}/${useCase.key}`,\n headers: { 'Content-Type': 'application/json' },\n body: { selection: toWireSelection(selection) },\n });\n // A bulk answer is a `bulkOutcome` envelope, one outcome per record in\n // its `data`; anything else is a peer speaking something else.\n const outcomes = response.body?.data;\n if (!Array.isArray(outcomes)) {\n return yield* new ProtocolFailure({\n reason:\n 'a bulk answer carries its outcomes in a bulkOutcome envelope',\n });\n }\n return outcomes as readonly BulkOutcome[];\n }),\n };\n};\n"],"names":["extractMetaEntity","ProtocolFailure","toWireSelection","Effect","performHttpRequestThroughFetch","buildEntityRestAdapterMixins","adapterMixins","readWriteResponse","makeEntityRestUseCaseRunner","entityConstructor","uriConfig","configuration","metaEntity","name","key","baseUrl","id","buildEntityBaseUrl","run","useCase","gen","url","binding","String","undefined","response","method","succeed","body","data","bulk","selection","headers","outcomes","Array","isArray","reason"],"mappings":"AAAA,SAKEA,iBAAiB,EACjBC,eAAe,EACfC,eAAe,QACV,gBAAgB;AACvB,SAASC,MAAM,QAAQ,SAAS;AAEhC,SAASC,8BAA8B,QAAQ,+BAA+B;AAC9E,SAASC,gCAAgCC,aAAa,QAAQ,2DAA2D;AACzH,SAASC,iBAAiB,QAAQ,wCAAwC;AAG1E;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,8BAA8B,CACzCC,mBACA,EAAEC,SAAS,EAAEC,aAAa,EAA0B;QAGvCC;IADb,MAAMA,aAAaZ,kBAAkBS;IACrC,MAAMI,QAAOD,kBAAAA,WAAWE,GAAG,YAAdF,kBAAkBA,WAAWC,IAAI;IAC9C,MAAME,UAAU,CAACC,KACfV,cAAcW,kBAAkB,CAACN,eAAe;YAAED;QAAU,GAAGG,MAAMG;IAEvE,OAAO;QACLE,KAAK,CAACC,SAASH,KACbb,OAAOiB,GAAG,CAAC;gBACT,MAAMC,MAAM,OAAON,QACjBI,QAAQG,OAAO,KAAK,YAAYN,MAAM,OAAOO,OAAOP,MAAMQ;gBAE5D,MAAMC,WAAW,OAAOrB,+BAErB;oBACDsB,QAAQ;oBACRL,KAAK,GAAGA,IAAI,CAAC,EAAEF,QAAQL,GAAG,EAAE;gBAC9B;gBACA,OAAO,OAAOP,kBAAkBkB,UAAU;wBACzBA;2BAAftB,OAAOwB,OAAO,EAACF,iBAAAA,SAASG,IAAI,qBAAbH,eAAeI,IAAI;;YAEtC;QACFC,MAAM,CAACX,SAASY,YACd5B,OAAOiB,GAAG,CAAC;oBAcQK;gBAbjB,MAAMJ,MAAM,OAAON;gBACnB,mEAAmE;gBACnE,oDAAoD;gBACpD,MAAMU,WAAW,OAAOrB,+BAErB;oBACDsB,QAAQ;oBACRL,KAAK,GAAGA,IAAI,CAAC,EAAEF,QAAQL,GAAG,EAAE;oBAC5BkB,SAAS;wBAAE,gBAAgB;oBAAmB;oBAC9CJ,MAAM;wBAAEG,WAAW7B,gBAAgB6B;oBAAW;gBAChD;gBACA,uEAAuE;gBACvE,+DAA+D;gBAC/D,MAAME,YAAWR,iBAAAA,SAASG,IAAI,qBAAbH,eAAeI,IAAI;gBACpC,IAAI,CAACK,MAAMC,OAAO,CAACF,WAAW;oBAC5B,OAAO,OAAO,IAAIhC,gBAAgB;wBAChCmC,QACE;oBACJ;gBACF;gBACA,OAAOH;YACT;IACJ;AACF,EAAE"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import '@entifix/transactions';
|
|
2
|
+
import { type EntifixFailure } from '@entifix/core';
|
|
3
|
+
import type { FlowStatusBody } from '@entifix/transactions';
|
|
4
|
+
import { Effect } from 'effect';
|
|
5
|
+
/** Reads where a flow stands from the `status` link its `202` named. */
|
|
6
|
+
export type FlowStatusReader = (href: string) => Effect.Effect<FlowStatusBody | undefined, EntifixFailure>;
|
|
7
|
+
/**
|
|
8
|
+
* Reads a flow's `status` link over HTTP, for a browser settling a write whose
|
|
9
|
+
* outcome it did not hear pushed.
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ **A `404` answers `undefined`, and that is not a failure.** A status read
|
|
12
|
+
* is a projection of the flow's events, so a flow that has just started may
|
|
13
|
+
* not be in it yet; the caller keeps the write pending, up to its own bound
|
|
14
|
+
* ([ADR 0022](../../../../../../docs/adr/0022-two-settle-modes-and-the-pending-flow-store.md)).
|
|
15
|
+
* Every other failure stays a failure, so an unreachable service is not read
|
|
16
|
+
* as "no such flow".
|
|
17
|
+
*/
|
|
18
|
+
export declare const buildFlowStatusReader: () => FlowStatusReader;
|
|
19
|
+
//# sourceMappingURL=build-flow-status-reader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-flow-status-reader.d.ts","sourceRoot":"","sources":["../../../../src/adapters/flow-status/build-flow-status-reader/build-flow-status-reader.ts"],"names":[],"mappings":"AACA,OAAO,uBAAuB,CAAC;AAE/B,OAAO,EAAkB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC,wEAAwE;AACxE,MAAM,MAAM,gBAAgB,GAAG,CAC7B,IAAI,EAAE,MAAM,KACT,MAAM,CAAC,MAAM,CAAC,cAAc,GAAG,SAAS,EAAE,cAAc,CAAC,CAAC;AAE/D;;;;;;;;;;GAUG;AACH,eAAO,MAAM,qBAAqB,QAAO,gBAatC,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Loaded for its registration of `flowStatus`, which the decode below reads.
|
|
2
|
+
import '@entifix/transactions';
|
|
3
|
+
import { decodeEnvelope } from '@entifix/core';
|
|
4
|
+
import { Effect } from 'effect';
|
|
5
|
+
import { performHttpRequestThroughFetch } from '../../../clients/fetch/index.js';
|
|
6
|
+
import { isNotFound } from '../../is-not-found.js';
|
|
7
|
+
/**
|
|
8
|
+
* Reads a flow's `status` link over HTTP, for a browser settling a write whose
|
|
9
|
+
* outcome it did not hear pushed.
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ **A `404` answers `undefined`, and that is not a failure.** A status read
|
|
12
|
+
* is a projection of the flow's events, so a flow that has just started may
|
|
13
|
+
* not be in it yet; the caller keeps the write pending, up to its own bound
|
|
14
|
+
* ([ADR 0022](../../../../../../docs/adr/0022-two-settle-modes-and-the-pending-flow-store.md)).
|
|
15
|
+
* Every other failure stays a failure, so an unreachable service is not read
|
|
16
|
+
* as "no such flow".
|
|
17
|
+
*/ export const buildFlowStatusReader = ()=>(href)=>Effect.gen(function*() {
|
|
18
|
+
const response = yield* performHttpRequestThroughFetch({
|
|
19
|
+
method: 'GET',
|
|
20
|
+
url: href
|
|
21
|
+
});
|
|
22
|
+
const envelope = yield* decodeEnvelope(response.body, 'flowStatus');
|
|
23
|
+
// Decoded against the registered `flowStatus` schema just above.
|
|
24
|
+
return envelope.data;
|
|
25
|
+
}).pipe(Effect.catch((error)=>isNotFound(error) ? Effect.succeed(undefined) : Effect.fail(error)));
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=build-flow-status-reader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/adapters/flow-status/build-flow-status-reader/build-flow-status-reader.ts"],"sourcesContent":["// Loaded for its registration of `flowStatus`, which the decode below reads.\nimport '@entifix/transactions';\n\nimport { decodeEnvelope, type EntifixFailure } from '@entifix/core';\nimport type { FlowStatusBody } from '@entifix/transactions';\nimport { Effect } from 'effect';\n\nimport { performHttpRequestThroughFetch } from '../../../clients/fetch/index.js';\nimport { isNotFound } from '../../is-not-found.js';\n\n/** Reads where a flow stands from the `status` link its `202` named. */\nexport type FlowStatusReader = (\n href: string,\n) => Effect.Effect<FlowStatusBody | undefined, EntifixFailure>;\n\n/**\n * Reads a flow's `status` link over HTTP, for a browser settling a write whose\n * outcome it did not hear pushed.\n *\n * ⚠️ **A `404` answers `undefined`, and that is not a failure.** A status read\n * is a projection of the flow's events, so a flow that has just started may\n * not be in it yet; the caller keeps the write pending, up to its own bound\n * ([ADR 0022](../../../../../../docs/adr/0022-two-settle-modes-and-the-pending-flow-store.md)).\n * Every other failure stays a failure, so an unreachable service is not read\n * as \"no such flow\".\n */\nexport const buildFlowStatusReader = (): FlowStatusReader => (href: string) =>\n Effect.gen(function* () {\n const response = yield* performHttpRequestThroughFetch({\n method: 'GET',\n url: href,\n });\n const envelope = yield* decodeEnvelope(response.body, 'flowStatus');\n // Decoded against the registered `flowStatus` schema just above.\n return envelope.data as FlowStatusBody;\n }).pipe(\n Effect.catch(error =>\n isNotFound(error) ? Effect.succeed(undefined) : Effect.fail(error),\n ),\n );\n"],"names":["decodeEnvelope","Effect","performHttpRequestThroughFetch","isNotFound","buildFlowStatusReader","href","gen","response","method","url","envelope","body","data","pipe","catch","error","succeed","undefined","fail"],"mappings":"AAAA,6EAA6E;AAC7E,OAAO,wBAAwB;AAE/B,SAASA,cAAc,QAA6B,gBAAgB;AAEpE,SAASC,MAAM,QAAQ,SAAS;AAEhC,SAASC,8BAA8B,QAAQ,kCAAkC;AACjF,SAASC,UAAU,QAAQ,wBAAwB;AAOnD;;;;;;;;;;CAUC,GACD,OAAO,MAAMC,wBAAwB,IAAwB,CAACC,OAC5DJ,OAAOK,GAAG,CAAC;YACT,MAAMC,WAAW,OAAOL,+BAA+B;gBACrDM,QAAQ;gBACRC,KAAKJ;YACP;YACA,MAAMK,WAAW,OAAOV,eAAeO,SAASI,IAAI,EAAE;YACtD,iEAAiE;YACjE,OAAOD,SAASE,IAAI;QACtB,GAAGC,IAAI,CACLZ,OAAOa,KAAK,CAACC,CAAAA,QACXZ,WAAWY,SAASd,OAAOe,OAAO,CAACC,aAAahB,OAAOiB,IAAI,CAACH,SAE9D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/flow-status/build-flow-status-reader/index.ts"],"names":[],"mappings":"AAAA,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/adapters/flow-status/build-flow-status-reader/index.ts"],"sourcesContent":["export * from './build-flow-status-reader.js';\n"],"names":[],"mappings":"AAAA,cAAc,gCAAgC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A `404`, however it arrived: a service that answers a problem body says
|
|
3
|
+
* `NotFound`; one that answers no body at all is a protocol failure that
|
|
4
|
+
* still carries the status.
|
|
5
|
+
*/
|
|
6
|
+
export declare const isNotFound: (error: unknown) => boolean;
|
|
7
|
+
//# sourceMappingURL=is-not-found.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-not-found.d.ts","sourceRoot":"","sources":["../../src/adapters/is-not-found.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,eAAO,MAAM,UAAU,GAAI,OAAO,OAAO,KAAG,OAGgC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { isTag } from '@entifix/core';
|
|
2
|
+
/**
|
|
3
|
+
* A `404`, however it arrived: a service that answers a problem body says
|
|
4
|
+
* `NotFound`; one that answers no body at all is a protocol failure that
|
|
5
|
+
* still carries the status.
|
|
6
|
+
*/ export const isNotFound = (error)=>isTag('NotFound')(error) || isTag('ProtocolFailure')(error) && error.upstreamStatus === 404;
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=is-not-found.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/adapters/is-not-found.ts"],"sourcesContent":["import { isTag } from '@entifix/core';\n\n/**\n * A `404`, however it arrived: a service that answers a problem body says\n * `NotFound`; one that answers no body at all is a protocol failure that\n * still carries the status.\n */\nexport const isNotFound = (error: unknown): boolean =>\n isTag('NotFound')(error) ||\n (isTag('ProtocolFailure')(error) &&\n (error as { readonly upstreamStatus?: unknown }).upstreamStatus === 404);\n"],"names":["isTag","isNotFound","error","upstreamStatus"],"mappings":"AAAA,SAASA,KAAK,QAAQ,gBAAgB;AAEtC;;;;CAIC,GACD,OAAO,MAAMC,aAAa,CAACC,QACzBF,MAAM,YAAYE,UACjBF,MAAM,mBAAmBE,UACxB,AAACA,MAAgDC,cAAc,KAAK,IAAK"}
|
package/dist/clients/types.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/clients/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/clients/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErE,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAEjD,MAAM,WAAW,WAAW,CAAC,KAAK,GAAG,KAAK;IACxC,MAAM,EAAE,UAAU,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,IAAI,CAAC,EAAE,KAAK,CAAC;CACd;AAED,MAAM,WAAW,YAAY,CAAC,KAAK;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,WAAW,CAAC;IACrB,IAAI,EAAE,KAAK,CAAC;CACb"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/clients/types.ts"],"sourcesContent":["export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\nexport type HttpHeaders = Record<string, string>;\n\nexport interface HttpRequest<TBody = never> {\n method: HttpMethod;\n url: string;\n headers?: HttpHeaders;\n body?: TBody;\n}\n\nexport interface HttpResponse<TBody> {\n status: number;\n headers: HttpHeaders;\n body: TBody;\n}\n"],"names":[],"mappings":"AAWA,WAIC"}
|
|
1
|
+
{"version":3,"sources":["../../src/clients/types.ts"],"sourcesContent":["export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n\nexport type HttpHeaders = Record<string, string>;\n\nexport interface HttpRequest<TBody = never> {\n method: HttpMethod;\n url: string;\n headers?: HttpHeaders;\n body?: TBody;\n}\n\nexport interface HttpResponse<TBody> {\n status: number;\n headers: HttpHeaders;\n body: TBody;\n}\n"],"names":[],"mappings":"AAWA,WAIC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"configuration-client-rest-client.d.ts","sourceRoot":"","sources":["../../src/configuration-client/configuration-client-rest-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EAKzB,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,oCAAoC;IACnD,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5C;
|
|
1
|
+
{"version":3,"file":"configuration-client-rest-client.d.ts","sourceRoot":"","sources":["../../src/configuration-client/configuration-client-rest-client.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EAKzB,MAAM,eAAe,CAAC;AAGvB,MAAM,WAAW,oCAAoC;IACnD,8DAA8D;IAC9D,GAAG,CAAC,EAAE,MAAM,CAAC;IACb;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CAC5C;AAoED;;;;;;;;;;;;GAYG;AACH,qBAAa,6BAA8B,YAAW,mBAAmB;;gBAG3D,OAAO,CAAC,EAAE,oCAAoC;IAgC1D,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB;CAG5C"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _ as _class_private_field_loose_base } from "@swc/helpers/_/_class_private_field_loose_base";
|
|
2
2
|
import { _ as _class_private_field_loose_key } from "@swc/helpers/_/_class_private_field_loose_key";
|
|
3
|
-
import { ConfigurationClientInMemory,
|
|
3
|
+
import { ConfigurationClientInMemory, Unavailable } from '@entifix/core';
|
|
4
4
|
import { Effect } from 'effect';
|
|
5
5
|
const DEFAULT_CONFIG_URL = '/api/config';
|
|
6
6
|
var _pending = /*#__PURE__*/ _class_private_field_loose_key("_pending");
|
|
@@ -102,8 +102,10 @@ var _loadPlain = /*#__PURE__*/ _class_private_field_loose_key("_loadPlain");
|
|
|
102
102
|
};
|
|
103
103
|
_class_private_field_loose_base(this, _loadPlain)[_loadPlain] = Effect.tryPromise({
|
|
104
104
|
try: load,
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
// The configuration source could not be reached or did not answer: a
|
|
106
|
+
// dependency, so the next read asks again.
|
|
107
|
+
catch: ()=>new Unavailable({
|
|
108
|
+
dependency: url
|
|
107
109
|
})
|
|
108
110
|
});
|
|
109
111
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/configuration-client/configuration-client-rest-client.ts"],"sourcesContent":["import {\n ConfigurationClient,\n ConfigurationClientGroup,\n ConfigurationClientInMemory,\n ConfigurationExtractMode,\n ConfigurationPlain,\n
|
|
1
|
+
{"version":3,"sources":["../../src/configuration-client/configuration-client-rest-client.ts"],"sourcesContent":["import {\n ConfigurationClient,\n ConfigurationClientGroup,\n ConfigurationClientInMemory,\n ConfigurationExtractMode,\n ConfigurationPlain,\n Unavailable,\n} from '@entifix/core';\nimport { Effect } from 'effect';\n\nexport interface ConfigurationClientRestClientOptions {\n /** Endpoint returning this service's `ConfigurationPlain`. */\n url?: string;\n /**\n * Headers to send with the lookup.\n *\n * Empty for the browser, which reads its own app's same-origin `/api/config`\n * and needs nothing. A **server** component reads config-service directly —\n * there is no origin to proxy through and no browser to hide an address from\n * — and that endpoint is gated on the shared fleet token, so the caller has\n * to carry it. The header itself stays out of this package: the token is a\n * Next server concern and lives in `@entifix/next-shell`.\n */\n headers?: Readonly<Record<string, string>>;\n}\n\nconst DEFAULT_CONFIG_URL = '/api/config';\n\n/**\n * {@link ConfigurationClientGroup} view over an HTTP-sourced\n * {@link ConfigurationPlain}. Resolution is delegated to an in-memory store\n * once the plain configuration has been fetched.\n */\nclass ConfigurationClientGroupRestClient implements ConfigurationClientGroup {\n constructor(\n private readonly loadPlain: Effect.Effect<ConfigurationPlain, Unavailable>,\n private readonly group: string,\n ) {}\n\n #pending() {\n return Effect.die(\n new Error(\n 'ConfigurationClientGroupRestClient getter not implemented yet',\n ),\n );\n }\n\n getString(key: string, extractMode?: ConfigurationExtractMode) {\n return this.loadPlain.pipe(\n Effect.flatMap(plain =>\n new ConfigurationClientInMemory(plain)\n .in(this.group)\n .getString(key, extractMode),\n ),\n );\n }\n\n getNumber() {\n return this.#pending();\n }\n getDate() {\n return this.#pending();\n }\n getArrayNumber() {\n return this.#pending();\n }\n getArrayString() {\n return this.#pending();\n }\n getArrayDate() {\n return this.#pending();\n }\n getOptionalNumber() {\n return this.#pending();\n }\n getOptionalString() {\n return this.#pending();\n }\n getOptionalDate() {\n return this.#pending();\n }\n getOptionalArrayNumber() {\n return this.#pending();\n }\n getOptionalArrayString() {\n return this.#pending();\n }\n getOptionalArrayDate() {\n return this.#pending();\n }\n}\n\n/**\n * {@link ConfigurationClient} that sources its `ConfigurationPlain` over HTTP\n * (by default the same-origin `/api/config` route, which proxies\n * marketplace-config-api). The fetched configuration is memoized so it is\n * requested at most once per client instance — **once it has arrived**.\n *\n * ⚠️ A failed load is not memoized. Clients are usually built once per process\n * (a server component's module scope), and in a fleet that starts together the\n * first read routinely races config-service's boot. Caching that rejection made\n * the failure permanent: a storefront rendered an empty catalog until it was\n * restarted, while every service it reads from was healthy. Callers that arrive\n * while a request is in flight still share it.\n */\nexport class ConfigurationClientRestClient implements ConfigurationClient {\n #loadPlain: Effect.Effect<ConfigurationPlain, Unavailable>;\n\n constructor(options?: ConfigurationClientRestClientOptions) {\n const url = options?.url ?? DEFAULT_CONFIG_URL;\n const headers = options?.headers;\n let cache: Promise<ConfigurationPlain> | undefined;\n\n const load = (): Promise<ConfigurationPlain> => {\n if (cache !== undefined) return cache;\n const pending = fetch(url, { headers }).then(response => {\n if (!response.ok) {\n throw new Error(\n `Configuration request to ${url} failed with status ${response.status}`,\n );\n }\n return response.json() as Promise<ConfigurationPlain>;\n });\n cache = pending;\n // Forget a failure so the next read asks again. Nothing else clears the\n // cache, so the entry being cleared is always this request's own.\n pending.catch(() => {\n cache = undefined;\n });\n return pending;\n };\n\n this.#loadPlain = Effect.tryPromise({\n try: load,\n // The configuration source could not be reached or did not answer: a\n // dependency, so the next read asks again.\n catch: () => new Unavailable({ dependency: url }),\n });\n }\n\n in(group: string): ConfigurationClientGroup {\n return new ConfigurationClientGroupRestClient(this.#loadPlain, group);\n }\n}\n"],"names":["ConfigurationClientInMemory","Unavailable","Effect","DEFAULT_CONFIG_URL","ConfigurationClientGroupRestClient","getString","key","extractMode","loadPlain","pipe","flatMap","plain","in","group","getNumber","getDate","getArrayNumber","getArrayString","getArrayDate","getOptionalNumber","getOptionalString","getOptionalDate","getOptionalArrayNumber","getOptionalArrayString","getOptionalArrayDate","die","Error","ConfigurationClientRestClient","options","url","headers","cache","load","undefined","pending","fetch","then","response","ok","status","json","catch","tryPromise","try","dependency"],"mappings":";;AAAA,SAGEA,2BAA2B,EAG3BC,WAAW,QACN,gBAAgB;AACvB,SAASC,MAAM,QAAQ,SAAS;AAkBhC,MAAMC,qBAAqB;IAazB;AAXF;;;;CAIC,GACD,IAAA,AAAMC,qCAAN,MAAMA;IAcJC,UAAUC,GAAW,EAAEC,WAAsC,EAAE;QAC7D,OAAO,IAAI,CAACC,SAAS,CAACC,IAAI,CACxBP,OAAOQ,OAAO,CAACC,CAAAA,QACb,IAAIX,4BAA4BW,OAC7BC,EAAE,CAAC,IAAI,CAACC,KAAK,EACbR,SAAS,CAACC,KAAKC;IAGxB;IAEAO,YAAY;QACV,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,UAAU;QACR,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,iBAAiB;QACf,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,iBAAiB;QACf,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,eAAe;QACb,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,oBAAoB;QAClB,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,oBAAoB;QAClB,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,kBAAkB;QAChB,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,yBAAyB;QACvB,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,yBAAyB;QACvB,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IACAC,uBAAuB;QACrB,OAAO,gCAAA,IAAI,EAAC,UAAA;IACd;IAvDA,YACE,AAAiBhB,SAAyD,EAC1E,AAAiBK,KAAa,CAC9B;QAEF,4BAAA;mBAAA;;aAJmBL,YAAAA;aACAK,QAAAA;IAChB;AAqDL;AAnDE,SAAA;IACE,OAAOX,OAAOuB,GAAG,CACf,IAAIC,MACF;AAGN;IA6DA;AAdF;;;;;;;;;;;;CAYC,GACD,OAAO,MAAMC;IAmCXf,GAAGC,KAAa,EAA4B;QAC1C,OAAO,IAAIT,mCAAmC,gCAAA,IAAI,EAAC,YAAA,aAAYS;IACjE;IAlCA,YAAYe,OAA8C,CAAE;;QAF5D,4BAAA;;mBAAA,KAAA;;QAGE,MAAMC,cAAMD,2BAAAA,QAASC,GAAG,mBAAI1B;QAC5B,MAAM2B,UAAUF,2BAAAA,QAASE,OAAO;QAChC,IAAIC;QAEJ,MAAMC,OAAO;YACX,IAAID,UAAUE,WAAW,OAAOF;YAChC,MAAMG,UAAUC,MAAMN,KAAK;gBAAEC;YAAQ,GAAGM,IAAI,CAACC,CAAAA;gBAC3C,IAAI,CAACA,SAASC,EAAE,EAAE;oBAChB,MAAM,IAAIZ,MACR,CAAC,yBAAyB,EAAEG,IAAI,oBAAoB,EAAEQ,SAASE,MAAM,EAAE;gBAE3E;gBACA,OAAOF,SAASG,IAAI;YACtB;YACAT,QAAQG;YACR,wEAAwE;YACxE,kEAAkE;YAClEA,QAAQO,KAAK,CAAC;gBACZV,QAAQE;YACV;YACA,OAAOC;QACT;QAEA,gCAAA,IAAI,EAAC,YAAA,cAAahC,OAAOwC,UAAU,CAAC;YAClCC,KAAKX;YACL,qEAAqE;YACrE,2CAA2C;YAC3CS,OAAO,IAAM,IAAIxC,YAAY;oBAAE2C,YAAYf;gBAAI;QACjD;IACF;AAKF"}
|
|
@@ -11,8 +11,9 @@ export interface ParticipantAddress {
|
|
|
11
11
|
* Calls participants over HTTP, as the slip pinned each step's call
|
|
12
12
|
* ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)):
|
|
13
13
|
* the crossing token the participant takes, the step's `Idempotency-Key`, the
|
|
14
|
-
* flow's remaining deadline,
|
|
15
|
-
*
|
|
14
|
+
* flow's remaining deadline, the organization the inputs name, and the inputs
|
|
15
|
+
* themselves as a flat JSON body — what the participant's own route declares,
|
|
16
|
+
* never a wrapper of the flow's. A refusal decodes into the failure the participant
|
|
16
17
|
* sent, by its code; a body that is not a problem is `protocol`; no answer at
|
|
17
18
|
* all is `unavailable`. A step with no call — the commit point that names no
|
|
18
19
|
* participant — answers at once.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"participant-client.d.ts","sourceRoot":"","sources":["../../src/endpoint/participant-client.ts"],"names":[],"mappings":"AAaA,OAAO,EAEL,KAAK,iBAAiB,EACtB,oBAAoB,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAU,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAE5D,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACnD;
|
|
1
|
+
{"version":3,"file":"participant-client.d.ts","sourceRoot":"","sources":["../../src/endpoint/participant-client.ts"],"names":[],"mappings":"AAaA,OAAO,EAEL,KAAK,iBAAiB,EACtB,oBAAoB,EACrB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAU,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACjD,OAAO,EAAE,UAAU,EAAqB,MAAM,aAAa,CAAC;AAE5D,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,mEAAmE;IACnE,QAAQ,CAAC,aAAa,EAAE,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;CACnD;AAqBD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,yBAAyB,GACpC,QAAQ,UAAU,CAAC,UAAU,EAC7B,cAAc,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,KACzD,iBA8DD,CAAC;AAEH,gEAAgE;AAChE,eAAO,MAAM,0BAA0B,GACrC,cAAc,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,oEAOzD,CAAC"}
|
|
@@ -12,27 +12,24 @@ const parse = (text)=>{
|
|
|
12
12
|
return undefined;
|
|
13
13
|
}
|
|
14
14
|
};
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
*/ const pathOf = (call, path)=>path.replace(/:([A-Za-z0-9_]+)/g, (_match, name)=>{
|
|
19
|
-
var _ref, _ref1;
|
|
20
|
-
var _call_step_parameters, _call_outputs_name;
|
|
21
|
-
return encodeURIComponent(String((_ref = (_ref1 = (_call_step_parameters = call.step.parameters) == null ? void 0 : _call_step_parameters[name]) != null ? _ref1 : (_call_outputs_name = call.outputs[name]) == null ? void 0 : _call_outputs_name['id']) != null ? _ref : ''));
|
|
15
|
+
/** The step's path with each `:name` taken from the call's inputs. */ const pathOf = (call, path)=>path.replace(/:([A-Za-z0-9_]+)/g, (_match, name)=>{
|
|
16
|
+
var _call_inputs_name;
|
|
17
|
+
return encodeURIComponent(String((_call_inputs_name = call.inputs[name]) != null ? _call_inputs_name : ''));
|
|
22
18
|
});
|
|
23
19
|
/**
|
|
24
20
|
* Calls participants over HTTP, as the slip pinned each step's call
|
|
25
21
|
* ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)):
|
|
26
22
|
* the crossing token the participant takes, the step's `Idempotency-Key`, the
|
|
27
|
-
* flow's remaining deadline,
|
|
28
|
-
*
|
|
23
|
+
* flow's remaining deadline, the organization the inputs name, and the inputs
|
|
24
|
+
* themselves as a flat JSON body — what the participant's own route declares,
|
|
25
|
+
* never a wrapper of the flow's. A refusal decodes into the failure the participant
|
|
29
26
|
* sent, by its code; a body that is not a problem is `protocol`; no answer at
|
|
30
27
|
* all is `unavailable`. A step with no call — the commit point that names no
|
|
31
28
|
* participant — answers at once.
|
|
32
29
|
*/ export const makeHttpParticipantClient = (client, participants)=>({
|
|
33
30
|
call: (request)=>Effect.gen(function*() {
|
|
34
|
-
var _request_step_participant
|
|
35
|
-
var
|
|
31
|
+
var _request_step_participant;
|
|
32
|
+
var _response_headers_contenttype;
|
|
36
33
|
const target = request.kind === 'action' ? request.step.call : request.step.compensation;
|
|
37
34
|
if (target === undefined) return undefined;
|
|
38
35
|
const name = (_request_step_participant = request.step.participant) != null ? _request_step_participant : '';
|
|
@@ -43,7 +40,7 @@ const parse = (text)=>{
|
|
|
43
40
|
if (remaining === 0) return yield* Effect.fail(new Timeout({
|
|
44
41
|
dependency
|
|
45
42
|
}));
|
|
46
|
-
const organizationId =
|
|
43
|
+
const organizationId = request.inputs['organizationId'];
|
|
47
44
|
const outgoing = HttpClientRequest.make(target.method)(`${address.baseUrl}${pathOf(request, target.path)}`).pipe(HttpClientRequest.setHeaders(_extends({
|
|
48
45
|
accept: 'application/json',
|
|
49
46
|
[CROSSING_TOKEN_HEADER]: Redacted.value(address.crossingToken),
|
|
@@ -52,10 +49,7 @@ const parse = (text)=>{
|
|
|
52
49
|
[ORGANIZATION_HEADER]: organizationId
|
|
53
50
|
} : {}, remaining === undefined ? {} : {
|
|
54
51
|
[DEADLINE_HEADER]: String(remaining)
|
|
55
|
-
})), HttpClientRequest.bodyText(JSON.stringify(
|
|
56
|
-
parameters: (_request_step_parameters = request.step.parameters) != null ? _request_step_parameters : {},
|
|
57
|
-
outputs: request.outputs
|
|
58
|
-
}), 'application/json'));
|
|
52
|
+
})), target.method === 'GET' ? (outgoing)=>outgoing : HttpClientRequest.bodyText(JSON.stringify(request.inputs), 'application/json'));
|
|
59
53
|
const response = yield* client.execute(outgoing).pipe(Effect.mapError(()=>new Unavailable({
|
|
60
54
|
dependency
|
|
61
55
|
})));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoint/participant-client.ts"],"sourcesContent":["import {\n currentRemainingMs,\n DEADLINE_HEADER,\n decodeProblem,\n type EntifixFailure,\n formatIdempotencyKey,\n IDEMPOTENCY_KEY_HEADER,\n Internal,\n PROBLEM_CONTENT_TYPE,\n ProtocolFailure,\n Timeout,\n Unavailable,\n} from '@entifix/core';\nimport {\n type ParticipantCall,\n type ParticipantClient,\n ParticipantClientTag,\n} from '@entifix/transactions';\nimport { Effect, Layer, Redacted } from 'effect';\nimport { HttpClient, HttpClientRequest } from 'effect/http';\n\n/** Where one participant is reached, and the token it takes. */\nexport interface ParticipantAddress {\n readonly baseUrl: string;\n /** The crossing token this caller presents to that participant. */\n readonly crossingToken: Redacted.Redacted<string>;\n}\n\n/** The header a crossing token travels in. */\nconst CROSSING_TOKEN_HEADER = 'x-crossing-token';\n/** The header a crossing names the organization it acts for in. */\nconst ORGANIZATION_HEADER = 'x-organization-id';\n\nconst parse = (text: string): unknown => {\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return undefined;\n }\n};\n\n
|
|
1
|
+
{"version":3,"sources":["../../src/endpoint/participant-client.ts"],"sourcesContent":["import {\n currentRemainingMs,\n DEADLINE_HEADER,\n decodeProblem,\n type EntifixFailure,\n formatIdempotencyKey,\n IDEMPOTENCY_KEY_HEADER,\n Internal,\n PROBLEM_CONTENT_TYPE,\n ProtocolFailure,\n Timeout,\n Unavailable,\n} from '@entifix/core';\nimport {\n type ParticipantCall,\n type ParticipantClient,\n ParticipantClientTag,\n} from '@entifix/transactions';\nimport { Effect, Layer, Redacted } from 'effect';\nimport { HttpClient, HttpClientRequest } from 'effect/http';\n\n/** Where one participant is reached, and the token it takes. */\nexport interface ParticipantAddress {\n readonly baseUrl: string;\n /** The crossing token this caller presents to that participant. */\n readonly crossingToken: Redacted.Redacted<string>;\n}\n\n/** The header a crossing token travels in. */\nconst CROSSING_TOKEN_HEADER = 'x-crossing-token';\n/** The header a crossing names the organization it acts for in. */\nconst ORGANIZATION_HEADER = 'x-organization-id';\n\nconst parse = (text: string): unknown => {\n try {\n return JSON.parse(text) as unknown;\n } catch {\n return undefined;\n }\n};\n\n/** The step's path with each `:name` taken from the call's inputs. */\nconst pathOf = (call: ParticipantCall, path: string) =>\n path.replace(/:([A-Za-z0-9_]+)/g, (_match, name: string) =>\n encodeURIComponent(String(call.inputs[name] ?? '')),\n );\n\n/**\n * Calls participants over HTTP, as the slip pinned each step's call\n * ([ADR 0016](../../../../../docs/adr/0016-a-flow-engine-port-and-a-durable-workflow-adapter.md)):\n * the crossing token the participant takes, the step's `Idempotency-Key`, the\n * flow's remaining deadline, the organization the inputs name, and the inputs\n * themselves as a flat JSON body — what the participant's own route declares,\n * never a wrapper of the flow's. A refusal decodes into the failure the participant\n * sent, by its code; a body that is not a problem is `protocol`; no answer at\n * all is `unavailable`. A step with no call — the commit point that names no\n * participant — answers at once.\n */\nexport const makeHttpParticipantClient = (\n client: HttpClient.HttpClient,\n participants: Readonly<Record<string, ParticipantAddress>>,\n): ParticipantClient => ({\n call: request =>\n Effect.gen(function* () {\n const target =\n request.kind === 'action'\n ? request.step.call\n : request.step.compensation;\n if (target === undefined) return undefined;\n const name = request.step.participant ?? '';\n const address = participants[name];\n if (address === undefined)\n return yield* Effect.fail(new Internal() as EntifixFailure);\n const dependency = `${name} ${target.method} ${target.path}`;\n\n const remaining = yield* currentRemainingMs;\n if (remaining === 0)\n return yield* Effect.fail(new Timeout({ dependency }));\n\n const organizationId = request.inputs['organizationId'];\n const outgoing = HttpClientRequest.make(target.method)(\n `${address.baseUrl}${pathOf(request, target.path)}`,\n ).pipe(\n HttpClientRequest.setHeaders({\n accept: 'application/json',\n [CROSSING_TOKEN_HEADER]: Redacted.value(address.crossingToken),\n [IDEMPOTENCY_KEY_HEADER]: formatIdempotencyKey(\n request.idempotencyKey,\n ),\n ...(typeof organizationId === 'string'\n ? { [ORGANIZATION_HEADER]: organizationId }\n : {}),\n ...(remaining === undefined\n ? {}\n : { [DEADLINE_HEADER]: String(remaining) }),\n }),\n target.method === 'GET'\n ? (outgoing: HttpClientRequest.HttpClientRequest) => outgoing\n : HttpClientRequest.bodyText(\n JSON.stringify(request.inputs),\n 'application/json',\n ),\n );\n\n const response = yield* client\n .execute(outgoing)\n .pipe(Effect.mapError(() => new Unavailable({ dependency })));\n const text = yield* response.text.pipe(\n Effect.mapError(() => new Unavailable({ dependency })),\n );\n if (response.status < 400) return text === '' ? undefined : parse(text);\n const isProblem =\n response.headers['content-type']?.startsWith(PROBLEM_CONTENT_TYPE) ===\n true;\n return yield* Effect.fail(\n isProblem\n ? decodeProblem(parse(text), response.status)\n : new ProtocolFailure({\n reason: `${dependency} answered ${String(response.status)} without a problem body`,\n upstreamStatus: response.status,\n }),\n );\n }),\n});\n\n/** The HTTP participant client over the host's `HttpClient`. */\nexport const HttpParticipantClientLayer = (\n participants: Readonly<Record<string, ParticipantAddress>>,\n) =>\n Layer.effect(\n ParticipantClientTag,\n Effect.map(HttpClient.HttpClient, client =>\n makeHttpParticipantClient(client, participants),\n ),\n );\n"],"names":["currentRemainingMs","DEADLINE_HEADER","decodeProblem","formatIdempotencyKey","IDEMPOTENCY_KEY_HEADER","Internal","PROBLEM_CONTENT_TYPE","ProtocolFailure","Timeout","Unavailable","ParticipantClientTag","Effect","Layer","Redacted","HttpClient","HttpClientRequest","CROSSING_TOKEN_HEADER","ORGANIZATION_HEADER","parse","text","JSON","undefined","pathOf","call","path","replace","_match","name","encodeURIComponent","String","inputs","makeHttpParticipantClient","client","participants","request","gen","response","target","kind","step","compensation","participant","address","fail","dependency","method","remaining","organizationId","outgoing","make","baseUrl","pipe","setHeaders","accept","value","crossingToken","idempotencyKey","bodyText","stringify","execute","mapError","status","isProblem","headers","startsWith","reason","upstreamStatus","HttpParticipantClientLayer","effect","map"],"mappings":";AAAA,SACEA,kBAAkB,EAClBC,eAAe,EACfC,aAAa,EAEbC,oBAAoB,EACpBC,sBAAsB,EACtBC,QAAQ,EACRC,oBAAoB,EACpBC,eAAe,EACfC,OAAO,EACPC,WAAW,QACN,gBAAgB;AACvB,SAGEC,oBAAoB,QACf,wBAAwB;AAC/B,SAASC,MAAM,EAAEC,KAAK,EAAEC,QAAQ,QAAQ,SAAS;AACjD,SAASC,UAAU,EAAEC,iBAAiB,QAAQ,cAAc;AAS5D,4CAA4C,GAC5C,MAAMC,wBAAwB;AAC9B,iEAAiE,GACjE,MAAMC,sBAAsB;AAE5B,MAAMC,QAAQ,CAACC;IACb,IAAI;QACF,OAAOC,KAAKF,KAAK,CAACC;IACpB,EAAE,eAAM;QACN,OAAOE;IACT;AACF;AAEA,oEAAoE,GACpE,MAAMC,SAAS,CAACC,MAAuBC,OACrCA,KAAKC,OAAO,CAAC,qBAAqB,CAACC,QAAQC;YACfJ;eAA1BK,mBAAmBC,QAAON,oBAAAA,KAAKO,MAAM,CAACH,KAAK,YAAjBJ,oBAAqB;;AAGnD;;;;;;;;;;CAUC,GACD,OAAO,MAAMQ,4BAA4B,CACvCC,QACAC,eACuB,CAAA;QACvBV,MAAMW,CAAAA,UACJvB,OAAOwB,GAAG,CAAC;oBAMID;oBA2CXE;gBAhDF,MAAMC,SACJH,QAAQI,IAAI,KAAK,WACbJ,QAAQK,IAAI,CAAChB,IAAI,GACjBW,QAAQK,IAAI,CAACC,YAAY;gBAC/B,IAAIH,WAAWhB,WAAW,OAAOA;gBACjC,MAAMM,QAAOO,4BAAAA,QAAQK,IAAI,CAACE,WAAW,YAAxBP,4BAA4B;gBACzC,MAAMQ,UAAUT,YAAY,CAACN,KAAK;gBAClC,IAAIe,YAAYrB,WACd,OAAO,OAAOV,OAAOgC,IAAI,CAAC,IAAItC;gBAChC,MAAMuC,aAAa,GAAGjB,KAAK,CAAC,EAAEU,OAAOQ,MAAM,CAAC,CAAC,EAAER,OAAOb,IAAI,EAAE;gBAE5D,MAAMsB,YAAY,OAAO9C;gBACzB,IAAI8C,cAAc,GAChB,OAAO,OAAOnC,OAAOgC,IAAI,CAAC,IAAInC,QAAQ;oBAAEoC;gBAAW;gBAErD,MAAMG,iBAAiBb,QAAQJ,MAAM,CAAC,iBAAiB;gBACvD,MAAMkB,WAAWjC,kBAAkBkC,IAAI,CAACZ,OAAOQ,MAAM,EACnD,GAAGH,QAAQQ,OAAO,GAAG5B,OAAOY,SAASG,OAAOb,IAAI,GAAG,EACnD2B,IAAI,CACJpC,kBAAkBqC,UAAU,CAAC;oBAC3BC,QAAQ;oBACR,CAACrC,sBAAsB,EAAEH,SAASyC,KAAK,CAACZ,QAAQa,aAAa;oBAC7D,CAACnD,uBAAuB,EAAED,qBACxB+B,QAAQsB,cAAc;mBAEpB,OAAOT,mBAAmB,WAC1B;oBAAE,CAAC9B,oBAAoB,EAAE8B;gBAAe,IACxC,CAAC,GACDD,cAAczB,YACd,CAAC,IACD;oBAAE,CAACpB,gBAAgB,EAAE4B,OAAOiB;gBAAW,KAE7CT,OAAOQ,MAAM,KAAK,QACd,CAACG,WAAkDA,WACnDjC,kBAAkB0C,QAAQ,CACxBrC,KAAKsC,SAAS,CAACxB,QAAQJ,MAAM,GAC7B;gBAIR,MAAMM,WAAW,OAAOJ,OACrB2B,OAAO,CAACX,UACRG,IAAI,CAACxC,OAAOiD,QAAQ,CAAC,IAAM,IAAInD,YAAY;wBAAEmC;oBAAW;gBAC3D,MAAMzB,OAAO,OAAOiB,SAASjB,IAAI,CAACgC,IAAI,CACpCxC,OAAOiD,QAAQ,CAAC,IAAM,IAAInD,YAAY;wBAAEmC;oBAAW;gBAErD,IAAIR,SAASyB,MAAM,GAAG,KAAK,OAAO1C,SAAS,KAAKE,YAAYH,MAAMC;gBAClE,MAAM2C,YACJ1B,EAAAA,gCAAAA,SAAS2B,OAAO,CAAC,eAAe,qBAAhC3B,8BAAkC4B,UAAU,CAAC1D,2BAC7C;gBACF,OAAO,OAAOK,OAAOgC,IAAI,CACvBmB,YACI5D,cAAcgB,MAAMC,OAAOiB,SAASyB,MAAM,IAC1C,IAAItD,gBAAgB;oBAClB0D,QAAQ,GAAGrB,WAAW,UAAU,EAAEf,OAAOO,SAASyB,MAAM,EAAE,uBAAuB,CAAC;oBAClFK,gBAAgB9B,SAASyB,MAAM;gBACjC;YAER;IACJ,CAAA,EAAG;AAEH,8DAA8D,GAC9D,OAAO,MAAMM,6BAA6B,CACxClC,eAEArB,MAAMwD,MAAM,CACV1D,sBACAC,OAAO0D,GAAG,CAACvD,WAAWA,UAAU,EAAEkB,CAAAA,SAChCD,0BAA0BC,QAAQC,gBAEpC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,10 @@ export * from './adapters/entity-rest/build-entity-rest-adapter-facets/index.js'
|
|
|
4
4
|
export * from './adapters/entity-rest/build-entity-rest-adapter-get/index.js';
|
|
5
5
|
export * from './adapters/entity-rest/build-entity-rest-adapter-load/index.js';
|
|
6
6
|
export * from './adapters/entity-rest/build-entity-rest-adapter-save/index.js';
|
|
7
|
+
export * from './adapters/entity-rest/build-entity-rest-adapter-write/index.js';
|
|
7
8
|
export * from './adapters/entity-rest/types.js';
|
|
8
9
|
export * from './adapters/entity-use-case/index.js';
|
|
9
|
-
export * from './adapters/
|
|
10
|
+
export * from './adapters/flow-status/build-flow-status-reader/index.js';
|
|
10
11
|
export * from './clients/fetch/index.js';
|
|
11
12
|
export * from './clients/types.js';
|
|
12
13
|
export * from './configuration-client/index.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iEAAiE,CAAC;AAChF,cAAc,kEAAkE,CAAC;AACjF,cAAc,kEAAkE,CAAC;AACjF,cAAc,+DAA+D,CAAC;AAC9E,cAAc,gEAAgE,CAAC;AAC/E,cAAc,gEAAgE,CAAC;AAC/E,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iEAAiE,CAAC;AAChF,cAAc,kEAAkE,CAAC;AACjF,cAAc,kEAAkE,CAAC;AACjF,cAAc,+DAA+D,CAAC;AAC9E,cAAc,gEAAgE,CAAC;AAC/E,cAAc,gEAAgE,CAAC;AAC/E,cAAc,iEAAiE,CAAC;AAChF,cAAc,iCAAiC,CAAC;AAChD,cAAc,qCAAqC,CAAC;AACpD,cAAc,0DAA0D,CAAC;AACzE,cAAc,0BAA0B,CAAC;AACzC,cAAc,oBAAoB,CAAC;AACnC,cAAc,iCAAiC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -4,9 +4,10 @@ export * from './adapters/entity-rest/build-entity-rest-adapter-facets/index.js'
|
|
|
4
4
|
export * from './adapters/entity-rest/build-entity-rest-adapter-get/index.js';
|
|
5
5
|
export * from './adapters/entity-rest/build-entity-rest-adapter-load/index.js';
|
|
6
6
|
export * from './adapters/entity-rest/build-entity-rest-adapter-save/index.js';
|
|
7
|
+
export * from './adapters/entity-rest/build-entity-rest-adapter-write/index.js';
|
|
7
8
|
export * from './adapters/entity-rest/types.js';
|
|
8
9
|
export * from './adapters/entity-use-case/index.js';
|
|
9
|
-
export * from './adapters/
|
|
10
|
+
export * from './adapters/flow-status/build-flow-status-reader/index.js';
|
|
10
11
|
export * from './clients/fetch/index.js';
|
|
11
12
|
export * from './clients/types.js';
|
|
12
13
|
export * from './configuration-client/index.js';
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './adapters/entity-metadata/make-entity-metadata-source/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-delete/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-facets/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-get/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-load/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-save/index.js';\nexport * from './adapters/entity-rest/types.js';\nexport * from './adapters/entity-use-case/index.js';\nexport * from './adapters/
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export * from './adapters/entity-metadata/make-entity-metadata-source/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-delete/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-facets/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-get/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-load/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-save/index.js';\nexport * from './adapters/entity-rest/build-entity-rest-adapter-write/index.js';\nexport * from './adapters/entity-rest/types.js';\nexport * from './adapters/entity-use-case/index.js';\nexport * from './adapters/flow-status/build-flow-status-reader/index.js';\nexport * from './clients/fetch/index.js';\nexport * from './clients/types.js';\nexport * from './configuration-client/index.js';\n"],"names":[],"mappings":"AAAA,cAAc,kEAAkE;AAChF,cAAc,mEAAmE;AACjF,cAAc,mEAAmE;AACjF,cAAc,gEAAgE;AAC9E,cAAc,iEAAiE;AAC/E,cAAc,iEAAiE;AAC/E,cAAc,kEAAkE;AAChF,cAAc,kCAAkC;AAChD,cAAc,sCAAsC;AACpD,cAAc,2DAA2D;AACzE,cAAc,2BAA2B;AACzC,cAAc,qBAAqB;AACnC,cAAc,kCAAkC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entifix/rest",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "HTTP entity adapter for the browser: get, load, save and delete against an entifix service, plus served metadata and transaction status.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -56,14 +56,14 @@
|
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@swc/helpers": "0.5.23",
|
|
59
|
-
"@entifix/core": "0.
|
|
60
|
-
"@entifix/transactions": "0.
|
|
59
|
+
"@entifix/core": "0.15.0",
|
|
60
|
+
"@entifix/transactions": "0.15.0"
|
|
61
61
|
},
|
|
62
62
|
"devDependencies": {
|
|
63
|
-
"effect": "4.0.
|
|
64
|
-
"@entifix/testing-unit": "0.
|
|
63
|
+
"effect": "4.0.7",
|
|
64
|
+
"@entifix/testing-unit": "0.15.0"
|
|
65
65
|
},
|
|
66
66
|
"peerDependencies": {
|
|
67
|
-
"effect": "^4.0.
|
|
67
|
+
"effect": "^4.0.7"
|
|
68
68
|
}
|
|
69
69
|
}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { type TransactionStatusReader } from '@entifix/transactions';
|
|
2
|
-
import type { BuildEntityRestOptions } from '../../entity-rest/types.js';
|
|
3
|
-
export declare const buildTransactionStatusReader: (options: Pick<BuildEntityRestOptions, "uriConfig" | "configuration">) => TransactionStatusReader;
|
|
4
|
-
//# sourceMappingURL=build-transaction-status-reader.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"build-transaction-status-reader.d.ts","sourceRoot":"","sources":["../../../../src/adapters/transaction-status/build-transaction-status-reader/build-transaction-status-reader.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,uBAAuB,CAAC;AAK/B,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AAqCzE,eAAO,MAAM,4BAA4B,GACvC,SAAS,IAAI,CAAC,sBAAsB,EAAE,WAAW,GAAG,eAAe,CAAC,KACnE,uBA0BF,CAAC"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import { isTag } from '@entifix/core';
|
|
2
|
-
import { readTransactionRecordEnvelope } from '@entifix/transactions';
|
|
3
|
-
import { Effect } from 'effect';
|
|
4
|
-
import { performHttpRequestThroughFetch } from '../../../clients/fetch/index.js';
|
|
5
|
-
import { buildEntityRestAdapterMixins as adapterMixins } from '../../entity-rest/build-entity-rest-adapter-mixins/index.js';
|
|
6
|
-
/**
|
|
7
|
-
* The tracker's own path segment. It is not an entity — nothing decorates a
|
|
8
|
-
* `TransactionRecord` — but the URL is composed the same way every entity URL
|
|
9
|
-
* is, so `buildEntityBaseUrl` (already generic over an arbitrary name) needs no
|
|
10
|
-
* transaction-shaped sibling.
|
|
11
|
-
*/ const TRANSACTION_PATH = 'transaction';
|
|
12
|
-
/**
|
|
13
|
-
* Reads one transaction's record over HTTP, for a browser reconciling a write it
|
|
14
|
-
* started.
|
|
15
|
-
*
|
|
16
|
-
* ⚠️ **A `404` answers `undefined`, and that is not a failure.** `accepted`
|
|
17
|
-
* reaches the tracker over the bus, so with the broker down the entity write
|
|
18
|
-
* commits — the outbox is in the same Mongo transaction — while no event is ever
|
|
19
|
-
* published and the tracker holds no record at all. A caller that treated this
|
|
20
|
-
* as terminal would un-render a healthy write during a broker outage, which is
|
|
21
|
-
* the moment nobody can tell a UI bug from an outage. The route also
|
|
22
|
-
* answers `404` for another tenant's record, deliberately, so it cannot be
|
|
23
|
-
* walked to probe ids that are also primary keys — indistinguishable here, and
|
|
24
|
-
* correctly so: neither is a record this caller may reconcile against.
|
|
25
|
-
*
|
|
26
|
-
* Every other status stays an error, so an unreachable service is not quietly
|
|
27
|
-
* read as "no such transaction".
|
|
28
|
-
*/ /**
|
|
29
|
-
* A `404`, however it arrived: a tracker that answers a problem body says
|
|
30
|
-
* `NotFound`; one that answers no body at all is a protocol failure that
|
|
31
|
-
* still carries the status.
|
|
32
|
-
*/ const isNotFound = (error)=>isTag('NotFound')(error) || isTag('ProtocolFailure')(error) && error.upstreamStatus === 404;
|
|
33
|
-
export const buildTransactionStatusReader = (options)=>{
|
|
34
|
-
const { configuration } = options;
|
|
35
|
-
return {
|
|
36
|
-
read: (transactionId)=>Effect.gen(function*() {
|
|
37
|
-
const url = yield* adapterMixins.buildEntityBaseUrl(configuration, options, TRANSACTION_PATH, transactionId);
|
|
38
|
-
const response = yield* performHttpRequestThroughFetch(adapterMixins.buildEntityRequest({
|
|
39
|
-
method: 'GET',
|
|
40
|
-
url
|
|
41
|
-
}));
|
|
42
|
-
return yield* readTransactionRecordEnvelope(response.body);
|
|
43
|
-
}).pipe(Effect.catch((error)=>isNotFound(error) ? Effect.succeed(undefined) : Effect.fail(error)))
|
|
44
|
-
};
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
//# sourceMappingURL=build-transaction-status-reader.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/adapters/transaction-status/build-transaction-status-reader/build-transaction-status-reader.ts"],"sourcesContent":["import { isTag, type TransitionalFailure } from '@entifix/core';\nimport {\n readTransactionRecordEnvelope,\n type TransactionRecord,\n type TransactionStatusReader,\n} from '@entifix/transactions';\nimport { Effect } from 'effect';\n\nimport { performHttpRequestThroughFetch } from '../../../clients/fetch/index.js';\nimport { buildEntityRestAdapterMixins as adapterMixins } from '../../entity-rest/build-entity-rest-adapter-mixins/index.js';\nimport type { BuildEntityRestOptions } from '../../entity-rest/types.js';\n\n/**\n * The tracker's own path segment. It is not an entity — nothing decorates a\n * `TransactionRecord` — but the URL is composed the same way every entity URL\n * is, so `buildEntityBaseUrl` (already generic over an arbitrary name) needs no\n * transaction-shaped sibling.\n */\nconst TRANSACTION_PATH = 'transaction';\n\n/**\n * Reads one transaction's record over HTTP, for a browser reconciling a write it\n * started.\n *\n * ⚠️ **A `404` answers `undefined`, and that is not a failure.** `accepted`\n * reaches the tracker over the bus, so with the broker down the entity write\n * commits — the outbox is in the same Mongo transaction — while no event is ever\n * published and the tracker holds no record at all. A caller that treated this\n * as terminal would un-render a healthy write during a broker outage, which is\n * the moment nobody can tell a UI bug from an outage. The route also\n * answers `404` for another tenant's record, deliberately, so it cannot be\n * walked to probe ids that are also primary keys — indistinguishable here, and\n * correctly so: neither is a record this caller may reconcile against.\n *\n * Every other status stays an error, so an unreachable service is not quietly\n * read as \"no such transaction\".\n */\n/**\n * A `404`, however it arrived: a tracker that answers a problem body says\n * `NotFound`; one that answers no body at all is a protocol failure that\n * still carries the status.\n */\nconst isNotFound = (error: unknown): boolean =>\n isTag('NotFound')(error) ||\n (isTag('ProtocolFailure')(error) &&\n (error as { readonly upstreamStatus?: unknown }).upstreamStatus === 404);\n\nexport const buildTransactionStatusReader = (\n options: Pick<BuildEntityRestOptions, 'uriConfig' | 'configuration'>,\n): TransactionStatusReader => {\n const { configuration } = options;\n\n return {\n read: (\n transactionId: string,\n ): Effect.Effect<TransactionRecord | undefined, TransitionalFailure> =>\n Effect.gen(function* () {\n const url = yield* adapterMixins.buildEntityBaseUrl(\n configuration,\n options,\n TRANSACTION_PATH,\n transactionId,\n );\n\n const response = yield* performHttpRequestThroughFetch(\n adapterMixins.buildEntityRequest({ method: 'GET', url }),\n );\n\n return yield* readTransactionRecordEnvelope(response.body);\n }).pipe(\n Effect.catch(error =>\n isNotFound(error) ? Effect.succeed(undefined) : Effect.fail(error),\n ),\n ),\n };\n};\n"],"names":["isTag","readTransactionRecordEnvelope","Effect","performHttpRequestThroughFetch","buildEntityRestAdapterMixins","adapterMixins","TRANSACTION_PATH","isNotFound","error","upstreamStatus","buildTransactionStatusReader","options","configuration","read","transactionId","gen","url","buildEntityBaseUrl","response","buildEntityRequest","method","body","pipe","catch","succeed","undefined","fail"],"mappings":"AAAA,SAASA,KAAK,QAAkC,gBAAgB;AAChE,SACEC,6BAA6B,QAGxB,wBAAwB;AAC/B,SAASC,MAAM,QAAQ,SAAS;AAEhC,SAASC,8BAA8B,QAAQ,kCAAkC;AACjF,SAASC,gCAAgCC,aAAa,QAAQ,8DAA8D;AAG5H;;;;;CAKC,GACD,MAAMC,mBAAmB;AAEzB;;;;;;;;;;;;;;;;CAgBC,GACD;;;;CAIC,GACD,MAAMC,aAAa,CAACC,QAClBR,MAAM,YAAYQ,UACjBR,MAAM,mBAAmBQ,UACxB,AAACA,MAAgDC,cAAc,KAAK;AAExE,OAAO,MAAMC,+BAA+B,CAC1CC;IAEA,MAAM,EAAEC,aAAa,EAAE,GAAGD;IAE1B,OAAO;QACLE,MAAM,CACJC,gBAEAZ,OAAOa,GAAG,CAAC;gBACT,MAAMC,MAAM,OAAOX,cAAcY,kBAAkB,CACjDL,eACAD,SACAL,kBACAQ;gBAGF,MAAMI,WAAW,OAAOf,+BACtBE,cAAcc,kBAAkB,CAAC;oBAAEC,QAAQ;oBAAOJ;gBAAI;gBAGxD,OAAO,OAAOf,8BAA8BiB,SAASG,IAAI;YAC3D,GAAGC,IAAI,CACLpB,OAAOqB,KAAK,CAACf,CAAAA,QACXD,WAAWC,SAASN,OAAOsB,OAAO,CAACC,aAAavB,OAAOwB,IAAI,CAAClB;IAGpE;AACF,EAAE"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/adapters/transaction-status/build-transaction-status-reader/index.ts"],"names":[],"mappings":"AAAA,cAAc,sCAAsC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/adapters/transaction-status/build-transaction-status-reader/index.ts"],"sourcesContent":["export * from './build-transaction-status-reader.js';\n"],"names":[],"mappings":"AAAA,cAAc,uCAAuC"}
|