@viu/emporix-sdk 1.0.0 → 2.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +13 -0
  3. package/dist/cart.d.cts +1 -1
  4. package/dist/cart.d.ts +1 -1
  5. package/dist/category.d.cts +1 -1
  6. package/dist/category.d.ts +1 -1
  7. package/dist/checkout.d.cts +1 -1
  8. package/dist/checkout.d.ts +1 -1
  9. package/dist/chunk-WSXRUYBE.js +248 -0
  10. package/dist/chunk-WSXRUYBE.js.map +1 -0
  11. package/dist/companies.d.cts +1 -1
  12. package/dist/companies.d.ts +1 -1
  13. package/dist/contacts.d.cts +1 -1
  14. package/dist/contacts.d.ts +1 -1
  15. package/dist/{context-vKgzZ-5f.d.cts → context-mMTqsW1Z.d.cts} +15 -0
  16. package/dist/{context-vKgzZ-5f.d.ts → context-mMTqsW1Z.d.ts} +15 -0
  17. package/dist/customer-groups.d.cts +1 -1
  18. package/dist/customer-groups.d.ts +1 -1
  19. package/dist/customer.d.cts +1 -1
  20. package/dist/customer.d.ts +1 -1
  21. package/dist/index.cjs +186 -9
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +3 -3
  24. package/dist/index.d.ts +3 -3
  25. package/dist/index.js +53 -2
  26. package/dist/index.js.map +1 -1
  27. package/dist/locations.d.cts +1 -1
  28. package/dist/locations.d.ts +1 -1
  29. package/dist/media.cjs +218 -9
  30. package/dist/media.cjs.map +1 -1
  31. package/dist/media.d.cts +103 -7
  32. package/dist/media.d.ts +103 -7
  33. package/dist/media.js +2 -1
  34. package/dist/orders.d.cts +1 -1
  35. package/dist/orders.d.ts +1 -1
  36. package/dist/payment.d.cts +1 -1
  37. package/dist/payment.d.ts +1 -1
  38. package/dist/price.d.cts +1 -1
  39. package/dist/price.d.ts +1 -1
  40. package/dist/product.d.cts +1 -1
  41. package/dist/product.d.ts +1 -1
  42. package/dist/segment.d.cts +1 -1
  43. package/dist/segment.d.ts +1 -1
  44. package/package.json +2 -2
  45. package/dist/chunk-F3WAQH2E.js +0 -120
  46. package/dist/chunk-F3WAQH2E.js.map +0 -1
package/dist/media.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext } from './context-vKgzZ-5f.js';
1
+ import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-mMTqsW1Z.js';
2
2
 
