react-shopwave-connect 0.4.2 → 0.4.4
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 +19 -5
- package/dist/core/index.cjs +630 -510
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.d.cts +109 -5
- package/dist/core/index.d.ts +109 -5
- package/dist/core/index.js +623 -511
- package/dist/core/index.js.map +1 -1
- package/dist/hooks/index.cjs +287 -188
- package/dist/hooks/index.cjs.map +1 -1
- package/dist/hooks/index.d.cts +40 -1
- package/dist/hooks/index.d.ts +40 -1
- package/dist/hooks/index.js +286 -189
- package/dist/hooks/index.js.map +1 -1
- package/dist/index.cjs +716 -567
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +129 -5
- package/dist/index.d.ts +129 -5
- package/dist/index.js +707 -568
- package/dist/index.js.map +1 -1
- package/dist/next/index.cjs +87 -45
- package/dist/next/index.cjs.map +1 -1
- package/dist/next/index.d.cts +65 -7
- package/dist/next/index.d.ts +65 -7
- package/dist/next/index.js +86 -46
- package/dist/next/index.js.map +1 -1
- package/dist/server/index.cjs +84 -45
- package/dist/server/index.cjs.map +1 -1
- package/dist/server/index.d.cts +67 -8
- package/dist/server/index.d.ts +67 -8
- package/dist/server/index.js +83 -46
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
package/dist/next/index.d.cts
CHANGED
|
@@ -87,8 +87,9 @@ interface ShopwaveOAuthClient {
|
|
|
87
87
|
//#region src/core/entities.d.ts
|
|
88
88
|
/**
|
|
89
89
|
* How each Shopwave entity is addressed, shared by the client functions below
|
|
90
|
-
* and the server route handlers in `react-shopwave-connect/
|
|
91
|
-
*
|
|
90
|
+
* and the server route handlers in `react-shopwave-connect/server` (wrapped with
|
|
91
|
+
* the session by `react-shopwave-connect/next`), so the two halves of the
|
|
92
|
+
* contract can't drift apart.
|
|
92
93
|
*/
|
|
93
94
|
interface EntityDefinition {
|
|
94
95
|
/** App route segment: `/api/<route>` and `/api/<route>/<id>`. */
|
|
@@ -148,7 +149,7 @@ declare const SHOPWAVE_ENTITIES: Readonly<Record<EntityKind, EntityDefinition>>;
|
|
|
148
149
|
*
|
|
149
150
|
* Like `SHOPWAVE_ENTITIES`, this table is shared by the client functions
|
|
150
151
|
* (`fetchMerchant`, `fetchUser`, `uploadImage`, …) and the server route
|
|
151
|
-
* handlers in `react-shopwave-connect/
|
|
152
|
+
* handlers in `react-shopwave-connect/server`, so the two halves of the contract
|
|
152
153
|
* can't drift apart. These aren't in `SHOPWAVE_ENTITIES` because they aren't
|
|
153
154
|
* keyed collections: `GET /merchant` answers `{ merchant: {…} }`, not a map by id.
|
|
154
155
|
*/
|
|
@@ -181,6 +182,50 @@ declare const SHOPWAVE_RESOURCES: Readonly<Record<ResourceKind, ResourceDefiniti
|
|
|
181
182
|
type UploadKind = "merchant" | "merchantFeature" | "product" | "user" | "applicationLogo" | "applicationImages";
|
|
182
183
|
/** `UploadKind` → the API's `contentType` value. */
|
|
183
184
|
declare const UPLOAD_KINDS: Readonly<Record<UploadKind, string>>;
|
|
185
|
+
/**
|
|
186
|
+
* The role an image plays, sent to Shopwave as the uploader's `prefix` header.
|
|
187
|
+
* The uploader names the file `<prefix>_<hash>.<ext>`, so the role travels with
|
|
188
|
+
* the file wherever a record stores it (a product's `images`). Live, merchant
|
|
189
|
+
* 5644, 4 Nov 2026: all four values answered 201.
|
|
190
|
+
* - `product`: a product gallery image;
|
|
191
|
+
* - `product_thumbnail`: the product's lead image, shown in lists;
|
|
192
|
+
* - `variant` / `variant_thumbnail`: a variant's own image and its lead image
|
|
193
|
+
* (used by the Connect integrations).
|
|
194
|
+
*
|
|
195
|
+
* Values are the ones Connect's `uploadFileToShopwave` sends.
|
|
196
|
+
*/
|
|
197
|
+
type UploadPrefix = "product" | "product_thumbnail" | "variant" | "variant_thumbnail";
|
|
198
|
+
/** Every `UploadPrefix`, longest first so a name check never takes `product` for `product_thumbnail`. */
|
|
199
|
+
declare const UPLOAD_PREFIXES: ReadonlyArray<UploadPrefix>;
|
|
200
|
+
/**
|
|
201
|
+
* Read-only lists that aren't records: the merchant's distinct tags.
|
|
202
|
+
*
|
|
203
|
+
* Like `SHOPWAVE_RESOURCES`, shared by the client functions
|
|
204
|
+
* (`fetchProductTags`, `fetchProductInstanceTags`) and the server route
|
|
205
|
+
* handlers (`shopwave.lookup(kind)`), so the two halves can't drift apart.
|
|
206
|
+
*
|
|
207
|
+
* - productTags: `GET /product/tags` → `{ tags: string[] }`, every distinct tag
|
|
208
|
+
* on the merchant's products. No parameters. The API reference says
|
|
209
|
+
* "internal SKU tags are excluded", but the live API includes system tags
|
|
210
|
+
* written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
|
|
211
|
+
* test merchant 5644, 29 Oct 2026). Apps that offer the list as suggestions
|
|
212
|
+
* filter those themselves. Tags of deleted products drop out of the list.
|
|
213
|
+
* - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
|
|
214
|
+
* the same for price instances (channels such as "Eat In", "Takeout").
|
|
215
|
+
*
|
|
216
|
+
* The app route for instance tags is `products/instance-tags`, one segment
|
|
217
|
+
* under `products`, so it sits beside `products/[id]` without nesting deeper.
|
|
218
|
+
*/
|
|
219
|
+
interface LookupDefinition {
|
|
220
|
+
/** App route: `/api/<route>`. */
|
|
221
|
+
route: string;
|
|
222
|
+
/** Key of the list in the response (`{ tags: [...] }`). */
|
|
223
|
+
key: string;
|
|
224
|
+
/** Shopwave API path. */
|
|
225
|
+
upstream: string;
|
|
226
|
+
}
|
|
227
|
+
type LookupKind = "productTags" | "productInstanceTags";
|
|
228
|
+
declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
|
|
184
229
|
//#endregion
|
|
185
230
|
//#region src/server/api.d.ts
|
|
186
231
|
/**
|
|
@@ -284,9 +329,11 @@ interface UploadOptions {
|
|
|
284
329
|
}
|
|
285
330
|
interface UploadHandlers {
|
|
286
331
|
/**
|
|
287
|
-
* Multipart `file` + `kind` (see `UploadKind`)
|
|
288
|
-
*
|
|
289
|
-
*
|
|
332
|
+
* Multipart `file` + `kind` (see `UploadKind`), and optionally `prefix`
|
|
333
|
+
* (see `UploadPrefix`) → `PUT {apiUrl}/uploader` with the `contentType` and
|
|
334
|
+
* `prefix` headers. Answers with Shopwave's reply (201 `{ fileName, path, api }`);
|
|
335
|
+
* 400 for a missing file or an unknown kind or prefix, 413 when too large,
|
|
336
|
+
* 415 for other types.
|
|
290
337
|
*/
|
|
291
338
|
POST: RouteHandler;
|
|
292
339
|
}
|
|
@@ -303,6 +350,14 @@ interface ShopwaveApiHandlers {
|
|
|
303
350
|
passthrough(path: string): {
|
|
304
351
|
GET: RouteHandler;
|
|
305
352
|
};
|
|
353
|
+
/**
|
|
354
|
+
* Handler for a read-only list (see `SHOPWAVE_LOOKUPS`), e.g.
|
|
355
|
+
* `app/api/products/tags/route.ts`: `export const { GET } = shopwave.lookup("productTags")`.
|
|
356
|
+
* Takes no parameters, so the caller's `extras` aren't forwarded.
|
|
357
|
+
*/
|
|
358
|
+
lookup(kind: LookupKind): {
|
|
359
|
+
GET: RouteHandler;
|
|
360
|
+
};
|
|
306
361
|
/** Handlers for a singleton resource: `app/api/merchant/route.ts`, `app/api/user/route.ts`. */
|
|
307
362
|
resource(kind: ResourceKind): ResourceHandlers;
|
|
308
363
|
/** Handler for `app/api/upload/route.ts`. */
|
|
@@ -510,9 +565,12 @@ interface ShopwaveNextApiConfig extends Omit<ShopwaveApiConfig, "getAuthorizatio
|
|
|
510
565
|
* export const { GET } = shopwave.resource("user");
|
|
511
566
|
* // app/api/upload/route.ts
|
|
512
567
|
* export const { POST } = shopwave.upload();
|
|
568
|
+
* // app/api/products/tags/route.ts, app/api/products/instance-tags/route.ts
|
|
569
|
+
* export const { GET } = shopwave.lookup("productTags");
|
|
570
|
+
* export const { GET } = shopwave.lookup("productInstanceTags");
|
|
513
571
|
* ```
|
|
514
572
|
*/
|
|
515
573
|
declare function createShopwaveApi(config: ShopwaveNextApiConfig): ShopwaveApiHandlers;
|
|
516
574
|
//#endregion
|
|
517
|
-
export { AuthContext, type CollectionHandlers, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, ProtectOptions, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_RESOURCES, type SessionStatus, type ShopwaveApiHandlers, ShopwaveAuth, ShopwaveAuthConfig, ShopwaveAuthError, ShopwaveNextApiConfig, ShopwaveSessionConfig, ShopwaveSessionData, type ShopwaveToken, UPLOAD_KINDS, type UploadHandlers, type UploadKind, type UploadOptions, authorizationHeader, createShopwaveApi, createShopwaveAuth, isExpiredTokenResponse, readRequestToken };
|
|
575
|
+
export { AuthContext, type CollectionHandlers, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, type LookupKind, ProtectOptions, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, type SessionStatus, type ShopwaveApiHandlers, ShopwaveAuth, ShopwaveAuthConfig, ShopwaveAuthError, ShopwaveNextApiConfig, ShopwaveSessionConfig, ShopwaveSessionData, type ShopwaveToken, UPLOAD_KINDS, UPLOAD_PREFIXES, type UploadHandlers, type UploadKind, type UploadOptions, type UploadPrefix, authorizationHeader, createShopwaveApi, createShopwaveAuth, isExpiredTokenResponse, readRequestToken };
|
|
518
576
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/next/index.d.ts
CHANGED
|
@@ -87,8 +87,9 @@ interface ShopwaveOAuthClient {
|
|
|
87
87
|
//#region src/core/entities.d.ts
|
|
88
88
|
/**
|
|
89
89
|
* How each Shopwave entity is addressed, shared by the client functions below
|
|
90
|
-
* and the server route handlers in `react-shopwave-connect/
|
|
91
|
-
*
|
|
90
|
+
* and the server route handlers in `react-shopwave-connect/server` (wrapped with
|
|
91
|
+
* the session by `react-shopwave-connect/next`), so the two halves of the
|
|
92
|
+
* contract can't drift apart.
|
|
92
93
|
*/
|
|
93
94
|
interface EntityDefinition {
|
|
94
95
|
/** App route segment: `/api/<route>` and `/api/<route>/<id>`. */
|
|
@@ -148,7 +149,7 @@ declare const SHOPWAVE_ENTITIES: Readonly<Record<EntityKind, EntityDefinition>>;
|
|
|
148
149
|
*
|
|
149
150
|
* Like `SHOPWAVE_ENTITIES`, this table is shared by the client functions
|
|
150
151
|
* (`fetchMerchant`, `fetchUser`, `uploadImage`, …) and the server route
|
|
151
|
-
* handlers in `react-shopwave-connect/
|
|
152
|
+
* handlers in `react-shopwave-connect/server`, so the two halves of the contract
|
|
152
153
|
* can't drift apart. These aren't in `SHOPWAVE_ENTITIES` because they aren't
|
|
153
154
|
* keyed collections: `GET /merchant` answers `{ merchant: {…} }`, not a map by id.
|
|
154
155
|
*/
|
|
@@ -181,6 +182,50 @@ declare const SHOPWAVE_RESOURCES: Readonly<Record<ResourceKind, ResourceDefiniti
|
|
|
181
182
|
type UploadKind = "merchant" | "merchantFeature" | "product" | "user" | "applicationLogo" | "applicationImages";
|
|
182
183
|
/** `UploadKind` → the API's `contentType` value. */
|
|
183
184
|
declare const UPLOAD_KINDS: Readonly<Record<UploadKind, string>>;
|
|
185
|
+
/**
|
|
186
|
+
* The role an image plays, sent to Shopwave as the uploader's `prefix` header.
|
|
187
|
+
* The uploader names the file `<prefix>_<hash>.<ext>`, so the role travels with
|
|
188
|
+
* the file wherever a record stores it (a product's `images`). Live, merchant
|
|
189
|
+
* 5644, 4 Nov 2026: all four values answered 201.
|
|
190
|
+
* - `product`: a product gallery image;
|
|
191
|
+
* - `product_thumbnail`: the product's lead image, shown in lists;
|
|
192
|
+
* - `variant` / `variant_thumbnail`: a variant's own image and its lead image
|
|
193
|
+
* (used by the Connect integrations).
|
|
194
|
+
*
|
|
195
|
+
* Values are the ones Connect's `uploadFileToShopwave` sends.
|
|
196
|
+
*/
|
|
197
|
+
type UploadPrefix = "product" | "product_thumbnail" | "variant" | "variant_thumbnail";
|
|
198
|
+
/** Every `UploadPrefix`, longest first so a name check never takes `product` for `product_thumbnail`. */
|
|
199
|
+
declare const UPLOAD_PREFIXES: ReadonlyArray<UploadPrefix>;
|
|
200
|
+
/**
|
|
201
|
+
* Read-only lists that aren't records: the merchant's distinct tags.
|
|
202
|
+
*
|
|
203
|
+
* Like `SHOPWAVE_RESOURCES`, shared by the client functions
|
|
204
|
+
* (`fetchProductTags`, `fetchProductInstanceTags`) and the server route
|
|
205
|
+
* handlers (`shopwave.lookup(kind)`), so the two halves can't drift apart.
|
|
206
|
+
*
|
|
207
|
+
* - productTags: `GET /product/tags` → `{ tags: string[] }`, every distinct tag
|
|
208
|
+
* on the merchant's products. No parameters. The API reference says
|
|
209
|
+
* "internal SKU tags are excluded", but the live API includes system tags
|
|
210
|
+
* written by imports and syncs (`PID-133`, `VID-137`, `#Hash:…`, `upc-…`;
|
|
211
|
+
* test merchant 5644, 29 Oct 2026). Apps that offer the list as suggestions
|
|
212
|
+
* filter those themselves. Tags of deleted products drop out of the list.
|
|
213
|
+
* - productInstanceTags: `GET /product/instance/tags` → `{ tags: string[] }`,
|
|
214
|
+
* the same for price instances (channels such as "Eat In", "Takeout").
|
|
215
|
+
*
|
|
216
|
+
* The app route for instance tags is `products/instance-tags`, one segment
|
|
217
|
+
* under `products`, so it sits beside `products/[id]` without nesting deeper.
|
|
218
|
+
*/
|
|
219
|
+
interface LookupDefinition {
|
|
220
|
+
/** App route: `/api/<route>`. */
|
|
221
|
+
route: string;
|
|
222
|
+
/** Key of the list in the response (`{ tags: [...] }`). */
|
|
223
|
+
key: string;
|
|
224
|
+
/** Shopwave API path. */
|
|
225
|
+
upstream: string;
|
|
226
|
+
}
|
|
227
|
+
type LookupKind = "productTags" | "productInstanceTags";
|
|
228
|
+
declare const SHOPWAVE_LOOKUPS: Readonly<Record<LookupKind, LookupDefinition>>;
|
|
184
229
|
//#endregion
|
|
185
230
|
//#region src/server/api.d.ts
|
|
186
231
|
/**
|
|
@@ -284,9 +329,11 @@ interface UploadOptions {
|
|
|
284
329
|
}
|
|
285
330
|
interface UploadHandlers {
|
|
286
331
|
/**
|
|
287
|
-
* Multipart `file` + `kind` (see `UploadKind`)
|
|
288
|
-
*
|
|
289
|
-
*
|
|
332
|
+
* Multipart `file` + `kind` (see `UploadKind`), and optionally `prefix`
|
|
333
|
+
* (see `UploadPrefix`) → `PUT {apiUrl}/uploader` with the `contentType` and
|
|
334
|
+
* `prefix` headers. Answers with Shopwave's reply (201 `{ fileName, path, api }`);
|
|
335
|
+
* 400 for a missing file or an unknown kind or prefix, 413 when too large,
|
|
336
|
+
* 415 for other types.
|
|
290
337
|
*/
|
|
291
338
|
POST: RouteHandler;
|
|
292
339
|
}
|
|
@@ -303,6 +350,14 @@ interface ShopwaveApiHandlers {
|
|
|
303
350
|
passthrough(path: string): {
|
|
304
351
|
GET: RouteHandler;
|
|
305
352
|
};
|
|
353
|
+
/**
|
|
354
|
+
* Handler for a read-only list (see `SHOPWAVE_LOOKUPS`), e.g.
|
|
355
|
+
* `app/api/products/tags/route.ts`: `export const { GET } = shopwave.lookup("productTags")`.
|
|
356
|
+
* Takes no parameters, so the caller's `extras` aren't forwarded.
|
|
357
|
+
*/
|
|
358
|
+
lookup(kind: LookupKind): {
|
|
359
|
+
GET: RouteHandler;
|
|
360
|
+
};
|
|
306
361
|
/** Handlers for a singleton resource: `app/api/merchant/route.ts`, `app/api/user/route.ts`. */
|
|
307
362
|
resource(kind: ResourceKind): ResourceHandlers;
|
|
308
363
|
/** Handler for `app/api/upload/route.ts`. */
|
|
@@ -510,9 +565,12 @@ interface ShopwaveNextApiConfig extends Omit<ShopwaveApiConfig, "getAuthorizatio
|
|
|
510
565
|
* export const { GET } = shopwave.resource("user");
|
|
511
566
|
* // app/api/upload/route.ts
|
|
512
567
|
* export const { POST } = shopwave.upload();
|
|
568
|
+
* // app/api/products/tags/route.ts, app/api/products/instance-tags/route.ts
|
|
569
|
+
* export const { GET } = shopwave.lookup("productTags");
|
|
570
|
+
* export const { GET } = shopwave.lookup("productInstanceTags");
|
|
513
571
|
* ```
|
|
514
572
|
*/
|
|
515
573
|
declare function createShopwaveApi(config: ShopwaveNextApiConfig): ShopwaveApiHandlers;
|
|
516
574
|
//#endregion
|
|
517
|
-
export { AuthContext, type CollectionHandlers, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, ProtectOptions, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_RESOURCES, type SessionStatus, type ShopwaveApiHandlers, ShopwaveAuth, ShopwaveAuthConfig, ShopwaveAuthError, ShopwaveNextApiConfig, ShopwaveSessionConfig, ShopwaveSessionData, type ShopwaveToken, UPLOAD_KINDS, type UploadHandlers, type UploadKind, type UploadOptions, authorizationHeader, createShopwaveApi, createShopwaveAuth, isExpiredTokenResponse, readRequestToken };
|
|
575
|
+
export { AuthContext, type CollectionHandlers, type EntityDefinition, type EntityKind, type ForwardInit, type ItemHandlers, type LookupKind, ProtectOptions, type ResourceHandlers, type ResourceKind, type RouteContext, type RouteHandler, SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, type SessionStatus, type ShopwaveApiHandlers, ShopwaveAuth, ShopwaveAuthConfig, ShopwaveAuthError, ShopwaveNextApiConfig, ShopwaveSessionConfig, ShopwaveSessionData, type ShopwaveToken, UPLOAD_KINDS, UPLOAD_PREFIXES, type UploadHandlers, type UploadKind, type UploadOptions, type UploadPrefix, authorizationHeader, createShopwaveApi, createShopwaveAuth, isExpiredTokenResponse, readRequestToken };
|
|
518
576
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/next/index.js
CHANGED
|
@@ -248,6 +248,74 @@ function safeEqual(a, b) {
|
|
|
248
248
|
return diff === 0;
|
|
249
249
|
}
|
|
250
250
|
|
|
251
|
+
//#endregion
|
|
252
|
+
//#region src/core/resources.ts
|
|
253
|
+
/**
|
|
254
|
+
* - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
|
|
255
|
+
* updates it (without an `id` the API would create a second merchant, so the
|
|
256
|
+
* route requires one).
|
|
257
|
+
* - user: `GET /user` (read-only here; the API's `POST /user` invites users and
|
|
258
|
+
* needs the admin scope).
|
|
259
|
+
*/
|
|
260
|
+
const SHOPWAVE_RESOURCES = Object.freeze({
|
|
261
|
+
merchant: {
|
|
262
|
+
route: "merchant",
|
|
263
|
+
key: "merchant",
|
|
264
|
+
upstream: "merchant",
|
|
265
|
+
writable: true
|
|
266
|
+
},
|
|
267
|
+
user: {
|
|
268
|
+
route: "user",
|
|
269
|
+
key: "user",
|
|
270
|
+
upstream: "user",
|
|
271
|
+
writable: false
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
/** `UploadKind` → the API's `contentType` value. */
|
|
275
|
+
const UPLOAD_KINDS = Object.freeze({
|
|
276
|
+
merchant: "merchant",
|
|
277
|
+
merchantFeature: "merchantFeature",
|
|
278
|
+
product: "product",
|
|
279
|
+
user: "user",
|
|
280
|
+
applicationLogo: "applicaionLogo",
|
|
281
|
+
applicationImages: "applicaionImages"
|
|
282
|
+
});
|
|
283
|
+
/** Every `UploadPrefix`, longest first so a name check never takes `product` for `product_thumbnail`. */
|
|
284
|
+
const UPLOAD_PREFIXES = Object.freeze([
|
|
285
|
+
"product_thumbnail",
|
|
286
|
+
"variant_thumbnail",
|
|
287
|
+
"product",
|
|
288
|
+
"variant"
|
|
289
|
+
]);
|
|
290
|
+
/** How uploads are addressed (app route and Shopwave uploader). */
|
|
291
|
+
const SHOPWAVE_UPLOAD = Object.freeze({
|
|
292
|
+
route: "upload",
|
|
293
|
+
upstream: "uploader",
|
|
294
|
+
kindHeader: "contentType",
|
|
295
|
+
prefixHeader: "prefix",
|
|
296
|
+
fileField: "file",
|
|
297
|
+
kindField: "kind",
|
|
298
|
+
prefixField: "prefix"
|
|
299
|
+
});
|
|
300
|
+
function isUploadKind(value) {
|
|
301
|
+
return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
|
|
302
|
+
}
|
|
303
|
+
function isUploadPrefix(value) {
|
|
304
|
+
return typeof value === "string" && UPLOAD_PREFIXES.includes(value);
|
|
305
|
+
}
|
|
306
|
+
const SHOPWAVE_LOOKUPS = Object.freeze({
|
|
307
|
+
productTags: {
|
|
308
|
+
route: "products/tags",
|
|
309
|
+
key: "tags",
|
|
310
|
+
upstream: "product/tags"
|
|
311
|
+
},
|
|
312
|
+
productInstanceTags: {
|
|
313
|
+
route: "products/instance-tags",
|
|
314
|
+
key: "tags",
|
|
315
|
+
upstream: "product/instance/tags"
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
|
|
251
319
|
//#endregion
|
|
252
320
|
//#region src/core/entities.ts
|
|
253
321
|
/**
|
|
@@ -324,50 +392,6 @@ const SHOPWAVE_ENTITIES = Object.freeze({
|
|
|
324
392
|
}
|
|
325
393
|
});
|
|
326
394
|
|
|
327
|
-
//#endregion
|
|
328
|
-
//#region src/core/resources.ts
|
|
329
|
-
/**
|
|
330
|
-
* - merchant: `GET /merchant`; `POST /merchant` with `{ merchant: { id, … } }`
|
|
331
|
-
* updates it (without an `id` the API would create a second merchant, so the
|
|
332
|
-
* route requires one).
|
|
333
|
-
* - user: `GET /user` (read-only here; the API's `POST /user` invites users and
|
|
334
|
-
* needs the admin scope).
|
|
335
|
-
*/
|
|
336
|
-
const SHOPWAVE_RESOURCES = Object.freeze({
|
|
337
|
-
merchant: {
|
|
338
|
-
route: "merchant",
|
|
339
|
-
key: "merchant",
|
|
340
|
-
upstream: "merchant",
|
|
341
|
-
writable: true
|
|
342
|
-
},
|
|
343
|
-
user: {
|
|
344
|
-
route: "user",
|
|
345
|
-
key: "user",
|
|
346
|
-
upstream: "user",
|
|
347
|
-
writable: false
|
|
348
|
-
}
|
|
349
|
-
});
|
|
350
|
-
/** `UploadKind` → the API's `contentType` value. */
|
|
351
|
-
const UPLOAD_KINDS = Object.freeze({
|
|
352
|
-
merchant: "merchant",
|
|
353
|
-
merchantFeature: "merchantFeature",
|
|
354
|
-
product: "product",
|
|
355
|
-
user: "user",
|
|
356
|
-
applicationLogo: "applicaionLogo",
|
|
357
|
-
applicationImages: "applicaionImages"
|
|
358
|
-
});
|
|
359
|
-
/** How uploads are addressed (app route and Shopwave uploader). */
|
|
360
|
-
const SHOPWAVE_UPLOAD = Object.freeze({
|
|
361
|
-
route: "upload",
|
|
362
|
-
upstream: "uploader",
|
|
363
|
-
kindHeader: "contentType",
|
|
364
|
-
fileField: "file",
|
|
365
|
-
kindField: "kind"
|
|
366
|
-
});
|
|
367
|
-
function isUploadKind(value) {
|
|
368
|
-
return typeof value === "string" && Object.prototype.hasOwnProperty.call(UPLOAD_KINDS, value);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
395
|
//#endregion
|
|
372
396
|
//#region src/server/api.ts
|
|
373
397
|
/**
|
|
@@ -696,6 +720,8 @@ function createShopwaveApiHandlers(config) {
|
|
|
696
720
|
if (!file || typeof file === "string" || file.size === 0) return jsonError(400, "invalid_body", `Missing "${SHOPWAVE_UPLOAD.fileField}"`);
|
|
697
721
|
const kind = form.get(SHOPWAVE_UPLOAD.kindField);
|
|
698
722
|
if (!isUploadKind(kind)) return jsonError(400, "invalid_body", `"${SHOPWAVE_UPLOAD.kindField}" must be one of ${Object.keys(UPLOAD_KINDS).join(", ")}`);
|
|
723
|
+
const prefix = form.get(SHOPWAVE_UPLOAD.prefixField);
|
|
724
|
+
if (prefix !== null && !isUploadPrefix(prefix)) return jsonError(400, "invalid_body", `"${SHOPWAVE_UPLOAD.prefixField}" must be one of ${UPLOAD_PREFIXES.join(", ")}`);
|
|
699
725
|
if (file.size > maxBytes) return jsonError(413, "too_large", `The file is larger than ${maxBytes} bytes`);
|
|
700
726
|
if (!acceptsType(file.type || "", accept)) return jsonError(415, "unsupported_type", `Files of type "${file.type || "unknown"}" aren't accepted`);
|
|
701
727
|
const upstreamForm = new FormData();
|
|
@@ -703,7 +729,10 @@ function createShopwaveApiHandlers(config) {
|
|
|
703
729
|
return forward(request, {
|
|
704
730
|
method: "PUT",
|
|
705
731
|
path: SHOPWAVE_UPLOAD.upstream,
|
|
706
|
-
headers: {
|
|
732
|
+
headers: {
|
|
733
|
+
[SHOPWAVE_UPLOAD.kindHeader]: UPLOAD_KINDS[kind],
|
|
734
|
+
...prefix !== null ? { [SHOPWAVE_UPLOAD.prefixHeader]: prefix } : {}
|
|
735
|
+
},
|
|
707
736
|
formData: upstreamForm,
|
|
708
737
|
forwardExtras: false
|
|
709
738
|
});
|
|
@@ -808,6 +837,14 @@ function createShopwaveApiHandlers(config) {
|
|
|
808
837
|
passthrough(path) {
|
|
809
838
|
return { GET: (request) => forward(request, { path }) };
|
|
810
839
|
},
|
|
840
|
+
lookup(kind) {
|
|
841
|
+
const def = SHOPWAVE_LOOKUPS[kind];
|
|
842
|
+
if (!def) throw new Error(`Unknown Shopwave lookup "${kind}"`);
|
|
843
|
+
return { GET: (request) => forward(request, {
|
|
844
|
+
path: def.upstream,
|
|
845
|
+
forwardExtras: false
|
|
846
|
+
}) };
|
|
847
|
+
},
|
|
811
848
|
resource(kind) {
|
|
812
849
|
const def = resourceDef(kind);
|
|
813
850
|
const save = (request) => writeResource(request, def);
|
|
@@ -1150,6 +1187,9 @@ function createShopwaveAuth(config) {
|
|
|
1150
1187
|
* export const { GET } = shopwave.resource("user");
|
|
1151
1188
|
* // app/api/upload/route.ts
|
|
1152
1189
|
* export const { POST } = shopwave.upload();
|
|
1190
|
+
* // app/api/products/tags/route.ts, app/api/products/instance-tags/route.ts
|
|
1191
|
+
* export const { GET } = shopwave.lookup("productTags");
|
|
1192
|
+
* export const { GET } = shopwave.lookup("productInstanceTags");
|
|
1153
1193
|
* ```
|
|
1154
1194
|
*/
|
|
1155
1195
|
function createShopwaveApi(config) {
|
|
@@ -1162,5 +1202,5 @@ function createShopwaveApi(config) {
|
|
|
1162
1202
|
}
|
|
1163
1203
|
|
|
1164
1204
|
//#endregion
|
|
1165
|
-
export { SHOPWAVE_ENTITIES, SHOPWAVE_RESOURCES, ShopwaveAuthError, UPLOAD_KINDS, authorizationHeader, createShopwaveApi, createShopwaveAuth, isExpiredTokenResponse, readRequestToken };
|
|
1205
|
+
export { SHOPWAVE_ENTITIES, SHOPWAVE_LOOKUPS, SHOPWAVE_RESOURCES, ShopwaveAuthError, UPLOAD_KINDS, UPLOAD_PREFIXES, authorizationHeader, createShopwaveApi, createShopwaveAuth, isExpiredTokenResponse, readRequestToken };
|
|
1166
1206
|
//# sourceMappingURL=index.js.map
|