torta-js 1.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 (2) hide show
  1. package/index.js +205 -0
  2. package/package.json +16 -0
package/index.js ADDED
@@ -0,0 +1,205 @@
1
+ /**
2
+ * torta-js — JavaScript client SDK for Torta CRM
3
+ *
4
+ * Usage:
5
+ * import { createClient } from 'torta-js';
6
+ * const client = createClient('http://localhost:8000', 'your-api-key');
7
+ *
8
+ * After publish, from CDN:
9
+ * import { createClient } from 'https://cdn.jsdelivr.net/npm/torta-js/+esm';
10
+ */
11
+
12
+ export function createClient(baseUrl, apiKey) {
13
+ const base = `${baseUrl}/${apiKey}`;
14
+
15
+ // ─── User cache ───────────────────────────────────────────────────────────
16
+ let _user = undefined; // undefined = never fetched, null = not logged in
17
+ let _userPromise = null; // deduplicates concurrent getUser() calls
18
+
19
+ // ─── Core request helper ──────────────────────────────────────────────────
20
+ async function req(method, path, body) {
21
+ const options = {
22
+ method,
23
+ credentials: "include",
24
+ headers: {},
25
+ };
26
+ if (body !== undefined) {
27
+ options.headers["Content-Type"] = "application/json";
28
+ options.body = JSON.stringify(body);
29
+ }
30
+ const res = await fetch(`${base}${path}`, options);
31
+ let data = null;
32
+ try {
33
+ if (res.headers.get("content-type")?.includes("application/json")) {
34
+ data = await res.json();
35
+ }
36
+ } catch { /* ignore */ }
37
+ return { ok: res.ok, status: res.status, data };
38
+ }
39
+
40
+ // ─── Client ───────────────────────────────────────────────────────────────
41
+ return {
42
+
43
+ // ── Auth ─────────────────────────────────────────────────────────────────
44
+ auth: {
45
+ /** Cached user object. undefined = not yet fetched, null = not logged in. */
46
+ get user() { return _user; },
47
+
48
+ /**
49
+ * Fetch current user from /api/me (cached after first call).
50
+ * Pass force=true to bypass cache (e.g. after login).
51
+ */
52
+ async getUser(force = false) {
53
+ if (!force && _user !== undefined) return _user;
54
+ if (!force && _userPromise) return _userPromise;
55
+ _userPromise = req("GET", "/api/me").then(({ ok, data }) => {
56
+ _user = ok ? data : null;
57
+ _userPromise = null;
58
+ return _user;
59
+ }).catch(() => {
60
+ _user = null;
61
+ _userPromise = null;
62
+ return null;
63
+ });
64
+ return _userPromise;
65
+ },
66
+
67
+ /** Clear user cache (called automatically on login/logout). */
68
+ invalidateUser() {
69
+ _user = undefined;
70
+ _userPromise = null;
71
+ },
72
+
73
+ /**
74
+ * Send email verification code.
75
+ * payload: { email, password, type: "login"|"register", name? }
76
+ */
77
+ async sendCode(payload) {
78
+ return req("POST", "/api/send-code", payload);
79
+ },
80
+
81
+ /** Verify the 6-digit code. Clears user cache on success. */
82
+ async verifyCode(email, code) {
83
+ const result = await req("POST", "/api/verify-code", { email, code });
84
+ if (result.ok) this.invalidateUser();
85
+ return result;
86
+ },
87
+
88
+ /** Resend verification code to email. */
89
+ async resendCode(email) {
90
+ return req("POST", "/api/resend-code", { email });
91
+ },
92
+
93
+ /** Log out. Clears user cache. */
94
+ async logout() {
95
+ const result = await req("POST", "/api/logout");
96
+ _user = null;
97
+ _userPromise = null;
98
+ return result;
99
+ },
100
+
101
+ /** Send password reset link to email. */
102
+ async forgotPassword(email) {
103
+ return req("POST", "/api/forgot-password", { email });
104
+ },
105
+
106
+ /** Validate a reset token. Returns { ok, data: { email } }. */
107
+ async validateResetToken(token) {
108
+ return req("GET", `/api/reset-password/validate/${token}`);
109
+ },
110
+
111
+ /** Submit a new password using a reset token. */
112
+ async resetPassword(token, password, repeat_password) {
113
+ return req("POST", "/api/reset-password", { token, password, repeat_password });
114
+ },
115
+ },
116
+
117
+ // ── Products ─────────────────────────────────────────────────────────────
118
+ products: {
119
+ /** List all products (public endpoint). */
120
+ async list() {
121
+ return req("GET", "/api-products");
122
+ },
123
+
124
+ /** Get full product page by hash id. */
125
+ async get(id) {
126
+ return req("GET", `/api/product/${id}`);
127
+ },
128
+ },
129
+
130
+ // ── Cart ─────────────────────────────────────────────────────────────────
131
+ cart: {
132
+ /** Get cart with items and subtotal. */
133
+ async get() {
134
+ return req("GET", "/api/cart");
135
+ },
136
+
137
+ /** Add item to cart. */
138
+ async add(product_id, variation_id, size_id, quantity = 1) {
139
+ return req("POST", "/api/cart/add", { product_id, variation_id, size_id, quantity });
140
+ },
141
+
142
+ /** Update quantity of a cart item. */
143
+ async update(cartItemId, quantity) {
144
+ return req("PUT", `/api/cart/${cartItemId}`, { quantity });
145
+ },
146
+
147
+ /** Remove an item from the cart. */
148
+ async remove(cartItemId) {
149
+ return req("DELETE", `/api/cart/${cartItemId}`);
150
+ },
151
+ },
152
+
153
+ // ── Favorites ────────────────────────────────────────────────────────────
154
+ favorites: {
155
+ /** Get list of favorited product ids. */
156
+ async list() {
157
+ return req("GET", "/api/favorites");
158
+ },
159
+
160
+ /** Add a product to favorites by numeric id. */
161
+ async add(product_id) {
162
+ return req("POST", "/api/favorites/add", { product_id });
163
+ },
164
+
165
+ /** Remove a product from favorites by hash. */
166
+ async remove(productHash) {
167
+ return req("DELETE", `/api/favorites/${productHash}`);
168
+ },
169
+ },
170
+
171
+ // ── Promos ───────────────────────────────────────────────────────────────
172
+ promos: {
173
+ /** Apply a promo code to the current cart. */
174
+ async apply(code) {
175
+ return req("POST", "/api/promo-code/apply", { code });
176
+ },
177
+ },
178
+
179
+ // ── Reviews ──────────────────────────────────────────────────────────────
180
+ reviews: {
181
+ /** Submit a product review. */
182
+ async add(product_id, rating, comment) {
183
+ return req("POST", "/api/reviews/add", { product_id, rating, comment });
184
+ },
185
+
186
+ /** Delete own review by id. */
187
+ async delete(reviewId) {
188
+ return req("DELETE", `/api/reviews/${reviewId}`);
189
+ },
190
+ },
191
+
192
+ // ── Track ────────────────────────────────────────────────────────────────
193
+ track: {
194
+ /** Record a site visit (fire-and-forget). */
195
+ visit() {
196
+ req("POST", "/api/track/visit").catch(() => {});
197
+ },
198
+
199
+ /** Record a product page view (fire-and-forget). */
200
+ productView(product_id) {
201
+ req("POST", "/api/track/product-view", { product_id }).catch(() => {});
202
+ },
203
+ },
204
+ };
205
+ }
package/package.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "torta-js",
3
+ "version": "1.0.0",
4
+ "description": "JavaScript client SDK for Torta CRM — connect your storefront to the API in one line",
5
+ "type": "module",
6
+ "main": "index.js",
7
+ "exports": {
8
+ ".": "./index.js"
9
+ },
10
+ "keywords": ["torta", "crm", "sdk", "client", "api"],
11
+ "license": "MIT",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/YOUR_USERNAME/torta-js"
15
+ }
16
+ }