@mapples/request 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Bridges the `@mapples/action` store to request execution: subscribes to
3
+ * emitted actions, resolves `mapples:request` actions into commands, executes
4
+ * them (sample or real fetch), stores responses via the surrounding
5
+ * `RequestProvider`, and re-emits `onSuccess`/`onError` follow-up actions
6
+ * (e.g. `mapples:navigate`) onto the same bus. Renders nothing.
7
+ *
8
+ * Must be rendered inside both `RequestProvider` and `ActionProvider`.
9
+ */
10
+ declare const RequestActionHandler: () => null;
11
+ export default RequestActionHandler;
12
+ //# sourceMappingURL=RequestActionHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestActionHandler.d.ts","sourceRoot":"","sources":["../src/RequestActionHandler.tsx"],"names":[],"mappings":"AAWA;;;;;;;;GAQG;AACH,QAAA,MAAM,oBAAoB,YAuFzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -0,0 +1,97 @@
1
+ import { useEffect } from 'react';
2
+ import { useActionStore } from '@mapples/action';
3
+ import { useDataState } from '@mapples/state';
4
+ import { toRequestCommand } from './actionCommands';
5
+ import { useRequestRuntime } from './RequestProvider';
6
+ /** Artificial latency for sample mode so loading states are visible. */
7
+ const SAMPLE_DELAY_MS = 500;
8
+ /**
9
+ * Bridges the `@mapples/action` store to request execution: subscribes to
10
+ * emitted actions, resolves `mapples:request` actions into commands, executes
11
+ * them (sample or real fetch), stores responses via the surrounding
12
+ * `RequestProvider`, and re-emits `onSuccess`/`onError` follow-up actions
13
+ * (e.g. `mapples:navigate`) onto the same bus. Renders nothing.
14
+ *
15
+ * Must be rendered inside both `RequestProvider` and `ActionProvider`.
16
+ */
17
+ const RequestActionHandler = () => {
18
+ const actionStore = useActionStore();
19
+ const runtime = useRequestRuntime();
20
+ const { getValue } = useDataState();
21
+ useEffect(() => {
22
+ if (!runtime?.document)
23
+ return;
24
+ const { document, mode, secrets, setResponse } = runtime;
25
+ const emitFollowUp = (followUp) => {
26
+ if (!followUp?.type)
27
+ return;
28
+ actionStore.next({
29
+ time: Date.now(),
30
+ type: followUp.type,
31
+ payload: { data: followUp.data },
32
+ });
33
+ };
34
+ const execute = async (command) => {
35
+ setResponse(command.stateKey, { loading: true });
36
+ if (mode === 'sample') {
37
+ setTimeout(() => {
38
+ setResponse(command.stateKey, {
39
+ loading: false,
40
+ data: command.responseSample ?? null,
41
+ status: 200,
42
+ });
43
+ emitFollowUp(command.onSuccess);
44
+ }, SAMPLE_DELAY_MS);
45
+ return;
46
+ }
47
+ try {
48
+ const response = await fetch(command.url, {
49
+ method: command.method,
50
+ headers: command.headers,
51
+ body: command.body !== undefined
52
+ ? JSON.stringify(command.body)
53
+ : undefined,
54
+ });
55
+ // Only bodies that declare JSON are parsed. A body that claims JSON and
56
+ // fails to parse is a broken server contract, so the parse error is left
57
+ // to reach the handler below instead of quietly becoming `null` data.
58
+ const contentType = response.headers.get('content-type') ?? '';
59
+ const data = contentType.includes('json')
60
+ ? await response.json()
61
+ : null;
62
+ setResponse(command.stateKey, {
63
+ loading: false,
64
+ data,
65
+ status: response.status,
66
+ error: response.ok ? undefined : `HTTP ${response.status}`,
67
+ });
68
+ emitFollowUp(response.ok ? command.onSuccess : command.onError);
69
+ }
70
+ catch (error) {
71
+ // A network/CORS/parse failure is a failed request. It is reported as
72
+ // one: no sample data is substituted for the real response, and only
73
+ // the configured error follow-up runs — never `onSuccess`, which would
74
+ // advance the flow as if the request had worked.
75
+ setResponse(command.stateKey, {
76
+ loading: false,
77
+ data: null,
78
+ error: error instanceof Error ? error.message : 'Request failed',
79
+ });
80
+ emitFollowUp(command.onError);
81
+ }
82
+ };
83
+ const subscription = actionStore.subscribe((action) => {
84
+ const command = toRequestCommand(action, document, {
85
+ getStateValue: (path) => getValue({ key: path, active: true }),
86
+ secrets,
87
+ });
88
+ if (!command)
89
+ return;
90
+ void execute(command);
91
+ });
92
+ return () => subscription.unsubscribe();
93
+ }, [actionStore, getValue, runtime]);
94
+ return null;
95
+ };
96
+ export default RequestActionHandler;
97
+ //# sourceMappingURL=RequestActionHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestActionHandler.js","sourceRoot":"","sources":["../src/RequestActionHandler.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,35 @@
1
+ import { FC, PropsWithChildren } from 'react';
2
+ import { ApiDocument } from '@mapples/types';
3
+ /** Per-request response state, exposed to bindings under the state key. */
4
+ export interface ResponseState {
5
+ loading: boolean;
6
+ data?: unknown;
7
+ error?: string;
8
+ status?: number;
9
+ }
10
+ export type RequestExecutionMode = 'sample' | 'fetch';
11
+ export interface RequestRuntimeContextType {
12
+ document: ApiDocument | null;
13
+ mode: RequestExecutionMode;
14
+ secrets?: Record<string, string>;
15
+ setResponse: (stateKey: string, state: ResponseState) => void;
16
+ }
17
+ export declare const useRequestRuntime: () => RequestRuntimeContextType | null;
18
+ export interface RequestProviderProps {
19
+ document?: ApiDocument | null;
20
+ /** Base state the responses are merged over. */
21
+ state?: object;
22
+ /** `sample` resolves `responseSample`s; `fetch` performs real requests. */
23
+ mode?: RequestExecutionMode;
24
+ secrets?: Record<string, string>;
25
+ }
26
+ /**
27
+ * Holds API response state and republishes it through `@mapples/state`, so
28
+ * bindings like `api.login.data.user.name` and conditions like
29
+ * `api.login.loading::eq::true` resolve with zero changes to the state
30
+ * package. Pair with `RequestActionHandler` (rendered as a child) to execute
31
+ * `mapples:request` actions.
32
+ */
33
+ declare const RequestProvider: FC<PropsWithChildren<RequestProviderProps>>;
34
+ export default RequestProvider;
35
+ //# sourceMappingURL=RequestProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestProvider.d.ts","sourceRoot":"","sources":["../src/RequestProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,EAAE,EACF,iBAAiB,EAKlB,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,oBAAoB,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,EAAE,WAAW,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,oBAAoB,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,WAAW,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;CAC/D;AAMD,eAAO,MAAM,iBAAiB,wCAA0C,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IAC9B,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED;;;;;;GAMG;AACH,QAAA,MAAM,eAAe,EAAE,EAAE,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAoChE,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { createContext, useCallback, useContext, useMemo, useState, } from 'react';
2
+ import StateProvider from '@mapples/state';
3
+ import { cloneDeep, set } from 'lodash';
4
+ const RequestRuntimeContext = createContext(null);
5
+ export const useRequestRuntime = () => useContext(RequestRuntimeContext);
6
+ /**
7
+ * Holds API response state and republishes it through `@mapples/state`, so
8
+ * bindings like `api.login.data.user.name` and conditions like
9
+ * `api.login.loading::eq::true` resolve with zero changes to the state
10
+ * package. Pair with `RequestActionHandler` (rendered as a child) to execute
11
+ * `mapples:request` actions.
12
+ */
13
+ const RequestProvider = ({ children, document = null, state, mode = 'sample', secrets, }) => {
14
+ const [responses, setResponses] = useState({});
15
+ const setResponse = useCallback((stateKey, response) => {
16
+ setResponses((prev) => ({ ...prev, [stateKey]: response }));
17
+ }, []);
18
+ // State keys are dot paths (`api.login`) — expand them into the nested
19
+ // object shape @mapples/state resolves against.
20
+ const mergedState = useMemo(() => {
21
+ const result = cloneDeep(state ?? {});
22
+ for (const [stateKey, response] of Object.entries(responses)) {
23
+ set(result, stateKey, response);
24
+ }
25
+ return result;
26
+ }, [responses, state]);
27
+ const contextValue = useMemo(() => ({ document, mode, secrets, setResponse }), [document, mode, secrets, setResponse]);
28
+ return (<RequestRuntimeContext value={contextValue}>
29
+ <StateProvider state={mergedState}>{children}</StateProvider>
30
+ </RequestRuntimeContext>);
31
+ };
32
+ export default RequestProvider;
33
+ //# sourceMappingURL=RequestProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RequestProvider.js","sourceRoot":"","sources":["../src/RequestProvider.tsx"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAGb,WAAW,EACX,UAAU,EACV,OAAO,EACP,QAAQ,GACT,MAAM,OAAO,CAAC;AAEf,OAAO,aAAa,MAAM,gBAAgB,CAAC;AAE3C,OAAO,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,QAAQ,CAAC;AAmBxC,MAAM,qBAAqB,GAAG,aAAa,CACzC,IAAI,CACL,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,EAAE,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC;AAWzE;;;;;;GAMG;AACH,MAAM,eAAe,GAAgD,CAAC,EACpE,QAAQ,EACR,QAAQ,GAAG,IAAI,EACf,KAAK,EACL,IAAI,GAAG,QAAQ,EACf,OAAO,GACR,EAAE,EAAE;IACH,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAgC,EAAE,CAAC,CAAC;IAE9E,MAAM,WAAW,GAAG,WAAW,CAC7B,CAAC,QAAgB,EAAE,QAAuB,EAAE,EAAE;QAC5C,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC;IAC9D,CAAC,EACD,EAAE,CACH,CAAC;IAEF,uEAAuE;IACvE,gDAAgD;IAChD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,EAAE;QAC/B,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;QACtC,KAAK,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7D,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAClC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,EAAE,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC;IAEvB,MAAM,YAAY,GAAG,OAAO,CAC1B,GAAG,EAAE,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,EAChD,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,CAAC,CACvC,CAAC;IAEF,OAAO,CACL,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CACzC;MAAA,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,aAAa,CAC9D;IAAA,EAAE,qBAAqB,CAAC,CACzB,CAAC;AACJ,CAAC,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { Action, ApiDocument, HttpMethod } from '@mapples/types';
2
+ /** A follow-up action re-emitted after the request settles. */
3
+ export interface FollowUpAction {
4
+ type: string;
5
+ data?: unknown;
6
+ }
7
+ /** A fully-resolved request, ready to execute. */
8
+ export interface RequestCommand {
9
+ requestId: string;
10
+ stateKey: string;
11
+ url: string;
12
+ method: HttpMethod;
13
+ headers: Record<string, string>;
14
+ body?: unknown;
15
+ responseSample?: unknown;
16
+ onSuccess?: FollowUpAction;
17
+ onError?: FollowUpAction;
18
+ }
19
+ /** Everything value resolution may need at emit time. */
20
+ export interface RequestResolutionContext {
21
+ /** Resolves `state`-kind value sources (a `@mapples/state` lookup). */
22
+ getStateValue?: (path: string) => unknown;
23
+ /** Secrets by `secretRef`, resolved by the host — never stored. */
24
+ secrets?: Record<string, string>;
25
+ }
26
+ /**
27
+ * Maps a `mapples:request` action to an executable {@link RequestCommand} —
28
+ * pure and unit-testable; returns null for anything else or when the request
29
+ * id doesn't resolve.
30
+ */
31
+ export declare const toRequestCommand: (action: Action, document: ApiDocument, context?: RequestResolutionContext) => RequestCommand | null;
32
+ //# sourceMappingURL=actionCommands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionCommands.d.ts","sourceRoot":"","sources":["../src/actionCommands.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,MAAM,EACN,WAAW,EAIX,UAAU,EACX,MAAM,gBAAgB,CAAC;AAKxB,+DAA+D;AAC/D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,UAAU,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B,OAAO,CAAC,EAAE,cAAc,CAAC;CAC1B;AAED,yDAAyD;AACzD,MAAM,WAAW,wBAAwB;IACvC,uEAAuE;IACvE,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;IAC1C,mEAAmE;IACnE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AA2FD;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,QAAQ,MAAM,EACd,UAAU,WAAW,EACrB,UAAS,wBAA6B,KACrC,cAAc,GAAG,IAiEnB,CAAC"}
@@ -0,0 +1,113 @@
1
+ import { apiRequestStateKey, } from '@mapples/types';
2
+ import { get, isPlainObject } from 'lodash';
3
+ import { RequestActionType } from './constants';
4
+ const isValueSource = (value) => isPlainObject(value) &&
5
+ ['static', 'state', 'event'].includes(value.kind ?? '');
6
+ const resolveSource = (source, action, context) => {
7
+ switch (source.kind) {
8
+ case 'static':
9
+ return source.value;
10
+ case 'state':
11
+ return context.getStateValue?.(source.dataProp);
12
+ case 'event': {
13
+ const payload = action.payload?.data;
14
+ return source.path ? get(payload, source.path) : payload;
15
+ }
16
+ }
17
+ };
18
+ const resolveTemplate = (template, action, context) => {
19
+ if (isValueSource(template)) {
20
+ return resolveSource(template, action, context);
21
+ }
22
+ if (Array.isArray(template)) {
23
+ return template.map((entry) => resolveTemplate(entry, action, context));
24
+ }
25
+ if (isPlainObject(template)) {
26
+ const result = {};
27
+ for (const [key, value] of Object.entries(template)) {
28
+ result[key] = resolveTemplate(value, action, context);
29
+ }
30
+ return result;
31
+ }
32
+ return template;
33
+ };
34
+ /** Interpolates `{{variable}}` templates from environment variables. */
35
+ const interpolate = (input, variables) => input.replace(/\{\{([^}]+)\}\}/g, (match, name) => {
36
+ const value = variables?.[name.trim()];
37
+ return value !== undefined ? value : match;
38
+ });
39
+ const buildUrl = (request, baseUrl, variables, action, context) => {
40
+ let path = interpolate(request.path, variables);
41
+ const query = [];
42
+ for (const [key, source] of Object.entries(request.params ?? {})) {
43
+ const value = resolveSource(source, action, context);
44
+ const encoded = encodeURIComponent(String(value ?? ''));
45
+ if (path.includes(`{${key}}`)) {
46
+ path = path.replaceAll(`{${key}}`, encoded);
47
+ }
48
+ else {
49
+ query.push(`${encodeURIComponent(key)}=${encoded}`);
50
+ }
51
+ }
52
+ const absolute = /^https?:\/\//i.test(path)
53
+ ? path
54
+ : `${interpolate(baseUrl, variables).replace(/\/$/, '')}${path.startsWith('/') ? '' : '/'}${path}`;
55
+ return query.length > 0
56
+ ? `${absolute}${absolute.includes('?') ? '&' : '?'}${query.join('&')}`
57
+ : absolute;
58
+ };
59
+ /**
60
+ * Maps a `mapples:request` action to an executable {@link RequestCommand} —
61
+ * pure and unit-testable; returns null for anything else or when the request
62
+ * id doesn't resolve.
63
+ */
64
+ export const toRequestCommand = (action, document, context = {}) => {
65
+ if (action.type !== RequestActionType.Execute)
66
+ return null;
67
+ const data = (action.payload?.data ?? {});
68
+ if (!data.requestId)
69
+ return null;
70
+ const request = document.requests[data.requestId];
71
+ if (!request)
72
+ return null;
73
+ const environment = (document.activeEnvironmentId
74
+ ? document.environments[document.activeEnvironmentId]
75
+ : undefined) ?? Object.values(document.environments)[0];
76
+ const variables = environment?.variables;
77
+ const headers = {
78
+ ...environment?.headers,
79
+ ...request.headers,
80
+ };
81
+ for (const [key, value] of Object.entries(headers)) {
82
+ headers[key] = interpolate(value, variables);
83
+ }
84
+ if (request.auth && request.auth.kind !== 'none' && request.auth.secretRef) {
85
+ const secret = context.secrets?.[request.auth.secretRef];
86
+ if (secret !== undefined) {
87
+ if (request.auth.kind === 'bearer') {
88
+ headers.Authorization = `Bearer ${secret}`;
89
+ }
90
+ else {
91
+ headers[request.auth.header ?? 'Authorization'] = secret;
92
+ }
93
+ }
94
+ }
95
+ const body = request.body
96
+ ? resolveTemplate(request.body.template, action, context)
97
+ : undefined;
98
+ if (body !== undefined && !headers['Content-Type']) {
99
+ headers['Content-Type'] = 'application/json';
100
+ }
101
+ return {
102
+ requestId: request.id,
103
+ stateKey: apiRequestStateKey(request),
104
+ url: buildUrl(request, environment?.baseUrl ?? '', variables, action, context),
105
+ method: request.method,
106
+ headers,
107
+ body,
108
+ responseSample: request.responseSample,
109
+ onSuccess: data.onSuccess,
110
+ onError: data.onError,
111
+ };
112
+ };
113
+ //# sourceMappingURL=actionCommands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionCommands.js","sourceRoot":"","sources":["../src/actionCommands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Action `type` strings handled by the request runtime. Components wire these
3
+ * to interactions via `actionProps` and emit them through the
4
+ * `@mapples/action` store.
5
+ */
6
+ export declare const RequestActionType: {
7
+ /**
8
+ * Execute an API request. `payload.data: { requestId, onSuccess?,
9
+ * onError? }` — the follow-up actions are re-emitted onto the action bus
10
+ * after the request settles (e.g. a `mapples:navigate`).
11
+ */
12
+ readonly Execute: "mapples:request";
13
+ };
14
+ export type RequestActionTypeValue = (typeof RequestActionType)[keyof typeof RequestActionType];
15
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,eAAO,MAAM,iBAAiB;IAC5B;;;;OAIG;;CAEK,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,OAAO,iBAAiB,CAAC,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Action `type` strings handled by the request runtime. Components wire these
3
+ * to interactions via `actionProps` and emit them through the
4
+ * `@mapples/action` store.
5
+ */
6
+ export const RequestActionType = {
7
+ /**
8
+ * Execute an API request. `payload.data: { requestId, onSuccess?,
9
+ * onError? }` — the follow-up actions are re-emitted onto the action bus
10
+ * after the request settles (e.g. a `mapples:navigate`).
11
+ */
12
+ Execute: 'mapples:request',
13
+ };
14
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B;;;;OAIG;IACH,OAAO,EAAE,iBAAiB;CAClB,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @fileoverview Runtime for the Mapples `ApiDocument`: executes
3
+ * `mapples:request` actions (sample or real fetch), publishes responses into
4
+ * `@mapples/state`, and chains follow-up actions on the action bus.
5
+ */
6
+ export { default as RequestProvider } from './RequestProvider';
7
+ export { useRequestRuntime } from './RequestProvider';
8
+ export type { RequestExecutionMode, RequestProviderProps, RequestRuntimeContextType, ResponseState, } from './RequestProvider';
9
+ export { default as RequestActionHandler } from './RequestActionHandler';
10
+ export * from './actionCommands';
11
+ export * from './constants';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACtD,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,yBAAyB,EACzB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEzE,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,11 @@
1
+ /**
2
+ * @fileoverview Runtime for the Mapples `ApiDocument`: executes
3
+ * `mapples:request` actions (sample or real fetch), publishes responses into
4
+ * `@mapples/state`, and chains follow-up actions on the action bus.
5
+ */
6
+ export { default as RequestProvider } from './RequestProvider';
7
+ export { useRequestRuntime } from './RequestProvider';
8
+ export { default as RequestActionHandler } from './RequestActionHandler';
9
+ export * from './actionCommands';
10
+ export * from './constants';
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAC/D,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAOtD,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEzE,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC"}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@mapples/request",
3
+ "version": "0.1.0",
4
+ "main": "dist/index.js",
5
+ "types": "dist/index.d.ts",
6
+ "scripts": {
7
+ "build": "tsc -b tsconfig.build.json",
8
+ "lint": "eslint .",
9
+ "type-check": "tsc --noEmit",
10
+ "clean": "rm -rf dist"
11
+ },
12
+ "author": {
13
+ "name": "Oleksandr Soloviov",
14
+ "url": "https://mapples.org/people/olek_soloviov"
15
+ },
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/mapplesorg/mapples-open-kit.git",
20
+ "directory": "packages/@mapples/request"
21
+ },
22
+ "peerDependencies": {
23
+ "@mapples/action": "*",
24
+ "@mapples/state": "*",
25
+ "@mapples/types": "*",
26
+ "lodash": "^4.18.0",
27
+ "react": ">=18.0.0 <20.0.0",
28
+ "rxjs": "^7.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/react": ">=18.0.0 <20.0.0",
32
+ "typescript": "~6.0.3"
33
+ },
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "package.json"
38
+ ]
39
+ }