@caldik/client 0.0.1 → 0.0.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 ADDED
@@ -0,0 +1,24 @@
1
+ # Caldik SDK
2
+
3
+ ## Caldik-hosted storefront
4
+
5
+ No credentials or store configuration are required:
6
+
7
+ ```ts
8
+ import { CaldikClient } from "@caldik/client"
9
+
10
+ const caldik = new CaldikClient()
11
+ const { products } = await caldik.products.list()
12
+ ```
13
+
14
+ ## External server
15
+
16
+ External integrations explicitly provide the store ID and a private `sk_` API
17
+ key:
18
+
19
+ ```ts
20
+ const caldik = new CaldikClient({
21
+ storeId: "STORE_...",
22
+ apiKey: process.env.CALDIK_PRIVATE_API_KEY,
23
+ })
24
+ ```
package/dist/index.d.mts CHANGED
@@ -5,8 +5,8 @@ interface Category {
5
5
  slug: string;
6
6
  description: string;
7
7
  price: string;
8
- logo: string;
9
- banner: string;
8
+ logo: string | null;
9
+ banner: string | null;
10
10
  }
11
11
  interface CategoriesResponse {
12
12
  success: boolean;
@@ -21,8 +21,8 @@ interface CategoryProduct {
21
21
  color: string;
22
22
  }[];
23
23
  price: string;
24
- logo: string;
25
- banner: string;
24
+ logo: string | null;
25
+ banner: string | null;
26
26
  }
