@pevey/medusa 2.14.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 Lacey Pevey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # @pevey/medusa
2
+
3
+ Extended Medusa JS SDK with support for custom plugins. Drop-in replacement for `@medusajs/js-sdk` that adds typed methods for Reviews, Content, Forms, and Analytics alongside all core Medusa functionality.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ yarn add @pevey/medusa
9
+ ```
10
+
11
+ ## Setup
12
+
13
+ ```ts
14
+ import Medusa from '@pevey/medusa'
15
+
16
+ const sdk = new Medusa({
17
+ baseUrl: 'http://localhost:9000',
18
+ publishableKey: 'pk_...',
19
+ auth: {
20
+ type: 'session'
21
+ }
22
+ })
23
+ ```
24
+
25
+ All [configuration options](https://docs.medusajs.com/resources/js-sdk#configuration) from `@medusajs/js-sdk` are supported, plus:
26
+
27
+ | Option | Type | Description |
28
+ |--------|------|-------------|
29
+ | `analytics.salesChannelId` | `string` | Default sales channel ID for analytics events |
30
+ | `analytics.cartId` | `string` | Default actor ID (typically cart ID) |
31
+ | `analytics.batchSize` | `number` | Flush when batch reaches this size (default: 10) |
32
+ | `analytics.flushInterval` | `number` | Flush interval in ms (default: 2000) |
33
+
34
+ ## Store
35
+
36
+ All core store methods from `@medusajs/js-sdk` are available unchanged:
37
+
38
+ ```ts
39
+ const regions = await sdk.store.region.list()
40
+ const cart = await sdk.store.cart.create({})
41
+ const products = await sdk.store.product.list()
42
+ ```
43
+
44
+ ### Reviews
45
+
46
+ ```ts
47
+ // List approved reviews for a product
48
+ const { reviews, count } = await sdk.store.review.list('prod_123')
49
+
50
+ // Submit a review (requires customer authentication)
51
+ const { review } = await sdk.store.review.create('prod_123', {
52
+ rating: 5,
53
+ body: 'Excellent quality',
54
+ author_name: 'Alice',
55
+ author_email: 'alice@example.com'
56
+ })
57
+ ```
58
+
59
+ ### Content
60
+
61
+ ```ts
62
+ // List content collections
63
+ const { content_collections } = await sdk.store.content.list()
64
+
65
+ // Get a specific collection
66
+ const { content_collection } = await sdk.store.content.retrieve('blog')
67
+
68
+ // List published items in a collection
69
+ const { content_items } = await sdk.store.content.listItems('blog', {
70
+ tag: 'announcements',
71
+ limit: 10
72
+ })
73
+
74
+ // Get a specific content item
75
+ const { content_item } = await sdk.store.content.retrieveItem('blog', 'hello-world')
76
+ ```
77
+
78
+ ### Forms
79
+
80
+ ```ts
81
+ // Submit a form
82
+ const { submitted } = await sdk.store.form.submit('contact', {
83
+ data: {
84
+ name: 'Alice',
85
+ email: 'alice@example.com',
86
+ message: 'Hello!'
87
+ },
88
+ cf_turnstile_response: 'token...' // optional, if Turnstile is enabled
89
+ })
90
+ ```
91
+
92
+ ### Products (Expanded Types)
93
+
94
+ `sdk.store.product.list()` and `sdk.store.product.retrieve()` return an expanded `StoreProduct` type that includes review data when the reviews plugin is installed:
95
+
96
+ ```ts
97
+ const { products } = await sdk.store.product.list()
98
+
99
+ // products[0].reviews — Review[]
100
+ // products[0].review_stats — { average_rating: number, count: number }
101
+ ```
102
+
103
+ ## Admin
104
+
105
+ All core admin methods from `@medusajs/js-sdk` are available unchanged:
106
+
107
+ ```ts
108
+ const { orders } = await sdk.admin.order.list()
109
+ const { products } = await sdk.admin.product.list()
110
+ ```
111
+
112
+ ### Reviews
113
+
114
+ ```ts
115
+ // List reviews with filtering
116
+ const { reviews } = await sdk.admin.review.list({
117
+ status: 'pending',
118
+ product_id: 'prod_123'
119
+ })
120
+
121
+ // Get a single review
122
+ const { review } = await sdk.admin.review.retrieve('rev_123')
123
+
124
+ // Update a review
125
+ await sdk.admin.review.update('rev_123', { status: 'approved' })
126
+
127
+ // Delete a review
128
+ await sdk.admin.review.delete('rev_123')
129
+
130
+ // Bulk approve/reject
131
+ await sdk.admin.review.approve(['rev_123', 'rev_456'])
132
+ await sdk.admin.review.reject(['rev_789'])
133
+ ```
134
+
135
+ ## Analytics
136
+
137
+ Privacy-focused event tracking with automatic batching. Events are sent to the Mildred analytics endpoint at `/store/ping`.
138
+
139
+ ```ts
140
+ // Track an event
141
+ sdk.analytics.track('product_viewed', {
142
+ properties: { product_id: 'prod_123' }
143
+ })
144
+
145
+ // Identify a customer
146
+ sdk.analytics.identify('cust_123', {
147
+ anonymous_id: 'cart_abc'
148
+ })
149
+
150
+ // Set default actor/sales channel
151
+ sdk.analytics.setCartId('cart_abc')
152
+ sdk.analytics.setSalesChannelId('sc_123')
153
+
154
+ // Force flush queued events
155
+ await sdk.analytics.flush()
156
+
157
+ // Cleanup (flushes and stops timer)
158
+ await sdk.analytics.destroy()
159
+ ```
160
+
161
+ **Browser behavior:** Events are queued and flushed in batches (default: 10 events or every 2 seconds). On page unload, remaining events are sent via `navigator.sendBeacon` for reliability.
162
+
163
+ **Server behavior:** Events are sent immediately with no batching.
164
+
165
+ ## Authentication
166
+
167
+ Authentication works exactly like `@medusajs/js-sdk`:
168
+
169
+ ```ts
170
+ // Customer login
171
+ await sdk.auth.login('customer', 'emailpass', {
172
+ email: 'customer@example.com',
173
+ password: 'password'
174
+ })
175
+
176
+ // Customer registration
177
+ await sdk.auth.register('customer', 'emailpass', {
178
+ email: 'customer@example.com',
179
+ password: 'password'
180
+ })
181
+
182
+ // Logout
183
+ await sdk.auth.logout()
184
+ ```
185
+
186
+ ## Raw Client
187
+
188
+ For endpoints not covered by the SDK, use `sdk.client.fetch()`:
189
+
190
+ ```ts
191
+ const result = await sdk.client.fetch('/admin/custom-endpoint', {
192
+ method: 'POST',
193
+ body: { key: 'value' }
194
+ })
195
+ ```
196
+
197
+ ## Types
198
+
199
+ All types are exported for use in your application:
200
+
201
+ ```ts
202
+ import type {
203
+ // Custom plugin types
204
+ Review,
205
+ StoreCreateReviewInput,
206
+ ContentCollection,
207
+ ContentItem,
208
+ FormSubmitInput,
209
+ TrackOptions,
210
+
211
+ // Expanded core types
212
+ StoreProduct,
213
+ AdminProduct,
214
+
215
+ // SDK config types
216
+ MedusaConfig,
217
+ Config,
218
+ ClientHeaders,
219
+ } from '@pevey/medusa'
220
+ ```
@@ -0,0 +1,57 @@
1
+ import { Client, Admin as MedusaAdmin } from '@medusajs/js-sdk';
2
+ import { createAdminReviewResource } from './resources/admin/review';
3
+ type CoreAdmin = InstanceType<typeof MedusaAdmin>;
4
+ export declare class Admin {
5
+ private core;
6
+ review: ReturnType<typeof createAdminReviewResource>;
7
+ constructor(client: Client);
8
+ get apiKey(): CoreAdmin['apiKey'];
9
+ get campaign(): CoreAdmin['campaign'];
10
+ get claim(): CoreAdmin['claim'];
11
+ get currency(): CoreAdmin['currency'];
12
+ get customer(): CoreAdmin['customer'];
13
+ get customerGroup(): CoreAdmin['customerGroup'];
14
+ get draftOrder(): CoreAdmin['draftOrder'];
15
+ get exchange(): CoreAdmin['exchange'];
16
+ get fulfillment(): CoreAdmin['fulfillment'];
17
+ get fulfillmentProvider(): CoreAdmin['fulfillmentProvider'];
18
+ get fulfillmentSet(): CoreAdmin['fulfillmentSet'];
19
+ get inventoryItem(): CoreAdmin['inventoryItem'];
20
+ get invite(): CoreAdmin['invite'];
21
+ get locale(): CoreAdmin['locale'];
22
+ get notification(): CoreAdmin['notification'];
23
+ get order(): CoreAdmin['order'];
24
+ get orderEdit(): CoreAdmin['orderEdit'];
25
+ get payment(): CoreAdmin['payment'];
26
+ get paymentCollection(): CoreAdmin['paymentCollection'];
27
+ get plugin(): CoreAdmin['plugin'];
28
+ get priceList(): CoreAdmin['priceList'];
29
+ get pricePreference(): CoreAdmin['pricePreference'];
30
+ get product(): CoreAdmin['product'];
31
+ get productCategory(): CoreAdmin['productCategory'];
32
+ get productCollection(): CoreAdmin['productCollection'];
33
+ get productTag(): CoreAdmin['productTag'];
34
+ get productType(): CoreAdmin['productType'];
35
+ get productVariant(): CoreAdmin['productVariant'];
36
+ get promotion(): CoreAdmin['promotion'];
37
+ get refundReason(): CoreAdmin['refundReason'];
38
+ get region(): CoreAdmin['region'];
39
+ get reservation(): CoreAdmin['reservation'];
40
+ get return(): CoreAdmin['return'];
41
+ get returnReason(): CoreAdmin['returnReason'];
42
+ get salesChannel(): CoreAdmin['salesChannel'];
43
+ get shippingOption(): CoreAdmin['shippingOption'];
44
+ get shippingOptionType(): CoreAdmin['shippingOptionType'];
45
+ get shippingProfile(): CoreAdmin['shippingProfile'];
46
+ get stockLocation(): CoreAdmin['stockLocation'];
47
+ get store(): CoreAdmin['store'];
48
+ get taxProvider(): CoreAdmin['taxProvider'];
49
+ get taxRate(): CoreAdmin['taxRate'];
50
+ get taxRegion(): CoreAdmin['taxRegion'];
51
+ get translation(): CoreAdmin['translation'];
52
+ get upload(): CoreAdmin['upload'];
53
+ get user(): CoreAdmin['user'];
54
+ get views(): CoreAdmin['views'];
55
+ get workflowExecution(): CoreAdmin['workflowExecution'];
56
+ }
57
+ export {};
package/dist/admin.js ADDED
@@ -0,0 +1,57 @@
1
+ import { Admin as MedusaAdmin } from '@medusajs/js-sdk';
2
+ import { createAdminReviewResource } from './resources/admin/review';
3
+ export class Admin {
4
+ constructor(client) {
5
+ this.core = new MedusaAdmin(client);
6
+ this.review = createAdminReviewResource(client);
7
+ }
8
+ // ── Delegated core resources ─────────────────────────────────────────────
9
+ get apiKey() { return this.core.apiKey; }
10
+ get campaign() { return this.core.campaign; }
11
+ get claim() { return this.core.claim; }
12
+ get currency() { return this.core.currency; }
13
+ get customer() { return this.core.customer; }
14
+ get customerGroup() { return this.core.customerGroup; }
15
+ get draftOrder() { return this.core.draftOrder; }
16
+ get exchange() { return this.core.exchange; }
17
+ get fulfillment() { return this.core.fulfillment; }
18
+ get fulfillmentProvider() { return this.core.fulfillmentProvider; }
19
+ get fulfillmentSet() { return this.core.fulfillmentSet; }
20
+ get inventoryItem() { return this.core.inventoryItem; }
21
+ get invite() { return this.core.invite; }
22
+ get locale() { return this.core.locale; }
23
+ get notification() { return this.core.notification; }
24
+ get order() { return this.core.order; }
25
+ get orderEdit() { return this.core.orderEdit; }
26
+ get payment() { return this.core.payment; }
27
+ get paymentCollection() { return this.core.paymentCollection; }
28
+ get plugin() { return this.core.plugin; }
29
+ get priceList() { return this.core.priceList; }
30
+ get pricePreference() { return this.core.pricePreference; }
31
+ get product() { return this.core.product; }
32
+ get productCategory() { return this.core.productCategory; }
33
+ get productCollection() { return this.core.productCollection; }
34
+ get productTag() { return this.core.productTag; }
35
+ get productType() { return this.core.productType; }
36
+ get productVariant() { return this.core.productVariant; }
37
+ get promotion() { return this.core.promotion; }
38
+ get refundReason() { return this.core.refundReason; }
39
+ get region() { return this.core.region; }
40
+ get reservation() { return this.core.reservation; }
41
+ get return() { return this.core.return; }
42
+ get returnReason() { return this.core.returnReason; }
43
+ get salesChannel() { return this.core.salesChannel; }
44
+ get shippingOption() { return this.core.shippingOption; }
45
+ get shippingOptionType() { return this.core.shippingOptionType; }
46
+ get shippingProfile() { return this.core.shippingProfile; }
47
+ get stockLocation() { return this.core.stockLocation; }
48
+ get store() { return this.core.store; }
49
+ get taxProvider() { return this.core.taxProvider; }
50
+ get taxRate() { return this.core.taxRate; }
51
+ get taxRegion() { return this.core.taxRegion; }
52
+ get translation() { return this.core.translation; }
53
+ get upload() { return this.core.upload; }
54
+ get user() { return this.core.user; }
55
+ get views() { return this.core.views; }
56
+ get workflowExecution() { return this.core.workflowExecution; }
57
+ }
@@ -0,0 +1,37 @@
1
+ import type { Client } from '@medusajs/js-sdk';
2
+ import type { AnalyticsConfig, TrackOptions } from './types/analytics';
3
+ export declare class Analytics {
4
+ private client;
5
+ private salesChannelId?;
6
+ private cartId?;
7
+ private batchSize;
8
+ private flushIntervalMs;
9
+ private isBrowser;
10
+ private queue;
11
+ private timer;
12
+ private flushing;
13
+ constructor(client: Client, config?: AnalyticsConfig);
14
+ /**
15
+ * Track an analytics event.
16
+ *
17
+ * Browser: queues the event and flushes when batch is full or on interval.
18
+ * Server: sends immediately.
19
+ */
20
+ track(event: string, options?: TrackOptions): void;
21
+ /**
22
+ * Identify an actor. Sends a special `_identify` event that the backend
23
+ * routes to `analyticsService.identify()`.
24
+ */
25
+ identify(actorId: string, properties?: Record<string, unknown>): void;
26
+ /** Update the default actor ID (typically when cart is created/loaded). */
27
+ setCartId(cartId: string): void;
28
+ /** Update the default sales channel ID. */
29
+ setSalesChannelId(salesChannelId: string): void;
30
+ /** Flush all queued events immediately. */
31
+ flush(): Promise<void>;
32
+ /** Stop the flush timer and flush remaining events. Call on cleanup. */
33
+ destroy(): Promise<void>;
34
+ private send;
35
+ private startFlushTimer;
36
+ private bindUnloadHandler;
37
+ }
@@ -0,0 +1,131 @@
1
+ // Source: packages/mildred/src/api/validators.ts
2
+ // Routes: POST /store/ping
3
+ const ENDPOINT = '/store/ping';
4
+ export class Analytics {
5
+ constructor(client, config) {
6
+ this.queue = [];
7
+ this.timer = null;
8
+ this.flushing = false;
9
+ this.client = client;
10
+ this.salesChannelId = config?.salesChannelId;
11
+ this.cartId = config?.cartId;
12
+ this.batchSize = config?.batchSize ?? 10;
13
+ this.flushIntervalMs = config?.flushInterval ?? 2000;
14
+ this.isBrowser = typeof window !== 'undefined';
15
+ if (this.isBrowser) {
16
+ this.startFlushTimer();
17
+ this.bindUnloadHandler();
18
+ }
19
+ }
20
+ /**
21
+ * Track an analytics event.
22
+ *
23
+ * Browser: queues the event and flushes when batch is full or on interval.
24
+ * Server: sends immediately.
25
+ */
26
+ track(event, options) {
27
+ const payload = {
28
+ event,
29
+ actor_id: options?.cartId ?? this.cartId,
30
+ session_id: options?.sessionId,
31
+ properties: options?.properties,
32
+ sales_channel_id: options?.salesChannelId ?? this.salesChannelId
33
+ };
34
+ if (this.isBrowser) {
35
+ this.queue.push(payload);
36
+ if (this.queue.length >= this.batchSize) {
37
+ void this.flush();
38
+ }
39
+ }
40
+ else {
41
+ void this.send(payload);
42
+ }
43
+ }
44
+ /**
45
+ * Identify an actor. Sends a special `_identify` event that the backend
46
+ * routes to `analyticsService.identify()`.
47
+ */
48
+ identify(actorId, properties) {
49
+ const payload = {
50
+ event: '_identify',
51
+ actor_id: actorId,
52
+ properties: {
53
+ ...properties,
54
+ anonymous_id: this.cartId
55
+ },
56
+ sales_channel_id: this.salesChannelId
57
+ };
58
+ if (this.isBrowser) {
59
+ this.queue.push(payload);
60
+ void this.flush();
61
+ }
62
+ else {
63
+ void this.send(payload);
64
+ }
65
+ }
66
+ /** Update the default actor ID (typically when cart is created/loaded). */
67
+ setCartId(cartId) {
68
+ this.cartId = cartId;
69
+ }
70
+ /** Update the default sales channel ID. */
71
+ setSalesChannelId(salesChannelId) {
72
+ this.salesChannelId = salesChannelId;
73
+ }
74
+ /** Flush all queued events immediately. */
75
+ async flush() {
76
+ if (this.flushing || this.queue.length === 0)
77
+ return;
78
+ this.flushing = true;
79
+ const batch = this.queue.splice(0);
80
+ try {
81
+ await Promise.all(batch.map(event => this.send(event)));
82
+ }
83
+ catch {
84
+ this.queue.unshift(...batch);
85
+ }
86
+ finally {
87
+ this.flushing = false;
88
+ }
89
+ }
90
+ /** Stop the flush timer and flush remaining events. Call on cleanup. */
91
+ async destroy() {
92
+ if (this.timer) {
93
+ clearInterval(this.timer);
94
+ this.timer = null;
95
+ }
96
+ await this.flush();
97
+ }
98
+ async send(payload) {
99
+ await this.client.fetch(ENDPOINT, {
100
+ method: 'POST',
101
+ body: payload
102
+ });
103
+ }
104
+ startFlushTimer() {
105
+ this.timer = setInterval(() => {
106
+ void this.flush();
107
+ }, this.flushIntervalMs);
108
+ }
109
+ bindUnloadHandler() {
110
+ if (typeof document === 'undefined')
111
+ return;
112
+ const onUnload = () => {
113
+ if (this.queue.length === 0)
114
+ return;
115
+ if (typeof navigator?.sendBeacon === 'function') {
116
+ const batch = this.queue.splice(0);
117
+ for (const event of batch) {
118
+ const blob = new Blob([JSON.stringify(event)], {
119
+ type: 'application/json'
120
+ });
121
+ navigator.sendBeacon(ENDPOINT, blob);
122
+ }
123
+ }
124
+ };
125
+ document.addEventListener('visibilitychange', () => {
126
+ if (document.visibilityState === 'hidden') {
127
+ onUnload();
128
+ }
129
+ });
130
+ }
131
+ }
@@ -0,0 +1,26 @@
1
+ import { Client, Auth } from '@medusajs/js-sdk';
2
+ import type { Config } from '@medusajs/js-sdk';
3
+ import { Store } from './store';
4
+ import { Admin } from './admin';
5
+ import { Analytics } from './analytics';
6
+ import type { AnalyticsConfig } from './types/analytics';
7
+ export interface MedusaConfig extends Config {
8
+ /** Analytics configuration (batching, flush interval, etc.) */
9
+ analytics?: AnalyticsConfig;
10
+ }
11
+ export default class Medusa {
12
+ client: Client;
13
+ store: Store;
14
+ admin: Admin;
15
+ auth: Auth;
16
+ analytics: Analytics;
17
+ constructor(config: MedusaConfig);
18
+ setLocale(locale: string): void;
19
+ getLocale(): string;
20
+ }
21
+ export { Store } from './store';
22
+ export { Admin } from './admin';
23
+ export { Analytics } from './analytics';
24
+ export { Client, Auth, FetchError } from '@medusajs/js-sdk';
25
+ export type { Config, ClientHeaders, FetchArgs, FetchInput, FetchStreamResponse, Logger } from '@medusajs/js-sdk';
26
+ export * from './types';
package/dist/index.js ADDED
@@ -0,0 +1,25 @@
1
+ import { Client, Auth } from '@medusajs/js-sdk';
2
+ import { Store } from './store';
3
+ import { Admin } from './admin';
4
+ import { Analytics } from './analytics';
5
+ export default class Medusa {
6
+ constructor(config) {
7
+ this.client = new Client(config);
8
+ this.store = new Store(this.client);
9
+ this.admin = new Admin(this.client);
10
+ this.auth = new Auth(this.client, config);
11
+ this.analytics = new Analytics(this.client, config.analytics);
12
+ }
13
+ setLocale(locale) {
14
+ this.client.setLocale(locale);
15
+ }
16
+ getLocale() {
17
+ return this.client.locale;
18
+ }
19
+ }
20
+ // Re-export types for consumers
21
+ export { Store } from './store';
22
+ export { Admin } from './admin';
23
+ export { Analytics } from './analytics';
24
+ export { Client, Auth, FetchError } from '@medusajs/js-sdk';
25
+ export * from './types';
@@ -0,0 +1,11 @@
1
+ import type { Client, ClientHeaders } from '@medusajs/js-sdk';
2
+ import type { AdminReviewListQuery, AdminReviewListResponse, AdminReviewResponse, AdminReviewDeleteResponse, AdminReviewBatchResponse, AdminUpdateReviewInput } from '../../types/review';
3
+ export declare function createAdminReviewResource(client: Client): {
4
+ list: (query?: AdminReviewListQuery, headers?: ClientHeaders) => Promise<AdminReviewListResponse>;
5
+ retrieve: (id: string, query?: Record<string, unknown>, headers?: ClientHeaders) => Promise<AdminReviewResponse>;
6
+ update: (id: string, body: AdminUpdateReviewInput, headers?: ClientHeaders) => Promise<AdminReviewResponse>;
7
+ delete: (id: string, headers?: ClientHeaders) => Promise<AdminReviewDeleteResponse>;
8
+ batchDelete: (ids: string[], headers?: ClientHeaders) => Promise<AdminReviewBatchResponse>;
9
+ approve: (ids: string[], headers?: ClientHeaders) => Promise<AdminReviewBatchResponse>;
10
+ reject: (ids: string[], headers?: ClientHeaders) => Promise<AdminReviewBatchResponse>;
11
+ };
@@ -0,0 +1,27 @@
1
+ // Source: packages/reviews/src/api/admin/ + packages/reviews/src/api/validators.ts
2
+ // Routes: GET/POST/DELETE /admin/reviews, POST /admin/reviews/approve, POST /admin/reviews/reject
3
+ export function createAdminReviewResource(client) {
4
+ return {
5
+ list: async (query, headers) => {
6
+ return client.fetch(`/admin/reviews`, { query, headers });
7
+ },
8
+ retrieve: async (id, query, headers) => {
9
+ return client.fetch(`/admin/reviews/${id}`, { query, headers });
10
+ },
11
+ update: async (id, body, headers) => {
12
+ return client.fetch(`/admin/reviews/${id}`, { method: 'POST', body, headers });
13
+ },
14
+ delete: async (id, headers) => {
15
+ return client.fetch(`/admin/reviews/${id}`, { method: 'DELETE', headers });
16
+ },
17
+ batchDelete: async (ids, headers) => {
18
+ return client.fetch(`/admin/reviews`, { method: 'DELETE', body: { ids }, headers });
19
+ },
20
+ approve: async (ids, headers) => {
21
+ return client.fetch(`/admin/reviews/approve`, { method: 'POST', body: { ids }, headers });
22
+ },
23
+ reject: async (ids, headers) => {
24
+ return client.fetch(`/admin/reviews/reject`, { method: 'POST', body: { ids }, headers });
25
+ },
26
+ };
27
+ }
@@ -0,0 +1,8 @@
1
+ import type { Client, ClientHeaders } from '@medusajs/js-sdk';
2
+ import type { StoreContentListQuery, StoreContentCollectionListResponse, StoreContentCollectionResponse, StoreContentItemListQuery, StoreContentItemListResponse, StoreContentItemResponse } from '../../types/content';
3
+ export declare function createStoreContentResource(client: Client): {
4
+ list: (query?: StoreContentListQuery, headers?: ClientHeaders) => Promise<StoreContentCollectionListResponse>;
5
+ retrieve: (slug: string, query?: StoreContentListQuery, headers?: ClientHeaders) => Promise<StoreContentCollectionResponse>;
6
+ listItems: (slug: string, query?: StoreContentItemListQuery, headers?: ClientHeaders) => Promise<StoreContentItemListResponse>;
7
+ retrieveItem: (slug: string, itemSlug: string, query?: StoreContentListQuery, headers?: ClientHeaders) => Promise<StoreContentItemResponse>;
8
+ };
@@ -0,0 +1,18 @@
1
+ // Source: packages/content/src/api/store/ + packages/content/src/api/validators.ts
2
+ // Routes: GET /content, GET /content/:slug, GET /content/:slug/items, GET /content/:slug/items/:itemSlug
3
+ export function createStoreContentResource(client) {
4
+ return {
5
+ list: async (query, headers) => {
6
+ return client.fetch(`/content`, { query, headers });
7
+ },
8
+ retrieve: async (slug, query, headers) => {
9
+ return client.fetch(`/content/${slug}`, { query, headers });
10
+ },
11
+ listItems: async (slug, query, headers) => {
12
+ return client.fetch(`/content/${slug}/items`, { query, headers });
13
+ },
14
+ retrieveItem: async (slug, itemSlug, query, headers) => {
15
+ return client.fetch(`/content/${slug}/items/${itemSlug}`, { query, headers });
16
+ },
17
+ };
18
+ }
@@ -0,0 +1,5 @@
1
+ import type { Client, ClientHeaders } from '@medusajs/js-sdk';
2
+ import type { FormSubmitInput, FormSubmitResponse } from '../../types/form';
3
+ export declare function createStoreFormResource(client: Client): {
4
+ submit: (handle: string, body: FormSubmitInput, headers?: ClientHeaders) => Promise<FormSubmitResponse>;
5
+ };
@@ -0,0 +1,9 @@
1
+ // Source: packages/forms/src/api/ + packages/forms/src/api/validators.ts
2
+ // Routes: POST /forms/:handle
3
+ export function createStoreFormResource(client) {
4
+ return {
5
+ submit: async (handle, body, headers) => {
6
+ return client.fetch(`/forms/${handle}`, { method: 'POST', body, headers });
7
+ },
8
+ };
9
+ }
@@ -0,0 +1,6 @@
1
+ import type { Client, ClientHeaders } from '@medusajs/js-sdk';
2
+ import type { StoreCreateReviewInput, StoreReviewListResponse, StoreReviewResponse } from '../../types/review';
3
+ export declare function createStoreReviewResource(client: Client): {
4
+ list: (productId: string, query?: Record<string, unknown>, headers?: ClientHeaders) => Promise<StoreReviewListResponse>;
5
+ create: (productId: string, body: StoreCreateReviewInput, headers?: ClientHeaders) => Promise<StoreReviewResponse>;
6
+ };
@@ -0,0 +1,12 @@
1
+ // Source: packages/reviews/src/api/store/ + packages/reviews/src/api/validators.ts
2
+ // Routes: GET/POST /store/reviews/:productId
3
+ export function createStoreReviewResource(client) {
4
+ return {
5
+ list: async (productId, query, headers) => {
6
+ return client.fetch(`/store/reviews/${productId}`, { query, headers });
7
+ },
8
+ create: async (productId, body, headers) => {
9
+ return client.fetch(`/store/reviews/${productId}`, { method: 'POST', body, headers });
10
+ },
11
+ };
12
+ }
@@ -0,0 +1,30 @@
1
+ import { Client, Store as MedusaStore } from '@medusajs/js-sdk';
2
+ import type { ClientHeaders } from '@medusajs/js-sdk';
3
+ import type { HttpTypes, SelectParams } from '@medusajs/types';
4
+ import { createStoreReviewResource } from './resources/store/review';
5
+ import { createStoreContentResource } from './resources/store/content';
6
+ import { createStoreFormResource } from './resources/store/form';
7
+ import type { StoreProductListResponse, StoreProductResponse } from './types/expanded';
8
+ type CoreStore = InstanceType<typeof MedusaStore>;
9
+ export declare class Store {
10
+ private core;
11
+ private client;
12
+ review: ReturnType<typeof createStoreReviewResource>;
13
+ content: ReturnType<typeof createStoreContentResource>;
14
+ form: ReturnType<typeof createStoreFormResource>;
15
+ constructor(client: Client);
16
+ product: {
17
+ list: (query?: HttpTypes.StoreProductListParams, headers?: ClientHeaders) => Promise<StoreProductListResponse>;
18
+ retrieve: (id: string, query?: SelectParams, headers?: ClientHeaders) => Promise<StoreProductResponse>;
19
+ };
20
+ get region(): CoreStore['region'];
21
+ get collection(): CoreStore['collection'];
22
+ get category(): CoreStore['category'];
23
+ get cart(): CoreStore['cart'];
24
+ get order(): CoreStore['order'];
25
+ get customer(): CoreStore['customer'];
26
+ get fulfillment(): CoreStore['fulfillment'];
27
+ get payment(): CoreStore['payment'];
28
+ get locale(): CoreStore['locale'];
29
+ }
30
+ export {};
package/dist/store.js ADDED
@@ -0,0 +1,32 @@
1
+ import { Store as MedusaStore } from '@medusajs/js-sdk';
2
+ import { createStoreReviewResource } from './resources/store/review';
3
+ import { createStoreContentResource } from './resources/store/content';
4
+ import { createStoreFormResource } from './resources/store/form';
5
+ export class Store {
6
+ constructor(client) {
7
+ // ── Overridden resources (expanded types) ────────────────────────────────
8
+ this.product = {
9
+ list: async (query, headers) => {
10
+ return this.client.fetch(`/store/products`, { query, headers });
11
+ },
12
+ retrieve: async (id, query, headers) => {
13
+ return this.client.fetch(`/store/products/${id}`, { query, headers });
14
+ },
15
+ };
16
+ this.client = client;
17
+ this.core = new MedusaStore(client);
18
+ this.review = createStoreReviewResource(client);
19
+ this.content = createStoreContentResource(client);
20
+ this.form = createStoreFormResource(client);
21
+ }
22
+ // ── Delegated core resources ─────────────────────────────────────────────
23
+ get region() { return this.core.region; }
24
+ get collection() { return this.core.collection; }
25
+ get category() { return this.core.category; }
26
+ get cart() { return this.core.cart; }
27
+ get order() { return this.core.order; }
28
+ get customer() { return this.core.customer; }
29
+ get fulfillment() { return this.core.fulfillment; }
30
+ get payment() { return this.core.payment; }
31
+ get locale() { return this.core.locale; }
32
+ }
@@ -0,0 +1,27 @@
1
+ export interface AnalyticsConfig {
2
+ /** Default sales channel ID attached to all events */
3
+ salesChannelId?: string;
4
+ /** Default actor ID (typically cart ID from cookie) */
5
+ cartId?: string;
6
+ /** Client-side only: flush when batch reaches this size (default: 10) */
7
+ batchSize?: number;
8
+ /** Client-side only: flush interval in ms (default: 2000) */
9
+ flushInterval?: number;
10
+ }
11
+ export interface TrackOptions {
12
+ /** Actor ID for this event (overrides default cartId) */
13
+ cartId?: string;
14
+ /** Event properties */
15
+ properties?: Record<string, unknown>;
16
+ /** Session ID */
17
+ sessionId?: string;
18
+ /** Sales channel ID (overrides default) */
19
+ salesChannelId?: string;
20
+ }
21
+ export interface AnalyticsEvent {
22
+ event: string;
23
+ actor_id?: string;
24
+ session_id?: string;
25
+ properties?: Record<string, unknown>;
26
+ sales_channel_id?: string;
27
+ }
@@ -0,0 +1,3 @@
1
+ // Source: packages/mildred/src/api/validators.ts
2
+ // Routes: POST /store/ping
3
+ export {};
@@ -0,0 +1,78 @@
1
+ export interface ContentCollection {
2
+ id: string;
3
+ label: string;
4
+ slug: string;
5
+ format: string;
6
+ prefix?: string;
7
+ metadata?: Record<string, unknown>;
8
+ content_fields?: ContentField[];
9
+ created_at: string;
10
+ updated_at: string;
11
+ }
12
+ export interface ContentField {
13
+ id: string;
14
+ name: string;
15
+ label: string;
16
+ field_type: string;
17
+ required?: boolean;
18
+ options?: string;
19
+ default_value?: string;
20
+ sort_order?: number;
21
+ }
22
+ export interface ContentItem {
23
+ id: string;
24
+ title: string;
25
+ slug: string;
26
+ body?: string;
27
+ format?: string;
28
+ status: string;
29
+ published_at?: string;
30
+ metadata?: Record<string, unknown>;
31
+ content_collection?: Pick<ContentCollection, 'id' | 'label' | 'slug' | 'format'>;
32
+ creator?: ContentCreator;
33
+ tags?: ContentTag[];
34
+ created_at: string;
35
+ updated_at?: string;
36
+ }
37
+ export interface ContentCreator {
38
+ id: string;
39
+ name: string;
40
+ bio?: string;
41
+ avatar_url?: string;
42
+ }
43
+ export interface ContentTag {
44
+ id: string;
45
+ value: string;
46
+ metadata?: Record<string, unknown>;
47
+ }
48
+ export interface StoreContentListQuery {
49
+ q?: string;
50
+ limit?: number;
51
+ offset?: number;
52
+ fields?: string;
53
+ }
54
+ export interface StoreContentCollectionListResponse {
55
+ content_collections: ContentCollection[];
56
+ count: number;
57
+ limit: number;
58
+ offset: number;
59
+ }
60
+ export interface StoreContentCollectionResponse {
61
+ content_collection: ContentCollection;
62
+ }
63
+ export interface StoreContentItemListQuery {
64
+ tag?: string;
65
+ q?: string;
66
+ limit?: number;
67
+ offset?: number;
68
+ fields?: string;
69
+ }
70
+ export interface StoreContentItemListResponse {
71
+ content_items: ContentItem[];
72
+ count: number;
73
+ limit: number;
74
+ offset: number;
75
+ }
76
+ export interface StoreContentItemResponse {
77
+ content_item: ContentItem;
78
+ }
@@ -0,0 +1,3 @@
1
+ // Source: packages/content/src/api/validators.ts
2
+ // Routes: GET /content, GET /content/:slug, GET /content/:slug/items, GET /content/:slug/items/:itemSlug
3
+ export {};
@@ -0,0 +1,30 @@
1
+ import type { HttpTypes } from '@medusajs/types';
2
+ import type { Review } from './review';
3
+ export interface StoreProduct extends HttpTypes.StoreProduct {
4
+ reviews?: Review[];
5
+ review_stats?: {
6
+ average_rating: number;
7
+ count: number;
8
+ };
9
+ }
10
+ export interface StoreProductListResponse {
11
+ products: StoreProduct[];
12
+ count: number;
13
+ offset: number;
14
+ limit: number;
15
+ }
16
+ export interface StoreProductResponse {
17
+ product: StoreProduct;
18
+ }
19
+ export interface AdminProduct extends HttpTypes.AdminProduct {
20
+ reviews?: Review[];
21
+ }
22
+ export interface AdminProductListResponse {
23
+ products: AdminProduct[];
24
+ count: number;
25
+ offset: number;
26
+ limit: number;
27
+ }
28
+ export interface AdminProductResponse {
29
+ product: AdminProduct;
30
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,7 @@
1
+ export interface FormSubmitInput {
2
+ cf_turnstile_response?: string;
3
+ data: Record<string, unknown>;
4
+ }
5
+ export interface FormSubmitResponse {
6
+ submitted: boolean;
7
+ }
@@ -0,0 +1,3 @@
1
+ // Source: packages/forms/src/api/validators.ts
2
+ // Routes: POST /forms/:handle
3
+ export {};
@@ -0,0 +1,5 @@
1
+ export * from './review';
2
+ export * from './content';
3
+ export * from './form';
4
+ export * from './analytics';
5
+ export * from './expanded';
@@ -0,0 +1,5 @@
1
+ export * from './review';
2
+ export * from './content';
3
+ export * from './form';
4
+ export * from './analytics';
5
+ export * from './expanded';
@@ -0,0 +1,66 @@
1
+ export interface Review {
2
+ id: string;
3
+ status: 'pending' | 'approved' | 'rejected';
4
+ rating: number;
5
+ title?: string;
6
+ body: string;
7
+ author_name: string;
8
+ author_email?: string;
9
+ product_id: string;
10
+ order_id?: string;
11
+ customer_id?: string;
12
+ metadata?: Record<string, unknown>;
13
+ created_at: string;
14
+ updated_at: string;
15
+ }
16
+ export interface StoreCreateReviewInput {
17
+ rating: number;
18
+ title?: string;
19
+ body: string;
20
+ author_name: string;
21
+ author_email?: string;
22
+ order_id?: string;
23
+ }
24
+ export interface StoreReviewListResponse {
25
+ reviews: Review[];
26
+ count: number;
27
+ limit: number;
28
+ offset: number;
29
+ }
30
+ export interface StoreReviewResponse {
31
+ review: Review;
32
+ }
33
+ export interface AdminReviewListQuery {
34
+ q?: string;
35
+ status?: 'pending' | 'approved' | 'rejected';
36
+ product_id?: string;
37
+ customer_id?: string;
38
+ limit?: number;
39
+ offset?: number;
40
+ order?: string;
41
+ fields?: string;
42
+ }
43
+ export interface AdminUpdateReviewInput {
44
+ status?: 'pending' | 'approved' | 'rejected';
45
+ title?: string;
46
+ body?: string;
47
+ rating?: number;
48
+ metadata?: Record<string, unknown>;
49
+ }
50
+ export interface AdminReviewListResponse {
51
+ reviews: Review[];
52
+ count: number;
53
+ limit: number;
54
+ offset: number;
55
+ }
56
+ export interface AdminReviewResponse {
57
+ review: Review;
58
+ }
59
+ export interface AdminReviewDeleteResponse {
60
+ id: string;
61
+ object: string;
62
+ deleted: boolean;
63
+ }
64
+ export interface AdminReviewBatchResponse {
65
+ ids: string[];
66
+ }
@@ -0,0 +1,3 @@
1
+ // Source: packages/reviews/src/api/validators.ts
2
+ // Routes: GET/POST /store/reviews/:productId, GET/POST/DELETE /admin/reviews
3
+ export {};
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@pevey/medusa",
3
+ "version": "2.14.2",
4
+ "description": "Extended Medusa JS SDK with custom plugin support",
5
+ "author": "Lacey Pevey",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "build": "tsc",
24
+ "dev": "tsc --watch",
25
+ "prepublishOnly": "tsc"
26
+ },
27
+ "dependencies": {
28
+ "@medusajs/js-sdk": "2.14.2",
29
+ "@medusajs/types": "2.14.2"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "5.6.2"
33
+ },
34
+ "engines": {
35
+ "node": ">=18"
36
+ },
37
+ "gitHead": "35f16164d0d17e6281b2801a9f1eb355b5035571"
38
+ }