3
3
  type MetadataUpdate = {
4
4
  /**
@@ -156,9 +156,44 @@ type AssetUpdateBlob = Asset$1 & {
156
156
  /** Generated media types (caller sends the exact wire shape). */
157
157
  type AssetCreateBlobInput = AssetCreateBlob;
158
158
  type AssetCreateLinkInput = AssetCreateLink;
159
+ type AssetUpdateBlobInput = AssetUpdateBlob;
160
+ type AssetUpdateLinkInput = AssetUpdateLink;
159
161
  type AssetUpdateInput = AssetUpdateBlob | AssetUpdateLink;
160
162
  type Asset = GetAsset;
161
163
  type AssetRefId = RefId;
164
+ /**
165
+ * Filter / pagination options for {@link MediaService.list}. The explicit
166
+ * fields are typed for autocomplete; the index signature stays open so
167
+ * Emporix `q`-syntax filters like `"refIds.id"` can be passed verbatim.
168
+ */
169
+ interface ListAssetsQuery {
170
+ pageNumber?: number;
171
+ pageSize?: number;
172
+ /** Emporix sort syntax, e.g. `"name,metadata.createdAt:desc"`. */
173
+ sort?: string;
174
+ /** Emporix `q`-syntax filter, e.g. `"name:hero"`. */
175
+ q?: string;
176
+ [key: string]: string | number | undefined;
177
+ }
178
+ /**
179
+ * Result of {@link MediaService.download}. The endpoint's behaviour depends
180
+ * on the asset's `access`:
181
+ * - `PUBLIC` assets respond with a 30x redirect whose `Location` header
182
+ * carries the externally-cacheable storage URL — useful when the
183
+ * storefront wants to send the user there directly.
184
+ * - `PRIVATE` assets respond with the raw bytes (plus an `ETag` header
185
+ * for caching). The asset is delivered through Cloudinary behind the
186
+ * server-side service token, never publicly addressable.
187
+ */
188
+ type DownloadResult = {
189
+ kind: "redirect";
190
+ url: string;
191
+ } | {
192
+ kind: "bytes";
193
+ data: ArrayBuffer;
194
+ etag?: string;
195
+ contentType?: string;
196
+ };
162
197
  declare function isProductRef(r: AssetRefId, productId: string): boolean;
163
198
  /**
164
199
  * Media assets (BLOB/LINK). All endpoints require a backend-only scope
@@ -179,14 +214,61 @@ declare class MediaService {
179
214
  }, auth?: AuthContext): Promise<{
180
215
  id: string;
181
216
  }>;
182
- /** List assets. Optional `query` is passed through to Emporix verbatim. */
183
- list(query?: Record<string, string | number | undefined>, auth?: AuthContext): Promise<Asset[]>;
217
+ /**
218
+ * List assets, wrapped in the shared {@link PaginatedItems} envelope so
219
+ * callers can iterate over pages consistently with the rest of the SDK.
220
+ * `hasNextPage` is the standard SDK heuristic: `true` when the returned
221
+ * page is full (`items.length === requested pageSize`). Pagination
222
+ * defaults match Emporix's server defaults (`pageNumber: 1`,
223
+ * `pageSize: 60`) so an empty `query` produces stable expectations.
224
+ */
225
+ list(query?: ListAssetsQuery, auth?: AuthContext): Promise<PaginatedItems<Asset>>;
184
226
  /** Fetch an asset by id. */
185
227
  get(assetId: string, auth?: AuthContext): Promise<Asset>;
186
- /** Update an asset (e.g. swap `refIds` or `access`). */
187
- update(assetId: string, patch: AssetUpdateInput, auth?: AuthContext): Promise<Asset>;
228
+ /**
229
+ * Update an asset. The input is a discriminated union mirroring
230
+ * {@link create}:
231
+ * - `{ kind: "json", body }` — metadata-only patch (BLOB or LINK).
232
+ * Sends `application/json`. Used for `refIds`, `details`, `metadata`,
233
+ * or `url` changes.
234
+ * - `{ kind: "blob", file, body }` — replaces the BLOB file content
235
+ * (max 10MB) AND patches metadata in the same request. Sends
236
+ * `multipart/form-data`.
237
+ *
238
+ * `type` and `access` are immutable per Emporix — they must match the
239
+ * existing asset's values. Optimistic-locking is via `body.metadata.version`;
240
+ * the server returns 409 Conflict on a stale version.
241
+ */
242
+ update(assetId: string, input: {
243
+ kind: "json";
244
+ body: AssetUpdateInput;
245
+ } | {
246
+ kind: "blob";
247
+ file: Blob;
248
+ body: AssetUpdateBlobInput;
249
+ }, auth?: AuthContext): Promise<Asset>;
188
250
  /** Remove an asset. */
189
251
  remove(assetId: string, auth?: AuthContext): Promise<void>;
252
+ /**
253
+ * Download an asset by id. Returns a discriminated union:
254
+ * - `{ kind: "redirect", url }` for `PUBLIC` assets (server-side 30x with
255
+ * the storage URL in `Location`).
256
+ * - `{ kind: "bytes", data }` for `PRIVATE` assets (server-side 200 with
257
+ * the asset bytes; `etag` + `contentType` headers are exposed for
258
+ * caching). When the server reports `text/plain` Content-Type (the
259
+ * OpenAPI-documented format), the SDK decodes the base64 stream into
260
+ * an `ArrayBuffer` transparently; binary Content-Types are passed
261
+ * through verbatim.
262
+ *
263
+ * Implementation note: uses `redirect: "manual"` so the redirect-location
264
+ * is observable. In Node.js this works; in a browser the redirect Location
265
+ * is intentionally hidden by fetch — there, `PUBLIC` downloads will
266
+ * surface as an opaque-redirect and the SDK throws. Browser code should
267
+ * use the asset's `url` field from `get()` for `LINK` assets, or the
268
+ * direct storage URL for `PUBLIC` `BLOB` assets (typically delivered via
269
+ * an `<img>` tag rather than `download()`).
270
+ */
271
+ download(assetId: string, auth?: AuthContext): Promise<DownloadResult>;
190
272
  /** Multipart upload sugar: builds `AssetCreateBlob` from input. */
191
273
  uploadFile(input: {
192
274
  file: Blob;
@@ -197,6 +279,20 @@ declare class MediaService {
197
279
  }, auth?: AuthContext): Promise<{
198
280
  id: string;
199
281
  }>;
282
+ /**
283
+ * Replace the file content of an existing BLOB asset. Sugar over
284
+ * {@link update} with `kind: "blob"`. `access` is required because the
285
+ * field is immutable and the server validates that the patch matches.
286
+ * Pass `version` from `asset.metadata.version` if you want optimistic
287
+ * locking (recommended when concurrent writers are possible).
288
+ */
289
+ replaceFile(assetId: string, input: {
290
+ file: Blob;
291
+ access: "PUBLIC" | "PRIVATE";
292
+ filename?: string;
293
+ mimeType?: string;
294
+ version?: number;
295
+ }, auth?: AuthContext): Promise<Asset>;
200
296
  /** External-URL sugar: builds `AssetCreateLink`. */
201
297
  link(input: {
202
298
  url: string;
@@ -210,10 +306,10 @@ declare class MediaService {
210
306
  /** Remove a PRODUCT refId from an asset (no-op if absent). */
211
307
  detachFromProduct(assetId: string, productId: string, auth?: AuthContext): Promise<Asset>;
212
308
  /** Convenience: list assets attached to a product (server-side filter). */
213
- listForProduct(productId: string, auth?: AuthContext): Promise<Asset[]>;
309
+ listForProduct(productId: string, auth?: AuthContext): Promise<PaginatedItems<Asset>>;
214
310
  }
215
311
  declare const _internalMedia: {
216
312
  isProductRef: typeof isProductRef;
217
313
  };
218
314
 
219
- export { type Asset, type AssetCreateBlobInput, type AssetCreateLinkInput, type AssetRefId, type AssetUpdateInput, MediaService, _internalMedia };
315
+ export { type Asset, type AssetCreateBlobInput, type AssetCreateLinkInput, type AssetRefId, type AssetUpdateBlobInput, type AssetUpdateInput, type AssetUpdateLinkInput, type DownloadResult, type ListAssetsQuery, MediaService, _internalMedia };
package/dist/media.js CHANGED
@@ -1,3 +1,4 @@
1
- export { MediaService, _internalMedia } from './chunk-F3WAQH2E.js';
1
+ export { MediaService, _internalMedia } from './chunk-WSXRUYBE.js';
2
+ import './chunk-KTODT6DV.js';
2
3
  //# sourceMappingURL=media.js.map
3
4
  //# sourceMappingURL=media.js.map
package/dist/orders.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-vKgzZ-5f.cjs';
1
+ import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-mMTqsW1Z.cjs';
2
2
 
3
3
  /**
4
4
  * Hand-written mirror of the Emporix Order-v2 schemas (storefront-relevant
package/dist/orders.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-vKgzZ-5f.js';
1
+ import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-mMTqsW1Z.js';
2
2
 
3
3
  /**
4
4
  * Hand-written mirror of the Emporix Order-v2 schemas (storefront-relevant
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext } from './context-vKgzZ-5f.cjs';
1
+ import { C as ClientContext, b as AuthContext } from './context-mMTqsW1Z.cjs';
2
2
 
3
3
  type PaymentModeFrontendResponse = {
4
4
  /**
package/dist/payment.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext } from './context-vKgzZ-5f.js';
1
+ import { C as ClientContext, b as AuthContext } from './context-mMTqsW1Z.js';
2
2
 
3
3
  type PaymentModeFrontendResponse = {
4
4
  /**
package/dist/price.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext } from './context-vKgzZ-5f.cjs';
1
+ import { C as ClientContext, b as AuthContext } from './context-mMTqsW1Z.cjs';
2
2
 
3
3
  type Metadata = {
4
4
  /**
package/dist/price.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext } from './context-vKgzZ-5f.js';
1
+ import { C as ClientContext, b as AuthContext } from './context-mMTqsW1Z.js';
2
2
 
3
3
  type Metadata = {
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-vKgzZ-5f.cjs';
1
+ import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-mMTqsW1Z.cjs';
2
2
 
3
3
  /**
4
4
  * Localized value which can have different structure which depends on provided `Content-Language` header.
package/dist/product.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-vKgzZ-5f.js';
1
+ import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-mMTqsW1Z.js';
2
2
 
3
3
  /**
4
4
  * Localized value which can have different structure which depends on provided `Content-Language` header.
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-vKgzZ-5f.cjs';
1
+ import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-mMTqsW1Z.cjs';
2
2
  import { ProductService } from './product.cjs';
3
3
  import { CategoryService } from './category.cjs';
4
4
 
package/dist/segment.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-vKgzZ-5f.js';
1
+ import { C as ClientContext, b as AuthContext, P as PaginatedItems } from './context-mMTqsW1Z.js';
2
2
  import { ProductService } from './product.js';
3
3
  import { CategoryService } from './category.js';
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viu/emporix-sdk",
3
- "version": "1.0.0",
3
+ "version": "2.0.0",
4
4
  "description": "TypeScript SDK for the Emporix Commerce Engine",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -114,7 +114,7 @@
114
114
  },
115
115
  "publishConfig": {
116
116
  "access": "public",
117
- "provenance": false
117
+ "provenance": true
118
118
  },
119
119
  "devDependencies": {
120
120
  "@hey-api/openapi-ts": "^0.64.0",
@@ -1,120 +0,0 @@
1
- // src/services/media.ts
2
- var SERVICE = { kind: "service" };
3
- function isProductRef(r, productId) {
4
- return r.type === "PRODUCT" && r.id === productId;
5
- }
6
- var MediaService = class {
7
- constructor(ctx) {
8
- this.ctx = ctx;
9
- }
10
- ctx;
11
- base() {
12
- return `/media/${this.ctx.tenant}/assets`;
13
- }
14
- /** Create an asset. BLOB uploads via multipart; LINK via JSON. */
15
- async create(input, auth = SERVICE) {
16
- if (input.kind === "blob") {
17
- const fd = new FormData();
18
- fd.set("file", input.file);
19
- fd.set("body", JSON.stringify(input.body));
20
- return this.ctx.http.request({
21
- method: "POST",
22
- path: this.base(),
23
- auth,
24
- body: fd
25
- });
26
- }
27
- return this.ctx.http.request({
28
- method: "POST",
29
- path: this.base(),
30
- auth,
31
- body: input.body
32
- });
33
- }
34
- /** List assets. Optional `query` is passed through to Emporix verbatim. */
35
- async list(query, auth = SERVICE) {
36
- return this.ctx.http.request({
37
- method: "GET",
38
- path: this.base(),
39
- auth,
40
- ...query ? { query } : {}
41
- });
42
- }
43
- /** Fetch an asset by id. */
44
- async get(assetId, auth = SERVICE) {
45
- return this.ctx.http.request({
46
- method: "GET",
47
- path: `${this.base()}/${assetId}`,
48
- auth
49
- });
50
- }
51
- /** Update an asset (e.g. swap `refIds` or `access`). */
52
- async update(assetId, patch, auth = SERVICE) {
53
- return this.ctx.http.request({
54
- method: "PUT",
55
- path: `${this.base()}/${assetId}`,
56
- auth,
57
- body: patch
58
- });
59
- }
60
- /** Remove an asset. */
61
- async remove(assetId, auth = SERVICE) {
62
- await this.ctx.http.request({
63
- method: "DELETE",
64
- path: `${this.base()}/${assetId}`,
65
- auth
66
- });
67
- }
68
- /** Multipart upload sugar: builds `AssetCreateBlob` from input. */
69
- async uploadFile(input, auth = SERVICE) {
70
- const body = {
71
- type: "BLOB",
72
- access: input.access ?? "PUBLIC",
73
- ...input.productId ? { refIds: [{ type: "PRODUCT", id: input.productId }] } : {},
74
- ...input.filename || input.mimeType ? {
75
- details: {
76
- ...input.filename ? { filename: input.filename } : {},
77
- ...input.mimeType ? { mimeType: input.mimeType } : {}
78
- }
79
- } : {}
80
- };
81
- return this.create({ kind: "blob", file: input.file, body }, auth);
82
- }
83
- /** External-URL sugar: builds `AssetCreateLink`. */
84
- async link(input, auth = SERVICE) {
85
- const body = {
86
- type: "LINK",
87
- access: input.access ?? "PUBLIC",
88
- url: input.url,
89
- ...input.productId ? { refIds: [{ type: "PRODUCT", id: input.productId }] } : {}
90
- };
91
- return this.create({ kind: "link", body }, auth);
92
- }
93
- /** Idempotently add a PRODUCT refId to an asset. */
94
- async attachToProduct(assetId, productId, auth = SERVICE) {
95
- const a = await this.get(assetId, auth);
96
- const refIds = a.refIds ?? [];
97
- if (refIds.some((r) => isProductRef(r, productId))) return a;
98
- const next = [...refIds, { type: "PRODUCT", id: productId }];
99
- const patch = { type: a.type, refIds: next };
100
- return this.update(assetId, patch, auth);
101
- }
102
- /** Remove a PRODUCT refId from an asset (no-op if absent). */
103
- async detachFromProduct(assetId, productId, auth = SERVICE) {
104
- const a = await this.get(assetId, auth);
105
- const refIds = a.refIds ?? [];
106
- const next = refIds.filter((r) => !isProductRef(r, productId));
107
- if (next.length === refIds.length) return a;
108
- const patch = { type: a.type, refIds: next };
109
- return this.update(assetId, patch, auth);
110
- }
111
- /** Convenience: list assets attached to a product (server-side filter). */
112
- async listForProduct(productId, auth = SERVICE) {
113
- return this.list({ "refIds.id": productId }, auth);
114
- }
115
- };
116
- var _internalMedia = { isProductRef };
117
-
118
- export { MediaService, _internalMedia };
119
- //# sourceMappingURL=chunk-F3WAQH2E.js.map
120
- //# sourceMappingURL=chunk-F3WAQH2E.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/services/media.ts"],"names":[],"mappings":"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","file":"chunk-F3WAQH2E.js","sourcesContent":["import type { ClientContext } from \"../core/context\";\nimport type { AuthContext } from \"../core/auth\";\nimport type {\n AssetCreateBlob,\n AssetCreateLink,\n AssetUpdateBlob,\n AssetUpdateLink,\n GetAsset,\n RefId,\n} from \"../generated/media\";\n\n/** Generated media types (caller sends the exact wire shape). */\nexport type AssetCreateBlobInput = AssetCreateBlob;\nexport type AssetCreateLinkInput = AssetCreateLink;\nexport type AssetUpdateInput = AssetUpdateBlob | AssetUpdateLink;\nexport type Asset = GetAsset;\nexport type AssetRefId = RefId;\n\nconst SERVICE: AuthContext = { kind: \"service\" };\n\nfunction isProductRef(r: AssetRefId, productId: string): boolean {\n return r.type === \"PRODUCT\" && r.id === productId;\n}\n\n/**\n * Media assets (BLOB/LINK). All endpoints require a backend-only scope\n * (`media.asset_manage` / `media.asset_read`) — default auth: service.\n */\nexport class MediaService {\n constructor(private readonly ctx: ClientContext) {}\n\n private base(): string {\n return `/media/${this.ctx.tenant}/assets`;\n }\n\n /** Create an asset. BLOB uploads via multipart; LINK via JSON. */\n async create(\n input:\n | { kind: \"blob\"; file: Blob; body: AssetCreateBlobInput }\n | { kind: \"link\"; body: AssetCreateLinkInput },\n auth: AuthContext = SERVICE,\n ): Promise<{ id: string }> {\n if (input.kind === \"blob\") {\n const fd = new FormData();\n fd.set(\"file\", input.file);\n fd.set(\"body\", JSON.stringify(input.body));\n return this.ctx.http.request<{ id: string }>({\n method: \"POST\",\n path: this.base(),\n auth,\n body: fd,\n });\n }\n return this.ctx.http.request<{ id: string }>({\n method: \"POST\",\n path: this.base(),\n auth,\n body: input.body,\n });\n }\n\n /** List assets. Optional `query` is passed through to Emporix verbatim. */\n async list(\n query?: Record<string, string | number | undefined>,\n auth: AuthContext = SERVICE,\n ): Promise<Asset[]> {\n return this.ctx.http.request<Asset[]>({\n method: \"GET\",\n path: this.base(),\n auth,\n ...(query ? { query } : {}),\n });\n }\n\n /** Fetch an asset by id. */\n async get(assetId: string, auth: AuthContext = SERVICE): Promise<Asset> {\n return this.ctx.http.request<Asset>({\n method: \"GET\",\n path: `${this.base()}/${assetId}`,\n auth,\n });\n }\n\n /** Update an asset (e.g. swap `refIds` or `access`). */\n async update(\n assetId: string,\n patch: AssetUpdateInput,\n auth: AuthContext = SERVICE,\n ): Promise<Asset> {\n return this.ctx.http.request<Asset>({\n method: \"PUT\",\n path: `${this.base()}/${assetId}`,\n auth,\n body: patch,\n });\n }\n\n /** Remove an asset. */\n async remove(assetId: string, auth: AuthContext = SERVICE): Promise<void> {\n await this.ctx.http.request<void>({\n method: \"DELETE\",\n path: `${this.base()}/${assetId}`,\n auth,\n });\n }\n\n /** Multipart upload sugar: builds `AssetCreateBlob` from input. */\n async uploadFile(\n input: {\n file: Blob;\n productId?: string;\n filename?: string;\n mimeType?: string;\n access?: \"PUBLIC\" | \"PRIVATE\";\n },\n auth: AuthContext = SERVICE,\n ): Promise<{ id: string }> {\n const body: AssetCreateBlobInput = {\n type: \"BLOB\",\n access: input.access ?? \"PUBLIC\",\n ...(input.productId\n ? { refIds: [{ type: \"PRODUCT\", id: input.productId }] }\n : {}),\n ...(input.filename || input.mimeType\n ? {\n details: {\n ...(input.filename ? { filename: input.filename } : {}),\n ...(input.mimeType ? { mimeType: input.mimeType } : {}),\n },\n }\n : {}),\n };\n return this.create({ kind: \"blob\", file: input.file, body }, auth);\n }\n\n /** External-URL sugar: builds `AssetCreateLink`. */\n async link(\n input: { url: string; productId?: string; access?: \"PUBLIC\" | \"PRIVATE\" },\n auth: AuthContext = SERVICE,\n ): Promise<{ id: string }> {\n const body: AssetCreateLinkInput = {\n type: \"LINK\",\n access: input.access ?? \"PUBLIC\",\n url: input.url,\n ...(input.productId\n ? { refIds: [{ type: \"PRODUCT\", id: input.productId }] }\n : {}),\n };\n return this.create({ kind: \"link\", body }, auth);\n }\n\n /** Idempotently add a PRODUCT refId to an asset. */\n async attachToProduct(\n assetId: string,\n productId: string,\n auth: AuthContext = SERVICE,\n ): Promise<Asset> {\n const a = await this.get(assetId, auth);\n const refIds: AssetRefId[] = a.refIds ?? [];\n if (refIds.some((r) => isProductRef(r, productId))) return a;\n const next: AssetRefId[] = [...refIds, { type: \"PRODUCT\", id: productId }];\n // Preserve the asset's type discriminator so the update body satisfies\n // the AssetUpdateBlob | AssetUpdateLink union.\n const patch = { type: a.type, refIds: next } as unknown as AssetUpdateInput;\n return this.update(assetId, patch, auth);\n }\n\n /** Remove a PRODUCT refId from an asset (no-op if absent). */\n async detachFromProduct(\n assetId: string,\n productId: string,\n auth: AuthContext = SERVICE,\n ): Promise<Asset> {\n const a = await this.get(assetId, auth);\n const refIds: AssetRefId[] = a.refIds ?? [];\n const next = refIds.filter((r) => !isProductRef(r, productId));\n if (next.length === refIds.length) return a;\n const patch = { type: a.type, refIds: next } as unknown as AssetUpdateInput;\n return this.update(assetId, patch, auth);\n }\n\n /** Convenience: list assets attached to a product (server-side filter). */\n async listForProduct(productId: string, auth: AuthContext = SERVICE): Promise<Asset[]> {\n return this.list({ \"refIds.id\": productId }, auth);\n }\n}\n\n// Re-export so consumers can `import { isProductRef } from \"@viu/emporix-sdk/media\"`?\n// Internal helper — kept module-private; convenience methods in Task 4 use it.\nexport const _internalMedia = { isProductRef };\n"]}