@swell/apps-sdk 1.0.190 → 2.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +188 -254
- package/dist/backend.d.cts +81 -0
- package/dist/backend.d.ts +81 -0
- package/dist/backend.js +154 -0
- package/dist/browser-refusal.d.cts +1 -0
- package/dist/browser-refusal.d.ts +1 -0
- package/dist/browser-refusal.js +2 -0
- package/dist/context.d.cts +7 -0
- package/dist/context.d.ts +7 -0
- package/dist/context.js +29 -0
- package/dist/error.d.cts +23 -0
- package/dist/error.d.ts +23 -0
- package/dist/error.js +30 -0
- package/dist/guard.d.cts +1 -0
- package/dist/guard.d.ts +1 -0
- package/dist/guard.js +4 -0
- package/dist/index.d.cts +11 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.js +6 -20299
- package/dist/jwks.d.cts +1 -0
- package/dist/jwks.d.ts +1 -0
- package/dist/jwks.js +70 -0
- package/dist/request-context.d.cts +37 -0
- package/dist/request-context.d.ts +37 -0
- package/dist/request-context.js +99 -0
- package/dist/staff.d.cts +7 -0
- package/dist/staff.d.ts +7 -0
- package/dist/staff.js +7 -0
- package/dist/storefront.d.cts +28 -0
- package/dist/storefront.d.ts +28 -0
- package/dist/storefront.js +44 -0
- package/dist/version.d.cts +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +2 -0
- package/dist/workflow.d.cts +1 -0
- package/dist/workflow.d.ts +1 -0
- package/dist/workflow.js +35 -0
- package/package.json +48 -63
- package/dist/index.cjs +0 -20547
- package/dist/index.cjs.map +0 -7
- package/dist/index.js.map +0 -7
- package/dist/index.mjs +0 -20404
- package/dist/index.mjs.map +0 -7
- package/dist/src/api.d.ts +0 -96
- package/dist/src/cache/cache.d.ts +0 -41
- package/dist/src/cache/cf-worker-kv-keyv-adapter.d.ts +0 -18
- package/dist/src/cache/constants.d.ts +0 -7
- package/dist/src/cache/content-cache.d.ts +0 -21
- package/dist/src/cache/html-cache/html-cache-backend.d.ts +0 -64
- package/dist/src/cache/html-cache/html-cache-factory.d.ts +0 -9
- package/dist/src/cache/html-cache/html-cache-kv.d.ts +0 -38
- package/dist/src/cache/html-cache/html-cache-worker.d.ts +0 -8
- package/dist/src/cache/html-cache/html-cache.d.ts +0 -120
- package/dist/src/cache/html-cache/index.d.ts +0 -4
- package/dist/src/cache/index.d.ts +0 -9
- package/dist/src/cache/kv-variety.d.ts +0 -10
- package/dist/src/cache/request-cache.d.ts +0 -4
- package/dist/src/cache/resource-cache.d.ts +0 -4
- package/dist/src/cache/theme-cache.d.ts +0 -4
- package/dist/src/cache/theme-file-cache.d.ts +0 -87
- package/dist/src/compatibility/drops/all_products.d.ts +0 -10
- package/dist/src/compatibility/drops/articles.d.ts +0 -10
- package/dist/src/compatibility/drops/blogs.d.ts +0 -10
- package/dist/src/compatibility/drops/collections.d.ts +0 -19
- package/dist/src/compatibility/drops/image-src.d.ts +0 -15
- package/dist/src/compatibility/drops/image.d.ts +0 -29
- package/dist/src/compatibility/drops/images.d.ts +0 -9
- package/dist/src/compatibility/drops/money.d.ts +0 -10
- package/dist/src/compatibility/drops/object-handles.d.ts +0 -6
- package/dist/src/compatibility/drops/pages.d.ts +0 -17
- package/dist/src/compatibility/drops/robots-rule.d.ts +0 -9
- package/dist/src/compatibility/drops/template.d.ts +0 -9
- package/dist/src/compatibility/shopify-configs.d.ts +0 -8
- package/dist/src/compatibility/shopify-fonts.d.ts +0 -1
- package/dist/src/compatibility/shopify-objects/address.d.ts +0 -7
- package/dist/src/compatibility/shopify-objects/article.d.ts +0 -7
- package/dist/src/compatibility/shopify-objects/blog.d.ts +0 -6
- package/dist/src/compatibility/shopify-objects/cart.d.ts +0 -6
- package/dist/src/compatibility/shopify-objects/collection.d.ts +0 -7
- package/dist/src/compatibility/shopify-objects/collections.d.ts +0 -6
- package/dist/src/compatibility/shopify-objects/content.d.ts +0 -12
- package/dist/src/compatibility/shopify-objects/currency.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/customer.d.ts +0 -6
- package/dist/src/compatibility/shopify-objects/filter.d.ts +0 -6
- package/dist/src/compatibility/shopify-objects/font.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/form.d.ts +0 -29
- package/dist/src/compatibility/shopify-objects/image.d.ts +0 -10
- package/dist/src/compatibility/shopify-objects/index.d.ts +0 -27
- package/dist/src/compatibility/shopify-objects/line_item.d.ts +0 -7
- package/dist/src/compatibility/shopify-objects/link.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/localization.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/media.d.ts +0 -9
- package/dist/src/compatibility/shopify-objects/money.d.ts +0 -3
- package/dist/src/compatibility/shopify-objects/order.d.ts +0 -11
- package/dist/src/compatibility/shopify-objects/page.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/paginate.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/predictive_search.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/product.d.ts +0 -9
- package/dist/src/compatibility/shopify-objects/recommendations.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/resource.d.ts +0 -27
- package/dist/src/compatibility/shopify-objects/search.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/shop.d.ts +0 -5
- package/dist/src/compatibility/shopify-objects/template.d.ts +0 -4
- package/dist/src/compatibility/shopify-objects/variant.d.ts +0 -6
- package/dist/src/compatibility/shopify.d.ts +0 -134
- package/dist/src/constants.d.ts +0 -598
- package/dist/src/content.d.ts +0 -8
- package/dist/src/easyblocks/config.d.ts +0 -152
- package/dist/src/easyblocks/index.d.ts +0 -2
- package/dist/src/easyblocks/utils.d.ts +0 -23
- package/dist/src/editor/resources.d.ts +0 -9
- package/dist/src/fonts.d.ts +0 -6
- package/dist/src/globals.d.ts +0 -7
- package/dist/src/index.d.ts +0 -16
- package/dist/src/liquid/color.d.ts +0 -33
- package/dist/src/liquid/drops/render.d.ts +0 -10
- package/dist/src/liquid/filters/asset_url.d.ts +0 -3
- package/dist/src/liquid/filters/brightness_difference.d.ts +0 -2
- package/dist/src/liquid/filters/color_brightness.d.ts +0 -2
- package/dist/src/liquid/filters/color_contrast.d.ts +0 -2
- package/dist/src/liquid/filters/color_darken.d.ts +0 -2
- package/dist/src/liquid/filters/color_desaturate.d.ts +0 -2
- package/dist/src/liquid/filters/color_difference.d.ts +0 -2
- package/dist/src/liquid/filters/color_extract.d.ts +0 -4
- package/dist/src/liquid/filters/color_lighten.d.ts +0 -2
- package/dist/src/liquid/filters/color_mix.d.ts +0 -2
- package/dist/src/liquid/filters/color_modify.d.ts +0 -3
- package/dist/src/liquid/filters/color_saturate.d.ts +0 -2
- package/dist/src/liquid/filters/color_to_hex.d.ts +0 -2
- package/dist/src/liquid/filters/color_to_hsl.d.ts +0 -2
- package/dist/src/liquid/filters/color_to_rgb.d.ts +0 -2
- package/dist/src/liquid/filters/date.d.ts +0 -7
- package/dist/src/liquid/filters/date_next_interval.d.ts +0 -3
- package/dist/src/liquid/filters/default_errors.d.ts +0 -3
- package/dist/src/liquid/filters/divided_by.d.ts +0 -2
- package/dist/src/liquid/filters/embedded_content.d.ts +0 -2
- package/dist/src/liquid/filters/escape.d.ts +0 -3
- package/dist/src/liquid/filters/font_face.d.ts +0 -2
- package/dist/src/liquid/filters/font_modify.d.ts +0 -3
- package/dist/src/liquid/filters/font_url.d.ts +0 -2
- package/dist/src/liquid/filters/format_address.d.ts +0 -6
- package/dist/src/liquid/filters/handleize.d.ts +0 -3
- package/dist/src/liquid/filters/image_tag.d.ts +0 -3
- package/dist/src/liquid/filters/image_url.d.ts +0 -8
- package/dist/src/liquid/filters/index.d.ts +0 -120
- package/dist/src/liquid/filters/inline_asset_content.d.ts +0 -2
- package/dist/src/liquid/filters/inline_editable.d.ts +0 -4
- package/dist/src/liquid/filters/json.d.ts +0 -3
- package/dist/src/liquid/filters/json_pretty.d.ts +0 -3
- package/dist/src/liquid/filters/locale_flag.d.ts +0 -2
- package/dist/src/liquid/filters/minus.d.ts +0 -2
- package/dist/src/liquid/filters/money.d.ts +0 -4
- package/dist/src/liquid/filters/money_with_currency.d.ts +0 -3
- package/dist/src/liquid/filters/money_without_currency.d.ts +0 -3
- package/dist/src/liquid/filters/money_without_trailing_zeros.d.ts +0 -3
- package/dist/src/liquid/filters/preload_tag.d.ts +0 -3
- package/dist/src/liquid/filters/script_tag.d.ts +0 -3
- package/dist/src/liquid/filters/shopify/asset_img_url.d.ts +0 -3
- package/dist/src/liquid/filters/shopify/default_pagination.d.ts +0 -3
- package/dist/src/liquid/filters/shopify/hex_to_rgba.d.ts +0 -2
- package/dist/src/liquid/filters/shopify/img_url.d.ts +0 -3
- package/dist/src/liquid/filters/shopify/item_count_for_variant.d.ts +0 -6
- package/dist/src/liquid/filters/shopify/payment_button.d.ts +0 -2
- package/dist/src/liquid/filters/shopify/payment_terms.d.ts +0 -2
- package/dist/src/liquid/filters/shopify/placeholder-svgs/index.d.ts +0 -5
- package/dist/src/liquid/filters/shopify/placeholder_svg_tag.d.ts +0 -3
- package/dist/src/liquid/filters/shopify/shopify_asset_url.d.ts +0 -3
- package/dist/src/liquid/filters/shopify/structured_data.d.ts +0 -3
- package/dist/src/liquid/filters/stylesheet_tag.d.ts +0 -3
- package/dist/src/liquid/filters/time_tag.d.ts +0 -2
- package/dist/src/liquid/filters/translate.d.ts +0 -3
- package/dist/src/liquid/filters/where.d.ts +0 -3
- package/dist/src/liquid/font.d.ts +0 -51
- package/dist/src/liquid/form.d.ts +0 -17
- package/dist/src/liquid/hash.d.ts +0 -5
- package/dist/src/liquid/index.d.ts +0 -52
- package/dist/src/liquid/operators.d.ts +0 -10
- package/dist/src/liquid/tags/assign.d.ts +0 -3
- package/dist/src/liquid/tags/case.d.ts +0 -3
- package/dist/src/liquid/tags/comment.d.ts +0 -3
- package/dist/src/liquid/tags/content_for.d.ts +0 -3
- package/dist/src/liquid/tags/doc.d.ts +0 -2
- package/dist/src/liquid/tags/for.d.ts +0 -3
- package/dist/src/liquid/tags/form.d.ts +0 -3
- package/dist/src/liquid/tags/if.d.ts +0 -4
- package/dist/src/liquid/tags/index.d.ts +0 -42
- package/dist/src/liquid/tags/inline_editable.d.ts +0 -3
- package/dist/src/liquid/tags/javascript.d.ts +0 -3
- package/dist/src/liquid/tags/layout.d.ts +0 -3
- package/dist/src/liquid/tags/paginate.d.ts +0 -3
- package/dist/src/liquid/tags/render.d.ts +0 -6
- package/dist/src/liquid/tags/section.d.ts +0 -3
- package/dist/src/liquid/tags/sections.d.ts +0 -3
- package/dist/src/liquid/tags/shopify/include.d.ts +0 -3
- package/dist/src/liquid/tags/shopify/schema.d.ts +0 -3
- package/dist/src/liquid/tags/style.d.ts +0 -3
- package/dist/src/liquid/tags/stylesheet.d.ts +0 -3
- package/dist/src/liquid/test-helpers.d.ts +0 -8
- package/dist/src/liquid/tokens/identifier-token.d.ts +0 -9
- package/dist/src/liquid/tokens/index.d.ts +0 -2
- package/dist/src/liquid/tokienizer.d.ts +0 -5
- package/dist/src/liquid/utils.d.ts +0 -45
- package/dist/src/menus.d.ts +0 -25
- package/dist/src/resources/account.d.ts +0 -6
- package/dist/src/resources/addresses.d.ts +0 -7
- package/dist/src/resources/blog.d.ts +0 -7
- package/dist/src/resources/blog_category.d.ts +0 -7
- package/dist/src/resources/cart.d.ts +0 -6
- package/dist/src/resources/categories.d.ts +0 -7
- package/dist/src/resources/category.d.ts +0 -7
- package/dist/src/resources/index.d.ts +0 -48
- package/dist/src/resources/order.d.ts +0 -7
- package/dist/src/resources/orders.d.ts +0 -7
- package/dist/src/resources/page.d.ts +0 -7
- package/dist/src/resources/predictive_search.d.ts +0 -6
- package/dist/src/resources/product.d.ts +0 -7
- package/dist/src/resources/product_helpers.d.ts +0 -21
- package/dist/src/resources/search.d.ts +0 -6
- package/dist/src/resources/subscription.d.ts +0 -7
- package/dist/src/resources/subscriptions.d.ts +0 -7
- package/dist/src/resources/swell_types.d.ts +0 -163
- package/dist/src/resources/variant.d.ts +0 -9
- package/dist/src/resources.d.ts +0 -113
- package/dist/src/theme/theme-loader.d.ts +0 -110
- package/dist/src/theme.d.ts +0 -204
- package/dist/src/utils/escape.d.ts +0 -1
- package/dist/src/utils/index.d.ts +0 -34
- package/dist/src/utils/kv-flavor.d.ts +0 -7
- package/dist/src/utils/logger.d.ts +0 -21
- package/dist/src/utils/md5.d.ts +0 -1
- package/dist/types/cloudflare.d.ts +0 -61
- package/dist/types/shopify.d.ts +0 -1035
- package/dist/types/swell.d.ts +0 -576
- package/types/index.d.ts +0 -4
- package/types/svg.d.ts +0 -4
package/dist/backend.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { requireString, validateUrl } from './context.js';
|
|
2
|
+
import { SwellError } from './error.js';
|
|
3
|
+
import { validateWorkflowParams } from './workflow.js';
|
|
4
|
+
import { USER_AGENT } from './version.js';
|
|
5
|
+
// Matches JSON bodies: undefined values are omitted and Dates become ISO strings.
|
|
6
|
+
function queryParts(query, prefix = '') {
|
|
7
|
+
return Object.entries(query).flatMap(([key, value]) => {
|
|
8
|
+
const name = prefix ? `${prefix}[${key}]` : key;
|
|
9
|
+
if (value === undefined)
|
|
10
|
+
return [];
|
|
11
|
+
// A bare key decodes to native null on the server; `key=null` would be the string "null".
|
|
12
|
+
if (value === null)
|
|
13
|
+
return [encodeURIComponent(name)];
|
|
14
|
+
if (value instanceof Date)
|
|
15
|
+
value = value.toISOString();
|
|
16
|
+
return typeof value === 'object' ? queryParts(value, name)
|
|
17
|
+
: [`${encodeURIComponent(name)}=${encodeURIComponent(value)}`];
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
/** Backend client from a frontend request context or explicit server credentials. */
|
|
21
|
+
export class SwellBackendAPI {
|
|
22
|
+
#baseUrl;
|
|
23
|
+
#authorization;
|
|
24
|
+
#appId;
|
|
25
|
+
#requestId;
|
|
26
|
+
get userAgent() { return USER_AGENT; }
|
|
27
|
+
workflows = {
|
|
28
|
+
/** Creates a workflow instance. Optional params must be JSON-safe and at most 128 KiB of UTF-8 JSON; invalid params reject. */
|
|
29
|
+
create: async (name, params) => {
|
|
30
|
+
const data = { workflow_name: name };
|
|
31
|
+
if (params !== undefined)
|
|
32
|
+
data.params = validateWorkflowParams(params);
|
|
33
|
+
return this.post('/:workflows/instances', data);
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
functions = {
|
|
37
|
+
/**
|
|
38
|
+
* Invokes an app's private function from server code and resolves to its response payload,
|
|
39
|
+
* without the envelope's status or headers.
|
|
40
|
+
* `appId` is the app identifier from the request context (`context.appId`).
|
|
41
|
+
* `method` (default `post`) selects the function's handler. GET data reaches the function
|
|
42
|
+
* as query parameters, so its values must be flat strings, numbers or booleans.
|
|
43
|
+
* Throws `SwellError` when the function reports a non-2xx status or an error.
|
|
44
|
+
* Callers authorize the operation first; no caller headers are forwarded.
|
|
45
|
+
*/
|
|
46
|
+
call: async (appId, name, data, { method = 'post' } = {}) => {
|
|
47
|
+
requireString(appId, 'appId');
|
|
48
|
+
requireString(name, 'function name');
|
|
49
|
+
if (!['get', 'post', 'put', 'delete'].includes(method))
|
|
50
|
+
throw new Error(`Invalid function method: ${method}`);
|
|
51
|
+
if (method === 'get' && data && Object.values(data).some(value => !['string', 'number', 'boolean'].includes(typeof value))) {
|
|
52
|
+
throw new Error('GET function data must contain only string, number or boolean values');
|
|
53
|
+
}
|
|
54
|
+
const result = await this.put(`/:functions/${encodeURIComponent(`app.${appId}.${name}`)}`, { $call: { data: data ?? {}, method } });
|
|
55
|
+
if (!result || typeof result !== 'object')
|
|
56
|
+
throw new SwellError(`Function not found: ${name}`, { status: 404 });
|
|
57
|
+
const { status, error, code, response } = result;
|
|
58
|
+
if (error !== undefined || (typeof status === 'number' && (status < 200 || status > 299))) {
|
|
59
|
+
const message = typeof error === 'string' ? error : typeof response?.error === 'string' ? response.error : `Function ${name} failed`;
|
|
60
|
+
const failure = new SwellError(message, { status, code });
|
|
61
|
+
failure.body = response ?? result;
|
|
62
|
+
throw failure;
|
|
63
|
+
}
|
|
64
|
+
return response;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
constructor(options) {
|
|
68
|
+
if ('headers' in options)
|
|
69
|
+
throw new Error('Pass a request context or explicit credentials, not raw headers');
|
|
70
|
+
if (options.context && ['storeId', 'apiHost', 'accessToken', 'secretKey', 'appId', 'requestId'].some(key => key in options)) {
|
|
71
|
+
throw new Error('context and explicit backend credentials are mutually exclusive');
|
|
72
|
+
}
|
|
73
|
+
const config = options.context ?? options;
|
|
74
|
+
const secretKey = 'secretKey' in config ? config.secretKey : undefined;
|
|
75
|
+
requireString(config.storeId, 'storeId');
|
|
76
|
+
if ((config.accessToken !== undefined) === (secretKey !== undefined))
|
|
77
|
+
throw new Error('Provide exactly one accessToken or secretKey');
|
|
78
|
+
const credential = config.accessToken ?? secretKey;
|
|
79
|
+
requireString(credential, 'accessToken or secretKey');
|
|
80
|
+
this.#baseUrl = validateUrl(config.apiHost, 'apiHost');
|
|
81
|
+
const bytes = new TextEncoder().encode(`${config.storeId}:${credential}`);
|
|
82
|
+
this.#authorization = `Basic ${btoa(Array.from(bytes, byte => String.fromCharCode(byte)).join(''))}`;
|
|
83
|
+
this.#appId = config.appId;
|
|
84
|
+
this.#requestId = config.requestId;
|
|
85
|
+
}
|
|
86
|
+
async #makeRequest(method, path, data) {
|
|
87
|
+
// Paths stay on the configured host: '' means '/', spaces are encoded, dot segments are
|
|
88
|
+
// normalized by URL parsing, fragments/backslashes/control characters are rejected.
|
|
89
|
+
if (typeof path !== 'string' || /^[a-z][a-z\d+.-]*:/i.test(path) || path.startsWith('//') || /[\\#\x00-\x1f\x7f]/.test(path)) {
|
|
90
|
+
throw new Error('Backend endpoint must be a path on the configured API host');
|
|
91
|
+
}
|
|
92
|
+
const endpointUrl = path.replace(/^\//, '').replaceAll(' ', '%20');
|
|
93
|
+
const headers = {
|
|
94
|
+
Authorization: this.#authorization, 'User-Agent': this.userAgent, 'Content-Type': 'application/json',
|
|
95
|
+
...(this.#requestId ? { 'Swell-Request-ID': this.#requestId } : {}),
|
|
96
|
+
};
|
|
97
|
+
const init = { method, headers, redirect: 'manual' };
|
|
98
|
+
let query = '';
|
|
99
|
+
if (data) {
|
|
100
|
+
try {
|
|
101
|
+
if (method !== 'GET')
|
|
102
|
+
init.body = JSON.stringify(data);
|
|
103
|
+
else {
|
|
104
|
+
const params = queryParts(data).join('&');
|
|
105
|
+
if (params)
|
|
106
|
+
query = `${path.includes('?') ? '&' : '?'}${params}`;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
throw new Error(`Error serializing data: ${data}`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const response = await fetch(`${this.#baseUrl}/${endpointUrl}${query}`, init);
|
|
114
|
+
const text = await response.text();
|
|
115
|
+
let result;
|
|
116
|
+
try {
|
|
117
|
+
result = JSON.parse(text);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
result = text.trim();
|
|
121
|
+
}
|
|
122
|
+
if (!response.ok)
|
|
123
|
+
throw new SwellError(result, { status: response.status, method, endpointUrl });
|
|
124
|
+
if (method !== 'GET' && result?.errors)
|
|
125
|
+
throw new SwellError(result.errors, { status: 400, method, endpointUrl });
|
|
126
|
+
return result;
|
|
127
|
+
}
|
|
128
|
+
get(path, query) { return this.#makeRequest('GET', path, query); }
|
|
129
|
+
put(path, data) { return this.#makeRequest('PUT', path, data); }
|
|
130
|
+
post(path, data) { return this.#makeRequest('POST', path, data); }
|
|
131
|
+
delete(path, data) { return this.#makeRequest('DELETE', path, data); }
|
|
132
|
+
/** Reads installed-app settings; defaults to the configured app ID and rejects when neither ID is supplied. */
|
|
133
|
+
async settings(appId = this.#appId) {
|
|
134
|
+
requireString(appId, 'appId for settings()');
|
|
135
|
+
return this.get(`/settings/${encodeURIComponent(appId)}`);
|
|
136
|
+
}
|
|
137
|
+
/** Atomic operations returning results in operation order; only conflicts and throttling retry, and only when requested. */
|
|
138
|
+
async transaction(ops, options = {}) {
|
|
139
|
+
const cfg = { limit: 3, base: 100, max: 5000, jitter: true, ...(options.retry === true ? {} : options.retry) };
|
|
140
|
+
let attempt = 0;
|
|
141
|
+
while (true) {
|
|
142
|
+
try {
|
|
143
|
+
return await this.post('/:transaction', ops);
|
|
144
|
+
}
|
|
145
|
+
catch (error) {
|
|
146
|
+
if (!options.retry || !(error instanceof SwellError) || !error.isRetryable || attempt >= cfg.limit)
|
|
147
|
+
throw error;
|
|
148
|
+
const delay = Math.min(cfg.base * 2 ** attempt, cfg.max);
|
|
149
|
+
await new Promise(resolve => setTimeout(resolve, cfg.jitter ? delay * (0.5 + Math.random() * 0.5) : delay));
|
|
150
|
+
attempt++;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PublicConfig } from 'swell-js';
|
|
2
|
+
import type { SwellRequestContext } from './request-context.cjs';
|
|
3
|
+
export type HeaderReader = Pick<Headers, 'get'>;
|
|
4
|
+
export declare function requireString(value: unknown, field: string): asserts value is string;
|
|
5
|
+
export declare function validateUrl(value: unknown, field: string): string;
|
|
6
|
+
/** Projects only public configuration. Deliver it with Cache-Control: private, no-store. */
|
|
7
|
+
export declare function getStorefrontConfig(context: SwellRequestContext): PublicConfig;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { PublicConfig } from 'swell-js';
|
|
2
|
+
import type { SwellRequestContext } from './request-context.js';
|
|
3
|
+
export type HeaderReader = Pick<Headers, 'get'>;
|
|
4
|
+
export declare function requireString(value: unknown, field: string): asserts value is string;
|
|
5
|
+
export declare function validateUrl(value: unknown, field: string): string;
|
|
6
|
+
/** Projects only public configuration. Deliver it with Cache-Control: private, no-store. */
|
|
7
|
+
export declare function getStorefrontConfig(context: SwellRequestContext): PublicConfig;
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function requireString(value, field) {
|
|
2
|
+
if (typeof value !== 'string' || !value.trim())
|
|
3
|
+
throw new Error(`Missing or invalid ${field}`);
|
|
4
|
+
}
|
|
5
|
+
export function validateUrl(value, field) {
|
|
6
|
+
requireString(value, field);
|
|
7
|
+
let url;
|
|
8
|
+
try {
|
|
9
|
+
url = new URL(value);
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw new Error(`Invalid ${field}: expected an absolute HTTP(S) URL`);
|
|
13
|
+
}
|
|
14
|
+
if (!['http:', 'https:'].includes(url.protocol) || url.username || url.password || url.search || url.hash) {
|
|
15
|
+
throw new Error(`Invalid ${field}: expected an HTTP(S) URL without credentials, query or fragment`);
|
|
16
|
+
}
|
|
17
|
+
return url.href.replace(/\/$/, '');
|
|
18
|
+
}
|
|
19
|
+
/** Projects only public configuration. Deliver it with Cache-Control: private, no-store. */
|
|
20
|
+
export function getStorefrontConfig(context) {
|
|
21
|
+
requireString(context.storeId, 'storeId');
|
|
22
|
+
requireString(context.publicKey, 'publicKey');
|
|
23
|
+
return {
|
|
24
|
+
storeId: context.storeId, publicKey: context.publicKey,
|
|
25
|
+
url: validateUrl(context.adminUrl, 'adminUrl'),
|
|
26
|
+
vaultUrl: context.vaultUrl === undefined ? 'https://vault.schema.io' : validateUrl(context.vaultUrl, 'vaultUrl'),
|
|
27
|
+
...(context.storefrontId ? { headers: { 'Swell-Storefront-Id': context.storefrontId } } : {}),
|
|
28
|
+
};
|
|
29
|
+
}
|
package/dist/error.d.cts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface SwellErrorOptions {
|
|
2
|
+
status?: number;
|
|
3
|
+
method?: string;
|
|
4
|
+
endpointUrl?: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
retry?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Backend or function error; ordinary operations never retry automatically.
|
|
10
|
+
* Machine-readable contract: `status`, optional `code` and optional `body`.
|
|
11
|
+
* Ordinary backend errors retain structured responses in `body`; string errors have no body.
|
|
12
|
+
* HTTP-200 non-GET validation failures retain the `errors` field map. Function invocation
|
|
13
|
+
* failures retain the response payload or, if nullish, the invocation envelope.
|
|
14
|
+
* `message` is for humans and may change.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SwellError extends Error {
|
|
17
|
+
status: number;
|
|
18
|
+
body?: any;
|
|
19
|
+
code?: string;
|
|
20
|
+
retry?: boolean;
|
|
21
|
+
constructor(message: any, options?: SwellErrorOptions);
|
|
22
|
+
get isRetryable(): boolean;
|
|
23
|
+
}
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface SwellErrorOptions {
|
|
2
|
+
status?: number;
|
|
3
|
+
method?: string;
|
|
4
|
+
endpointUrl?: string;
|
|
5
|
+
code?: string;
|
|
6
|
+
retry?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Backend or function error; ordinary operations never retry automatically.
|
|
10
|
+
* Machine-readable contract: `status`, optional `code` and optional `body`.
|
|
11
|
+
* Ordinary backend errors retain structured responses in `body`; string errors have no body.
|
|
12
|
+
* HTTP-200 non-GET validation failures retain the `errors` field map. Function invocation
|
|
13
|
+
* failures retain the response payload or, if nullish, the invocation envelope.
|
|
14
|
+
* `message` is for humans and may change.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SwellError extends Error {
|
|
17
|
+
status: number;
|
|
18
|
+
body?: any;
|
|
19
|
+
code?: string;
|
|
20
|
+
retry?: boolean;
|
|
21
|
+
constructor(message: any, options?: SwellErrorOptions);
|
|
22
|
+
get isRetryable(): boolean;
|
|
23
|
+
}
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Backend or function error; ordinary operations never retry automatically.
|
|
3
|
+
* Machine-readable contract: `status`, optional `code` and optional `body`.
|
|
4
|
+
* Ordinary backend errors retain structured responses in `body`; string errors have no body.
|
|
5
|
+
* HTTP-200 non-GET validation failures retain the `errors` field map. Function invocation
|
|
6
|
+
* failures retain the response payload or, if nullish, the invocation envelope.
|
|
7
|
+
* `message` is for humans and may change.
|
|
8
|
+
*/
|
|
9
|
+
export class SwellError extends Error {
|
|
10
|
+
status;
|
|
11
|
+
body;
|
|
12
|
+
code;
|
|
13
|
+
retry;
|
|
14
|
+
constructor(message, options = {}) {
|
|
15
|
+
const body = typeof message === 'string' ? undefined : message;
|
|
16
|
+
let formatted = typeof message === 'string' ? message
|
|
17
|
+
: typeof body?.error?.message === 'string' ? body.error.message : JSON.stringify(message, null, 2);
|
|
18
|
+
if (options.method && options.endpointUrl)
|
|
19
|
+
formatted = `${options.method} /${options.endpointUrl}\n${formatted}`;
|
|
20
|
+
super(formatted);
|
|
21
|
+
this.name = 'SwellError';
|
|
22
|
+
this.status = options.status || 500;
|
|
23
|
+
this.body = body;
|
|
24
|
+
this.code = options.code || body?.error?.code;
|
|
25
|
+
this.retry = options.retry;
|
|
26
|
+
}
|
|
27
|
+
get isRetryable() {
|
|
28
|
+
return this.code === 'transaction_conflict' || this.code === 'transaction_throttled';
|
|
29
|
+
}
|
|
30
|
+
}
|
package/dist/guard.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/guard.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/guard.js
ADDED
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import './guard.cjs';
|
|
2
|
+
export { getStorefrontConfig } from './context.cjs';
|
|
3
|
+
export type { HeaderReader } from './context.cjs';
|
|
4
|
+
export { verifySwellContext } from './request-context.cjs';
|
|
5
|
+
export type { SwellRequestContext, SwellHeadersEnv, VerifySwellContextOptions } from './request-context.cjs';
|
|
6
|
+
export { SwellBackendAPI } from './backend.cjs';
|
|
7
|
+
export type { BackendOptions, SwellCollection, SwellData, TransactionOperation, TransactionOptions } from './backend.cjs';
|
|
8
|
+
export { SwellError } from './error.cjs';
|
|
9
|
+
export type { SwellErrorOptions } from './error.cjs';
|
|
10
|
+
export { requireStaff } from './staff.cjs';
|
|
11
|
+
export type { StaffIdentity } from './staff.cjs';
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import './guard.js';
|
|
2
|
+
export { getStorefrontConfig } from './context.js';
|
|
3
|
+
export type { HeaderReader } from './context.js';
|
|
4
|
+
export { verifySwellContext } from './request-context.js';
|
|
5
|
+
export type { SwellRequestContext, SwellHeadersEnv, VerifySwellContextOptions } from './request-context.js';
|
|
6
|
+
export { SwellBackendAPI } from './backend.js';
|
|
7
|
+
export type { BackendOptions, SwellCollection, SwellData, TransactionOperation, TransactionOptions } from './backend.js';
|
|
8
|
+
export { SwellError } from './error.js';
|
|
9
|
+
export type { SwellErrorOptions } from './error.js';
|
|
10
|
+
export { requireStaff } from './staff.js';
|
|
11
|
+
export type { StaffIdentity } from './staff.js';
|