@classytic/commerce-client 0.1.0 → 0.1.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.1 — 2026-10-20
4
+
5
+ Add tenant-scoped media removal through the guarded media resource, and type media folder, size and display metadata for Fluid library bindings. Report unsupported source formats and browser decoding failures before starting storage writes.
6
+
7
+ Add `@classytic/commerce-client/platform`: `createPlatformClient({ apiUrl, token })` for platform administration with a bearer token and no merchant organization. `organizations.list` pages organizations and `organizations.decide(id, { action, expectedStatus, note })` applies an approve, reject, suspend or reactivate decision (matches `@spinekit/auth` 0.17.0 `./organizations`).
8
+
9
+ Dependencies are already at the latest published (`arc-next` 0.18.0, `media-transform` 0.3.0, `primitives` 0.34.0).
10
+
3
11
  ## 0.1.0 — 2026-10-20
4
12
 
5
13
  First publish.
@@ -19,3 +27,5 @@ Typed store profiles, catalog reads, guest checkout with explicit retry keys, an
19
27
  The isolated `/management` entry supports merchant catalog/media, order commands
20
28
  and cash collection, store settings, Telegram connections and delivery history,
21
29
  plus API-key options, creation, rotation and revocation.
30
+
31
+ Platform administration: `./platform` exposes bearer-only organization lists and guarded status decisions without requiring a merchant organization.
@@ -98,6 +98,11 @@ export interface StoreSettings {
98
98
  }
99
99
  export interface MerchantMedia {
100
100
  _id: string;
101
+ folder: string;
102
+ size: number;
103
+ title?: string;
104
+ alt?: string;
105
+ createdAt?: string;
101
106
  url: string;
102
107
  filename: string;
103
108
  mimeType?: string;
@@ -86,6 +86,12 @@ export declare function createMerchantClient(options: MerchantClientOptions): {
86
86
  params?: import("@classytic/arc-next/api").QueryParams;
87
87
  options?: Omit<import("@classytic/arc-next/api").RequestOptions, "token" | "organizationId">;
88
88
  }) => Promise<import("@classytic/repo-core/pagination").PaginatedResult<MerchantMedia>>;
89
+ remove: ({ token, organizationId, id, options }: {
90
+ token?: string | null;
91
+ organizationId?: string | null;
92
+ id: string;
93
+ options?: Omit<import("@classytic/arc-next/api").RequestOptions, "token" | "organizationId">;
94
+ }) => Promise<import("@classytic/repo-core/repository").DeleteResult>;
89
95
  upload: (file: File, folder?: 'products' | 'categories') => Promise<MerchantMedia>;
90
96
  uploadImage(file: File, folder?: 'products' | 'categories'): Promise<MerchantMedia>;
91
97
  };
@@ -124,10 +124,12 @@ function createMerchantMedia(client, fetcher) {
124
124
  }