27
27
  interface CategoryDetails {
28
28
  id: string;
@@ -56,20 +56,144 @@ interface ReviewsResponse {
56
56
  interface Product {
57
57
  id: string;
58
58
  name: string;
59
- price: number;
59
+ type: string;
60
+ slug: string;
61
+ description: string;
62
+ price: string;
63
+ logo: string | null;
64
+ banner: string | null;
65
+ videoUrl: string | null;
66
+ deliveryType: string;
67
+ minimumQuantity: number | null;
68
+ maximumQuantity: number | null;
69
+ variants: ProductVariant[];
70
+ tags: ProductTag[];
71
+ }
72
+ interface ProductVariant {
73
+ id: string;
74
+ name: string;
75
+ price: string;
76
+ compareAtPrice: string | null;
77
+ }
78
+ interface ProductTag {
79
+ label: string;
80
+ color: string;
81
+ }
82
+ interface ProductsResponse {
83
+ success: boolean;
84
+ products: Product[];
85
+ }
86
+ interface ProductResponse {
87
+ success: boolean;
88
+ product: Product;
89
+ }
90
+ interface ManualCommerceItem {
91
+ name: string;
92
+ description?: string;
93
+ quantity?: number;
94
+ unitAmount: string | number;
95
+ }
96
+ interface ProductCommerceItem {
97
+ productId: string;
98
+ productVariantId?: string;
99
+ quantity?: number;
100
+ }
101
+ type CommerceItem = ManualCommerceItem | ProductCommerceItem;
102
+ interface CreateOrderInput {
103
+ customerId?: string;
104
+ email?: string;
105
+ paymentMethod: "customer_balance" | "stripe" | "ovgc";
106
+ items: CommerceItem[];
107
+ successUrl?: string;
108
+ cancelUrl?: string;
109
+ }
110
+ interface StorefrontOrder {
111
+ id: string;
112
+ shortId: string;
113
+ displayId: string;
114
+ customerId: string | null;
115
+ paymentStatus: string;
116
+ fulfillmentStatus: string;
117
+ amount: string;
118
+ currency: string;
119
+ }
120
+ interface CheckoutPayment {
121
+ type: "customer_balance" | "stripe" | "ovgc";
122
+ checkoutUrl?: string | null;
123
+ checkoutSessionId?: string | null;
124
+ balanceAfter?: string;
125
+ }
126
+ interface OrderResponse {
127
+ success: boolean;
128
+ order: StorefrontOrder;
129
+ payment: CheckoutPayment | null;
130
+ }
131
+ interface CreateSubscriptionInput {
132
+ customerId?: string;
133
+ email?: string;
134
+ items: CommerceItem[];
135
+ billingInterval: "day" | "week" | "month" | "year";
136
+ billingIntervalCount?: number;
137
+ trialDays?: number;
138
+ successUrl: string;
139
+ cancelUrl: string;
140
+ }
141
+ interface SubscriptionResponse {
142
+ success: boolean;
143
+ subscription: {
144
+ id: string;
145
+ shortId: string;
146
+ displayId: string;
147
+ customerId: string;
148
+ status: string;
149
+ billingInterval: string;
150
+ billingIntervalCount: number;
151
+ amount: string;
152
+ currency: string;
153
+ };
154
+ payment: {
155
+ type: "stripe";
156
+ checkoutUrl: string;
157
+ checkoutSessionId: string;
158
+ };
159
+ }
160
+ interface CustomerLoginResponse {
161
+ success: boolean;
162
+ message: string;
163
+ }
164
+ interface CustomerLoginVerifyResponse {
165
+ success: boolean;
166
+ customer: {
167
+ id: string;
168
+ shortId: string;
169
+ displayId: string;
170
+ email: string;
171
+ status: string;
172
+ };
60
173
  }
61
174
  //#endregion
62
175
  //#region src/internal/types.d.ts
63
176
  interface RequestOptions {
64
177
  edgeCache?: boolean;
178
+ /** Internal authorization policy. Protected hosted calls are the default. */
179
+ access?: "public" | "runtime";
65
180
  }
66
181
  //#endregion
67
182
  //#region src/internal/client.d.ts
183
+ type HttpClientOptions = {
184
+ apiKey?: string;
185
+ apiUrl?: string;
186
+ storeId?: string;
187
+ };
68
188
  declare class CaldikHttpClient {
69
- private publicKey?;
70
- private apiUrl;
71
- constructor(publicKey?: string | undefined, apiUrl?: string);
189
+ private readonly apiKey?;
190
+ private readonly apiUrl;
191
+ private readonly storeId?;
192
+ constructor(options?: HttpClientOptions);
193
+ private baseUrl;
194
+ private request;
72
195
  get<T>(path: string, params?: Record<string, string | number>, options?: RequestOptions): Promise<T>;
196
+ post<T>(path: string, input?: unknown, options?: RequestOptions): Promise<T>;
73
197
  }
74
198
  //#endregion
75
199
  //#region src/categories.d.ts
@@ -84,8 +208,8 @@ declare class CategoriesApi {
84
208
  declare class ProductsApi {
85
209
  private client;
86
210
  constructor(client: CaldikHttpClient);
87
- list(): Promise<Product[]>;
88
- get(productId: string): Promise<Product>;
211
+ list(): Promise<ProductsResponse>;
212
+ get(productId: string): Promise<ProductResponse>;
89
213
  }
90
214
  //#endregion
91
215
  //#region src/reviews.d.ts
@@ -102,9 +226,35 @@ declare class StoreApi {
102
226
  get(): Promise<StoreResponse>;
103
227
  }
104
228
  //#endregion
229
+ //#region src/checkout.d.ts
230
+ declare class CheckoutApi {
231
+ private client;
232
+ constructor(client: CaldikHttpClient);
233
+ create(input: CreateOrderInput): Promise<OrderResponse>;
234
+ payWithBalance(orderId: string): Promise<OrderResponse>;
235
+ }
236
+ //#endregion
237
+ //#region src/customer.d.ts
238
+ declare class CustomerApi {
239
+ private client;
240
+ constructor(client: CaldikHttpClient);
241
+ requestLogin(email: string): Promise<CustomerLoginResponse>;
242
+ verifyLogin(code: string): Promise<CustomerLoginVerifyResponse>;
243
+ }
244
+ //#endregion
245
+ //#region src/subscriptions.d.ts
246
+ declare class SubscriptionsApi {
247
+ private client;
248
+ constructor(client: CaldikHttpClient);
249
+ create(input: CreateSubscriptionInput): Promise<SubscriptionResponse>;
250
+ }
251
+ //#endregion
105
252
  //#region src/index.d.ts
106
253
  interface CaldikClientOptions {
107
- publicApiKey?: string;
254
+ /** Store ID for external servers. Hosted Workers receive it automatically. */
255
+ storeId?: string;
256
+ /** Private API key for external server integrations. Never use in browsers. */
257
+ apiKey?: string;
108
258
  apiUrl?: string;
109
259
  }
110
260
  declare class CaldikClient {
@@ -112,7 +262,10 @@ declare class CaldikClient {
112
262
  readonly products: ProductsApi;
113
263
  readonly reviews: ReviewsApi;
114
264
  readonly store: StoreApi;
265
+ readonly checkout: CheckoutApi;
266
+ readonly customer: CustomerApi;
267
+ readonly subscriptions: SubscriptionsApi;
115
268
  constructor(options?: CaldikClientOptions);
116
269
  }
117
270
  //#endregion
118
- export { CaldikClient, CaldikClientOptions };
271
+ export { CaldikClient, CaldikClientOptions, CategoriesResponse, Category, CategoryDetails, CategoryProduct, CategoryResponse, CheckoutPayment, CommerceItem, CreateOrderInput, CreateSubscriptionInput, CustomerLoginResponse, CustomerLoginVerifyResponse, ManualCommerceItem, OrderResponse, Product, ProductCommerceItem, ProductResponse, ProductTag, ProductVariant, ProductsResponse, Review, ReviewsResponse, Store, StoreResponse, StorefrontOrder, SubscriptionResponse };
package/dist/index.mjs CHANGED
@@ -2,29 +2,67 @@
2
2
  const defaultApiUrl = typeof API_URL !== "undefined" ? API_URL : "https://api.caldik.com";
3
3
  //#endregion
4
4
  //#region src/internal/client.ts
5
+ const STORE_ID_PATTERN = /^STORE_[a-f0-9]{32}$/i;
6
+ function isBrowserRuntime() {
7
+ return typeof window !== "undefined" && typeof document !== "undefined";
8
+ }
9
+ function boundRuntimeStoreId() {
10
+ const storeId = globalThis.process?.env?.CALDIK_STORE_ID?.trim();
11
+ return storeId && STORE_ID_PATTERN.test(storeId) ? storeId : null;
12
+ }
5
13
  var CaldikHttpClient = class {
6
- publicKey;
14
+ apiKey;
7
15
  apiUrl;
8
- constructor(publicKey, apiUrl = defaultApiUrl) {
9
- this.publicKey = publicKey;
10
- this.apiUrl = apiUrl;
16
+ storeId;
17
+ constructor(options = {}) {
18
+ this.apiKey = options.apiKey?.trim() || void 0;
19
+ this.apiUrl = options.apiUrl || defaultApiUrl;
20
+ this.storeId = options.storeId?.trim() || void 0;
21
+ if (this.apiKey && !this.apiKey.startsWith("sk_")) throw new Error("Caldik external integrations require a private sk_ API key");
22
+ if (this.storeId && !STORE_ID_PATTERN.test(this.storeId)) throw new Error("Caldik storeId is invalid");
23
+ if (isBrowserRuntime() && this.apiKey) throw new Error("Caldik private API keys cannot be used in browser code");
24
+ }
25
+ baseUrl() {
26
+ if (isBrowserRuntime()) {
27
+ if (typeof location === "undefined") throw new Error("Caldik browser transport requires a browser origin");
28
+ return new URL("/__caldik/api", location.origin).toString().replace(/\/+$/, "");
29
+ }
30
+ const boundStoreId = boundRuntimeStoreId();
31
+ if (boundStoreId && this.storeId && boundStoreId !== this.storeId) throw new Error("Caldik storeId does not match the hosted runtime");
32
+ const storeId = this.storeId || boundStoreId;
33
+ if (!storeId) throw new Error("Caldik authentication is unavailable. External servers must provide storeId and a private apiKey.");
34
+ if (!boundStoreId && !this.apiKey) throw new Error("Caldik authentication is unavailable. External servers must provide a private apiKey.");
35
+ return `${this.apiUrl.replace(/\/+$/, "")}/v1/stores/${encodeURIComponent(storeId)}`;
11
36
  }
12
- async get(path, params, options) {
13
- const baseUrl = this.apiUrl.replace(/\/+$/, "");
14
- const url = new URL(`${baseUrl}/v1${path}`);
37
+ async request(method, path, input, params, options) {
38
+ const url = new URL(`${this.baseUrl()}${path}`);
15
39
  if (params) for (const [key, value] of Object.entries(params)) url.searchParams.set(key, String(value));
16
- const headers = {
17
- "User-Agent": "CaldikClient/0.0.1",
18
- ...this.publicKey && { Authorization: `Bearer ${this.publicKey}` }
19
- };
40
+ const headers = {};
41
+ if (!isBrowserRuntime()) headers["User-Agent"] = "CaldikClient/0.0.2";
42
+ if (this.apiKey) headers.Authorization = `Bearer ${this.apiKey}`;
43
+ else if (options?.access === "public") headers["X-Caldik-Public-Request"] = "1";
44
+ if (input !== void 0) headers["Content-Type"] = "application/json";
20
45
  if (options?.edgeCache) headers["X-Cache-Policy"] = "public";
21
46
  const response = await fetch(url, {
47
+ method,
22
48
  headers,
23
- cache: "default"
49
+ ...input !== void 0 ? { body: JSON.stringify(input) } : {},
50
+ cache: "default",
51
+ credentials: "include"
24
52
  });
25
- if (!response.ok) throw new Error(response.statusText);
53
+ if (!response.ok) {
54
+ const error = await response.clone().json().catch(() => null);
55
+ const message = typeof error?.message === "string" && error.message ? error.message : `${response.status} ${response.statusText}`.trim();
56
+ throw new Error(message);
57
+ }
26
58
  return response.json();
27
59
  }
60
+ get(path, params, options) {
61
+ return this.request("GET", path, void 0, params, options);
62
+ }
63
+ post(path, input, options) {
64
+ return this.request("POST", path, input, void 0, options);
65
+ }
28
66
  };
29
67
  //#endregion
30
68
  //#region src/categories.ts
@@ -34,10 +72,10 @@ var CategoriesApi = class {
34
72
  this.client = client;
35
73
  }
36
74
  list(limit) {
37
- return this.client.get("/categories", limit ? { limit } : void 0);
75
+ return this.client.get("/categories", limit ? { limit } : void 0, { access: "public" });
38
76
  }
39
77
  get(categoryId) {
40
- return this.client.get(`/categories/${categoryId}`);
78
+ return this.client.get(`/categories/${categoryId}`, void 0, { access: "public" });
41
79
  }
42
80
  };
43
81
  //#endregion
@@ -48,10 +86,10 @@ var ProductsApi = class {
48
86
  this.client = client;
49
87
  }
50
88
  list() {
51
- return this.client.get("/products");
89
+ return this.client.get("/products", void 0, { access: "public" });
52
90
  }
53
91
  get(productId) {
54
- return this.client.get(`/products/${productId}`);
92
+ return this.client.get(`/products/${productId}`, void 0, { access: "public" });
55
93
  }
56
94
  };
57
95
  //#endregion
@@ -62,7 +100,7 @@ var ReviewsApi = class {
62
100
  this.client = client;
63
101
  }
64
102
  list(limit) {
65
- return this.client.get("/reviews", limit ? { limit } : void 0);
103
+ return this.client.get("/reviews", limit ? { limit } : void 0, { access: "public" });
66
104
  }
67
105
  };
68
106
  //#endregion
@@ -73,7 +111,46 @@ var StoreApi = class {
73
111
  this.client = client;
74
112
  }
75
113
  get() {
76
- return this.client.get("");
114
+ return this.client.get("", void 0, { access: "public" });
115
+ }
116
+ };
117
+ //#endregion
118
+ //#region src/checkout.ts
119
+ var CheckoutApi = class {
120
+ client;
121
+ constructor(client) {
122
+ this.client = client;
123
+ }
124
+ create(input) {
125
+ return this.client.post("/checkouts", input, { access: "public" });
126
+ }
127
+ payWithBalance(orderId) {
128
+ return this.client.post(`/checkouts/${encodeURIComponent(orderId)}/balance-payment`, void 0, { access: "public" });
129
+ }
130
+ };
131
+ //#endregion
132
+ //#region src/customer.ts
133
+ var CustomerApi = class {
134
+ client;
135
+ constructor(client) {
136
+ this.client = client;
137
+ }
138
+ requestLogin(email) {
139
+ return this.client.post("/customers/login", { email }, { access: "public" });
140
+ }
141
+ verifyLogin(code) {
142
+ return this.client.post("/customers/login/verify", { code }, { access: "public" });
143
+ }
144
+ };
145
+ //#endregion
146
+ //#region src/subscriptions.ts
147
+ var SubscriptionsApi = class {
148
+ client;
149
+ constructor(client) {
150
+ this.client = client;
151
+ }
152
+ create(input) {
153
+ return this.client.post("/subscriptions", input, { access: "public" });
77
154
  }
78
155
  };
79
156
  //#endregion
@@ -83,12 +160,22 @@ var CaldikClient = class {
83
160
  products;
84
161
  reviews;
85
162
  store;
163
+ checkout;
164
+ customer;
165
+ subscriptions;
86
166
  constructor(options = {}) {
87
- const client = new CaldikHttpClient(options.publicApiKey, options.apiUrl);
167
+ const client = new CaldikHttpClient({
168
+ apiKey: options.apiKey,
169
+ apiUrl: options.apiUrl,
170
+ storeId: options.storeId
171
+ });
88
172
  this.categories = new CategoriesApi(client);
89
173
  this.products = new ProductsApi(client);
90
174
  this.reviews = new ReviewsApi(client);
91
175
  this.store = new StoreApi(client);
176
+ this.checkout = new CheckoutApi(client);
177
+ this.customer = new CustomerApi(client);
178
+ this.subscriptions = new SubscriptionsApi(client);
92
179
  }
93
180
  };
94
181
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caldik/client",
3
- "version": "0.0.1",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "main": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.mts",
@@ -17,7 +17,8 @@
17
17
  "access": "public"
18
18
  },
19
19
  "scripts": {
20
- "build": "tsdown"
20
+ "build": "tsdown",
21
+ "test": "bun test"
21
22
  },
22
23
  "devDependencies": {
23
24
  "tsdown": "^0.22.3",