@brytdesigns/shopify-ajax-client 1.0.7 → 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.
@@ -1,11 +1,115 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
- import * as HttpClient from '@effect/platform/HttpClient';
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 Input: Schema.Struct<{
46
- sections: Schema.optional<Schema.transform<Schema.Array$<typeof Schema.String>, typeof Schema.String>>;
47
- sections_url: Schema.optional<typeof Schema.String>;
48
- }>;
49
- export type UniqueKeys<T extends string> = T extends `${infer K},${infer Rest}` ? K | UniqueKeys<Rest> : T;
50
- declare function makeResponseSchema<const T extends string>(input: T): Schema.Record$<Schema.SchemaClass<UniqueKeys<T>, UniqueKeys<T>, never>, Schema.NullOr<Schema.transformOrFail<typeof Schema.String, Schema.instanceOf<Element>, never>>>;
51
- declare namespace StorefrontClientConfig$1 {
52
- export { StorefrontClientConfig, make$1 as make$1 };
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 Window$1 {
58
- export { ShopifyRoutes$1 as ShopifyRoutes$1, StorefrontClientConfig$1 as StorefrontClientConfig$1 };
165
+ declare namespace StorefrontClientConfig$1 {
166
+ export { StorefrontClientConfig, make$1 as make$1 };
59
167
  }
60
- declare namespace Sections {
61
- export { Input, makeResponseSchema };
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
- * Represents a response from an AJAX client.
175
+ * Every route's input extends Shopify's `sections` pair, decoded.
68
176
  *
69
- * @template TData - The type of data expected in the response.
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 interface IAjaxClientResponse<TData = any> {
72
- /**
73
- * The data received from the server.
74
- */
75
- data?: TData;
76
- /**
77
- * An error object if the request failed.
78
- */
79
- error?: {
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.extend<Schema.Struct<{
98
- sections: Schema.optional<Schema.transform<Schema.Array$<typeof Schema.String>, typeof Schema.String>>;
99
- sections_url: Schema.optional<typeof Schema.String>;
100
- }>, Schema.Struct<{
101
- handle: typeof Schema.String;
102
- }>>;
103
- export declare const Default: import("effect/Layer").Layer<HttpClient.HttpClient, never, never>;
104
- export type ValidAjaxRoutes = keyof Pick<Ajax.Window.ShopifyRoutes.ShopifyRoutes, "product_url" | "products_url" | "predictive_search_url" | "product_recommendations_url" | "cart_add_url" | "cart_update_url" | "cart_url" | "cart_change_url" | "cart_clear_url">;
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
- * A factory function that creates an Effect to make AJAX requests to Shopify routes.
107
- *
108
- * @template RouteName - The type of Shopify route to make the request to.
109
- * @template A - The type of input data for the request.
110
- * @template I - The type of input data after decoding.
111
- * @template R - The type of input data after decoding, but with additional information.
112
- * @template B - The type of output data expected from the request.
113
- * @template J - The type of output data after decoding.
114
- * @template S - The type of output data after decoding, but with additional information.
115
- *
116
- * @param {object} params - The parameters for creating the factory function.
117
- * @param {RouteName} params.routeName - The name of the Shopify route to make the request to.
118
- * @param {Schema<A, I, R>} params.inputSchema - The schema for validating and decoding the input data.
119
- * @param {Schema<B, J, S>} params.outputSchema - The schema for validating and decoding the output data.
120
- *
121
- * - A function that takes input data and options, and returns an Effect to make the AJAX request.
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 makeFactory: <RouteName extends ValidAjaxRoutes, A extends RouteName extends "product_url" ? typeof ProductInputSchema.Type : typeof Ajax.Sections.Input.Type, I, R, B extends typeof BaseOutputSchema.Type, J, S>({ routeName, inputSchema, outputSchema, }: {
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.Schema<A, I, R>;
126
- outputSchema: Schema.Schema<B, J, S>;
127
- }) => (input?: Schema.Schema<A, I, R>["Encoded"], options?: {
128
- headers?: Record<string, string>;
129
- }) => Effect.Effect<AjaxClientResponse<undefined> | AjaxClientResponse<B>, Error, HttpClient.HttpClient | Exclude<R, import("effect/Scope").Scope> | Exclude<S, import("effect/Scope").Scope>>;
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 {};
@@ -1,158 +1,10 @@
1
- import * as Effect from 'effect/Effect';
2
- import * as Schema from 'effect/Schema';
3
- import * as Function from 'effect/Function';
4
- import * as HttpClient from '@effect/platform/HttpClient';
5
- import * as HttpClientResponse from '@effect/platform/HttpClientResponse';
6
- import * as HttpClientRequest from '@effect/platform/HttpClientRequest';
7
- import * as FetchHttpClient from '@effect/platform/FetchHttpClient';
8
- import { Ajax } from '@brytdesigns/shopify-utils/effect';
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 METHOD = {
22
- GET: "get",
23
- POST: "post"
24
- };
25
- const METHODS_BY_URL = {
26
- products_url: METHOD.GET,
27
- product_url: METHOD.GET,
28
- predictive_search_url: METHOD.GET,
29
- product_recommendations_url: METHOD.GET,
30
- cart_add_url: METHOD.POST,
31
- cart_update_url: METHOD.POST,
32
- cart_url: METHOD.GET,
33
- cart_change_url: METHOD.POST,
34
- cart_clear_url: METHOD.POST
35
- };
36
- const makeFactory = ({
37
- routeName,
38
- inputSchema,
39
- outputSchema
40
- }) => (input, options) => Effect.gen(function* () {
41
- const client = yield* HttpClient.HttpClient;
42
- const decodedInput = yield* Schema.decodeUnknown(inputSchema)(
43
- input || {}
44
- );
45
- const routes = Ajax.Window.ShopifyRoutes.make();
46
- let route;
47
- if (routeName === "product_url" && "handle" in decodedInput) {
48
- route = routes[routeName].replace(":handle", decodedInput.handle);
49
- } else {
50
- route = routes[routeName];
51
- }
52
- const url = `${window.location.origin}${route}`;
53
- const method = METHODS_BY_URL[routeName];
54
- let request;
55
- if (method === "post") {
56
- request = yield* HttpClientRequest.post(url, {
57
- acceptJson: true,
58
- headers: {
59
- "X-SDK-Variant": "brytdesigns",
60
- "X-SDK-Variant-Source": "shopify-ajax-client",
61
- ...options?.headers || {}
62
- }
63
- }).pipe(HttpClientRequest.bodyJson(decodedInput));
64
- } else if (method === "get") {
65
- request = HttpClientRequest.get(url, {
66
- acceptJson: true,
67
- headers: {
68
- "X-SDK-Variant": "brytdesigns",
69
- "X-SK-Variant-Source": "shopify-ajax-client",
70
- ...options?.headers || {}
71
- }
72
- }).pipe(HttpClientRequest.setUrlParams(decodedInput));
73
- } else {
74
- return yield* Effect.fail(new InvalidAjaxMethodError());
75
- }
76
- const response = yield* client.execute(request);
77
- if (response.status !== 200) {
78
- const data = yield* response.json;
79
- return AjaxClientResponse.make({
80
- error: {
81
- description: data.description,
82
- status: data.status,
83
- message: data.message
84
- }
85
- });
86
- }
87
- if (decodedInput.sections) {
88
- const output2 = outputSchema.pipe(
89
- Schema.extend(
90
- Schema.Struct({
91
- sections: Ajax.Sections.makeResponseSchema(decodedInput.sections)
92
- })
93
- )
94
- );
95
- const json2 = yield* Function.pipe(
96
- response,
97
- HttpClientResponse.schemaBodyJson(output2)
98
- );
99
- const clientResponse2 = AjaxClientResponse.make({
100
- data: json2
101
- });
102
- yield* Effect.annotateLogsScoped({
103
- method,
104
- route,
105
- input: decodedInput,
106
- output: clientResponse2
107
- });
108
- return clientResponse2;
109
- }
110
- const output = outputSchema;
111
- const json = yield* Function.pipe(
112
- response,
113
- HttpClientResponse.schemaBodyJson(output)
114
- );
115
- const clientResponse = AjaxClientResponse.make({
116
- data: json
117
- });
118
- yield* Effect.annotateLogsScoped({
119
- method,
120
- route,
121
- input: decodedInput,
122
- output: clientResponse
123
- });
124
- yield* Effect.logInfo("Request");
125
- return clientResponse;
126
- }).pipe(
127
- Effect.scoped,
128
- LoggerUtils.withNamespacedLogSpan(
129
- routeName.replace("_url", "").replace("_", ":")
130
- ),
131
- Effect.catchAll((error) => {
132
- if (error._tag === "ParseError" || error._tag === "RequestError" || error._tag === "ResponseError" || error._tag === "@brytdesigns/ajax-client/InvalidAjaxMethodError") {
133
- return Effect.fail(
134
- new Error(error.message, {
135
- cause: error.cause
136
- })
137
- );
138
- }
139
- if (error._tag === "HttpBodyError") {
140
- const reason = error.reason;
141
- if (reason._tag === "JsonError") {
142
- return Effect.fail(new Error("Failed to parse JSON response"));
143
- }
144
- if (reason._tag === "SchemaError") {
145
- return Effect.fail(
146
- new Error(reason.error.message, {
147
- cause: reason.error.cause
148
- })
149
- );
150
- }
151
- }
152
- return Effect.fail(new Error(error.toString()));
153
- })
154
- );
155
-
156
- export { Default, makeFactory };
157
- //# sourceMappingURL=index.js.map
158
10
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"names":["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\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 Effect.catchAll((error) => {\n if (\n error._tag === \"ParseError\" ||\n error._tag === \"RequestError\" ||\n error._tag === \"ResponseError\" ||\n error._tag === \"@brytdesigns/ajax-client/InvalidAjaxMethodError\"\n ) {\n return Effect.fail(\n new Error(error.message, {\n cause: error.cause,\n })\n );\n }\n if (error._tag === \"HttpBodyError\") {\n const reason = error.reason;\n if (reason._tag === \"JsonError\") {\n return Effect.fail(new Error(\"Failed to parse JSON response\"));\n }\n if (reason._tag === \"SchemaError\") {\n return Effect.fail(\n new Error(reason.error.message, {\n cause: reason.error.cause,\n })\n );\n }\n }\n return Effect.fail(new Error(error.toString()));\n })\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": "1.0.7",
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
- "import": "./dist/main/index.js"
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
- "@effect/vitest": "^0.19.0",
27
- "dts-bundle-generator": "^9.5.1",
28
- "tsup": "^8.4.0",
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
- "@effect/platform": "0.94.1",
33
- "effect": "3.19.14",
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": "tsup --clean",
32
+ "build": "vite build",
39
33
  "dev": "tsx src/index.ts",
40
34
  "typecheck": "tsc --noEmit",
41
35
  "test": "vitest"