@venizia/ignis-worker 0.4.2 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/LICENSE.md +2 -5
  2. package/README.md +13 -0
  3. package/package.json +9 -15
  4. package/dist/cjs/applications/common/index.d.ts +0 -2
  5. package/dist/cjs/applications/common/index.d.ts.map +0 -1
  6. package/dist/cjs/applications/common/index.js +0 -18
  7. package/dist/cjs/applications/common/index.js.map +0 -1
  8. package/dist/cjs/applications/common/types.d.ts +0 -10
  9. package/dist/cjs/applications/common/types.d.ts.map +0 -1
  10. package/dist/cjs/applications/common/types.js +0 -3
  11. package/dist/cjs/applications/common/types.js.map +0 -1
  12. package/dist/cjs/applications/index.d.ts +0 -3
  13. package/dist/cjs/applications/index.d.ts.map +0 -1
  14. package/dist/cjs/applications/index.js +0 -19
  15. package/dist/cjs/applications/index.js.map +0 -1
  16. package/dist/cjs/applications/worker.d.ts +0 -79
  17. package/dist/cjs/applications/worker.d.ts.map +0 -1
  18. package/dist/cjs/applications/worker.js +0 -190
  19. package/dist/cjs/applications/worker.js.map +0 -1
  20. package/dist/cjs/envelope/common/index.d.ts +0 -2
  21. package/dist/cjs/envelope/common/index.d.ts.map +0 -1
  22. package/dist/cjs/envelope/common/index.js +0 -18
  23. package/dist/cjs/envelope/common/index.js.map +0 -1
  24. package/dist/cjs/envelope/common/types.d.ts +0 -37
  25. package/dist/cjs/envelope/common/types.d.ts.map +0 -1
  26. package/dist/cjs/envelope/common/types.js +0 -3
  27. package/dist/cjs/envelope/common/types.js.map +0 -1
  28. package/dist/cjs/envelope/encode.d.ts +0 -61
  29. package/dist/cjs/envelope/encode.d.ts.map +0 -1
  30. package/dist/cjs/envelope/encode.js +0 -116
  31. package/dist/cjs/envelope/encode.js.map +0 -1
  32. package/dist/cjs/envelope/index.d.ts +0 -3
  33. package/dist/cjs/envelope/index.d.ts.map +0 -1
  34. package/dist/cjs/envelope/index.js +0 -19
  35. package/dist/cjs/envelope/index.js.map +0 -1
  36. package/dist/cjs/index.d.ts +0 -5
  37. package/dist/cjs/index.d.ts.map +0 -1
  38. package/dist/cjs/index.js +0 -21
  39. package/dist/cjs/index.js.map +0 -1
  40. package/dist/cjs/transport/common/index.d.ts +0 -2
  41. package/dist/cjs/transport/common/index.d.ts.map +0 -1
  42. package/dist/cjs/transport/common/index.js +0 -18
  43. package/dist/cjs/transport/common/index.js.map +0 -1
  44. package/dist/cjs/transport/common/types.d.ts +0 -6
  45. package/dist/cjs/transport/common/types.d.ts.map +0 -1
  46. package/dist/cjs/transport/common/types.js +0 -3
  47. package/dist/cjs/transport/common/types.js.map +0 -1
  48. package/dist/cjs/transport/fetch-bridge.d.ts +0 -41
  49. package/dist/cjs/transport/fetch-bridge.d.ts.map +0 -1
  50. package/dist/cjs/transport/fetch-bridge.js +0 -104
  51. package/dist/cjs/transport/fetch-bridge.js.map +0 -1
  52. package/dist/cjs/transport/in-process.d.ts +0 -23
  53. package/dist/cjs/transport/in-process.d.ts.map +0 -1
  54. package/dist/cjs/transport/in-process.js +0 -47
  55. package/dist/cjs/transport/in-process.js.map +0 -1
  56. package/dist/cjs/transport/index.d.ts +0 -6
  57. package/dist/cjs/transport/index.d.ts.map +0 -1
  58. package/dist/cjs/transport/index.js +0 -22
  59. package/dist/cjs/transport/index.js.map +0 -1
  60. package/dist/cjs/transport/shared/common/constants.d.ts +0 -14
  61. package/dist/cjs/transport/shared/common/constants.d.ts.map +0 -1
  62. package/dist/cjs/transport/shared/common/constants.js +0 -19
  63. package/dist/cjs/transport/shared/common/constants.js.map +0 -1
  64. package/dist/cjs/transport/shared/common/index.d.ts +0 -3
  65. package/dist/cjs/transport/shared/common/index.d.ts.map +0 -1
  66. package/dist/cjs/transport/shared/common/index.js +0 -19
  67. package/dist/cjs/transport/shared/common/index.js.map +0 -1
  68. package/dist/cjs/transport/shared/common/types.d.ts +0 -35
  69. package/dist/cjs/transport/shared/common/types.d.ts.map +0 -1
  70. package/dist/cjs/transport/shared/common/types.js +0 -3
  71. package/dist/cjs/transport/shared/common/types.js.map +0 -1
  72. package/dist/cjs/transport/shared/index.d.ts +0 -4
  73. package/dist/cjs/transport/shared/index.d.ts.map +0 -1
  74. package/dist/cjs/transport/shared/index.js +0 -11
  75. package/dist/cjs/transport/shared/index.js.map +0 -1
  76. package/dist/cjs/transport/shared/transport.d.ts +0 -87
  77. package/dist/cjs/transport/shared/transport.d.ts.map +0 -1
  78. package/dist/cjs/transport/shared/transport.js +0 -384
  79. package/dist/cjs/transport/shared/transport.js.map +0 -1
  80. package/dist/cjs/transport/worker.d.ts +0 -62
  81. package/dist/cjs/transport/worker.d.ts.map +0 -1
  82. package/dist/cjs/transport/worker.js +0 -224
  83. package/dist/cjs/transport/worker.js.map +0 -1
