@brytdesigns/shopify-ajax-client 1.0.8 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main/LoggerUtils.js +18 -8
- package/dist/main/LoggerUtils.js.map +1 -1
- package/dist/main/Request.js +200 -0
- package/dist/main/Request.js.map +1 -0
- package/dist/main/_virtual/_rolldown/runtime.js +13 -0
- package/dist/main/errors.js +58 -18
- package/dist/main/errors.js.map +1 -1
- package/dist/main/index.d.ts +261 -71
- package/dist/main/index.js +8 -184
- package/dist/main/index.js.map +1 -1
- package/package.json +9 -15
- package/dist/esm/index.js +0 -17682
- package/dist/esm/index.js.map +0 -1
- package/dist/main/AjaxClientResponse.js +0 -9
- package/dist/main/AjaxClientResponse.js.map +0 -1
package/dist/main/index.d.ts
CHANGED
|
@@ -1,11 +1,115 @@
|
|
|
1
1
|
// Generated by dts-bundle-generator v9.5.1
|
|
2
2
|
|
|
3
|
-
import * as
|
|
3
|
+
import * as Cause from 'effect/Cause';
|
|
4
|
+
import * as Context from 'effect/Context';
|
|
4
5
|
import * as Data from 'effect/Data';
|
|
5
6
|
import * as Effect from 'effect/Effect';
|
|
7
|
+
import { HttpClient } from 'effect/http';
|
|
8
|
+
import * as Layer from 'effect/Layer';
|
|
6
9
|
import * as LogLevel from 'effect/LogLevel';
|
|
10
|
+
import * as Pipeable from 'effect/Pipeable';
|
|
7
11
|
import * as Schema from 'effect/Schema';
|
|
12
|
+
import * as Scope from 'effect/Scope';
|
|
8
13
|
|
|
14
|
+
/**
|
|
15
|
+
* The shape Shopify returns in a non-200 response body.
|
|
16
|
+
*
|
|
17
|
+
* Distinct from {@link AjaxResponseError}: this is plain decoded JSON, that is
|
|
18
|
+
* the tagged error we raise from it. v3's looser response types let the two be
|
|
19
|
+
* conflated by a cast; v4 does not.
|
|
20
|
+
*/
|
|
21
|
+
export interface AjaxErrorBody {
|
|
22
|
+
status: number;
|
|
23
|
+
message: string;
|
|
24
|
+
description: string;
|
|
25
|
+
}
|
|
26
|
+
declare const AjaxResponseError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{
|
|
27
|
+
readonly [P in keyof A as P extends "_tag" ? never : P]: A[P];
|
|
28
|
+
}>) => import("effect/Cause").YieldableError & {
|
|
29
|
+
readonly _tag: "@brytdesigns/ajax-client/AjaxResponseError";
|
|
30
|
+
} & Readonly<A>;
|
|
31
|
+
/**
|
|
32
|
+
* A non-200 response from a Shopify Ajax route.
|
|
33
|
+
*
|
|
34
|
+
* This is the error channel's version of what used to be
|
|
35
|
+
* `AjaxClientResponse.error`. The envelope made every failure look like a
|
|
36
|
+
* success carrying an error payload, so each of the nine call sites in
|
|
37
|
+
* `shopify-ajax-cart` re-raised it by hand — with `throw response.error`,
|
|
38
|
+
* which threw a plain object with no stack and no `_tag`. Failing properly
|
|
39
|
+
* means `Effect.catchTag("...AjaxResponseError", ...)` works upstream, and
|
|
40
|
+
* `instanceof` works for plain-JS consumers once the facade squashes it.
|
|
41
|
+
*
|
|
42
|
+
* `route` is carried because the status and message alone rarely identify
|
|
43
|
+
* which request failed when several are in flight.
|
|
44
|
+
*/
|
|
45
|
+
export declare class AjaxResponseError extends AjaxResponseError_base<{
|
|
46
|
+
status: number;
|
|
47
|
+
message: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
route: string;
|
|
50
|
+
}> {
|
|
51
|
+
}
|
|
52
|
+
declare const InvalidAjaxMethodError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{
|
|
53
|
+
readonly [P in keyof A as P extends "_tag" ? never : P]: A[P];
|
|
54
|
+
}>) => import("effect/Cause").YieldableError & {
|
|
55
|
+
readonly _tag: "@brytdesigns/ajax-client/InvalidAjaxMethodError";
|
|
56
|
+
} & Readonly<A>;
|
|
57
|
+
/**
|
|
58
|
+
* A route was declared with an HTTP method this client cannot issue.
|
|
59
|
+
*
|
|
60
|
+
* Not reachable while every route in `METHODS_BY_URL` is `get` or `post`, which
|
|
61
|
+
* is all of them today. It is what `execute`'s method dispatch fails with if
|
|
62
|
+
* that stops being true. The alternative — a POST-or-else-GET fallback — would
|
|
63
|
+
* quietly issue a GET for a route declared as anything else.
|
|
64
|
+
*/
|
|
65
|
+
export declare class InvalidAjaxMethodError extends InvalidAjaxMethodError_base<{
|
|
66
|
+
message: string;
|
|
67
|
+
}> {
|
|
68
|
+
constructor();
|
|
69
|
+
}
|
|
70
|
+
declare const UnsafeAjaxRouteError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{
|
|
71
|
+
readonly [P in keyof A as P extends "_tag" ? never : P]: A[P];
|
|
72
|
+
}>) => import("effect/Cause").YieldableError & {
|
|
73
|
+
readonly _tag: "@brytdesigns/ajax-client/UnsafeAjaxRouteError";
|
|
74
|
+
} & Readonly<A>;
|
|
75
|
+
/**
|
|
76
|
+
* A route in the table did not resolve to the storefront origin.
|
|
77
|
+
*
|
|
78
|
+
* The table is `{ ...Defaults, ...window.BrytDesigns.routes }`, so anything
|
|
79
|
+
* that can set that global contributes paths which every cart request is then
|
|
80
|
+
* sent to — with the shopper's session cookies attached. The old
|
|
81
|
+
* `` `${origin}${route}` `` concatenation made that an off-origin POST for a
|
|
82
|
+
* route as unremarkable-looking as `"@evil.com/collect"`, because
|
|
83
|
+
* `https://shop.myshopify.com@evil.com/collect` parses `shop.myshopify.com`
|
|
84
|
+
* as userinfo and `evil.com` as the host.
|
|
85
|
+
*
|
|
86
|
+
* Calibration: whoever can write `window.BrytDesigns.routes` can usually
|
|
87
|
+
* patch `fetch` too, so this is defence in depth rather than a privilege
|
|
88
|
+
* boundary. It earns its place by also catching the honest typo — a route of
|
|
89
|
+
* `"cart.js"` concatenated to an origin yielded
|
|
90
|
+
* `https://shop.myshopify.comcart.js`, which fails as a DNS error somewhere
|
|
91
|
+
* far from the mistake.
|
|
92
|
+
*/
|
|
93
|
+
export declare class UnsafeAjaxRouteError extends UnsafeAjaxRouteError_base<{
|
|
94
|
+
message: string;
|
|
95
|
+
route: string;
|
|
96
|
+
routeName: string;
|
|
97
|
+
origin: string;
|
|
98
|
+
}> {
|
|
99
|
+
constructor(options: {
|
|
100
|
+
route: string;
|
|
101
|
+
routeName: string;
|
|
102
|
+
origin: string;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
declare const Input: Schema.Struct<{
|
|
106
|
+
readonly sections: Schema.optional<Schema.decodeTo<Schema.String, Schema.$Array<Schema.String>, never, never>>;
|
|
107
|
+
readonly sections_url: Schema.optional<Schema.String>;
|
|
108
|
+
}>;
|
|
109
|
+
export type UniqueKeys<T extends string> = T extends `${infer K},${infer Rest}` ? K | UniqueKeys<Rest> : T;
|
|
110
|
+
declare function makeResponseSchema<const T extends string>(input: T): Schema.$Record<Schema.Literals<UniqueKeys<T>[]>, Schema.NullOr<Schema.decodeTo<Schema.instanceOf<Element, Element>, Schema.String, never, never>>>;
|
|
111
|
+
declare const Origins: Context.Reference<readonly string[]>;
|
|
112
|
+
declare const layer$1: (origins: readonly string[]) => Layer.Layer<never>;
|
|
9
113
|
export interface IShopifyRoutes {
|
|
10
114
|
readonly account_addresses_url: string;
|
|
11
115
|
readonly account_login_url: string;
|
|
@@ -38,94 +142,180 @@ declare class ShopifyRoutes extends Data.Class<IShopifyRoutes> {
|
|
|
38
142
|
constructor();
|
|
39
143
|
}
|
|
40
144
|
declare const make: () => ShopifyRoutes;
|
|
145
|
+
declare const Routes: Context.Reference<IShopifyRoutes>;
|
|
146
|
+
declare const layer$2: (routes: IShopifyRoutes) => Layer.Layer<never>;
|
|
41
147
|
declare class StorefrontClientConfig extends Data.Class<IStorefrontClientConfig> {
|
|
42
148
|
constructor();
|
|
43
149
|
}
|
|
44
150
|
declare const make$1: () => StorefrontClientConfig;
|
|
45
|
-
declare const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
declare
|
|
51
|
-
|
|
52
|
-
|
|
151
|
+
declare const Origin: Context.Reference<string>;
|
|
152
|
+
declare const layer$3: (origin: string) => Layer.Layer<never>;
|
|
153
|
+
declare namespace Sections {
|
|
154
|
+
export { Input, makeResponseSchema };
|
|
155
|
+
}
|
|
156
|
+
declare namespace StorefrontOrigin {
|
|
157
|
+
export { Origin, layer$3 as layer$3 };
|
|
158
|
+
}
|
|
159
|
+
declare namespace AllowedRouteOrigins {
|
|
160
|
+
export { Origins, layer$1 as layer$1 };
|
|
53
161
|
}
|
|
54
162
|
declare namespace ShopifyRoutes$1 {
|
|
55
|
-
export { Defaults, ShopifyRoutes, make };
|
|
163
|
+
export { Defaults, Routes, ShopifyRoutes, layer$2 as layer$2, make };
|
|
56
164
|
}
|
|
57
|
-
declare namespace
|
|
58
|
-
export {
|
|
165
|
+
declare namespace StorefrontClientConfig$1 {
|
|
166
|
+
export { StorefrontClientConfig, make$1 as make$1 };
|
|
59
167
|
}
|
|
60
|
-
declare namespace
|
|
61
|
-
export {
|
|
168
|
+
declare namespace Window$1 {
|
|
169
|
+
export { AllowedRouteOrigins, ShopifyRoutes$1 as ShopifyRoutes$1, StorefrontClientConfig$1 as StorefrontClientConfig$1, StorefrontOrigin };
|
|
62
170
|
}
|
|
63
171
|
declare namespace Ajax {
|
|
64
172
|
export { Sections, Window$1 as Window$1 };
|
|
65
173
|
}
|
|
66
174
|
/**
|
|
67
|
-
*
|
|
175
|
+
* Every route's input extends Shopify's `sections` pair, decoded.
|
|
68
176
|
*
|
|
69
|
-
*
|
|
177
|
+
* Constraining the descriptor on this is what lets {@link execute} read
|
|
178
|
+
* `decodedInput.sections` and {@link withSections} write it without a cast.
|
|
70
179
|
*/
|
|
71
|
-
export
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
* The HTTP status code of the error response.
|
|
82
|
-
*/
|
|
83
|
-
status: number;
|
|
84
|
-
/**
|
|
85
|
-
* A brief description of the error.
|
|
86
|
-
*/
|
|
87
|
-
message: string;
|
|
88
|
-
/**
|
|
89
|
-
* A more detailed description of the error.
|
|
90
|
-
*/
|
|
91
|
-
description?: string;
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
declare class AjaxClientResponse<TData = any> extends Data.Class<IAjaxClientResponse<TData>> {
|
|
95
|
-
}
|
|
180
|
+
export type AjaxInput = typeof Ajax.Sections.Input.Type;
|
|
181
|
+
/**
|
|
182
|
+
* The same input, encoded — which is what a descriptor actually carries.
|
|
183
|
+
*
|
|
184
|
+
* Worth stating plainly because the two differ in a way that bites:
|
|
185
|
+
* `sections` decodes from `ReadonlyArray<string>` to a comma-joined `string`,
|
|
186
|
+
* so the encoded side is the array. A descriptor holds encoded input, so
|
|
187
|
+
* {@link withSections} takes the array form.
|
|
188
|
+
*/
|
|
189
|
+
export type AjaxInputEncoded = typeof Ajax.Sections.Input.Encoded;
|
|
96
190
|
declare const BaseOutputSchema: Schema.Struct<{}>;
|
|
97
|
-
declare const ProductInputSchema: Schema.
|
|
98
|
-
sections: Schema.optional<Schema.
|
|
99
|
-
sections_url: Schema.optional<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
191
|
+
declare const ProductInputSchema: Schema.Struct<{
|
|
192
|
+
readonly sections: Schema.optional<Schema.decodeTo<Schema.String, Schema.$Array<Schema.String>, never, never>>;
|
|
193
|
+
readonly sections_url: Schema.optional<Schema.String>;
|
|
194
|
+
readonly handle: Schema.String;
|
|
195
|
+
}>;
|
|
196
|
+
declare const METHODS_BY_URL: {
|
|
197
|
+
readonly products_url: "get";
|
|
198
|
+
readonly product_url: "get";
|
|
199
|
+
readonly predictive_search_url: "get";
|
|
200
|
+
readonly product_recommendations_url: "get";
|
|
201
|
+
readonly cart_add_url: "post";
|
|
202
|
+
readonly cart_update_url: "post";
|
|
203
|
+
readonly cart_url: "get";
|
|
204
|
+
readonly cart_change_url: "post";
|
|
205
|
+
readonly cart_clear_url: "post";
|
|
206
|
+
};
|
|
207
|
+
export type ValidAjaxRoutes = keyof typeof METHODS_BY_URL;
|
|
208
|
+
declare const TypeIdSymbol: unique symbol;
|
|
209
|
+
export type TypeId = typeof TypeIdSymbol;
|
|
210
|
+
/**
|
|
211
|
+
* A description of a Shopify Ajax request, before it is run.
|
|
212
|
+
*
|
|
213
|
+
* The reason this type exists at all: headers, sections and input are consumed
|
|
214
|
+
* *inside* the request effect, so there is nothing to modify once that effect
|
|
215
|
+
* has been constructed. `pipe(getCart(), withHeaders(...))` can only work if
|
|
216
|
+
* the thing in the pipe is a description rather than an `Effect`. {@link execute}
|
|
217
|
+
* is where the description becomes one.
|
|
218
|
+
*/
|
|
219
|
+
export interface AjaxRequest<A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD> extends Pipeable.Pipeable {
|
|
220
|
+
readonly [TypeIdSymbol]: TypeId;
|
|
221
|
+
readonly routeName: ValidAjaxRoutes;
|
|
222
|
+
readonly inputSchema: Schema.Codec<A, I, RD>;
|
|
223
|
+
readonly outputSchema: (sections?: string) => Schema.Codec<B, J, SD>;
|
|
224
|
+
readonly input: I;
|
|
225
|
+
readonly headers: Readonly<Record<string, string>>;
|
|
226
|
+
}
|
|
227
|
+
/** Narrows an unknown value to an {@link AjaxRequest}. */
|
|
228
|
+
export declare const isAjaxRequest: (u: unknown) => u is AjaxRequest<AjaxInput, AjaxInputEncoded, unknown, unknown, unknown, unknown>;
|
|
105
229
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
*
|
|
112
|
-
* @
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
230
|
+
* Builds a route constructor.
|
|
231
|
+
*
|
|
232
|
+
* Replaces `makeFactory`. The difference is only in what the returned function
|
|
233
|
+
* gives back: a description that can be piped through the combinators below,
|
|
234
|
+
* rather than an `Effect` that is already closed over its headers.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* ```ts
|
|
238
|
+
* const getCart = Request.makeRoute({
|
|
239
|
+
* routeName: "cart_url",
|
|
240
|
+
* inputSchema: CartGetInput,
|
|
241
|
+
* outputSchema: makeCartOutput,
|
|
242
|
+
* });
|
|
243
|
+
*
|
|
244
|
+
* pipe(
|
|
245
|
+
* getCart(),
|
|
246
|
+
* Request.withSections("cart-drawer"),
|
|
247
|
+
* Request.withHeader("X-Foo", "1"),
|
|
248
|
+
* Request.execute,
|
|
249
|
+
* );
|
|
250
|
+
* ```
|
|
122
251
|
*/
|
|
123
|
-
export declare const
|
|
252
|
+
export declare const makeRoute: <RouteName extends ValidAjaxRoutes, A extends RouteName extends "product_url" ? typeof ProductInputSchema.Type : AjaxInput, I extends AjaxInputEncoded, RD, B extends typeof BaseOutputSchema.Type, J, SD>({ routeName, inputSchema, outputSchema, }: {
|
|
124
253
|
routeName: RouteName;
|
|
125
|
-
inputSchema: Schema.
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
254
|
+
inputSchema: Schema.Codec<A, I, RD>;
|
|
255
|
+
/**
|
|
256
|
+
* Built per request from the caller's `sections` input.
|
|
257
|
+
*
|
|
258
|
+
* v4's schema extension (`fieldsAssign` / `extendTo`) only applies to a
|
|
259
|
+
* `Struct`, and output schemas here are transforms. Composing the
|
|
260
|
+
* sections field is therefore the caller's job - it holds the
|
|
261
|
+
* pre-transform struct and can extend that instead.
|
|
262
|
+
*/
|
|
263
|
+
outputSchema: (sections?: string) => Schema.Codec<B, J, SD>;
|
|
264
|
+
}) => (input?: I) => AjaxRequest<A, I, RD, B, J, SD>;
|
|
265
|
+
/**
|
|
266
|
+
* Merges headers into the request, right-biased.
|
|
267
|
+
*
|
|
268
|
+
* Dual: `withHeaders(request, h)` and `pipe(request, withHeaders(h))` are the
|
|
269
|
+
* same call.
|
|
270
|
+
*/
|
|
271
|
+
export declare const withHeaders: {
|
|
272
|
+
(headers: Readonly<Record<string, string>>): <A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>) => AjaxRequest<A, I, RD, B, J, SD>;
|
|
273
|
+
<A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>, headers: Readonly<Record<string, string>>): AjaxRequest<A, I, RD, B, J, SD>;
|
|
274
|
+
};
|
|
275
|
+
/** Sets a single header. Dual. */
|
|
276
|
+
export declare const withHeader: {
|
|
277
|
+
(name: string, value: string): <A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>) => AjaxRequest<A, I, RD, B, J, SD>;
|
|
278
|
+
<A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>, name: string, value: string): AjaxRequest<A, I, RD, B, J, SD>;
|
|
279
|
+
};
|
|
280
|
+
/** Replaces the request input wholesale. Dual. */
|
|
281
|
+
export declare const withInput: {
|
|
282
|
+
<I extends AjaxInputEncoded>(input: I): <A extends AjaxInput, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>) => AjaxRequest<A, I, RD, B, J, SD>;
|
|
283
|
+
<A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>, input: I): AjaxRequest<A, I, RD, B, J, SD>;
|
|
284
|
+
};
|
|
285
|
+
/**
|
|
286
|
+
* Asks Shopify to re-render `sections` alongside the response.
|
|
287
|
+
*
|
|
288
|
+
* Sugar over {@link withInput} for the one input field every route shares, and
|
|
289
|
+
* the field {@link AjaxRequest.outputSchema} is keyed on. Dual.
|
|
290
|
+
*/
|
|
291
|
+
export declare const withSections: {
|
|
292
|
+
(sections: string | ReadonlyArray<string>): <A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>) => AjaxRequest<A, I, RD, B, J, SD>;
|
|
293
|
+
<A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>, sections: string | ReadonlyArray<string>): AjaxRequest<A, I, RD, B, J, SD>;
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Runs the description.
|
|
297
|
+
*
|
|
298
|
+
* Named rather than untraced: this is the one place in the package worth a
|
|
299
|
+
* span, and upstream's guidance is to reserve `Effect.fn` for genuine tracing
|
|
300
|
+
* boundaries and prefer `fnUntraced` inside library internals. Transforms are
|
|
301
|
+
* passed as trailing arguments because `Effect.fn` explicitly must not be
|
|
302
|
+
* `.pipe`d.
|
|
303
|
+
*
|
|
304
|
+
* Errors are left as they come. `RequestError`, `ResponseError`, `ParseError`
|
|
305
|
+
* and `HttpBodyError` are already tagged, and flattening them into a plain
|
|
306
|
+
* `Error` — which this package used to do — destroyed the only machine-readable
|
|
307
|
+
* thing about them.
|
|
308
|
+
*/
|
|
309
|
+
export declare const execute: <A extends AjaxInput, I extends AjaxInputEncoded, RD, B, J, SD>(self: AjaxRequest<A, I, RD, B, J, SD>) => Effect.Effect<B, AjaxResponseError | InvalidAjaxMethodError | UnsafeAjaxRouteError | Schema.SchemaError | import("effect/http/HttpClientError").HttpClientError | import("effect/http/HttpBody").HttpBodyError, HttpClient.HttpClient | Exclude<RD, import("effect/Scope").Scope> | Exclude<SD, import("effect/Scope").Scope>>;
|
|
310
|
+
/** Named `layer` per the v4 convention, which replaces v3's `Default`/`Live`. */
|
|
311
|
+
export declare const layer: import("effect/Layer").Layer<import("effect/http/HttpClient").HttpClient, never, never>;
|
|
312
|
+
|
|
313
|
+
declare namespace Request$1 {
|
|
314
|
+
export { AjaxInput, AjaxInputEncoded, AjaxRequest, TypeId, ValidAjaxRoutes, execute, isAjaxRequest, makeRoute, withHeader, withHeaders, withInput, withSections };
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export {
|
|
318
|
+
Request$1 as Request,
|
|
319
|
+
};
|
|
130
320
|
|
|
131
321
|
export {};
|
package/dist/main/index.js
CHANGED
|
@@ -1,186 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
import * as LoggerUtils from './LoggerUtils.js';
|
|
10
|
-
import { InvalidAjaxMethodError } from './errors.js';
|
|
11
|
-
import * as AjaxClientResponse from './AjaxClientResponse.js';
|
|
1
|
+
import { AjaxResponseError, InvalidAjaxMethodError, UnsafeAjaxRouteError } from "./errors.js";
|
|
2
|
+
import { Request_exports, execute, isAjaxRequest, makeRoute, withHeader, withHeaders, withInput, withSections } from "./Request.js";
|
|
3
|
+
import { FetchHttpClient } from "effect/http";
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
/** Named `layer` per the v4 convention, which replaces v3's `Default`/`Live`. */
|
|
6
|
+
var layer = FetchHttpClient.layer;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { AjaxResponseError, InvalidAjaxMethodError, Request_exports as Request, UnsafeAjaxRouteError, execute, isAjaxRequest, layer, makeRoute, withHeader, withHeaders, withInput, withSections };
|
|
12
9
|
|
|
13
|
-
Schema.Struct({});
|
|
14
|
-
Schema.extend(
|
|
15
|
-
Ajax.Sections.Input,
|
|
16
|
-
Schema.Struct({
|
|
17
|
-
handle: Schema.String
|
|
18
|
-
})
|
|
19
|
-
);
|
|
20
|
-
const Default = FetchHttpClient.layer;
|
|
21
|
-
const formatCause = (cause) => {
|
|
22
|
-
if (cause == null) return void 0;
|
|
23
|
-
if (cause instanceof Error) {
|
|
24
|
-
const nested = formatCause(cause.cause);
|
|
25
|
-
const base = `${cause.name}: ${cause.message}`;
|
|
26
|
-
return nested ? `${base} -> ${nested}` : base;
|
|
27
|
-
}
|
|
28
|
-
if (typeof cause === "object") {
|
|
29
|
-
try {
|
|
30
|
-
return JSON.stringify(cause);
|
|
31
|
-
} catch {
|
|
32
|
-
return String(cause);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return String(cause);
|
|
36
|
-
};
|
|
37
|
-
const toError = (error) => {
|
|
38
|
-
if (error._tag === "RequestError" || error._tag === "ResponseError") {
|
|
39
|
-
const detail = formatCause(error.cause);
|
|
40
|
-
const message2 = detail ? `${error.message}: ${detail}` : error.message;
|
|
41
|
-
return Object.assign(new Error(message2, { cause: error.cause }), {
|
|
42
|
-
_tag: error._tag,
|
|
43
|
-
reason: error.reason
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
if (error._tag === "ParseError" || error._tag === "@brytdesigns/ajax-client/InvalidAjaxMethodError") {
|
|
47
|
-
return new Error(error.message, { cause: error.cause });
|
|
48
|
-
}
|
|
49
|
-
if (error._tag === "HttpBodyError") {
|
|
50
|
-
const reason = error.reason;
|
|
51
|
-
if (reason._tag === "JsonError") {
|
|
52
|
-
return new Error("Failed to serialize JSON request body", {
|
|
53
|
-
cause: reason
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
if (reason._tag === "SchemaError") {
|
|
57
|
-
return new Error(reason.error.message, {
|
|
58
|
-
cause: reason.error.cause
|
|
59
|
-
});
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
const message = formatCause(error) ?? error?.message ?? error?.toString?.() ?? String(error);
|
|
63
|
-
return new Error(message, { cause: error });
|
|
64
|
-
};
|
|
65
|
-
const METHOD = {
|
|
66
|
-
GET: "get",
|
|
67
|
-
POST: "post"
|
|
68
|
-
};
|
|
69
|
-
const METHODS_BY_URL = {
|
|
70
|
-
products_url: METHOD.GET,
|
|
71
|
-
product_url: METHOD.GET,
|
|
72
|
-
predictive_search_url: METHOD.GET,
|
|
73
|
-
product_recommendations_url: METHOD.GET,
|
|
74
|
-
cart_add_url: METHOD.POST,
|
|
75
|
-
cart_update_url: METHOD.POST,
|
|
76
|
-
cart_url: METHOD.GET,
|
|
77
|
-
cart_change_url: METHOD.POST,
|
|
78
|
-
cart_clear_url: METHOD.POST
|
|
79
|
-
};
|
|
80
|
-
const makeFactory = ({
|
|
81
|
-
routeName,
|
|
82
|
-
inputSchema,
|
|
83
|
-
outputSchema
|
|
84
|
-
}) => (input, options) => Effect.gen(function* () {
|
|
85
|
-
const client = yield* HttpClient.HttpClient;
|
|
86
|
-
const decodedInput = yield* Schema.decodeUnknown(inputSchema)(
|
|
87
|
-
input || {}
|
|
88
|
-
);
|
|
89
|
-
const routes = Ajax.Window.ShopifyRoutes.make();
|
|
90
|
-
let route;
|
|
91
|
-
if (routeName === "product_url" && "handle" in decodedInput) {
|
|
92
|
-
route = routes[routeName].replace(":handle", decodedInput.handle);
|
|
93
|
-
} else {
|
|
94
|
-
route = routes[routeName];
|
|
95
|
-
}
|
|
96
|
-
const url = `${window.location.origin}${route}`;
|
|
97
|
-
const method = METHODS_BY_URL[routeName];
|
|
98
|
-
let request;
|
|
99
|
-
if (method === "post") {
|
|
100
|
-
request = yield* HttpClientRequest.post(url, {
|
|
101
|
-
acceptJson: true,
|
|
102
|
-
headers: {
|
|
103
|
-
"X-SDK-Variant": "brytdesigns",
|
|
104
|
-
"X-SDK-Variant-Source": "shopify-ajax-client",
|
|
105
|
-
...options?.headers || {}
|
|
106
|
-
}
|
|
107
|
-
}).pipe(HttpClientRequest.bodyJson(decodedInput));
|
|
108
|
-
} else if (method === "get") {
|
|
109
|
-
request = HttpClientRequest.get(url, {
|
|
110
|
-
acceptJson: true,
|
|
111
|
-
headers: {
|
|
112
|
-
"X-SDK-Variant": "brytdesigns",
|
|
113
|
-
"X-SK-Variant-Source": "shopify-ajax-client",
|
|
114
|
-
...options?.headers || {}
|
|
115
|
-
}
|
|
116
|
-
}).pipe(HttpClientRequest.setUrlParams(decodedInput));
|
|
117
|
-
} else {
|
|
118
|
-
return yield* Effect.fail(new InvalidAjaxMethodError());
|
|
119
|
-
}
|
|
120
|
-
const response = yield* client.execute(request);
|
|
121
|
-
if (response.status !== 200) {
|
|
122
|
-
const data = yield* response.json;
|
|
123
|
-
return AjaxClientResponse.make({
|
|
124
|
-
error: {
|
|
125
|
-
description: data.description,
|
|
126
|
-
status: data.status,
|
|
127
|
-
message: data.message
|
|
128
|
-
}
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
if (decodedInput.sections) {
|
|
132
|
-
const output2 = outputSchema.pipe(
|
|
133
|
-
Schema.extend(
|
|
134
|
-
Schema.Struct({
|
|
135
|
-
sections: Ajax.Sections.makeResponseSchema(decodedInput.sections)
|
|
136
|
-
})
|
|
137
|
-
)
|
|
138
|
-
);
|
|
139
|
-
const json2 = yield* Function.pipe(
|
|
140
|
-
response,
|
|
141
|
-
HttpClientResponse.schemaBodyJson(output2)
|
|
142
|
-
);
|
|
143
|
-
const clientResponse2 = AjaxClientResponse.make({
|
|
144
|
-
data: json2
|
|
145
|
-
});
|
|
146
|
-
yield* Effect.annotateLogsScoped({
|
|
147
|
-
method,
|
|
148
|
-
route,
|
|
149
|
-
input: decodedInput,
|
|
150
|
-
output: clientResponse2
|
|
151
|
-
});
|
|
152
|
-
return clientResponse2;
|
|
153
|
-
}
|
|
154
|
-
const output = outputSchema;
|
|
155
|
-
const json = yield* Function.pipe(
|
|
156
|
-
response,
|
|
157
|
-
HttpClientResponse.schemaBodyJson(output)
|
|
158
|
-
);
|
|
159
|
-
const clientResponse = AjaxClientResponse.make({
|
|
160
|
-
data: json
|
|
161
|
-
});
|
|
162
|
-
yield* Effect.annotateLogsScoped({
|
|
163
|
-
method,
|
|
164
|
-
route,
|
|
165
|
-
input: decodedInput,
|
|
166
|
-
output: clientResponse
|
|
167
|
-
});
|
|
168
|
-
yield* Effect.logInfo("Request");
|
|
169
|
-
return clientResponse;
|
|
170
|
-
}).pipe(
|
|
171
|
-
Effect.scoped,
|
|
172
|
-
LoggerUtils.withNamespacedLogSpan(
|
|
173
|
-
routeName.replace("_url", "").replace("_", ":")
|
|
174
|
-
),
|
|
175
|
-
// Log the full failure cause (including defects and the underlying
|
|
176
|
-
// `cause` chain) before we flatten it. This is gated by the consumer's
|
|
177
|
-
// minimum log level, so it only surfaces when `debug` is enabled.
|
|
178
|
-
Effect.tapErrorCause(
|
|
179
|
-
(cause) => Effect.logError("Ajax request failed", cause)
|
|
180
|
-
),
|
|
181
|
-
Effect.catchAll((error) => Effect.fail(toError(error)))
|
|
182
|
-
);
|
|
183
|
-
|
|
184
|
-
export { Default, makeFactory };
|
|
185
|
-
//# sourceMappingURL=index.js.map
|
|
186
10
|
//# sourceMappingURL=index.js.map
|
package/dist/main/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/index.ts"],"names":["message","output","json","clientResponse"],"mappings":"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","file":"index.js","sourcesContent":["import * as Effect from \"effect/Effect\";\nimport * as Schema from \"effect/Schema\";\nimport * as Function from \"effect/Function\";\nimport * as HttpClient from \"@effect/platform/HttpClient\";\nimport * as HttpClientResponse from \"@effect/platform/HttpClientResponse\";\nimport * as HttpClientRequest from \"@effect/platform/HttpClientRequest\";\nimport * as FetchHttpClient from \"@effect/platform/FetchHttpClient\";\n\nimport { Ajax } from \"@brytdesigns/shopify-utils/effect\";\n\nimport * as LoggerUtils from \"./LoggerUtils.js\";\nimport { type CartError, InvalidAjaxMethodError } from \"./errors.js\";\nimport * as AjaxClientResponse from \"./AjaxClientResponse.js\";\n\nconst BaseOutputSchema = Schema.Struct({});\nconst ProductInputSchema = Schema.extend(\n Ajax.Sections.Input,\n Schema.Struct({\n handle: Schema.String,\n })\n);\n\nexport const Default = FetchHttpClient.layer;\n\n/**\n * Recursively renders an unknown `cause` (typically the value thrown by an\n * overridden `window.fetch`) into a human readable string, walking the\n * `Error.cause` chain so the underlying reason is never lost.\n */\nconst formatCause = (cause: unknown): string | undefined => {\n if (cause == null) return undefined;\n if (cause instanceof Error) {\n const nested = formatCause(cause.cause);\n const base = `${cause.name}: ${cause.message}`;\n return nested ? `${base} -> ${nested}` : base;\n }\n if (typeof cause === \"object\") {\n try {\n return JSON.stringify(cause);\n } catch {\n return String(cause);\n }\n }\n return String(cause);\n};\n\n/**\n * Normalizes the tagged errors produced inside the request effect into a plain\n * `Error` with a descriptive message. The underlying `cause` is always\n * preserved (and folded into the message) so failures such as a rejecting\n * external `fetch` override report WHY they failed instead of just\n * \"Transport error\".\n */\nconst toError = (error: any): Error => {\n // HttpClientError — RequestError (\"Transport\"/\"Encode\"/\"InvalidUrl\") and\n // ResponseError (\"Decode\"/\"StatusCode\"/...). The actionable detail lives on\n // `error.cause`, which Effect's own `message` getter does not include.\n if (error._tag === \"RequestError\" || error._tag === \"ResponseError\") {\n const detail = formatCause(error.cause);\n const message = detail ? `${error.message}: ${detail}` : error.message;\n return Object.assign(new Error(message, { cause: error.cause }), {\n _tag: error._tag,\n reason: error.reason,\n });\n }\n\n if (\n error._tag === \"ParseError\" ||\n error._tag === \"@brytdesigns/ajax-client/InvalidAjaxMethodError\"\n ) {\n return new Error(error.message, { cause: error.cause });\n }\n\n if (error._tag === \"HttpBodyError\") {\n const reason = error.reason;\n if (reason._tag === \"JsonError\") {\n return new Error(\"Failed to serialize JSON request body\", {\n cause: reason,\n });\n }\n if (reason._tag === \"SchemaError\") {\n return new Error(reason.error.message, {\n cause: reason.error.cause,\n });\n }\n }\n\n const message =\n formatCause(error) ?? error?.message ?? error?.toString?.() ?? String(error);\n return new Error(message, { cause: error });\n};\n\nconst METHOD = {\n GET: \"get\",\n POST: \"post\",\n};\n\nconst METHODS_BY_URL = {\n products_url: METHOD.GET,\n product_url: METHOD.GET,\n predictive_search_url: METHOD.GET,\n product_recommendations_url: METHOD.GET,\n cart_add_url: METHOD.POST,\n cart_update_url: METHOD.POST,\n cart_url: METHOD.GET,\n cart_change_url: METHOD.POST,\n cart_clear_url: METHOD.POST,\n};\n\ntype ValidAjaxRoutes = keyof Pick<\n Ajax.Window.ShopifyRoutes.ShopifyRoutes,\n | \"product_url\"\n | \"products_url\"\n | \"predictive_search_url\"\n | \"product_recommendations_url\"\n | \"cart_add_url\"\n | \"cart_update_url\"\n | \"cart_url\"\n | \"cart_change_url\"\n | \"cart_clear_url\"\n>;\n\n/**\n * A factory function that creates an Effect to make AJAX requests to Shopify routes.\n *\n * @template RouteName - The type of Shopify route to make the request to.\n * @template A - The type of input data for the request.\n * @template I - The type of input data after decoding.\n * @template R - The type of input data after decoding, but with additional information.\n * @template B - The type of output data expected from the request.\n * @template J - The type of output data after decoding.\n * @template S - The type of output data after decoding, but with additional information.\n *\n * @param {object} params - The parameters for creating the factory function.\n * @param {RouteName} params.routeName - The name of the Shopify route to make the request to.\n * @param {Schema<A, I, R>} params.inputSchema - The schema for validating and decoding the input data.\n * @param {Schema<B, J, S>} params.outputSchema - The schema for validating and decoding the output data.\n *\n * - A function that takes input data and options, and returns an Effect to make the AJAX request.\n */\nexport const makeFactory =\n <\n RouteName extends ValidAjaxRoutes,\n A extends RouteName extends \"product_url\"\n ? typeof ProductInputSchema.Type\n : typeof Ajax.Sections.Input.Type,\n I,\n R,\n B extends typeof BaseOutputSchema.Type,\n J,\n S,\n >({\n routeName,\n inputSchema,\n outputSchema,\n }: {\n routeName: RouteName;\n inputSchema: Schema.Schema<A, I, R>;\n outputSchema: Schema.Schema<B, J, S>;\n }) =>\n (\n input?: Schema.Schema<A, I, R>[\"Encoded\"],\n options?: { headers?: Record<string, string> }\n ) =>\n Effect.gen(function* () {\n const client = yield* HttpClient.HttpClient;\n const decodedInput = yield* Schema.decodeUnknown(inputSchema)(\n input || {}\n );\n const routes = Ajax.Window.ShopifyRoutes.make();\n\n let route: string;\n\n if (routeName === \"product_url\" && \"handle\" in decodedInput) {\n route = routes[routeName].replace(\":handle\", decodedInput.handle);\n } else {\n route = routes[routeName];\n }\n\n const url = `${window.location.origin}${route}`;\n const method = METHODS_BY_URL[routeName];\n\n let request: HttpClientRequest.HttpClientRequest;\n\n if (method === \"post\") {\n request = yield* HttpClientRequest.post(url, {\n acceptJson: true,\n headers: {\n \"X-SDK-Variant\": \"brytdesigns\",\n \"X-SDK-Variant-Source\": \"shopify-ajax-client\",\n ...(options?.headers || {}),\n },\n }).pipe(HttpClientRequest.bodyJson(decodedInput));\n } else if (method === \"get\") {\n request = HttpClientRequest.get(url, {\n acceptJson: true,\n headers: {\n \"X-SDK-Variant\": \"brytdesigns\",\n \"X-SK-Variant-Source\": \"shopify-ajax-client\",\n ...(options?.headers || {}),\n },\n }).pipe(HttpClientRequest.setUrlParams(decodedInput));\n } else {\n return yield* Effect.fail(new InvalidAjaxMethodError());\n }\n\n const response = yield* client.execute(request);\n\n if (response.status !== 200) {\n const data = (yield* response.json) as CartError;\n return AjaxClientResponse.make({\n error: {\n description: data.description,\n status: data.status,\n message: data.message,\n },\n });\n }\n\n if (decodedInput.sections) {\n const output = outputSchema.pipe(\n Schema.extend(\n Schema.Struct({\n sections: Ajax.Sections.makeResponseSchema(decodedInput.sections),\n })\n )\n );\n\n const json = yield* Function.pipe(\n response,\n HttpClientResponse.schemaBodyJson(output)\n );\n\n const clientResponse = AjaxClientResponse.make({\n data: json,\n });\n\n yield* Effect.annotateLogsScoped({\n method,\n route,\n input: decodedInput,\n output: clientResponse,\n });\n\n return clientResponse;\n }\n\n const output = outputSchema;\n\n const json = yield* Function.pipe(\n response,\n HttpClientResponse.schemaBodyJson(output)\n );\n\n const clientResponse = AjaxClientResponse.make({\n data: json,\n });\n\n yield* Effect.annotateLogsScoped({\n method,\n route,\n input: decodedInput,\n output: clientResponse,\n });\n\n yield* Effect.logInfo(\"Request\");\n\n return clientResponse;\n }).pipe(\n Effect.scoped,\n LoggerUtils.withNamespacedLogSpan(\n routeName.replace(\"_url\", \"\").replace(\"_\", \":\")\n ),\n // Log the full failure cause (including defects and the underlying\n // `cause` chain) before we flatten it. This is gated by the consumer's\n // minimum log level, so it only surfaces when `debug` is enabled.\n Effect.tapErrorCause((cause) =>\n Effect.logError(\"Ajax request failed\", cause)\n ),\n Effect.catchAll((error) => Effect.fail(toError(error)))\n );\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["// v4 absorbed @effect/platform into the core package. These sat under\n// effect/unstable/http during the RCs and graduated to effect/http at 4.0.0,\n// so they are covered by semver now rather than exempt from it.\nimport { FetchHttpClient } from \"effect/http\";\n\n/** Named `layer` per the v4 convention, which replaces v3's `Default`/`Live`. */\nexport const layer = FetchHttpClient.layer;\n\nexport {\n\ttype AjaxErrorBody,\n\tAjaxResponseError,\n\tInvalidAjaxMethodError,\n\tUnsafeAjaxRouteError,\n} from \"./errors.js\";\nexport type {\n\tAjaxInput,\n\tAjaxInputEncoded,\n\tAjaxRequest,\n\tValidAjaxRoutes,\n} from \"./Request.js\";\nexport * as Request from \"./Request.js\";\nexport {\n\texecute,\n\tisAjaxRequest,\n\tmakeRoute,\n\twithHeader,\n\twithHeaders,\n\twithInput,\n\twithSections,\n} from \"./Request.js\";\n"],"mappings":";;;;;AAMA,IAAa,QAAQ,gBAAgB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brytdesigns/shopify-ajax-client",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "An AJAX cart that integrates with ALL shopify ajax apis",
|
|
5
5
|
"main": "./dist/main/index.js",
|
|
6
6
|
"types": "./dist/main/index.d.ts",
|
|
@@ -11,11 +11,7 @@
|
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
13
|
"types": "./dist/main/index.d.ts",
|
|
14
|
-
"
|
|
15
|
-
},
|
|
16
|
-
"./effect": {
|
|
17
|
-
"types": "./dist/effect/index.d.ts",
|
|
18
|
-
"import": "./dist/effect/index.js"
|
|
14
|
+
"default": "./dist/main/index.js"
|
|
19
15
|
}
|
|
20
16
|
},
|
|
21
17
|
"type": "module",
|
|
@@ -23,19 +19,17 @@
|
|
|
23
19
|
"author": "Bryt Designs",
|
|
24
20
|
"license": "ISC",
|
|
25
21
|
"devDependencies": {
|
|
26
|
-
"@
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"vitest": "^3.0.6"
|
|
22
|
+
"@repo/vite-config": "0.0.0",
|
|
23
|
+
"vite": "^8.2.2",
|
|
24
|
+
"vitest": "^3.2.7"
|
|
30
25
|
},
|
|
31
26
|
"dependencies": {
|
|
32
|
-
"@
|
|
33
|
-
"effect": "
|
|
34
|
-
"lz-string": "^1.5.0"
|
|
35
|
-
"@brytdesigns/shopify-utils": "1.2.22"
|
|
27
|
+
"@brytdesigns/shopify-utils": "3.0.0",
|
|
28
|
+
"effect": "4.0.3",
|
|
29
|
+
"lz-string": "^1.5.0"
|
|
36
30
|
},
|
|
37
31
|
"scripts": {
|
|
38
|
-
"build": "
|
|
32
|
+
"build": "vite build",
|
|
39
33
|
"dev": "tsx src/index.ts",
|
|
40
34
|
"typecheck": "tsc --noEmit",
|
|
41
35
|
"test": "vitest"
|