@webiny/app 6.4.11 → 6.6.0-alpha.1
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/config/RouterConfig.d.ts +1 -3
- package/core/Plugins.d.ts +2 -1
- package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/ErrorOverlay.js +9 -15
- package/errors/overlay/ErrorOverlay.js.map +1 -0
- package/errors/overlay/GqlErrorOverlay.js.map +1 -0
- package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/LocalAwsLambdaTimeoutMessage.js +3 -6
- package/errors/overlay/LocalAwsLambdaTimeoutMessage.js.map +1 -0
- package/errors/overlay/StyledComponents.d.ts +7 -0
- package/errors/overlay/StyledComponents.js +10 -0
- package/errors/overlay/StyledComponents.js.map +1 -0
- package/errors/overlay/Typography.js.map +1 -0
- package/errors/overlay/assets/close_24px.js.map +1 -0
- package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/createErrorOverlay.js +2 -2
- package/errors/overlay/createErrorOverlay.js.map +1 -0
- package/exports/admin.d.ts +1 -0
- package/exports/admin.js +1 -0
- package/features/apiStreamClient/FetchApiStreamClient.d.ts +9 -0
- package/features/apiStreamClient/FetchApiStreamClient.js +63 -0
- package/features/apiStreamClient/FetchApiStreamClient.js.map +1 -0
- package/features/apiStreamClient/__tests__/FetchApiStreamClient.test.d.ts +1 -0
- package/features/apiStreamClient/__tests__/FetchApiStreamClient.test.js +170 -0
- package/features/apiStreamClient/__tests__/FetchApiStreamClient.test.js.map +1 -0
- package/features/apiStreamClient/__tests__/readServerSentEvents.test.d.ts +1 -0
- package/features/apiStreamClient/__tests__/readServerSentEvents.test.js +160 -0
- package/features/apiStreamClient/__tests__/readServerSentEvents.test.js.map +1 -0
- package/features/apiStreamClient/abstractions.d.ts +44 -0
- package/features/apiStreamClient/abstractions.js +10 -0
- package/features/apiStreamClient/abstractions.js.map +1 -0
- package/features/apiStreamClient/feature.d.ts +3 -0
- package/features/apiStreamClient/feature.js +17 -0
- package/features/apiStreamClient/feature.js.map +1 -0
- package/features/apiStreamClient/index.d.ts +5 -0
- package/features/apiStreamClient/index.js +5 -0
- package/features/apiStreamClient/readServerSentEvents.d.ts +10 -0
- package/features/apiStreamClient/readServerSentEvents.js +29 -0
- package/features/apiStreamClient/readServerSentEvents.js.map +1 -0
- package/features/apiStreamClient/toPayloadHash.d.ts +14 -0
- package/features/apiStreamClient/toPayloadHash.js +7 -0
- package/features/apiStreamClient/toPayloadHash.js.map +1 -0
- package/features/router/HistoryRouterGateway.d.ts +3 -0
- package/features/router/HistoryRouterGateway.js +12 -0
- package/features/router/HistoryRouterGateway.js.map +1 -1
- package/features/router/Route.d.ts +1 -1
- package/features/router/RouterPresenter.d.ts +2 -0
- package/features/router/RouterPresenter.js +10 -0
- package/features/router/RouterPresenter.js.map +1 -1
- package/features/router/RouterRepository.d.ts +2 -0
- package/features/router/RouterRepository.js +8 -2
- package/features/router/RouterRepository.js.map +1 -1
- package/features/router/abstractions.d.ts +9 -0
- package/features/router/abstractions.js.map +1 -1
- package/index.d.ts +0 -3
- package/index.js +0 -3
- package/package.json +13 -26
- package/plugins/image.d.ts +1 -1
- package/presentation/router/components/RouteParamsSync.d.ts +22 -0
- package/presentation/router/components/RouteParamsSync.js +53 -0
- package/presentation/router/components/RouteParamsSync.js.map +1 -0
- package/presentation/router/hooks/useRoute.d.ts +1 -0
- package/presentation/router/hooks/useRoute.js +2 -1
- package/presentation/router/hooks/useRoute.js.map +1 -1
- package/presentation/router/hooks/useRouter.d.ts +1 -0
- package/presentation/router/hooks/useRouter.js +1 -0
- package/presentation/router/hooks/useRouter.js.map +1 -1
- package/presentation/router/index.d.ts +2 -0
- package/presentation/router/index.js +1 -0
- package/types.d.ts +0 -21
- package/apollo-client/InMemoryCache.d.ts +0 -8
- package/apollo-client/InMemoryCache.js +0 -18
- package/apollo-client/InMemoryCache.js.map +0 -1
- package/apollo-client/IntrospectionFragmentMatcher.d.ts +0 -11
- package/apollo-client/IntrospectionFragmentMatcher.js +0 -33
- package/apollo-client/IntrospectionFragmentMatcher.js.map +0 -1
- package/hooks/useAutocomplete/index.d.ts +0 -1
- package/hooks/useAutocomplete/index.js +0 -1
- package/hooks/useAutocomplete/useAutocomplete.d.ts +0 -11
- package/hooks/useAutocomplete/useAutocomplete.js +0 -17
- package/hooks/useAutocomplete/useAutocomplete.js.map +0 -1
- package/hooks/useDataList/functions/getData.d.ts +0 -2
- package/hooks/useDataList/functions/getData.js +0 -5
- package/hooks/useDataList/functions/getData.js.map +0 -1
- package/hooks/useDataList/functions/getError.d.ts +0 -2
- package/hooks/useDataList/functions/getError.js +0 -5
- package/hooks/useDataList/functions/getError.js.map +0 -1
- package/hooks/useDataList/functions/getMeta.d.ts +0 -2
- package/hooks/useDataList/functions/getMeta.js +0 -5
- package/hooks/useDataList/functions/getMeta.js.map +0 -1
- package/hooks/useDataList/functions/index.d.ts +0 -3
- package/hooks/useDataList/functions/index.js +0 -3
- package/hooks/useDataList/functions/searchDataByKey.d.ts +0 -2
- package/hooks/useDataList/functions/searchDataByKey.js +0 -13
- package/hooks/useDataList/functions/searchDataByKey.js.map +0 -1
- package/hooks/useDataList/index.d.ts +0 -1
- package/hooks/useDataList/index.js +0 -1
- package/hooks/useDataList/useDataList.d.ts +0 -35
- package/hooks/useDataList/useDataList.js +0 -142
- package/hooks/useDataList/useDataList.js.map +0 -1
- package/hooks/useDataList/utils/index.d.ts +0 -1
- package/hooks/useDataList/utils/index.js +0 -1
- package/hooks/useDataList/utils/prepareLoadListParams.d.ts +0 -10
- package/hooks/useDataList/utils/prepareLoadListParams.js +0 -29
- package/hooks/useDataList/utils/prepareLoadListParams.js.map +0 -1
- package/plugins/AddQuerySelectionPlugin.d.ts +0 -22
- package/plugins/AddQuerySelectionPlugin.js +0 -47
- package/plugins/AddQuerySelectionPlugin.js.map +0 -1
- package/plugins/ApolloCacheObjectIdPlugin.d.ts +0 -15
- package/plugins/ApolloCacheObjectIdPlugin.js +0 -17
- package/plugins/ApolloCacheObjectIdPlugin.js.map +0 -1
- package/plugins/ApolloDynamicLink.d.ts +0 -7
- package/plugins/ApolloDynamicLink.js +0 -29
- package/plugins/ApolloDynamicLink.js.map +0 -1
- package/plugins/ApolloLinkPlugin.d.ts +0 -13
- package/plugins/ApolloLinkPlugin.js +0 -23
- package/plugins/ApolloLinkPlugin.js.map +0 -1
- package/plugins/ConsoleLinkPlugin.d.ts +0 -8
- package/plugins/ConsoleLinkPlugin.js +0 -24
- package/plugins/ConsoleLinkPlugin.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin/ErrorOverlay.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin/GqlErrorOverlay.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin/LocalAwsLambdaTimeoutMessage.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin/StyledComponents.d.ts +0 -8
- package/plugins/NetworkErrorLinkPlugin/StyledComponents.js +0 -69
- package/plugins/NetworkErrorLinkPlugin/StyledComponents.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin/Typography.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin/assets/close_24px.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin/createErrorOverlay.js.map +0 -1
- package/plugins/NetworkErrorLinkPlugin.d.ts +0 -10
- package/plugins/NetworkErrorLinkPlugin.js +0 -53
- package/plugins/NetworkErrorLinkPlugin.js.map +0 -1
- package/plugins/OmitTypenameLinkPlugin.d.ts +0 -8
- package/plugins/OmitTypenameLinkPlugin.js +0 -16
- package/plugins/OmitTypenameLinkPlugin.js.map +0 -1
- package/plugins/TenantHeaderLinkPlugin.d.ts +0 -10
- package/plugins/TenantHeaderLinkPlugin.js +0 -28
- package/plugins/TenantHeaderLinkPlugin.js.map +0 -1
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/ErrorOverlay.d.ts +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/GqlErrorOverlay.d.ts +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/GqlErrorOverlay.js +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/LocalAwsLambdaTimeoutMessage.d.ts +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/Typography.d.ts +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/Typography.js +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/assets/close_24px.js +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/assets/close_24px.svg +0 -0
- /package/{plugins/NetworkErrorLinkPlugin → errors/overlay}/createErrorOverlay.d.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/apiStreamClient/__tests__/readServerSentEvents.test.js","sources":["../../../../src/features/apiStreamClient/__tests__/readServerSentEvents.test.ts"],"sourcesContent":["import { describe, it, expect } from \"vitest\";\nimport { readServerSentEvents } from \"../readServerSentEvents.js\";\n\nconst encoder = new TextEncoder();\n\nfunction responseFrom(chunks: (string | Uint8Array)[]): Response {\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n for (const chunk of chunks) {\n controller.enqueue(typeof chunk === \"string\" ? encoder.encode(chunk) : chunk);\n }\n controller.close();\n }\n });\n\n return { body: stream } as Response;\n}\n\nasync function collect<T>(response: Response): Promise<T[]> {\n const events: T[] = [];\n for await (const event of readServerSentEvents<T>(response)) {\n events.push(event);\n }\n return events;\n}\n\ndescribe(\"readServerSentEvents\", () => {\n it(\"should parse one event per record\", async () => {\n const events = await collect(\n responseFrom(['data: {\"type\":\"start\"}\\n\\n', 'data: {\"type\":\"done\"}\\n\\n'])\n );\n\n expect(events).toEqual([{ type: \"start\" }, { type: \"done\" }]);\n });\n\n it(\"should parse multiple records arriving in a single chunk\", async () => {\n const events = await collect(\n responseFrom(['data: {\"n\":1}\\n\\ndata: {\"n\":2}\\n\\ndata: {\"n\":3}\\n\\n'])\n );\n\n expect(events).toEqual([{ n: 1 }, { n: 2 }, { n: 3 }]);\n });\n\n it(\"should parse a record split across chunks\", async () => {\n const events = await collect(responseFrom(['data: {\"ty', 'pe\":\"partial\"}', \"\\n\\n\"]));\n\n expect(events).toEqual([{ type: \"partial\" }]);\n });\n\n it(\"should handle CRLF line endings\", async () => {\n const events = await collect(responseFrom(['data: {\"ok\":true}\\r\\n\\r\\n']));\n\n expect(events).toEqual([{ ok: true }]);\n });\n\n it(\"should ignore comments and non-data fields\", async () => {\n const events = await collect(\n responseFrom([\n \": heartbeat\\n\\n\",\n 'event: message\\nid: 7\\nretry: 500\\ndata: {\"kept\":true}\\n\\n'\n ])\n );\n\n expect(events).toEqual([{ kept: true }]);\n });\n\n it(\"should join multi-line data fields\", async () => {\n const events = await collect(responseFrom(['data: {\"a\":1,\\ndata: \"b\":2}\\n\\n']));\n\n expect(events).toEqual([{ a: 1, b: 2 }]);\n });\n\n it(\"should preserve multi-byte characters split across chunks\", async () => {\n const payload = encoder.encode('data: {\"text\":\"café\"}\\n\\n');\n const split = 18;\n\n const events = await collect(responseFrom([payload.slice(0, split), payload.slice(split)]));\n\n expect(events).toEqual([{ text: \"café\" }]);\n });\n\n it(\"should drop a trailing record that never terminated\", async () => {\n // A truncated stream (server died mid-record) must not yield a half-parsed event.\n const events = await collect(responseFrom(['data: {\"complete\":true}\\n\\ndata: {\"trunc']));\n\n expect(events).toEqual([{ complete: true }]);\n });\n\n it(\"should yield events as they arrive rather than after the stream closes\", async () => {\n let released!: () => void;\n const gate = new Promise<void>(resolve => {\n released = resolve;\n });\n\n const stream = new ReadableStream<Uint8Array>({\n async start(controller) {\n controller.enqueue(encoder.encode('data: {\"n\":1}\\n\\n'));\n await gate;\n controller.enqueue(encoder.encode('data: {\"n\":2}\\n\\n'));\n controller.close();\n }\n });\n\n const iterator = readServerSentEvents<{ n: number }>({ body: stream } as Response);\n\n // Resolving before the gate opens proves events aren't buffered until close.\n expect((await iterator.next()).value).toEqual({ n: 1 });\n released();\n expect((await iterator.next()).value).toEqual({ n: 2 });\n expect((await iterator.next()).done).toBe(true);\n });\n\n it(\"should throw when the response has no body\", async () => {\n await expect(collect({ body: null } as Response)).rejects.toThrow(\n \"The response carried no readable body.\"\n );\n });\n\n it(\"should propagate a stream error\", async () => {\n const stream = new ReadableStream<Uint8Array>({\n start(controller) {\n controller.error(new Error(\"stream broke\"));\n }\n });\n\n await expect(collect({ body: stream } as Response)).rejects.toThrow(\"stream broke\");\n });\n});\n"],"names":["encoder","TextEncoder","responseFrom","chunks","stream","ReadableStream","controller","chunk","collect","response","events","event","readServerSentEvents","describe","it","expect","payload","split","released","gate","Promise","resolve","iterator","Error"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
type IHeaders = Record<string, string | number | undefined>;
|
|
2
|
+
/**
|
|
3
|
+
* The raw `fetch` response, handed to the caller unread so it owns the read loop. Aliased through
|
|
4
|
+
* the abstraction so consumers name the contract rather than the DOM type it currently happens to
|
|
5
|
+
* be — and so `ApiStreamClient.Response` reads as the counterpart to `ApiStreamClient.Request`.
|
|
6
|
+
*/
|
|
7
|
+
type IApiStreamResponse = globalThis.Response;
|
|
8
|
+
export interface IApiStreamRequest {
|
|
9
|
+
/** Path relative to the API root, e.g. `/stream/fm/files/abc/enrich`. */
|
|
10
|
+
path: string;
|
|
11
|
+
/** Serialized as JSON when present. */
|
|
12
|
+
body?: unknown;
|
|
13
|
+
headers?: IHeaders;
|
|
14
|
+
/**
|
|
15
|
+
* Aborts the request AND the caller's read loop. Streaming responses stay open for as long as the
|
|
16
|
+
* producer runs, so without this a caller that navigates away or closes its UI would leave the
|
|
17
|
+
* connection open and keep consuming events into a component that no longer exists.
|
|
18
|
+
*/
|
|
19
|
+
signal?: AbortSignal;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Client for API endpoints that stream their response.
|
|
23
|
+
*
|
|
24
|
+
* Deliberately separate from `GraphQLClient`: that abstraction returns `Promise<TResult>` — a
|
|
25
|
+
* buffered contract by type — and Webiny's GraphQL layer (graphql-js 16) has no incremental
|
|
26
|
+
* delivery, so a streaming response can't travel through it. This returns the raw `Response` so the
|
|
27
|
+
* caller owns the read loop and can hand `response.body` to any stream consumer.
|
|
28
|
+
*/
|
|
29
|
+
export interface IApiStreamClient {
|
|
30
|
+
execute(params: IApiStreamRequest): Promise<IApiStreamResponse>;
|
|
31
|
+
}
|
|
32
|
+
export declare const ApiStreamClient: import("@webiny/di").Abstraction<IApiStreamClient>;
|
|
33
|
+
export declare namespace ApiStreamClient {
|
|
34
|
+
type Headers = IHeaders;
|
|
35
|
+
type Interface = IApiStreamClient;
|
|
36
|
+
type Request = IApiStreamRequest;
|
|
37
|
+
type Response = IApiStreamResponse;
|
|
38
|
+
}
|
|
39
|
+
export declare class ApiStreamRequestError extends Error {
|
|
40
|
+
readonly statusCode: number;
|
|
41
|
+
readonly code?: string | undefined;
|
|
42
|
+
constructor(message: string, statusCode: number, code?: string | undefined);
|
|
43
|
+
}
|
|
44
|
+
export {};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { createAbstraction } from "@webiny/feature/admin";
|
|
2
|
+
const ApiStreamClient = createAbstraction("ApiStreamClient");
|
|
3
|
+
class ApiStreamRequestError extends Error {
|
|
4
|
+
constructor(message, statusCode, code){
|
|
5
|
+
super(message), this.statusCode = statusCode, this.code = code;
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
export { ApiStreamClient, ApiStreamRequestError };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=abstractions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/apiStreamClient/abstractions.js","sources":["../../../src/features/apiStreamClient/abstractions.ts"],"sourcesContent":["import { createAbstraction } from \"@webiny/feature/admin\";\n\ntype IHeaders = Record<string, string | number | undefined>;\n\n/**\n * The raw `fetch` response, handed to the caller unread so it owns the read loop. Aliased through\n * the abstraction so consumers name the contract rather than the DOM type it currently happens to\n * be — and so `ApiStreamClient.Response` reads as the counterpart to `ApiStreamClient.Request`.\n */\ntype IApiStreamResponse = globalThis.Response;\n\nexport interface IApiStreamRequest {\n /** Path relative to the API root, e.g. `/stream/fm/files/abc/enrich`. */\n path: string;\n /** Serialized as JSON when present. */\n body?: unknown;\n headers?: IHeaders;\n /**\n * Aborts the request AND the caller's read loop. Streaming responses stay open for as long as the\n * producer runs, so without this a caller that navigates away or closes its UI would leave the\n * connection open and keep consuming events into a component that no longer exists.\n */\n signal?: AbortSignal;\n}\n\n/**\n * Client for API endpoints that stream their response.\n *\n * Deliberately separate from `GraphQLClient`: that abstraction returns `Promise<TResult>` — a\n * buffered contract by type — and Webiny's GraphQL layer (graphql-js 16) has no incremental\n * delivery, so a streaming response can't travel through it. This returns the raw `Response` so the\n * caller owns the read loop and can hand `response.body` to any stream consumer.\n */\nexport interface IApiStreamClient {\n execute(params: IApiStreamRequest): Promise<IApiStreamResponse>;\n}\n\nexport const ApiStreamClient = createAbstraction<IApiStreamClient>(\"ApiStreamClient\");\n\nexport namespace ApiStreamClient {\n export type Headers = IHeaders;\n export type Interface = IApiStreamClient;\n export type Request = IApiStreamRequest;\n export type Response = IApiStreamResponse;\n}\n\nexport class ApiStreamRequestError extends Error {\n constructor(\n message: string,\n readonly statusCode: number,\n readonly code?: string\n ) {\n super(message);\n }\n}\n"],"names":["ApiStreamClient","createAbstraction","ApiStreamRequestError","Error","message","statusCode","code"],"mappings":";AAqCO,MAAMA,kBAAkBC,kBAAoC;AAS5D,MAAMC,8BAA8BC;IACvC,YACIC,OAAe,EACNC,UAAkB,EAClBC,IAAa,CACxB;QACE,KAAK,CAACF,UAAAA,IAAAA,CAHGC,UAAU,GAAVA,YAAAA,IAAAA,CACAC,IAAI,GAAJA;IAGb;AACJ"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { ApiStreamClient } from "./abstractions.js";
|
|
2
|
+
import { FetchApiStreamClient } from "./FetchApiStreamClient.js";
|
|
3
|
+
import { createFeature } from "../../shared/di/createFeature.js";
|
|
4
|
+
const ApiStreamClientFeature = createFeature({
|
|
5
|
+
name: "ApiStreamClient",
|
|
6
|
+
register (container) {
|
|
7
|
+
container.register(FetchApiStreamClient).inSingletonScope();
|
|
8
|
+
},
|
|
9
|
+
resolve (container) {
|
|
10
|
+
return {
|
|
11
|
+
client: container.resolve(ApiStreamClient)
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
export { ApiStreamClientFeature };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/apiStreamClient/feature.js","sources":["../../../src/features/apiStreamClient/feature.ts"],"sourcesContent":["import { ApiStreamClient } from \"./abstractions.js\";\nimport { FetchApiStreamClient } from \"./FetchApiStreamClient.js\";\nimport { createFeature } from \"~/shared/di/createFeature.js\";\n\nexport const ApiStreamClientFeature = createFeature({\n name: \"ApiStreamClient\",\n register(container) {\n container.register(FetchApiStreamClient).inSingletonScope();\n },\n resolve(container) {\n return {\n client: container.resolve(ApiStreamClient)\n };\n }\n});\n"],"names":["ApiStreamClientFeature","createFeature","container","FetchApiStreamClient","ApiStreamClient"],"mappings":";;;AAIO,MAAMA,yBAAyBC,cAAc;IAChD,MAAM;IACN,UAASC,SAAS;QACdA,UAAU,QAAQ,CAACC,sBAAsB,gBAAgB;IAC7D;IACA,SAAQD,SAAS;QACb,OAAO;YACH,QAAQA,UAAU,OAAO,CAACE;QAC9B;IACJ;AACJ"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read a `text/event-stream` response as a sequence of parsed JSON events.
|
|
3
|
+
*
|
|
4
|
+
* Written against `Response.body` rather than `EventSource` on purpose: `EventSource` can only issue
|
|
5
|
+
* GET requests and cannot set an `Authorization` header, both of which the API requires.
|
|
6
|
+
*
|
|
7
|
+
* Only the `data:` field is interpreted — enough for Webiny's streaming routes, which frame one JSON
|
|
8
|
+
* object per record. Comment lines (`:` heartbeats), `event:`, `id:` and `retry:` are ignored.
|
|
9
|
+
*/
|
|
10
|
+
export declare function readServerSentEvents<TEvent>(response: Response): AsyncGenerator<TEvent>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
async function* readServerSentEvents(response) {
|
|
2
|
+
const body = response.body;
|
|
3
|
+
if (!body) throw new Error("The response carried no readable body.");
|
|
4
|
+
const reader = body.getReader();
|
|
5
|
+
const decoder = new TextDecoder();
|
|
6
|
+
let buffer = "";
|
|
7
|
+
try {
|
|
8
|
+
while(true){
|
|
9
|
+
const { done, value } = await reader.read();
|
|
10
|
+
if (done) break;
|
|
11
|
+
buffer += decoder.decode(value, {
|
|
12
|
+
stream: true
|
|
13
|
+
}).replace(/\r\n/g, "\n");
|
|
14
|
+
let separator = buffer.indexOf("\n\n");
|
|
15
|
+
while(-1 !== separator){
|
|
16
|
+
const record = buffer.slice(0, separator);
|
|
17
|
+
buffer = buffer.slice(separator + 2);
|
|
18
|
+
const data = record.split("\n").filter((line)=>line.startsWith("data:")).map((line)=>line.slice(5).trim()).join("\n");
|
|
19
|
+
if (data) yield JSON.parse(data);
|
|
20
|
+
separator = buffer.indexOf("\n\n");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
} finally{
|
|
24
|
+
reader.releaseLock();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export { readServerSentEvents };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=readServerSentEvents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/apiStreamClient/readServerSentEvents.js","sources":["../../../src/features/apiStreamClient/readServerSentEvents.ts"],"sourcesContent":["/**\n * Read a `text/event-stream` response as a sequence of parsed JSON events.\n *\n * Written against `Response.body` rather than `EventSource` on purpose: `EventSource` can only issue\n * GET requests and cannot set an `Authorization` header, both of which the API requires.\n *\n * Only the `data:` field is interpreted — enough for Webiny's streaming routes, which frame one JSON\n * object per record. Comment lines (`:` heartbeats), `event:`, `id:` and `retry:` are ignored.\n */\nexport async function* readServerSentEvents<TEvent>(response: Response): AsyncGenerator<TEvent> {\n const body = response.body;\n if (!body) {\n throw new Error(\"The response carried no readable body.\");\n }\n\n const reader = body.getReader();\n const decoder = new TextDecoder();\n let buffer = \"\";\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\n if (done) {\n break;\n }\n\n // `stream: true` keeps a multi-byte character split across chunks intact.\n buffer += decoder.decode(value, { stream: true }).replace(/\\r\\n/g, \"\\n\");\n\n let separator = buffer.indexOf(\"\\n\\n\");\n while (separator !== -1) {\n const record = buffer.slice(0, separator);\n buffer = buffer.slice(separator + 2);\n\n const data = record\n .split(\"\\n\")\n .filter(line => line.startsWith(\"data:\"))\n .map(line => line.slice(\"data:\".length).trim())\n .join(\"\\n\");\n\n if (data) {\n yield JSON.parse(data) as TEvent;\n }\n\n separator = buffer.indexOf(\"\\n\\n\");\n }\n }\n } finally {\n reader.releaseLock();\n }\n}\n"],"names":["readServerSentEvents","response","body","Error","reader","decoder","TextDecoder","buffer","done","value","separator","record","data","line","JSON"],"mappings":"AASO,gBAAgBA,qBAA6BC,QAAkB;IAClE,MAAMC,OAAOD,SAAS,IAAI;IAC1B,IAAI,CAACC,MACD,MAAM,IAAIC,MAAM;IAGpB,MAAMC,SAASF,KAAK,SAAS;IAC7B,MAAMG,UAAU,IAAIC;IACpB,IAAIC,SAAS;IAEb,IAAI;QACA,MAAO,KAAM;YACT,MAAM,EAAEC,IAAI,EAAEC,KAAK,EAAE,GAAG,MAAML,OAAO,IAAI;YAEzC,IAAII,MACA;YAIJD,UAAUF,QAAQ,MAAM,CAACI,OAAO;gBAAE,QAAQ;YAAK,GAAG,OAAO,CAAC,SAAS;YAEnE,IAAIC,YAAYH,OAAO,OAAO,CAAC;YAC/B,MAAOG,AAAc,OAAdA,UAAkB;gBACrB,MAAMC,SAASJ,OAAO,KAAK,CAAC,GAAGG;gBAC/BH,SAASA,OAAO,KAAK,CAACG,YAAY;gBAElC,MAAME,OAAOD,OACR,KAAK,CAAC,MACN,MAAM,CAACE,CAAAA,OAAQA,KAAK,UAAU,CAAC,UAC/B,GAAG,CAACA,CAAAA,OAAQA,KAAK,KAAK,CAAC,GAAgB,IAAI,IAC3C,IAAI,CAAC;gBAEV,IAAID,MACA,MAAME,KAAK,KAAK,CAACF;gBAGrBF,YAAYH,OAAO,OAAO,CAAC;YAC/B;QACJ;IACJ,SAAU;QACNH,OAAO,WAAW;IACtB;AACJ"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hex SHA-256 of a request body, for the `x-amz-content-sha256` header.
|
|
3
|
+
*
|
|
4
|
+
* Required whenever a streaming route is reached through CloudFront with Origin Access Control. OAC
|
|
5
|
+
* signs the request with SigV4 but does NOT hash the body itself — it folds whatever this header says
|
|
6
|
+
* into the signature, and the Lambda Function URL's IAM authorizer then recomputes the hash from the
|
|
7
|
+
* body it received. Omit the header and the two disagree, so a POST WITH a body is rejected with
|
|
8
|
+
* `InvalidSignatureException` while a bodyless POST succeeds, because an empty payload hashes
|
|
9
|
+
* predictably.
|
|
10
|
+
*
|
|
11
|
+
* `crypto.subtle` needs a secure context, which the streaming behavior already requires
|
|
12
|
+
* (`viewerProtocolPolicy: "https-only"`).
|
|
13
|
+
*/
|
|
14
|
+
export declare function toPayloadHash(body: string): Promise<string>;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
async function toPayloadHash(body) {
|
|
2
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(body));
|
|
3
|
+
return Array.from(new Uint8Array(digest)).map((byte)=>byte.toString(16).padStart(2, "0")).join("");
|
|
4
|
+
}
|
|
5
|
+
export { toPayloadHash };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=toPayloadHash.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"features/apiStreamClient/toPayloadHash.js","sources":["../../../src/features/apiStreamClient/toPayloadHash.ts"],"sourcesContent":["/**\n * Hex SHA-256 of a request body, for the `x-amz-content-sha256` header.\n *\n * Required whenever a streaming route is reached through CloudFront with Origin Access Control. OAC\n * signs the request with SigV4 but does NOT hash the body itself — it folds whatever this header says\n * into the signature, and the Lambda Function URL's IAM authorizer then recomputes the hash from the\n * body it received. Omit the header and the two disagree, so a POST WITH a body is rejected with\n * `InvalidSignatureException` while a bodyless POST succeeds, because an empty payload hashes\n * predictably.\n *\n * `crypto.subtle` needs a secure context, which the streaming behavior already requires\n * (`viewerProtocolPolicy: \"https-only\"`).\n */\nexport async function toPayloadHash(body: string): Promise<string> {\n const digest = await crypto.subtle.digest(\"SHA-256\", new TextEncoder().encode(body));\n\n return Array.from(new Uint8Array(digest))\n .map(byte => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n"],"names":["toPayloadHash","body","digest","crypto","TextEncoder","Array","Uint8Array","byte"],"mappings":"AAaO,eAAeA,cAAcC,IAAY;IAC5C,MAAMC,SAAS,MAAMC,OAAO,MAAM,CAAC,MAAM,CAAC,WAAW,IAAIC,cAAc,MAAM,CAACH;IAE9E,OAAOI,MAAM,IAAI,CAAC,IAAIC,WAAWJ,SAC5B,GAAG,CAACK,CAAAA,OAAQA,KAAK,QAAQ,CAAC,IAAI,QAAQ,CAAC,GAAG,MAC1C,IAAI,CAAC;AACd"}
|
|
@@ -11,9 +11,12 @@ export declare class HistoryRouterGateway implements RouterGateway.Interface {
|
|
|
11
11
|
constructor(history: History, baseUrl: string);
|
|
12
12
|
addGuard(config: RouteTransitionGuardConfig): GuardDisposer;
|
|
13
13
|
goToRoute(name: string, params: z.ZodTypeAny): void;
|
|
14
|
+
replaceRoute(name: string, params: z.ZodTypeAny): void;
|
|
15
|
+
goBack(): void;
|
|
14
16
|
setRoutes(routes: RouteDefinition[]): void;
|
|
15
17
|
destroy(): void;
|
|
16
18
|
pushState(url: string): void;
|
|
19
|
+
replaceState(url: string): void;
|
|
17
20
|
private resolvePathname;
|
|
18
21
|
private findBlockingGuard;
|
|
19
22
|
private installBlocker;
|
|
@@ -25,6 +25,15 @@ class HistoryRouterGateway {
|
|
|
25
25
|
const baseUrl = this.router.getBaseUrl();
|
|
26
26
|
this.history.push(RouteUrl.fromPattern(route.path, params, baseUrl));
|
|
27
27
|
}
|
|
28
|
+
replaceRoute(name, params) {
|
|
29
|
+
const route = this.router.findRoute(name);
|
|
30
|
+
if (!route) return void console.warn(`Route "${name}" not found.`);
|
|
31
|
+
const baseUrl = this.router.getBaseUrl();
|
|
32
|
+
this.history.replace(RouteUrl.fromPattern(route.path, params, baseUrl));
|
|
33
|
+
}
|
|
34
|
+
goBack() {
|
|
35
|
+
this.history.back();
|
|
36
|
+
}
|
|
28
37
|
setRoutes(routes) {
|
|
29
38
|
this.router.setRoutes(routes);
|
|
30
39
|
const queryParams = Object.fromEntries(new URLSearchParams(this.history.location.search).entries());
|
|
@@ -39,6 +48,9 @@ class HistoryRouterGateway {
|
|
|
39
48
|
pushState(url) {
|
|
40
49
|
this.history.push(url);
|
|
41
50
|
}
|
|
51
|
+
replaceState(url) {
|
|
52
|
+
this.history.replace(url);
|
|
53
|
+
}
|
|
42
54
|
async resolvePathname(pathname, queryParams) {
|
|
43
55
|
const result = this.router.resolve(pathname, queryParams);
|
|
44
56
|
if (!result) return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/router/HistoryRouterGateway.js","sources":["../../../src/features/router/HistoryRouterGateway.ts"],"sourcesContent":["import type { z } from \"zod\";\nimport type { History } from \"history\";\nimport type { RouteDefinition, RouteTransitionGuardConfig, GuardDisposer } from \"./abstractions.js\";\nimport { RouterGateway } from \"./abstractions.js\";\nimport { RouteUrl } from \"./RouteUrl.js\";\nimport { Router } from \"./Router.js\";\n\nexport class HistoryRouterGateway implements RouterGateway.Interface {\n private readonly history: History;\n private readonly router: Router;\n private stopListening: () => void;\n private unblock: (() => void) | undefined;\n private guards = new Set<RouteTransitionGuardConfig>();\n\n constructor(history: History, baseUrl: string) {\n this.history = history;\n this.router = new Router(baseUrl);\n\n this.stopListening = history.listen(async ({ location }) => {\n const queryParams = Object.fromEntries(new URLSearchParams(location.search).entries());\n this.resolvePathname(location.pathname, queryParams);\n });\n }\n\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer {\n const hadGuards = this.guards.size > 0;\n this.guards.add(config);\n if (!hadGuards) {\n this.installBlocker();\n }\n return () => {\n this.guards.delete(config);\n if (this.guards.size === 0) {\n this.removeBlocker();\n }\n };\n }\n\n goToRoute(name: string, params: z.ZodTypeAny): void {\n const route = this.router.findRoute(name);\n if (!route) {\n console.warn(`Route \"${name}\" not found.`);\n return;\n }\n\n const baseUrl = this.router.getBaseUrl();\n this.history.push(RouteUrl.fromPattern(route.path, params, baseUrl));\n }\n\n setRoutes(routes: RouteDefinition[]) {\n this.router.setRoutes(routes);\n\n const queryParams = Object.fromEntries(\n new URLSearchParams(this.history.location.search).entries()\n );\n const currentPathname = this.history.location.pathname;\n this.resolvePathname(currentPathname, queryParams);\n }\n\n destroy(): void {\n this.stopListening();\n this.removeBlocker();\n this.guards.clear();\n }\n\n pushState(url: string): void {\n this.history.push(url);\n }\n\n private async resolvePathname(pathname: string, queryParams?: Record<string, unknown>) {\n const result = this.router.resolve(pathname, queryParams);\n if (!result) {\n return;\n }\n\n const { matchedRoute, onMatch } = result;\n\n onMatch(matchedRoute);\n }\n\n private findBlockingGuard(): RouteTransitionGuardConfig | undefined {\n for (const config of this.guards) {\n if (config.guard()) {\n return config;\n }\n }\n return undefined;\n }\n\n private installBlocker(): void {\n if (this.unblock) {\n this.unblock();\n }\n\n this.unblock = this.history.block(tx => {\n const blockingGuard = this.findBlockingGuard();\n if (blockingGuard) {\n let resolved = false;\n\n blockingGuard.onBlocked({\n continue: () => {\n if (!resolved) {\n resolved = true;\n this.removeBlockerAndRetry(tx);\n }\n },\n cancel: () => {\n resolved = true;\n // Do nothing — history v5 already reverted the URL.\n }\n });\n } else {\n this.removeBlockerAndRetry(tx);\n }\n });\n }\n\n private removeBlocker(): void {\n if (this.unblock) {\n this.unblock();\n this.unblock = undefined;\n }\n }\n\n private removeBlockerAndRetry(tx: { retry: () => void }): void {\n // We must remove the blocker before retrying because history v5's\n // allowTx() always returns false when any blocker is registered.\n this.removeBlocker();\n\n // Listen for the next navigation to complete, then reinstall the\n // blocker only if guards are still active.\n const unlisten = this.history.listen(() => {\n unlisten();\n if (this.guards.size > 0) {\n this.installBlocker();\n }\n });\n\n tx.retry();\n }\n}\n"],"names":["HistoryRouterGateway","history","baseUrl","Set","Router","location","queryParams","Object","URLSearchParams","config","hadGuards","name","params","route","console","RouteUrl","routes","currentPathname","url","pathname","result","matchedRoute","onMatch","tx","blockingGuard","resolved","undefined","unlisten"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"features/router/HistoryRouterGateway.js","sources":["../../../src/features/router/HistoryRouterGateway.ts"],"sourcesContent":["import type { z } from \"zod\";\nimport type { History } from \"history\";\nimport type { RouteDefinition, RouteTransitionGuardConfig, GuardDisposer } from \"./abstractions.js\";\nimport { RouterGateway } from \"./abstractions.js\";\nimport { RouteUrl } from \"./RouteUrl.js\";\nimport { Router } from \"./Router.js\";\n\nexport class HistoryRouterGateway implements RouterGateway.Interface {\n private readonly history: History;\n private readonly router: Router;\n private stopListening: () => void;\n private unblock: (() => void) | undefined;\n private guards = new Set<RouteTransitionGuardConfig>();\n\n constructor(history: History, baseUrl: string) {\n this.history = history;\n this.router = new Router(baseUrl);\n\n this.stopListening = history.listen(async ({ location }) => {\n const queryParams = Object.fromEntries(new URLSearchParams(location.search).entries());\n this.resolvePathname(location.pathname, queryParams);\n });\n }\n\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer {\n const hadGuards = this.guards.size > 0;\n this.guards.add(config);\n if (!hadGuards) {\n this.installBlocker();\n }\n return () => {\n this.guards.delete(config);\n if (this.guards.size === 0) {\n this.removeBlocker();\n }\n };\n }\n\n goToRoute(name: string, params: z.ZodTypeAny): void {\n const route = this.router.findRoute(name);\n if (!route) {\n console.warn(`Route \"${name}\" not found.`);\n return;\n }\n\n const baseUrl = this.router.getBaseUrl();\n this.history.push(RouteUrl.fromPattern(route.path, params, baseUrl));\n }\n\n replaceRoute(name: string, params: z.ZodTypeAny): void {\n const route = this.router.findRoute(name);\n if (!route) {\n console.warn(`Route \"${name}\" not found.`);\n return;\n }\n\n const baseUrl = this.router.getBaseUrl();\n this.history.replace(RouteUrl.fromPattern(route.path, params, baseUrl));\n }\n\n goBack(): void {\n this.history.back();\n }\n\n setRoutes(routes: RouteDefinition[]) {\n this.router.setRoutes(routes);\n\n const queryParams = Object.fromEntries(\n new URLSearchParams(this.history.location.search).entries()\n );\n const currentPathname = this.history.location.pathname;\n this.resolvePathname(currentPathname, queryParams);\n }\n\n destroy(): void {\n this.stopListening();\n this.removeBlocker();\n this.guards.clear();\n }\n\n pushState(url: string): void {\n this.history.push(url);\n }\n\n replaceState(url: string): void {\n this.history.replace(url);\n }\n\n private async resolvePathname(pathname: string, queryParams?: Record<string, unknown>) {\n const result = this.router.resolve(pathname, queryParams);\n if (!result) {\n return;\n }\n\n const { matchedRoute, onMatch } = result;\n\n onMatch(matchedRoute);\n }\n\n private findBlockingGuard(): RouteTransitionGuardConfig | undefined {\n for (const config of this.guards) {\n if (config.guard()) {\n return config;\n }\n }\n return undefined;\n }\n\n private installBlocker(): void {\n if (this.unblock) {\n this.unblock();\n }\n\n this.unblock = this.history.block(tx => {\n const blockingGuard = this.findBlockingGuard();\n if (blockingGuard) {\n let resolved = false;\n\n blockingGuard.onBlocked({\n continue: () => {\n if (!resolved) {\n resolved = true;\n this.removeBlockerAndRetry(tx);\n }\n },\n cancel: () => {\n resolved = true;\n // Do nothing — history v5 already reverted the URL.\n }\n });\n } else {\n this.removeBlockerAndRetry(tx);\n }\n });\n }\n\n private removeBlocker(): void {\n if (this.unblock) {\n this.unblock();\n this.unblock = undefined;\n }\n }\n\n private removeBlockerAndRetry(tx: { retry: () => void }): void {\n // We must remove the blocker before retrying because history v5's\n // allowTx() always returns false when any blocker is registered.\n this.removeBlocker();\n\n // Listen for the next navigation to complete, then reinstall the\n // blocker only if guards are still active.\n const unlisten = this.history.listen(() => {\n unlisten();\n if (this.guards.size > 0) {\n this.installBlocker();\n }\n });\n\n tx.retry();\n }\n}\n"],"names":["HistoryRouterGateway","history","baseUrl","Set","Router","location","queryParams","Object","URLSearchParams","config","hadGuards","name","params","route","console","RouteUrl","routes","currentPathname","url","pathname","result","matchedRoute","onMatch","tx","blockingGuard","resolved","undefined","unlisten"],"mappings":"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"}
|
|
@@ -13,7 +13,7 @@ export declare class Route<TParams extends RouteParamsDefinition | undefined = u
|
|
|
13
13
|
private readonly schema;
|
|
14
14
|
constructor(route: RouteParams<TParams>);
|
|
15
15
|
get name(): string;
|
|
16
|
-
get path(): `/${string}
|
|
16
|
+
get path(): "*" | `/${string}`;
|
|
17
17
|
get params(): TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined;
|
|
18
18
|
private coerceParams;
|
|
19
19
|
}
|
|
@@ -9,7 +9,9 @@ declare class RouterPresenterImpl implements Abstraction.Interface {
|
|
|
9
9
|
bootstrap: (routes: Route[]) => void;
|
|
10
10
|
goToRoute: (route: any, params?: any) => void;
|
|
11
11
|
setRouteParams: (cb: any) => void;
|
|
12
|
+
replaceRouteParams: (cb: any) => void;
|
|
12
13
|
getLink: (route: any, params?: any) => string;
|
|
14
|
+
goBack: () => void;
|
|
13
15
|
addTransitionGuard: (config: RouteTransitionGuardConfig) => GuardDisposer;
|
|
14
16
|
isTransitionBlocked: () => boolean;
|
|
15
17
|
unblockTransition: () => void;
|
|
@@ -16,7 +16,17 @@ class RouterPresenterImpl {
|
|
|
16
16
|
const newParams = cb(matchedRoute?.params ?? {});
|
|
17
17
|
this.goToRoute(currentRoute, newParams);
|
|
18
18
|
};
|
|
19
|
+
this.replaceRouteParams = (cb)=>{
|
|
20
|
+
const currentRoute = this.routerRepository.getCurrentRoute();
|
|
21
|
+
if (!currentRoute) return;
|
|
22
|
+
const matchedRoute = this.routerRepository.getMatchedRoute();
|
|
23
|
+
const newParams = cb(matchedRoute?.params ?? {});
|
|
24
|
+
this.routerRepository.replaceRoute(currentRoute, newParams);
|
|
25
|
+
};
|
|
19
26
|
this.getLink = (route, params)=>this.routerRepository.getLink(route, params);
|
|
27
|
+
this.goBack = ()=>{
|
|
28
|
+
this.routerRepository.goBack();
|
|
29
|
+
};
|
|
20
30
|
this.addTransitionGuard = (config)=>this.routerRepository.addGuard(config);
|
|
21
31
|
this.isTransitionBlocked = ()=>this.routerRepository.isBlocked();
|
|
22
32
|
this.unblockTransition = ()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/router/RouterPresenter.js","sources":["../../../src/features/router/RouterPresenter.ts"],"sourcesContent":["import { makeAutoObservable, toJS } from \"mobx\";\nimport { createImplementation } from \"@webiny/di\";\nimport { Route } from \"./Route.js\";\nimport {\n RouterRepository,\n RouterPresenter as Abstraction,\n type RouteTransitionGuardConfig,\n type GuardDisposer\n} from \"./abstractions.js\";\n\nclass RouterPresenterImpl implements Abstraction.Interface {\n private routerRepository: RouterRepository.Interface;\n\n constructor(routerRepository: RouterRepository.Interface) {\n this.routerRepository = routerRepository;\n\n makeAutoObservable(this);\n }\n\n get vm() {\n return {\n currentRoute: toJS(this.routerRepository.getMatchedRoute())\n };\n }\n\n bootstrap = (routes: Route[]) => {\n this.routerRepository.registerRoutes(routes);\n };\n\n goToRoute = (route: any, params?: any) => {\n this.routerRepository.goToRoute(route, params);\n };\n\n setRouteParams = (cb: any) => {\n const currentRoute = this.routerRepository.getCurrentRoute();\n if (!currentRoute) {\n return;\n }\n\n const matchedRoute = this.routerRepository.getMatchedRoute();\n const newParams = cb(matchedRoute?.params ?? {});\n this.goToRoute(currentRoute, newParams);\n };\n\n getLink = (route: any, params?: any) => {\n return this.routerRepository.getLink(route, params);\n };\n\n addTransitionGuard = (config: RouteTransitionGuardConfig): GuardDisposer => {\n return this.routerRepository.addGuard(config);\n };\n\n isTransitionBlocked = (): boolean => {\n return this.routerRepository.isBlocked();\n };\n\n unblockTransition = (): void => {\n this.routerRepository.unblock();\n };\n\n confirmTransition = (): void => {\n this.routerRepository.confirmTransition();\n };\n\n cancelTransition = (): void => {\n this.routerRepository.cancelTransition();\n };\n\n destroy = () => {\n this.routerRepository.destroy();\n };\n}\n\nexport const RouterPresenter = createImplementation({\n abstraction: Abstraction,\n implementation: RouterPresenterImpl,\n dependencies: [RouterRepository]\n});\n"],"names":["RouterPresenterImpl","routerRepository","routes","route","params","cb","currentRoute","matchedRoute","newParams","config","makeAutoObservable","toJS","RouterPresenter","createImplementation","Abstraction","RouterRepository"],"mappings":";;;AAUA,MAAMA;IAGF,YAAYC,gBAA4C,CAAE;aAY1D,SAAS,GAAG,CAACC;YACT,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAACA;QACzC;aAEA,SAAS,GAAG,CAACC,OAAYC;YACrB,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAACD,OAAOC;QAC3C;aAEA,cAAc,GAAG,CAACC;YACd,MAAMC,eAAe,IAAI,CAAC,gBAAgB,CAAC,eAAe;YAC1D,IAAI,CAACA,cACD;YAGJ,MAAMC,eAAe,IAAI,CAAC,gBAAgB,CAAC,eAAe;YAC1D,MAAMC,YAAYH,GAAGE,cAAc,UAAU,CAAC;YAC9C,IAAI,CAAC,SAAS,CAACD,cAAcE;QACjC;aAEA,OAAO,GAAG,CAACL,OAAYC,SACZ,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAACD,OAAOC;aAGhD,kBAAkB,GAAG,CAACK,SACX,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAACA;aAG1C,mBAAmB,GAAG,IACX,IAAI,CAAC,gBAAgB,CAAC,SAAS;aAG1C,iBAAiB,GAAG;YAChB,IAAI,CAAC,gBAAgB,CAAC,OAAO;QACjC;aAEA,iBAAiB,GAAG;YAChB,IAAI,CAAC,gBAAgB,CAAC,iBAAiB;QAC3C;aAEA,gBAAgB,GAAG;YACf,IAAI,CAAC,gBAAgB,CAAC,gBAAgB;QAC1C;aAEA,OAAO,GAAG;YACN,IAAI,CAAC,gBAAgB,CAAC,OAAO;QACjC;
|
|
1
|
+
{"version":3,"file":"features/router/RouterPresenter.js","sources":["../../../src/features/router/RouterPresenter.ts"],"sourcesContent":["import { makeAutoObservable, toJS } from \"mobx\";\nimport { createImplementation } from \"@webiny/di\";\nimport { Route } from \"./Route.js\";\nimport {\n RouterRepository,\n RouterPresenter as Abstraction,\n type RouteTransitionGuardConfig,\n type GuardDisposer\n} from \"./abstractions.js\";\n\nclass RouterPresenterImpl implements Abstraction.Interface {\n private routerRepository: RouterRepository.Interface;\n\n constructor(routerRepository: RouterRepository.Interface) {\n this.routerRepository = routerRepository;\n\n makeAutoObservable(this);\n }\n\n get vm() {\n return {\n currentRoute: toJS(this.routerRepository.getMatchedRoute())\n };\n }\n\n bootstrap = (routes: Route[]) => {\n this.routerRepository.registerRoutes(routes);\n };\n\n goToRoute = (route: any, params?: any) => {\n this.routerRepository.goToRoute(route, params);\n };\n\n setRouteParams = (cb: any) => {\n const currentRoute = this.routerRepository.getCurrentRoute();\n if (!currentRoute) {\n return;\n }\n\n const matchedRoute = this.routerRepository.getMatchedRoute();\n const newParams = cb(matchedRoute?.params ?? {});\n this.goToRoute(currentRoute, newParams);\n };\n\n replaceRouteParams = (cb: any) => {\n const currentRoute = this.routerRepository.getCurrentRoute();\n if (!currentRoute) {\n return;\n }\n\n const matchedRoute = this.routerRepository.getMatchedRoute();\n const newParams = cb(matchedRoute?.params ?? {});\n this.routerRepository.replaceRoute(currentRoute, newParams);\n };\n\n getLink = (route: any, params?: any) => {\n return this.routerRepository.getLink(route, params);\n };\n\n goBack = (): void => {\n this.routerRepository.goBack();\n };\n\n addTransitionGuard = (config: RouteTransitionGuardConfig): GuardDisposer => {\n return this.routerRepository.addGuard(config);\n };\n\n isTransitionBlocked = (): boolean => {\n return this.routerRepository.isBlocked();\n };\n\n unblockTransition = (): void => {\n this.routerRepository.unblock();\n };\n\n confirmTransition = (): void => {\n this.routerRepository.confirmTransition();\n };\n\n cancelTransition = (): void => {\n this.routerRepository.cancelTransition();\n };\n\n destroy = () => {\n this.routerRepository.destroy();\n };\n}\n\nexport const RouterPresenter = createImplementation({\n abstraction: Abstraction,\n implementation: RouterPresenterImpl,\n dependencies: [RouterRepository]\n});\n"],"names":["RouterPresenterImpl","routerRepository","routes","route","params","cb","currentRoute","matchedRoute","newParams","config","makeAutoObservable","toJS","RouterPresenter","createImplementation","Abstraction","RouterRepository"],"mappings":";;;AAUA,MAAMA;IAGF,YAAYC,gBAA4C,CAAE;aAY1D,SAAS,GAAG,CAACC;YACT,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAACA;QACzC;aAEA,SAAS,GAAG,CAACC,OAAYC;YACrB,IAAI,CAAC,gBAAgB,CAAC,SAAS,CAACD,OAAOC;QAC3C;aAEA,cAAc,GAAG,CAACC;YACd,MAAMC,eAAe,IAAI,CAAC,gBAAgB,CAAC,eAAe;YAC1D,IAAI,CAACA,cACD;YAGJ,MAAMC,eAAe,IAAI,CAAC,gBAAgB,CAAC,eAAe;YAC1D,MAAMC,YAAYH,GAAGE,cAAc,UAAU,CAAC;YAC9C,IAAI,CAAC,SAAS,CAACD,cAAcE;QACjC;aAEA,kBAAkB,GAAG,CAACH;YAClB,MAAMC,eAAe,IAAI,CAAC,gBAAgB,CAAC,eAAe;YAC1D,IAAI,CAACA,cACD;YAGJ,MAAMC,eAAe,IAAI,CAAC,gBAAgB,CAAC,eAAe;YAC1D,MAAMC,YAAYH,GAAGE,cAAc,UAAU,CAAC;YAC9C,IAAI,CAAC,gBAAgB,CAAC,YAAY,CAACD,cAAcE;QACrD;aAEA,OAAO,GAAG,CAACL,OAAYC,SACZ,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAACD,OAAOC;aAGhD,MAAM,GAAG;YACL,IAAI,CAAC,gBAAgB,CAAC,MAAM;QAChC;aAEA,kBAAkB,GAAG,CAACK,SACX,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAACA;aAG1C,mBAAmB,GAAG,IACX,IAAI,CAAC,gBAAgB,CAAC,SAAS;aAG1C,iBAAiB,GAAG;YAChB,IAAI,CAAC,gBAAgB,CAAC,OAAO;QACjC;aAEA,iBAAiB,GAAG;YAChB,IAAI,CAAC,gBAAgB,CAAC,iBAAiB;QAC3C;aAEA,gBAAgB,GAAG;YACf,IAAI,CAAC,gBAAgB,CAAC,gBAAgB;QAC1C;aAEA,OAAO,GAAG;YACN,IAAI,CAAC,gBAAgB,CAAC,OAAO;QACjC;QAvEI,IAAI,CAAC,gBAAgB,GAAGR;QAExBS,mBAAmB,IAAI;IAC3B;IAEA,IAAI,KAAK;QACL,OAAO;YACH,cAAcC,KAAK,IAAI,CAAC,gBAAgB,CAAC,eAAe;QAC5D;IACJ;AA+DJ;AAEO,MAAMC,kCAAkBC,qBAAqB;IAChD,aAAaC;IACb,gBAAgBd;IAChB,cAAc;QAACe;KAAiB;AACpC"}
|
|
@@ -14,6 +14,8 @@ declare class RouterRepositoryImpl implements Abstractions.RouterRepository.Inte
|
|
|
14
14
|
registerRoutes: (routes: Route[]) => void;
|
|
15
15
|
getLink<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, params?: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined): string;
|
|
16
16
|
goToRoute<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined): void;
|
|
17
|
+
replaceRoute<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined): void;
|
|
18
|
+
goBack(): void;
|
|
17
19
|
addGuard(config: RouteTransitionGuardConfig): GuardDisposer;
|
|
18
20
|
isBlocked(): boolean;
|
|
19
21
|
unblock(): void;
|
|
@@ -41,6 +41,12 @@ class RouterRepositoryImpl {
|
|
|
41
41
|
goToRoute(route, params) {
|
|
42
42
|
this.gateway.goToRoute(route.name, params);
|
|
43
43
|
}
|
|
44
|
+
replaceRoute(route, params) {
|
|
45
|
+
this.gateway.replaceRoute(route.name, params);
|
|
46
|
+
}
|
|
47
|
+
goBack() {
|
|
48
|
+
this.gateway.goBack();
|
|
49
|
+
}
|
|
44
50
|
addGuard(config) {
|
|
45
51
|
const gatewayGuard = {
|
|
46
52
|
guard: ()=>{
|
|
@@ -96,10 +102,10 @@ class RouterRepositoryImpl {
|
|
|
96
102
|
if (!route) return;
|
|
97
103
|
const params = "function" == typeof route.params?.parse ? route.params.parse(matchedRoute.params) : matchedRoute.params;
|
|
98
104
|
runInAction(()=>{
|
|
99
|
-
|
|
105
|
+
this.currentRoute = {
|
|
100
106
|
...matchedRoute,
|
|
101
107
|
params
|
|
102
|
-
}
|
|
108
|
+
};
|
|
103
109
|
});
|
|
104
110
|
}
|
|
105
111
|
getRouteByName(name) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/router/RouterRepository.js","sources":["../../../src/features/router/RouterRepository.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from \"mobx\";\nimport type {\n MatchedRoute,\n RouteDefinition,\n RouteTransitionGuardConfig,\n GuardDisposer,\n TransitionController\n} from \"./abstractions.js\";\nimport * as Abstractions from \"./abstractions.js\";\nimport { Route, RouteParamsDefinition, RouteParamsInfer } from \"./Route.js\";\nimport { RouteUrl } from \"./RouteUrl.js\";\n\nconst INIT_ROUTE = { name: \"__init__\", path: \"\", pathname: \"\", params: {} };\n\nclass RouterRepositoryImpl implements Abstractions.RouterRepository.Interface {\n private gateway: Abstractions.RouterGateway.Interface;\n private currentRoute: MatchedRoute = INIT_ROUTE;\n private routes: Route<any>[] = [];\n private pendingTransition: TransitionController | undefined;\n private forceUnblocked = false;\n private guardDisposers = new Map<RouteTransitionGuardConfig, GuardDisposer>();\n\n constructor(gateway: Abstractions.RouterGateway.Interface) {\n this.gateway = gateway;\n\n makeAutoObservable(this, {\n pendingTransition: false,\n forceUnblocked: false\n } as any);\n }\n\n getMatchedRoute() {\n return this.currentRoute.name !== INIT_ROUTE.name ? this.currentRoute : undefined;\n }\n\n getCurrentRoute(): Route<any> | undefined {\n return this.routes.find(route => route.name === this.currentRoute.name);\n }\n\n registerRoutes = (routes: Route[]) => {\n this.routes = routes;\n const routesWithAction = routes.map<RouteDefinition>(this.routeWithAction);\n\n this.gateway.setRoutes(routesWithAction);\n };\n\n getLink<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params?: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): string {\n return RouteUrl.fromPattern(route.path, params);\n }\n\n goToRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): void {\n this.gateway.goToRoute(route.name, params);\n }\n\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer {\n const gatewayGuard: RouteTransitionGuardConfig = {\n guard: () => {\n if (this.forceUnblocked) {\n this.forceUnblocked = false;\n return false;\n }\n return config.guard();\n },\n onBlocked: (controller: TransitionController) => {\n this.pendingTransition = controller;\n config.onBlocked(controller);\n }\n };\n\n const disposeGatewayGuard = this.gateway.addGuard(gatewayGuard);\n\n const dispose = () => {\n this.guardDisposers.delete(config);\n disposeGatewayGuard();\n };\n\n this.guardDisposers.set(config, dispose);\n return dispose;\n }\n\n isBlocked(): boolean {\n return this.pendingTransition !== undefined;\n }\n\n unblock(): void {\n this.forceUnblocked = true;\n if (this.pendingTransition) {\n this.forceUnblocked = false;\n const tx = this.pendingTransition;\n this.pendingTransition = undefined;\n tx.continue();\n } else {\n // No pending transition — expire the flag after the current\n // call stack so it only covers synchronous navigations that\n // follow immediately (e.g. router.goToRoute on the next line).\n setTimeout(() => {\n this.forceUnblocked = false;\n }, 0);\n }\n }\n\n confirmTransition(): void {\n const tx = this.pendingTransition;\n this.pendingTransition = undefined;\n if (tx) {\n tx.continue();\n }\n }\n\n cancelTransition(): void {\n if (this.pendingTransition) {\n this.pendingTransition.cancel();\n this.pendingTransition = undefined;\n }\n }\n\n destroy() {\n this.gateway.destroy();\n }\n\n private routeWithAction = (route: Route<any>) => {\n return {\n name: route.name,\n path: route.path,\n onMatch: this.transitionToRoute.bind(this)\n };\n };\n\n private async transitionToRoute(matchedRoute: MatchedRoute) {\n const route = this.getRouteByName(matchedRoute.name);\n if (!route) {\n return;\n }\n\n const params =\n typeof route.params?.parse === \"function\"\n ? route.params.parse(matchedRoute.params)\n : matchedRoute.params;\n\n runInAction(() => {\n
|
|
1
|
+
{"version":3,"file":"features/router/RouterRepository.js","sources":["../../../src/features/router/RouterRepository.ts"],"sourcesContent":["import { makeAutoObservable, runInAction } from \"mobx\";\nimport type {\n MatchedRoute,\n RouteDefinition,\n RouteTransitionGuardConfig,\n GuardDisposer,\n TransitionController\n} from \"./abstractions.js\";\nimport * as Abstractions from \"./abstractions.js\";\nimport { Route, RouteParamsDefinition, RouteParamsInfer } from \"./Route.js\";\nimport { RouteUrl } from \"./RouteUrl.js\";\n\nconst INIT_ROUTE = { name: \"__init__\", path: \"\", pathname: \"\", params: {} };\n\nclass RouterRepositoryImpl implements Abstractions.RouterRepository.Interface {\n private gateway: Abstractions.RouterGateway.Interface;\n private currentRoute: MatchedRoute = INIT_ROUTE;\n private routes: Route<any>[] = [];\n private pendingTransition: TransitionController | undefined;\n private forceUnblocked = false;\n private guardDisposers = new Map<RouteTransitionGuardConfig, GuardDisposer>();\n\n constructor(gateway: Abstractions.RouterGateway.Interface) {\n this.gateway = gateway;\n\n makeAutoObservable(this, {\n pendingTransition: false,\n forceUnblocked: false\n } as any);\n }\n\n getMatchedRoute() {\n return this.currentRoute.name !== INIT_ROUTE.name ? this.currentRoute : undefined;\n }\n\n getCurrentRoute(): Route<any> | undefined {\n return this.routes.find(route => route.name === this.currentRoute.name);\n }\n\n registerRoutes = (routes: Route[]) => {\n this.routes = routes;\n const routesWithAction = routes.map<RouteDefinition>(this.routeWithAction);\n\n this.gateway.setRoutes(routesWithAction);\n };\n\n getLink<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params?: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): string {\n return RouteUrl.fromPattern(route.path, params);\n }\n\n goToRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): void {\n this.gateway.goToRoute(route.name, params);\n }\n\n replaceRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): void {\n this.gateway.replaceRoute(route.name, params);\n }\n\n goBack(): void {\n this.gateway.goBack();\n }\n\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer {\n const gatewayGuard: RouteTransitionGuardConfig = {\n guard: () => {\n if (this.forceUnblocked) {\n this.forceUnblocked = false;\n return false;\n }\n return config.guard();\n },\n onBlocked: (controller: TransitionController) => {\n this.pendingTransition = controller;\n config.onBlocked(controller);\n }\n };\n\n const disposeGatewayGuard = this.gateway.addGuard(gatewayGuard);\n\n const dispose = () => {\n this.guardDisposers.delete(config);\n disposeGatewayGuard();\n };\n\n this.guardDisposers.set(config, dispose);\n return dispose;\n }\n\n isBlocked(): boolean {\n return this.pendingTransition !== undefined;\n }\n\n unblock(): void {\n this.forceUnblocked = true;\n if (this.pendingTransition) {\n this.forceUnblocked = false;\n const tx = this.pendingTransition;\n this.pendingTransition = undefined;\n tx.continue();\n } else {\n // No pending transition — expire the flag after the current\n // call stack so it only covers synchronous navigations that\n // follow immediately (e.g. router.goToRoute on the next line).\n setTimeout(() => {\n this.forceUnblocked = false;\n }, 0);\n }\n }\n\n confirmTransition(): void {\n const tx = this.pendingTransition;\n this.pendingTransition = undefined;\n if (tx) {\n tx.continue();\n }\n }\n\n cancelTransition(): void {\n if (this.pendingTransition) {\n this.pendingTransition.cancel();\n this.pendingTransition = undefined;\n }\n }\n\n destroy() {\n this.gateway.destroy();\n }\n\n private routeWithAction = (route: Route<any>) => {\n return {\n name: route.name,\n path: route.path,\n onMatch: this.transitionToRoute.bind(this)\n };\n };\n\n private async transitionToRoute(matchedRoute: MatchedRoute) {\n const route = this.getRouteByName(matchedRoute.name);\n if (!route) {\n return;\n }\n\n const params =\n typeof route.params?.parse === \"function\"\n ? route.params.parse(matchedRoute.params)\n : matchedRoute.params;\n\n runInAction(() => {\n this.currentRoute = { ...matchedRoute, params };\n });\n }\n\n private getRouteByName(name: string) {\n return this.routes.find(existingRoute => existingRoute.name === name);\n }\n}\n\nexport const RouterRepository = Abstractions.RouterRepository.createImplementation({\n implementation: RouterRepositoryImpl,\n dependencies: [Abstractions.RouterGateway]\n});\n"],"names":["INIT_ROUTE","RouterRepositoryImpl","gateway","Map","routes","routesWithAction","route","makeAutoObservable","undefined","params","RouteUrl","config","gatewayGuard","controller","disposeGatewayGuard","dispose","tx","setTimeout","matchedRoute","runInAction","name","existingRoute","RouterRepository","Abstractions"],"mappings":"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"}
|
|
@@ -12,6 +12,8 @@ export interface IRouterPresenter {
|
|
|
12
12
|
goToRoute<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, ...args: RouteParamsArgs<TParams>): void;
|
|
13
13
|
getLink<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, ...args: RouteParamsArgs<TParams>): string;
|
|
14
14
|
setRouteParams<T extends Record<string, any>>(cb: (params: T) => T): void;
|
|
15
|
+
replaceRouteParams<T extends Record<string, any>>(cb: (params: T) => T): void;
|
|
16
|
+
goBack(): void;
|
|
15
17
|
addTransitionGuard(config: RouteTransitionGuardConfig): GuardDisposer;
|
|
16
18
|
isTransitionBlocked(): boolean;
|
|
17
19
|
unblockTransition(): void;
|
|
@@ -34,7 +36,9 @@ export interface IRouterRepository {
|
|
|
34
36
|
getMatchedRoute(): MatchedRoute | undefined;
|
|
35
37
|
getCurrentRoute(): Route<any> | undefined;
|
|
36
38
|
goToRoute<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined): void;
|
|
39
|
+
replaceRoute<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined): void;
|
|
37
40
|
getLink<TParams extends RouteParamsDefinition | undefined>(route: Route<TParams>, params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined): string;
|
|
41
|
+
goBack(): void;
|
|
38
42
|
registerRoutes(routes: Route[]): void;
|
|
39
43
|
addGuard(config: RouteTransitionGuardConfig): GuardDisposer;
|
|
40
44
|
isBlocked(): boolean;
|
|
@@ -62,7 +66,12 @@ interface IRouterGateway {
|
|
|
62
66
|
goToRoute(name: string, params?: {
|
|
63
67
|
[k: string]: any;
|
|
64
68
|
}): void;
|
|
69
|
+
replaceRoute(name: string, params?: {
|
|
70
|
+
[k: string]: any;
|
|
71
|
+
}): void;
|
|
72
|
+
goBack(): void;
|
|
65
73
|
pushState(url: string): void;
|
|
74
|
+
replaceState(url: string): void;
|
|
66
75
|
addGuard(config: RouteTransitionGuardConfig): GuardDisposer;
|
|
67
76
|
destroy(): void;
|
|
68
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"features/router/abstractions.js","sources":["../../../src/features/router/abstractions.ts"],"sourcesContent":["import { Abstraction } from \"@webiny/di\";\nimport type { Route, RouteParamsDefinition, RouteParamsInfer } from \"./Route.js\";\nimport type { RequiredKeysOf } from \"type-fest\";\n\n/***** Presenter *****/\n\nexport type RouteParamsArgs<TParams extends RouteParamsDefinition | undefined> =\n TParams extends RouteParamsDefinition\n ? RequiredKeysOf<RouteParamsInfer<TParams>> extends never\n ? [params?: RouteParamsInfer<TParams>] // all optional → param optional\n : [params: RouteParamsInfer<TParams>] // some required → param required\n : [];\n\ninterface RouterViewModel {\n currentRoute: MatchedRoute | undefined;\n}\n\nexport interface IRouterPresenter {\n vm: RouterViewModel;\n bootstrap(routes: Route[]): void;\n goToRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n ...args: RouteParamsArgs<TParams>\n ): void;\n getLink<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n ...args: RouteParamsArgs<TParams>\n ): string;\n setRouteParams<T extends Record<string, any>>(cb: (params: T) => T): void;\n addTransitionGuard(config: RouteTransitionGuardConfig): GuardDisposer;\n isTransitionBlocked(): boolean;\n unblockTransition(): void;\n confirmTransition(): void;\n cancelTransition(): void;\n destroy(): void;\n}\nexport const RouterPresenter = new Abstraction<IRouterPresenter>(\"RouterPresenter\");\n\nexport namespace RouterPresenter {\n export type Interface = IRouterPresenter;\n}\n\n/***** Repository *****/\n\nexport interface MatchedRoute<TParams = Record<string, any>> {\n // Name of the matched route.\n name: string;\n // Pathname that was used to match the route.\n pathname: string;\n // Path pattern that matched this route.\n path: string;\n // Route params extracted from the pathname.\n params: TParams;\n}\n\nexport interface IRouterRepository {\n getMatchedRoute(): MatchedRoute | undefined;\n\n getCurrentRoute(): Route<any> | undefined;\n\n goToRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): void;\n\n getLink<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): string;\n\n registerRoutes(routes: Route[]): void;\n\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer;\n isBlocked(): boolean;\n unblock(): void;\n confirmTransition(): void;\n cancelTransition(): void;\n\n destroy(): void;\n}\n\nexport const RouterRepository = new Abstraction<IRouterRepository>(\"RouterRepository\");\n\nexport namespace RouterRepository {\n export type Interface = IRouterRepository;\n}\n\n/***** Gateway *****/\n\nexport interface RouteDefinition {\n name: string;\n path: string;\n onMatch(route: MatchedRoute): void;\n}\n\nexport type TransitionController = {\n continue: () => void;\n cancel: () => void;\n};\n\ninterface IRouterGateway {\n setRoutes(routes: RouteDefinition[]): void;\n goToRoute(name: string, params?: { [k: string]: any }): void;\n pushState(url: string): void;\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer;\n destroy(): void;\n}\n\nexport const RouterGateway = new Abstraction<IRouterGateway>(\"RouterGateway\");\n\nexport namespace RouterGateway {\n export type Interface = IRouterGateway;\n}\n\n/***** Route Transition *****/\n\nexport type GuardDisposer = () => void;\n\nexport interface RouteTransitionGuardConfig {\n /** Return true to block the transition. */\n guard: () => boolean;\n /** Called when this guard blocks a transition. Show a confirmation dialog here. */\n onBlocked: (controller: TransitionController) => void;\n}\n"],"names":["RouterPresenter","Abstraction","RouterRepository","RouterGateway"],"mappings":";
|
|
1
|
+
{"version":3,"file":"features/router/abstractions.js","sources":["../../../src/features/router/abstractions.ts"],"sourcesContent":["import { Abstraction } from \"@webiny/di\";\nimport type { Route, RouteParamsDefinition, RouteParamsInfer } from \"./Route.js\";\nimport type { RequiredKeysOf } from \"type-fest\";\n\n/***** Presenter *****/\n\nexport type RouteParamsArgs<TParams extends RouteParamsDefinition | undefined> =\n TParams extends RouteParamsDefinition\n ? RequiredKeysOf<RouteParamsInfer<TParams>> extends never\n ? [params?: RouteParamsInfer<TParams>] // all optional → param optional\n : [params: RouteParamsInfer<TParams>] // some required → param required\n : [];\n\ninterface RouterViewModel {\n currentRoute: MatchedRoute | undefined;\n}\n\nexport interface IRouterPresenter {\n vm: RouterViewModel;\n bootstrap(routes: Route[]): void;\n goToRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n ...args: RouteParamsArgs<TParams>\n ): void;\n getLink<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n ...args: RouteParamsArgs<TParams>\n ): string;\n setRouteParams<T extends Record<string, any>>(cb: (params: T) => T): void;\n replaceRouteParams<T extends Record<string, any>>(cb: (params: T) => T): void;\n goBack(): void;\n addTransitionGuard(config: RouteTransitionGuardConfig): GuardDisposer;\n isTransitionBlocked(): boolean;\n unblockTransition(): void;\n confirmTransition(): void;\n cancelTransition(): void;\n destroy(): void;\n}\nexport const RouterPresenter = new Abstraction<IRouterPresenter>(\"RouterPresenter\");\n\nexport namespace RouterPresenter {\n export type Interface = IRouterPresenter;\n}\n\n/***** Repository *****/\n\nexport interface MatchedRoute<TParams = Record<string, any>> {\n // Name of the matched route.\n name: string;\n // Pathname that was used to match the route.\n pathname: string;\n // Path pattern that matched this route.\n path: string;\n // Route params extracted from the pathname.\n params: TParams;\n}\n\nexport interface IRouterRepository {\n getMatchedRoute(): MatchedRoute | undefined;\n\n getCurrentRoute(): Route<any> | undefined;\n\n goToRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): void;\n\n replaceRoute<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): void;\n\n getLink<TParams extends RouteParamsDefinition | undefined>(\n route: Route<TParams>,\n params: TParams extends RouteParamsDefinition ? RouteParamsInfer<TParams> : undefined\n ): string;\n\n goBack(): void;\n\n registerRoutes(routes: Route[]): void;\n\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer;\n isBlocked(): boolean;\n unblock(): void;\n confirmTransition(): void;\n cancelTransition(): void;\n\n destroy(): void;\n}\n\nexport const RouterRepository = new Abstraction<IRouterRepository>(\"RouterRepository\");\n\nexport namespace RouterRepository {\n export type Interface = IRouterRepository;\n}\n\n/***** Gateway *****/\n\nexport interface RouteDefinition {\n name: string;\n path: string;\n onMatch(route: MatchedRoute): void;\n}\n\nexport type TransitionController = {\n continue: () => void;\n cancel: () => void;\n};\n\ninterface IRouterGateway {\n setRoutes(routes: RouteDefinition[]): void;\n goToRoute(name: string, params?: { [k: string]: any }): void;\n replaceRoute(name: string, params?: { [k: string]: any }): void;\n goBack(): void;\n pushState(url: string): void;\n replaceState(url: string): void;\n addGuard(config: RouteTransitionGuardConfig): GuardDisposer;\n destroy(): void;\n}\n\nexport const RouterGateway = new Abstraction<IRouterGateway>(\"RouterGateway\");\n\nexport namespace RouterGateway {\n export type Interface = IRouterGateway;\n}\n\n/***** Route Transition *****/\n\nexport type GuardDisposer = () => void;\n\nexport interface RouteTransitionGuardConfig {\n /** Return true to block the transition. */\n guard: () => boolean;\n /** Called when this guard blocks a transition. Show a confirmation dialog here. */\n onBlocked: (controller: TransitionController) => void;\n}\n"],"names":["RouterPresenter","Abstraction","RouterRepository","RouterGateway"],"mappings":";AAsCO,MAAMA,kBAAkB,IAAIC,YAA8B;AAoD1D,MAAMC,mBAAmB,IAAID,YAA+B;AA8B5D,MAAME,gBAAgB,IAAIF,YAA4B"}
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export { AddQuerySelectionPlugin } from "./plugins/AddQuerySelectionPlugin.js";
|
|
2
|
-
export { ApolloLinkPlugin } from "./plugins/ApolloLinkPlugin.js";
|
|
3
|
-
export { ApolloCacheObjectIdPlugin, type ApolloCacheObject } from "./plugins/ApolloCacheObjectIdPlugin.js";
|
|
4
1
|
export * from "@webiny/react-composition";
|
|
5
2
|
export type { HigherOrderComponent, ComposeProps, ComposableFC } from "@webiny/react-composition";
|
|
6
3
|
export * from "./App.js";
|
package/index.js
CHANGED
|
@@ -9,9 +9,6 @@ export * from "./core/createProviderPlugin.js";
|
|
|
9
9
|
export * from "./renderApp.js";
|
|
10
10
|
export * from "./utils/createGenericContext.js";
|
|
11
11
|
export * from "./helpers/InterfaceGenerator/index.js";
|
|
12
|
-
export { AddQuerySelectionPlugin } from "./plugins/AddQuerySelectionPlugin.js";
|
|
13
|
-
export { ApolloLinkPlugin } from "./plugins/ApolloLinkPlugin.js";
|
|
14
|
-
export { ApolloCacheObjectIdPlugin } from "./plugins/ApolloCacheObjectIdPlugin.js";
|
|
15
12
|
export { DiContainerProvider, useContainer } from "./shared/di/DiContainerProvider.js";
|
|
16
13
|
export { useFeature } from "./shared/di/useFeature.js";
|
|
17
14
|
export { createFeature } from "./shared/di/createFeature.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webiny/app",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.6.0-alpha.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./index.js",
|
|
@@ -18,45 +18,32 @@
|
|
|
18
18
|
],
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@apollo/react-hooks": "3.1.5",
|
|
22
|
-
"@emotion/styled": "11.14.1",
|
|
23
21
|
"@types/react": "18.3.31",
|
|
24
|
-
"@webiny/di": "1.0
|
|
25
|
-
"@webiny/feature": "6.
|
|
26
|
-
"@webiny/i18n": "6.
|
|
27
|
-
"@webiny/i18n-react": "6.
|
|
28
|
-
"@webiny/plugins": "6.
|
|
29
|
-
"@webiny/react-composition": "6.
|
|
30
|
-
"@webiny/react-properties": "6.
|
|
31
|
-
"@webiny/stdlib": "0.0.8",
|
|
32
|
-
"apollo-cache": "1.3.5",
|
|
33
|
-
"apollo-cache-inmemory": "1.6.6",
|
|
34
|
-
"apollo-client": "2.6.10",
|
|
35
|
-
"apollo-link": "1.2.14",
|
|
36
|
-
"apollo-link-context": "1.0.20",
|
|
37
|
-
"apollo-link-error": "1.1.13",
|
|
38
|
-
"apollo-link-http-common": "0.2.16",
|
|
39
|
-
"apollo-utilities": "1.3.4",
|
|
22
|
+
"@webiny/di": "1.1.0",
|
|
23
|
+
"@webiny/feature": "6.6.0-alpha.1",
|
|
24
|
+
"@webiny/i18n": "6.6.0-alpha.1",
|
|
25
|
+
"@webiny/i18n-react": "6.6.0-alpha.1",
|
|
26
|
+
"@webiny/plugins": "6.6.0-alpha.1",
|
|
27
|
+
"@webiny/react-composition": "6.6.0-alpha.1",
|
|
28
|
+
"@webiny/react-properties": "6.6.0-alpha.1",
|
|
40
29
|
"graphql": "16.14.2",
|
|
41
30
|
"history": "5.3.0",
|
|
42
31
|
"invariant": "2.2.4",
|
|
43
32
|
"lodash": "4.18.1",
|
|
44
|
-
"mobx": "
|
|
45
|
-
"nanoid": "5.1.16",
|
|
33
|
+
"mobx": "7.0.3",
|
|
46
34
|
"react": "18.3.1",
|
|
47
35
|
"react-dom": "18.3.1",
|
|
48
|
-
"ts-invariant": "0.10.3",
|
|
49
36
|
"warning": "4.0.3",
|
|
50
37
|
"zod": "4.4.3"
|
|
51
38
|
},
|
|
52
39
|
"devDependencies": {
|
|
53
|
-
"@types/lodash": "4.17.
|
|
40
|
+
"@types/lodash": "4.17.25",
|
|
54
41
|
"@types/warning": "3.0.4",
|
|
55
|
-
"@webiny/build-tools": "6.
|
|
42
|
+
"@webiny/build-tools": "6.6.0-alpha.1",
|
|
56
43
|
"rimraf": "6.1.3",
|
|
57
44
|
"type-fest": "5.8.0",
|
|
58
|
-
"typescript": "
|
|
59
|
-
"vitest": "4.1.
|
|
45
|
+
"typescript": "7.0.2",
|
|
46
|
+
"vitest": "4.1.11"
|
|
60
47
|
},
|
|
61
48
|
"publishConfig": {
|
|
62
49
|
"access": "public"
|
package/plugins/image.d.ts
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Route, RouteParamsDefinition } from "../../../features/router/Route.js";
|
|
2
|
+
export interface RouteParamFieldConfig<T> {
|
|
3
|
+
param: string;
|
|
4
|
+
read: () => T | undefined;
|
|
5
|
+
write: (value: T | undefined) => void;
|
|
6
|
+
storageKey?: string;
|
|
7
|
+
}
|
|
8
|
+
export interface RouteParamField {
|
|
9
|
+
param: string;
|
|
10
|
+
read: () => unknown;
|
|
11
|
+
write: (value: unknown) => void;
|
|
12
|
+
storageKey?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface RouteParamFieldBuilder {
|
|
15
|
+
create<T>(config: RouteParamFieldConfig<T>): RouteParamField;
|
|
16
|
+
}
|
|
17
|
+
interface RouteParamsSyncProps<TParams extends RouteParamsDefinition | undefined> {
|
|
18
|
+
route: Route<TParams>;
|
|
19
|
+
fields: (builder: RouteParamFieldBuilder) => RouteParamField[];
|
|
20
|
+
}
|
|
21
|
+
export declare function RouteParamsSync<TParams extends RouteParamsDefinition | undefined>({ route: routeDefinition, fields: buildFields }: RouteParamsSyncProps<TParams>): null;
|
|
22
|
+
export {};
|