@@ -1,61 +0,0 @@
1
- import type { ApplicationError } from '@venizia/ignis-helpers/core';
2
- import type { IBffErrorEnvelope, IBffRequestEnvelope, IBffResponseEnvelope } from './common';
3
- /**
4
- * Every request built inside the Worker uses this origin. Never `self.location.href`: a `blob:`
5
- * worker origin is opaque and `new URL(path, blobUrl)` throws, and Hono's `getPath()` mis-parses
6
- * `file://`. Hono never resolves the host - it string-scans from `indexOf(':') + 4`.
7
- */
8
- export declare const BFF_SYNTHETIC_ORIGIN = "http://ignis.internal";
9
- /** Turns `Request`/`Response`/`Error` into plain structured-cloneable shapes and back - none of the three survives `postMessage` as itself. */
10
- export declare class BffEnvelope {
11
- /**
12
- * Statuses the Fetch spec forbids a body on - `new Response(body, { status })` throws if `body`
13
- * is anything but `null` for one of these, even an empty `ArrayBuffer`.
14
- */
15
- private static readonly NULL_BODY_STATUSES;
16
- /**
17
- * Moves a URL onto the synthetic origin, keeping everything below it. A caller builds a request
18
- * against the page's real origin (or a relative path resolved against it); `decodeRequest` on the
19
- * far side always reconstructs on `BFF_SYNTHETIC_ORIGIN`.
20
- */
21
- static toSyntheticUrl(opts: {
22
- url: string;
23
- }): string;
24
- /**
25
- * `url` overrides the request's own, so the origin rewrite costs nothing: rebuilding the `Request`
26
- * to change its URL would read the body a second time, and a 10 MB upload would hold 20 MB on the
27
- * UI thread. Reading the body here disturbs the caller's request exactly as `globalThis.fetch`
28
- * does with the one it is handed.
29
- */
30
- static encodeRequest(opts: {
31
- request: Request;
32
- id: string;
33
- url?: string;
34
- }): Promise<IBffRequestEnvelope>;
35
- static decodeRequest(opts: {
36
- envelope: IBffRequestEnvelope;
37
- }): Request;
38
- static encodeResponse(opts: {
39
- response: Response;
40
- id: string;
41
- }): Promise<IBffResponseEnvelope>;
42
- static decodeResponse(opts: {
43
- envelope: IBffResponseEnvelope;
44
- }): Response;
45
- /**
46
- * Builds the shape an error crosses `postMessage` as. An `ApplicationError` cannot cross as itself
47
- * - a custom `Error` subclass loses its name, its own properties and its prototype through
48
- * structured clone - so it crosses normalised and `decodeError` rebuilds it on the far side.
49
- *
50
- * A foreign error gets `500`, matching what the framework's error middleware gives an UNEXPECTED
51
- * one on the server. Anything reaching here already escaped the whole HTTP layer.
52
- */
53
- static encodeError(opts: {
54
- id: string;
55
- error: unknown;
56
- }): IBffErrorEnvelope;
57
- static decodeError(opts: {
58
- envelope: IBffErrorEnvelope;
59
- }): ApplicationError;
60
- }
61
- //# sourceMappingURL=encode.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"encode.d.ts","sourceRoot":"","sources":["../../../src/envelope/encode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAGpE,OAAO,KAAK,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AAE7F;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,0BAA0B,CAAC;AAE5D,+IAA+I;AAC/I,qBAAa,WAAW;IACtB;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,kBAAkB,CAA4B;IAEtE;;;;OAIG;IACH,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,MAAM;IAKpD;;;;;OAKG;WACU,aAAa,CAAC,IAAI,EAAE;QAC/B,OAAO,EAAE,OAAO,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAahC,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,mBAAmB,CAAA;KAAE,GAAG,OAAO;WAUzD,cAAc,CAAC,IAAI,EAAE;QAChC,QAAQ,EAAE,QAAQ,CAAC;QACnB,EAAE,EAAE,MAAM,CAAC;KACZ,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAajC,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,oBAAoB,CAAA;KAAE,GAAG,QAAQ;IAazE;;;;;;;OAOG;IACH,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,GAAG,iBAAiB;IAoB3E,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,iBAAiB,CAAA;KAAE,GAAG,gBAAgB;CAc5E"}
@@ -1,116 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BffEnvelope = exports.BFF_SYNTHETIC_ORIGIN = void 0;
4
- const core_1 = require("@venizia/ignis-helpers/core");
5
- const common_1 = require("@venizia/ignis-helpers/common");
6
- /**
7
- * Every request built inside the Worker uses this origin. Never `self.location.href`: a `blob:`
8
- * worker origin is opaque and `new URL(path, blobUrl)` throws, and Hono's `getPath()` mis-parses
9
- * `file://`. Hono never resolves the host - it string-scans from `indexOf(':') + 4`.
10
- */
11
- exports.BFF_SYNTHETIC_ORIGIN = 'http://ignis.internal';
12
- /** Turns `Request`/`Response`/`Error` into plain structured-cloneable shapes and back - none of the three survives `postMessage` as itself. */
13
- class BffEnvelope {
14
- /**
15
- * Statuses the Fetch spec forbids a body on - `new Response(body, { status })` throws if `body`
16
- * is anything but `null` for one of these, even an empty `ArrayBuffer`.
17
- */
18
- static { this.NULL_BODY_STATUSES = new Set([204, 205, 304]); }
19
- /**
20
- * Moves a URL onto the synthetic origin, keeping everything below it. A caller builds a request
21
- * against the page's real origin (or a relative path resolved against it); `decodeRequest` on the
22
- * far side always reconstructs on `BFF_SYNTHETIC_ORIGIN`.
23
- */
24
- static toSyntheticUrl(opts) {
25
- const url = new URL(opts.url);
26
- return `${exports.BFF_SYNTHETIC_ORIGIN}${url.pathname}${url.search}${url.hash}`;
27
- }
28
- /**
29
- * `url` overrides the request's own, so the origin rewrite costs nothing: rebuilding the `Request`
30
- * to change its URL would read the body a second time, and a 10 MB upload would hold 20 MB on the
31
- * UI thread. Reading the body here disturbs the caller's request exactly as `globalThis.fetch`
32
- * does with the one it is handed.
33
- */
34
- static async encodeRequest(opts) {
35
- const { request, id, url } = opts;
36
- const hasBody = request.method !== 'GET' && request.method !== 'HEAD';
37
- return {
38
- id,
39
- method: request.method,
40
- url: url ?? request.url,
41
- headers: [...request.headers.entries()],
42
- body: hasBody ? await request.arrayBuffer() : undefined,
43
- };
44
- }
45
- static decodeRequest(opts) {
46
- const { envelope } = opts;
47
- return new Request(envelope.url, {
48
- method: envelope.method,
49
- headers: envelope.headers,
50
- body: envelope.body,
51
- });
52
- }
53
- static async encodeResponse(opts) {
54
- const { response, id } = opts;
55
- const hasBody = !BffEnvelope.NULL_BODY_STATUSES.has(response.status);
56
- return {
57
- id,
58
- status: response.status,
59
- statusText: response.statusText,
60
- headers: [...response.headers.entries()],
61
- body: hasBody ? await response.arrayBuffer() : undefined,
62
- };
63
- }
64
- static decodeResponse(opts) {
65
- const { envelope } = opts;
66
- const body = BffEnvelope.NULL_BODY_STATUSES.has(envelope.status)
67
- ? null
68
- : (envelope.body ?? null);
69
- return new Response(body, {
70
- status: envelope.status,
71
- statusText: envelope.statusText,
72
- headers: envelope.headers,
73
- });
74
- }
75
- /**
76
- * Builds the shape an error crosses `postMessage` as. An `ApplicationError` cannot cross as itself
77
- * - a custom `Error` subclass loses its name, its own properties and its prototype through
78
- * structured clone - so it crosses normalised and `decodeError` rebuilds it on the far side.
79
- *
80
- * A foreign error gets `500`, matching what the framework's error middleware gives an UNEXPECTED
81
- * one on the server. Anything reaching here already escaped the whole HTTP layer.
82
- */
83
- static encodeError(opts) {
84
- const { id, error } = opts;
85
- const applicationError = (0, core_1.isApplicationError)(error)
86
- ? error
87
- : (0, core_1.getError)({
88
- statusCode: common_1.HTTP.ResultCodes.RS_5.InternalServerError,
89
- message: error instanceof Error ? error.message : String(error),
90
- });
91
- return {
92
- id,
93
- statusCode: applicationError.statusCode,
94
- error: {
95
- text: applicationError.normalized.text,
96
- code: applicationError.normalized.code,
97
- args: applicationError.normalized.args,
98
- },
99
- };
100
- }
101
- static decodeError(opts) {
102
- const { envelope } = opts;
103
- return (0, core_1.fromError)({
104
- error: {
105
- statusCode: envelope.statusCode,
106
- normalized: {
107
- text: envelope.error.text,
108
- code: envelope.error.code,
109
- args: envelope.error.args,
110
- },
111
- },
112
- });
113
- }
114
- }
115
- exports.BffEnvelope = BffEnvelope;
116
- //# sourceMappingURL=encode.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"encode.js","sourceRoot":"","sources":["../../../src/envelope/encode.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ApplicationError } from '@venizia/ignis-helpers/core';\nimport { fromError, getError, isApplicationError } from '@venizia/ignis-helpers/core';\nimport { HTTP } from '@venizia/ignis-helpers/common';\nimport type { IBffErrorEnvelope, IBffRequestEnvelope, IBffResponseEnvelope } from './common';\n\n/**\n * Every request built inside the Worker uses this origin. Never `self.location.href`: a `blob:`\n * worker origin is opaque and `new URL(path, blobUrl)` throws, and Hono's `getPath()` mis-parses\n * `file://`. Hono never resolves the host - it string-scans from `indexOf(':') + 4`.\n */\nexport const BFF_SYNTHETIC_ORIGIN = 'http://ignis.internal';\n\n/** Turns `Request`/`Response`/`Error` into plain structured-cloneable shapes and back - none of the three survives `postMessage` as itself. */\nexport class BffEnvelope {\n /**\n * Statuses the Fetch spec forbids a body on - `new Response(body, { status })` throws if `body`\n * is anything but `null` for one of these, even an empty `ArrayBuffer`.\n */\n private static readonly NULL_BODY_STATUSES = new Set([204, 205, 304]);\n\n /**\n * Moves a URL onto the synthetic origin, keeping everything below it. A caller builds a request\n * against the page's real origin (or a relative path resolved against it); `decodeRequest` on the\n * far side always reconstructs on `BFF_SYNTHETIC_ORIGIN`.\n */\n static toSyntheticUrl(opts: { url: string }): string {\n const url = new URL(opts.url);\n return `${BFF_SYNTHETIC_ORIGIN}${url.pathname}${url.search}${url.hash}`;\n }\n\n /**\n * `url` overrides the request's own, so the origin rewrite costs nothing: rebuilding the `Request`\n * to change its URL would read the body a second time, and a 10 MB upload would hold 20 MB on the\n * UI thread. Reading the body here disturbs the caller's request exactly as `globalThis.fetch`\n * does with the one it is handed.\n */\n static async encodeRequest(opts: {\n request: Request;\n id: string;\n url?: string;\n }): Promise<IBffRequestEnvelope> {\n const { request, id, url } = opts;\n const hasBody = request.method !== 'GET' && request.method !== 'HEAD';\n\n return {\n id,\n method: request.method,\n url: url ?? request.url,\n headers: [...request.headers.entries()],\n body: hasBody ? await request.arrayBuffer() : undefined,\n };\n }\n\n static decodeRequest(opts: { envelope: IBffRequestEnvelope }): Request {\n const { envelope } = opts;\n\n return new Request(envelope.url, {\n method: envelope.method,\n headers: envelope.headers,\n body: envelope.body,\n });\n }\n\n static async encodeResponse(opts: {\n response: Response;\n id: string;\n }): Promise<IBffResponseEnvelope> {\n const { response, id } = opts;\n const hasBody = !BffEnvelope.NULL_BODY_STATUSES.has(response.status);\n\n return {\n id,\n status: response.status,\n statusText: response.statusText,\n headers: [...response.headers.entries()],\n body: hasBody ? await response.arrayBuffer() : undefined,\n };\n }\n\n static decodeResponse(opts: { envelope: IBffResponseEnvelope }): Response {\n const { envelope } = opts;\n const body = BffEnvelope.NULL_BODY_STATUSES.has(envelope.status)\n ? null\n : (envelope.body ?? null);\n\n return new Response(body, {\n status: envelope.status,\n statusText: envelope.statusText,\n headers: envelope.headers,\n });\n }\n\n /**\n * Builds the shape an error crosses `postMessage` as. An `ApplicationError` cannot cross as itself\n * - a custom `Error` subclass loses its name, its own properties and its prototype through\n * structured clone - so it crosses normalised and `decodeError` rebuilds it on the far side.\n *\n * A foreign error gets `500`, matching what the framework's error middleware gives an UNEXPECTED\n * one on the server. Anything reaching here already escaped the whole HTTP layer.\n */\n static encodeError(opts: { id: string; error: unknown }): IBffErrorEnvelope {\n const { id, error } = opts;\n const applicationError = isApplicationError(error)\n ? error\n : getError({\n statusCode: HTTP.ResultCodes.RS_5.InternalServerError,\n message: error instanceof Error ? error.message : String(error),\n });\n\n return {\n id,\n statusCode: applicationError.statusCode,\n error: {\n text: applicationError.normalized.text,\n code: applicationError.normalized.code,\n args: applicationError.normalized.args,\n },\n };\n }\n\n static decodeError(opts: { envelope: IBffErrorEnvelope }): ApplicationError {\n const { envelope } = opts;\n\n return fromError({\n error: {\n statusCode: envelope.statusCode,\n normalized: {\n text: envelope.error.text,\n code: envelope.error.code,\n args: envelope.error.args as Record<string, unknown> | undefined,\n },\n },\n });\n }\n}\n"]}
@@ -1,3 +0,0 @@
1
- export * from './common';
2
- export * from './encode';
3
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/envelope/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
@@ -1,19 +0,0 @@
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("./common"), exports);
18
- __exportStar(require("./encode"), exports);
19
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/envelope/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,2CAAyB","sourcesContent":["export * from './common';\nexport * from './encode';\n"]}
@@ -1,5 +0,0 @@
1
- import 'reflect-metadata';
2
- export * from './applications';
3
- export * from './envelope';
4
- export * from './transport';
5
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
package/dist/cjs/index.js DELETED
@@ -1,21 +0,0 @@
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
- require("reflect-metadata");
18
- __exportStar(require("./applications"), exports);
19
- __exportStar(require("./envelope"), exports);
20
- __exportStar(require("./transport"), exports);
21
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4BAA0B;AAE1B,iDAA+B;AAC/B,6CAA2B;AAC3B,8CAA4B","sourcesContent":["import 'reflect-metadata';\n\nexport * from './applications';\nexport * from './envelope';\nexport * from './transport';\n"]}
@@ -1,2 +0,0 @@
1
- export * from './types';
2
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/transport/common/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC"}
@@ -1,18 +0,0 @@
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("./types"), exports);
18
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/transport/common/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB","sourcesContent":["export * from './types';\n"]}
@@ -1,6 +0,0 @@
1
- export interface IBffTransport {
2
- fetch(opts: {
3
- request: Request;
4
- }): Promise<Response>;
5
- }
6
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/transport/common/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACtD"}
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/transport/common/types.ts"],"names":[],"mappings":"","sourcesContent":["export interface IBffTransport {\n fetch(opts: { request: Request }): Promise<Response>;\n}\n"]}
@@ -1,41 +0,0 @@
1
- import type { IBffTransport } from './common/types';
2
- type TFetch = typeof globalThis.fetch;
3
- /** The carrier whose `fetch` is replaced - `globalThis` in a page, an object a test controls otherwise. */
4
- interface IFetchCarrier {
5
- fetch: TFetch;
6
- }
7
- export interface IInstallBffFetchOptions {
8
- /** Anything implementing the transport contract, so an in-process transport works in a test. */
9
- transport: IBffTransport;
10
- /**
11
- * Path prefixes the BFF owns, matched on a segment boundary: `/api` claims `/api` and `/api/...`,
12
- * never `/apix`. Everything else is passed to the original `fetch` untouched.
13
- */
14
- basePath: string | Array<string>;
15
- /**
16
- * The origin, or origins, the BFF answers for - the page's own, or an upstream gateway whose
17
- * calls the BFF stands in for. A request to any other origin goes to the network whatever its path.
18
- * Unset, only the path decides, so a call to ANY origin under `basePath` is claimed.
19
- */
20
- origin?: string | Array<string>;
21
- /** Defaults to `globalThis`. */
22
- carrier?: IFetchCarrier;
23
- }
24
- /**
25
- * Routes the page's own `fetch` into a BFF transport for anything under `basePath`, and leaves every
26
- * other call on the network untouched.
27
- *
28
- * This is the seam that lets an existing HTTP client talk to an in-browser IGNIS application without
29
- * knowing one exists. A data provider, an SDK or a generated client reaches the network through the
30
- * global `fetch` and usually accepts no custom fetcher, so answering that `fetch` is the only place
31
- * an in-browser backend becomes a drop-in swap rather than a fork of the client.
32
- *
33
- * Install it BEFORE the application that will use it boots: a request issued while the original
34
- * `fetch` is still in place leaves the page and 404s against whatever is serving it.
35
- *
36
- * @returns The uninstall function. It restores the previous `fetch` only if this bridge is still the
37
- * installed one - if something patched `fetch` afterwards, restoring would silently discard that.
38
- */
39
- export declare const installBffFetch: (opts: IInstallBffFetchOptions) => (() => void);
40
- export {};
41
- //# sourceMappingURL=fetch-bridge.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetch-bridge.d.ts","sourceRoot":"","sources":["../../../src/transport/fetch-bridge.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAQpD,KAAK,MAAM,GAAG,OAAO,UAAU,CAAC,KAAK,CAAC;AAEtC,2GAA2G;AAC3G,UAAU,aAAa;IACrB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,gGAAgG;IAChG,SAAS,EAAE,aAAa,CAAC;IACzB;;;OAGG;IACH,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IACjC;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;IAChC,gCAAgC;IAChC,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAgDD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,eAAe,GAAI,MAAM,uBAAuB,KAAG,CAAC,MAAM,IAAI,CAwD1E,CAAC"}
@@ -1,104 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.installBffFetch = void 0;
4
- const core_1 = require("@venizia/ignis-helpers/core");
5
- /**
6
- * Marks the patched `fetch` so a second install is refused rather than silently stacking. `Symbol.for`
7
- * and not a private symbol: two copies of this package in one page must still see each other's mark.
8
- */
9
- const BRIDGE_MARKER = Symbol.for('@venizia/ignis-worker/bff-fetch');
10
- /**
11
- * Resolves a request's absolute URL WITHOUT constructing a `Request`.
12
- *
13
- * This is the whole reason this helper exists rather than one obvious line. `new Request(input)`,
14
- * where `input` is a `Request` carrying a body, marks that body disturbed - so building one just to
15
- * read `.url` breaks the very pass-through it is deciding about: the next line hands the same, now
16
- * unreadable, request to the network.
17
- *
18
- * Measured, because the runtimes disagree. Chromium:
19
- *
20
- * original.bodyUsed // false
21
- * new Request(original)
22
- * original.bodyUsed // true
23
- * await original.text() // TypeError: body stream already read
24
- *
25
- * Bun does NOT disturb it, so the unit tests pass either way and cannot guard this. The browser is
26
- * where this code runs, so the browser is the behaviour to write for.
27
- */
28
- const resolveRequestUrl = (input) => {
29
- if (typeof input === 'string') {
30
- return new URL(input, globalThis.location?.href).href;
31
- }
32
- if (input instanceof URL) {
33
- return input.href;
34
- }
35
- return input.url;
36
- };
37
- const toPrefixList = (basePath) => {
38
- // Trailing slashes trimmed once, so the boundary test below is one comparison and one prefix check.
39
- const prefixes = (Array.isArray(basePath) ? basePath : [basePath])
40
- .map((prefix) => prefix.replace(/\/+$/, ''))
41
- .filter((prefix) => prefix.length > 0);
42
- if (prefixes.length === 0) {
43
- throw (0, core_1.getError)({
44
- message: '[installBffFetch] Invalid basePath | At least one non-empty path prefix is required',
45
- });
46
- }
47
- return prefixes;
48
- };
49
- /**
50
- * Routes the page's own `fetch` into a BFF transport for anything under `basePath`, and leaves every
51
- * other call on the network untouched.
52
- *
53
- * This is the seam that lets an existing HTTP client talk to an in-browser IGNIS application without
54
- * knowing one exists. A data provider, an SDK or a generated client reaches the network through the
55
- * global `fetch` and usually accepts no custom fetcher, so answering that `fetch` is the only place
56
- * an in-browser backend becomes a drop-in swap rather than a fork of the client.
57
- *
58
- * Install it BEFORE the application that will use it boots: a request issued while the original
59
- * `fetch` is still in place leaves the page and 404s against whatever is serving it.
60
- *
61
- * @returns The uninstall function. It restores the previous `fetch` only if this bridge is still the
62
- * installed one - if something patched `fetch` afterwards, restoring would silently discard that.
63
- */
64
- const installBffFetch = (opts) => {
65
- const { transport, basePath } = opts;
66
- const origins = opts.origin === undefined
67
- ? undefined
68
- : new Set((Array.isArray(opts.origin) ? opts.origin : [opts.origin]).map((value) => new URL(value).origin));
69
- const carrier = opts.carrier ?? globalThis;
70
- const prefixes = toPrefixList(basePath);
71
- const previousFetch = carrier.fetch;
72
- if (Object.getOwnPropertyDescriptor(previousFetch, BRIDGE_MARKER)) {
73
- throw (0, core_1.getError)({
74
- message: '[installBffFetch] A BFF fetch bridge is already installed | Uninstall it first, or pass every prefix to a single install',
75
- });
76
- }
77
- const networkFetch = previousFetch.bind(carrier);
78
- const bridged = async (input, init) => {
79
- const url = new URL(resolveRequestUrl(input));
80
- const { pathname } = url;
81
- const isOwnOrigin = origins === undefined || origins.has(url.origin);
82
- const isOwnPath = prefixes.some((prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`));
83
- if (!isOwnOrigin || !isOwnPath) {
84
- return networkFetch(input, init);
85
- }
86
- // Constructed only now, on the branch that owns the request - so the pass-through above never
87
- // disturbs a body it is about to hand to the network.
88
- return transport.fetch({ request: new Request(input, init) });
89
- };
90
- // Whatever the runtime hung on `fetch` comes along - Bun puts `preconnect` there, and a
91
- // replacement that dropped it would break any caller reaching for it. Copying the descriptors is
92
- // also what makes this satisfy `typeof fetch` rather than merely resembling it.
93
- Object.defineProperties(bridged, Object.getOwnPropertyDescriptors(previousFetch));
94
- Object.defineProperty(bridged, BRIDGE_MARKER, { value: true });
95
- carrier.fetch = bridged;
96
- return () => {
97
- if (carrier.fetch !== bridged) {
98
- return;
99
- }
100
- carrier.fetch = previousFetch;
101
- };
102
- };
103
- exports.installBffFetch = installBffFetch;
104
- //# sourceMappingURL=fetch-bridge.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fetch-bridge.js","sourceRoot":"","sources":["../../../src/transport/fetch-bridge.ts"],"names":[],"mappings":"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","sourcesContent":["import { getError } from '@venizia/ignis-helpers/core';\nimport type { IBffTransport } from './common/types';\n\n/**\n * Marks the patched `fetch` so a second install is refused rather than silently stacking. `Symbol.for`\n * and not a private symbol: two copies of this package in one page must still see each other's mark.\n */\nconst BRIDGE_MARKER = Symbol.for('@venizia/ignis-worker/bff-fetch');\n\ntype TFetch = typeof globalThis.fetch;\n\n/** The carrier whose `fetch` is replaced - `globalThis` in a page, an object a test controls otherwise. */\ninterface IFetchCarrier {\n fetch: TFetch;\n}\n\nexport interface IInstallBffFetchOptions {\n /** Anything implementing the transport contract, so an in-process transport works in a test. */\n transport: IBffTransport;\n /**\n * Path prefixes the BFF owns, matched on a segment boundary: `/api` claims `/api` and `/api/...`,\n * never `/apix`. Everything else is passed to the original `fetch` untouched.\n */\n basePath: string | Array<string>;\n /**\n * The origin, or origins, the BFF answers for - the page's own, or an upstream gateway whose\n * calls the BFF stands in for. A request to any other origin goes to the network whatever its path.\n * Unset, only the path decides, so a call to ANY origin under `basePath` is claimed.\n */\n origin?: string | Array<string>;\n /** Defaults to `globalThis`. */\n carrier?: IFetchCarrier;\n}\n\n/**\n * Resolves a request's absolute URL WITHOUT constructing a `Request`.\n *\n * This is the whole reason this helper exists rather than one obvious line. `new Request(input)`,\n * where `input` is a `Request` carrying a body, marks that body disturbed - so building one just to\n * read `.url` breaks the very pass-through it is deciding about: the next line hands the same, now\n * unreadable, request to the network.\n *\n * Measured, because the runtimes disagree. Chromium:\n *\n * original.bodyUsed // false\n * new Request(original)\n * original.bodyUsed // true\n * await original.text() // TypeError: body stream already read\n *\n * Bun does NOT disturb it, so the unit tests pass either way and cannot guard this. The browser is\n * where this code runs, so the browser is the behaviour to write for.\n */\nconst resolveRequestUrl = (input: RequestInfo | URL): string => {\n if (typeof input === 'string') {\n return new URL(input, globalThis.location?.href).href;\n }\n\n if (input instanceof URL) {\n return input.href;\n }\n\n return input.url;\n};\n\nconst toPrefixList = (basePath: string | Array<string>): Array<string> => {\n // Trailing slashes trimmed once, so the boundary test below is one comparison and one prefix check.\n const prefixes = (Array.isArray(basePath) ? basePath : [basePath])\n .map((prefix) => prefix.replace(/\\/+$/, ''))\n .filter((prefix) => prefix.length > 0);\n\n if (prefixes.length === 0) {\n throw getError({\n message:\n '[installBffFetch] Invalid basePath | At least one non-empty path prefix is required',\n });\n }\n\n return prefixes;\n};\n\n/**\n * Routes the page's own `fetch` into a BFF transport for anything under `basePath`, and leaves every\n * other call on the network untouched.\n *\n * This is the seam that lets an existing HTTP client talk to an in-browser IGNIS application without\n * knowing one exists. A data provider, an SDK or a generated client reaches the network through the\n * global `fetch` and usually accepts no custom fetcher, so answering that `fetch` is the only place\n * an in-browser backend becomes a drop-in swap rather than a fork of the client.\n *\n * Install it BEFORE the application that will use it boots: a request issued while the original\n * `fetch` is still in place leaves the page and 404s against whatever is serving it.\n *\n * @returns The uninstall function. It restores the previous `fetch` only if this bridge is still the\n * installed one - if something patched `fetch` afterwards, restoring would silently discard that.\n */\nexport const installBffFetch = (opts: IInstallBffFetchOptions): (() => void) => {\n const { transport, basePath } = opts;\n const origins =\n opts.origin === undefined\n ? undefined\n : new Set(\n (Array.isArray(opts.origin) ? opts.origin : [opts.origin]).map(\n (value) => new URL(value).origin,\n ),\n );\n const carrier = opts.carrier ?? (globalThis as unknown as IFetchCarrier);\n\n const prefixes = toPrefixList(basePath);\n const previousFetch = carrier.fetch;\n\n if (Object.getOwnPropertyDescriptor(previousFetch, BRIDGE_MARKER)) {\n throw getError({\n message:\n '[installBffFetch] A BFF fetch bridge is already installed | Uninstall it first, or pass every prefix to a single install',\n });\n }\n\n const networkFetch = previousFetch.bind(carrier) as TFetch;\n\n const bridged = async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {\n const url = new URL(resolveRequestUrl(input));\n const { pathname } = url;\n const isOwnOrigin = origins === undefined || origins.has(url.origin);\n const isOwnPath = prefixes.some(\n (prefix) => pathname === prefix || pathname.startsWith(`${prefix}/`),\n );\n\n if (!isOwnOrigin || !isOwnPath) {\n return networkFetch(input, init);\n }\n\n // Constructed only now, on the branch that owns the request - so the pass-through above never\n // disturbs a body it is about to hand to the network.\n return transport.fetch({ request: new Request(input, init) });\n };\n\n // Whatever the runtime hung on `fetch` comes along - Bun puts `preconnect` there, and a\n // replacement that dropped it would break any caller reaching for it. Copying the descriptors is\n // also what makes this satisfy `typeof fetch` rather than merely resembling it.\n Object.defineProperties(bridged, Object.getOwnPropertyDescriptors(previousFetch));\n Object.defineProperty(bridged, BRIDGE_MARKER, { value: true });\n\n carrier.fetch = bridged as TFetch;\n\n return () => {\n if (carrier.fetch !== bridged) {\n return;\n }\n\n carrier.fetch = previousFetch;\n };\n};\n"]}
@@ -1,23 +0,0 @@
1
- import { BaseHelper } from '@venizia/ignis-helpers/core';
2
- import type { IBffTransport } from './common/types';
3
- /**
4
- * No worker, no browser - the seam that makes a BFF testable in-process. It still runs the full
5
- * envelope round trip, and that is the whole point: a bare pass-through lets a route pass here and
6
- * hang over a real Worker, because only the envelope applies the synthetic origin, buffers a
7
- * streaming body, and reduces a thrown error to `{ text, code, args }`. A test is worth what its
8
- * differences from production are worth.
9
- *
10
- * What it deliberately does NOT mirror is the timeout: in-process there is no message that can be
11
- * lost, so a handler either settles or the caller's own test timeout fires.
12
- */
13
- export declare class InProcessBffTransport extends BaseHelper implements IBffTransport {
14
- private readonly handler;
15
- private readonly requestIdGenerator;
16
- constructor(opts: {
17
- handler: (request: Request) => Promise<Response>;
18
- });
19
- fetch(opts: {
20
- request: Request;
21
- }): Promise<Response>;
22
- }
23
- //# sourceMappingURL=in-process.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"in-process.d.ts","sourceRoot":"","sources":["../../../src/transport/in-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAsB,MAAM,6BAA6B,CAAC;AAG7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAEpD;;;;;;;;;GASG;AACH,qBAAa,qBAAsB,SAAQ,UAAW,YAAW,aAAa;IAC5E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0C;IAClE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAEhC;gBAES,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;KAAE;IAMhE,KAAK,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC;CAyB3D"}
@@ -1,47 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InProcessBffTransport = void 0;
4
- const core_1 = require("@venizia/ignis-helpers/core");
5
- const encode_1 = require("../envelope/encode");
6
- /**
7
- * No worker, no browser - the seam that makes a BFF testable in-process. It still runs the full
8
- * envelope round trip, and that is the whole point: a bare pass-through lets a route pass here and
9
- * hang over a real Worker, because only the envelope applies the synthetic origin, buffers a
10
- * streaming body, and reduces a thrown error to `{ text, code, args }`. A test is worth what its
11
- * differences from production are worth.
12
- *
13
- * What it deliberately does NOT mirror is the timeout: in-process there is no message that can be
14
- * lost, so a handler either settles or the caller's own test timeout fires.
15
- */
16
- class InProcessBffTransport extends core_1.BaseHelper {
17
- constructor(opts) {
18
- super({ scope: InProcessBffTransport.name });
19
- this.requestIdGenerator = new core_1.RequestIdGenerator({
20
- scope: InProcessBffTransport.name,
21
- });
22
- this.handler = opts.handler;
23
- }
24
- async fetch(opts) {
25
- const id = this.requestIdGenerator.nextId();
26
- const requestEnvelope = await encode_1.BffEnvelope.encodeRequest({
27
- request: opts.request,
28
- id,
29
- url: encode_1.BffEnvelope.toSyntheticUrl({ url: opts.request.url }),
30
- });
31
- let responseEnvelope;
32
- try {
33
- const response = await this.handler(encode_1.BffEnvelope.decodeRequest({ envelope: requestEnvelope }));
34
- responseEnvelope = await encode_1.BffEnvelope.encodeResponse({ response, id });
35
- }
36
- catch (error) {
37
- this.logger.for(this.fetch.name).error('Handler failed | id: %s | error: %s', id, error);
38
- // Encoded and decoded rather than rethrown: what a UI receives over a real Worker is a
39
- // rebuilt `ApplicationError` carrying only the normalised shape - never the original object,
40
- // its stack or its `extra`.
41
- throw encode_1.BffEnvelope.decodeError({ envelope: encode_1.BffEnvelope.encodeError({ id, error }) });
42
- }
43
- return encode_1.BffEnvelope.decodeResponse({ envelope: responseEnvelope });
44
- }
45
- }
46
- exports.InProcessBffTransport = InProcessBffTransport;
47
- //# sourceMappingURL=in-process.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"in-process.js","sourceRoot":"","sources":["../../../src/transport/in-process.ts"],"names":[],"mappings":";;;AAAA,sDAA6E;AAC7E,8CAAgD;AAIhD;;;;;;;;;GASG;AACH,MAAa,qBAAsB,SAAQ,iBAAU;IAMnD,YAAY,IAA0D;QACpE,KAAK,CAAC,EAAE,KAAK,EAAE,qBAAqB,CAAC,IAAI,EAAE,CAAC,CAAC;QAL9B,uBAAkB,GAAG,IAAI,yBAAkB,CAAC;YAC3D,KAAK,EAAE,qBAAqB,CAAC,IAAI;SAClC,CAAC,CAAC;QAKD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,IAA0B;QACpC,MAAM,EAAE,GAAG,IAAI,CAAC,kBAAkB,CAAC,MAAM,EAAE,CAAC;QAE5C,MAAM,eAAe,GAAG,MAAM,oBAAW,CAAC,aAAa,CAAC;YACtD,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,EAAE;YACF,GAAG,EAAE,oBAAW,CAAC,cAAc,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;SAC3D,CAAC,CAAC;QAEH,IAAI,gBAAsC,CAAC;QAE3C,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,oBAAW,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC,CAAC;YAC9F,gBAAgB,GAAG,MAAM,oBAAW,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACxE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,qCAAqC,EAAE,EAAE,EAAE,KAAK,CAAC,CAAC;YAEzF,uFAAuF;YACvF,6FAA6F;YAC7F,4BAA4B;YAC5B,MAAM,oBAAW,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,oBAAW,CAAC,WAAW,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;QACtF,CAAC;QAED,OAAO,oBAAW,CAAC,cAAc,CAAC,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,CAAC;IACpE,CAAC;CACF;AArCD,sDAqCC","sourcesContent":["import { BaseHelper, RequestIdGenerator } from '@venizia/ignis-helpers/core';\nimport { BffEnvelope } from '@/envelope/encode';\nimport type { IBffResponseEnvelope } from '@/envelope/common';\nimport type { IBffTransport } from './common/types';\n\n/**\n * No worker, no browser - the seam that makes a BFF testable in-process. It still runs the full\n * envelope round trip, and that is the whole point: a bare pass-through lets a route pass here and\n * hang over a real Worker, because only the envelope applies the synthetic origin, buffers a\n * streaming body, and reduces a thrown error to `{ text, code, args }`. A test is worth what its\n * differences from production are worth.\n *\n * What it deliberately does NOT mirror is the timeout: in-process there is no message that can be\n * lost, so a handler either settles or the caller's own test timeout fires.\n */\nexport class InProcessBffTransport extends BaseHelper implements IBffTransport {\n private readonly handler: (request: Request) => Promise<Response>;\n private readonly requestIdGenerator = new RequestIdGenerator({\n scope: InProcessBffTransport.name,\n });\n\n constructor(opts: { handler: (request: Request) => Promise<Response> }) {\n super({ scope: InProcessBffTransport.name });\n\n this.handler = opts.handler;\n }\n\n async fetch(opts: { request: Request }): Promise<Response> {\n const id = this.requestIdGenerator.nextId();\n\n const requestEnvelope = await BffEnvelope.encodeRequest({\n request: opts.request,\n id,\n url: BffEnvelope.toSyntheticUrl({ url: opts.request.url }),\n });\n\n let responseEnvelope: IBffResponseEnvelope;\n\n try {\n const response = await this.handler(BffEnvelope.decodeRequest({ envelope: requestEnvelope }));\n responseEnvelope = await BffEnvelope.encodeResponse({ response, id });\n } catch (error) {\n this.logger.for(this.fetch.name).error('Handler failed | id: %s | error: %s', id, error);\n\n // Encoded and decoded rather than rethrown: what a UI receives over a real Worker is a\n // rebuilt `ApplicationError` carrying only the normalised shape - never the original object,\n // its stack or its `extra`.\n throw BffEnvelope.decodeError({ envelope: BffEnvelope.encodeError({ id, error }) });\n }\n\n return BffEnvelope.decodeResponse({ envelope: responseEnvelope });\n }\n}\n"]}
@@ -1,6 +0,0 @@
1
- export * from './common';
2
- export * from './fetch-bridge';
3
- export * from './in-process';
4
- export * from './shared';
5
- export * from './worker';
6
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/transport/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
@@ -1,22 +0,0 @@
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("./common"), exports);
18
- __exportStar(require("./fetch-bridge"), exports);
19
- __exportStar(require("./in-process"), exports);
20
- __exportStar(require("./shared"), exports);
21
- __exportStar(require("./worker"), exports);
22
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transport/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,2CAAyB;AACzB,iDAA+B;AAC/B,+CAA6B;AAC7B,2CAAyB;AACzB,2CAAyB","sourcesContent":["export * from './common';\nexport * from './fetch-bridge';\nexport * from './in-process';\nexport * from './shared';\nexport * from './worker';\n"]}