125
125
  return {
126
126
  list: media.getAll.bind(media),
127
+ remove: media.delete.bind(media),
127
128
  upload: (file, folder = "products") => upload(file, folder),
128
129
  async uploadImage(file, folder = "products") {
129
130
  const policy = await media.request("GET", `${media.baseUrl}/transform-policy`);
130
- const { resolveTransformPlan } = await import("@classytic/media-transform/policy");
131
+ const { resolveTransformPlan, isTransformableImage } = await import("@classytic/media-transform/policy");
132
+ if (!isTransformableImage(file.type)) throw new Error("Choose a JPEG, PNG, WebP, AVIF or BMP image that your browser can open.");
131
133
  const plan = resolveTransformPlan({
132
134
  folder,
133
135
  mimeType: file.type,
@@ -142,7 +144,9 @@ function createMerchantMedia(client, fetcher) {
142
144
  import("@classytic/media-transform/image/compressImageSet"),
143
145
  import("@classytic/media-transform/image/uploadHints")
144
146
  ]);
145
- const result = await compressImageSet(await createBrowserImageAdapter(), file, plan.options);
147
+ const result = await compressImageSet(await createBrowserImageAdapter(), file, plan.options).catch(() => {
148
+ throw new Error("Your browser could not process this image. Try a JPEG or PNG copy.");
149
+ });
146
150
  return upload(new File([result.blob], storedFilename(file.name, result.format), { type: result.blob.type }), folder, result, file.name);
147
151
  }
148
152
  };
@@ -0,0 +1,36 @@
1
+ //#region src/platform.d.ts
2
+ export type OrganizationStatus = 'pending' | 'active' | 'rejected' | 'suspended';
3
+ export type OrganizationAction = 'approve' | 'reject' | 'suspend' | 'reactivate';
4
+ export interface PlatformOrganization {
5
+ _id: string;
6
+ name: string;
7
+ slug: string;
8
+ status: OrganizationStatus;
9
+ createdAt?: string;
10
+ statusHistory?: Array<{
11
+ status: OrganizationStatus;
12
+ occurredAt: string;
13
+ by?: string;
14
+ note?: string;
15
+ }>;
16
+ }
17
+ /** Platform administration uses a bearer identity without selecting a merchant organization. */
18
+ export declare function createPlatformClient({ apiUrl, token }: {
19
+ apiUrl: string;
20
+ token: string;
21
+ }): {
22
+ organizations: {
23
+ list: ({ token, organizationId, params, options }?: {
24
+ token?: string | null;
25
+ organizationId?: string | null;
26
+ params?: import("@classytic/arc-next/api").QueryParams;
27
+ options?: Omit<import("@classytic/arc-next/api").RequestOptions, "token" | "organizationId">;
28
+ }) => Promise<import("@classytic/repo-core/pagination").PaginatedResult<PlatformOrganization>>;
29
+ decide(id: string, data: {
30
+ action: OrganizationAction;
31
+ expectedStatus: OrganizationStatus;
32
+ note: string;
33
+ }): Promise<PlatformOrganization>;
34
+ };
35
+ };
36
+ //#endregion
@@ -0,0 +1,29 @@
1
+ import { BaseApi } from "@classytic/arc-next/api";
2
+ import { createClient } from "@classytic/arc-next/client";
3
+ //#region src/platform.ts
4
+ /** Platform administration uses a bearer identity without selecting a merchant organization. */
5
+ function createPlatformClient({ apiUrl, token }) {
6
+ if (!token.trim()) throw new Error("A platform bearer token is required.");
7
+ const url = new URL(apiUrl);
8
+ if (url.username || url.password || url.search || url.hash) throw new Error("Use a plain API URL.");
9
+ const client = createClient({
10
+ baseUrl: url.href.replace(/\/+$/, ""),
11
+ getToken: () => token,
12
+ credentials: "omit",
13
+ autoIdempotency: false,
14
+ timeoutMs: 15e3
15
+ });
16
+ const organizations = new BaseApi("admin/organizations", {
17
+ client,
18
+ basePath: "",
19
+ cache: "no-store"
20
+ });
21
+ return { organizations: {
22
+ list: organizations.getAll.bind(organizations),
23
+ decide(id, data) {
24
+ return organizations.request("POST", `${organizations.baseUrl}/${encodeURIComponent(id)}/action`, { data });
25
+ }
26
+ } };
27
+ }
28
+ //#endregion
29
+ export { createPlatformClient };
package/management.md CHANGED
@@ -86,3 +86,15 @@ Product writes also accept `tags`, `collections` and
86
86
  `defaultMonetization.pricing.compareAtPrice`. The catalog derives `onSale`; clients
87
87
  never set it. Tags and collections use the existing catalog arrays, with no
88
88
  additional collection-management service.
89
+
90
+
91
+ ### Media library
92
+
93
+ `client.media.list({ params: { page: 1, limit: 20, folder: 'products' } })`
94
+ returns tenant-scoped media and pagination. `client.media.remove({ id })` uses
95
+ the media resource's guarded delete; an in-use image is refused by the server.
96
+
97
+ `client.media.uploadImage(file, folder)` resolves the server's transform policy
98
+ through media-transform before requesting storage writes. The server must accept
99
+ every output format in its policy, including the browser encoder's fallback.
100
+ Passthrough thresholds and dimensions belong to that policy, rather than the UI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/commerce-client",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Typed storefront and merchant clients for the Classytic Commerce API",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -30,6 +30,10 @@
30
30
  "./category-tree": {
31
31
  "types": "./dist/category-tree.d.ts",
32
32
  "default": "./dist/category-tree.js"
33
+ },
34
+ "./platform": {
35
+ "types": "./dist/platform.d.ts",
36
+ "default": "./dist/platform.js"
33
37
  }
34
38
  },
35
39
  "files": [