@blinkdotnew/sdk 0.13.2 → 0.14.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/README.md +12 -4
- package/dist/index.js +135 -17
- package/dist/index.mjs +135 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -195,23 +195,31 @@ const unsubscribe = blink.auth.onAuthStateChanged((state) => {
|
|
|
195
195
|
|
|
196
196
|
### Database Operations
|
|
197
197
|
|
|
198
|
+
**🎉 NEW: Automatic Case Conversion!**
|
|
199
|
+
The SDK now automatically converts between JavaScript camelCase and SQL snake_case:
|
|
200
|
+
- **Write code in camelCase**: `userId`, `createdAt`, `isCompleted`
|
|
201
|
+
- **Stored as snake_case**: `user_id`, `created_at`, `is_completed`
|
|
202
|
+
- **No manual conversion needed!**
|
|
203
|
+
|
|
198
204
|
```typescript
|
|
199
205
|
// Create (ID auto-generated if not provided)
|
|
200
206
|
const todo = await blink.db.todos.create({
|
|
201
207
|
id: 'todo_12345', // Optional - auto-generated if not provided
|
|
202
208
|
title: 'Learn Blink SDK',
|
|
203
|
-
|
|
209
|
+
userId: user.id, // camelCase in code
|
|
210
|
+
createdAt: new Date(), // camelCase in code
|
|
211
|
+
isCompleted: false // camelCase in code
|
|
204
212
|
})
|
|
205
213
|
|
|
206
|
-
// Read with filtering - returns
|
|
214
|
+
// Read with filtering - returns camelCase fields
|
|
207
215
|
const todos = await blink.db.todos.list({
|
|
208
216
|
where: {
|
|
209
217
|
AND: [
|
|
210
|
-
{
|
|
218
|
+
{ userId: user.id }, // camelCase in filters
|
|
211
219
|
{ OR: [{ status: 'open' }, { priority: 'high' }] }
|
|
212
220
|
]
|
|
213
221
|
},
|
|
214
|
-
orderBy: {
|
|
222
|
+
orderBy: { createdAt: 'desc' }, // camelCase in orderBy
|
|
215
223
|
limit: 20
|
|
216
224
|
})
|
|
217
225
|
// `todos` is a direct array: Todo[]
|
package/dist/index.js
CHANGED
|
@@ -67,6 +67,28 @@ var BlinkNotificationsError = class extends BlinkError {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
// ../core/src/query-builder.ts
|
|
70
|
+
function camelToSnake(str) {
|
|
71
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
72
|
+
}
|
|
73
|
+
function convertFilterKeysToSnakeCase(condition) {
|
|
74
|
+
if (!condition) return condition;
|
|
75
|
+
if ("AND" in condition) {
|
|
76
|
+
return {
|
|
77
|
+
AND: condition.AND?.map(convertFilterKeysToSnakeCase)
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
if ("OR" in condition) {
|
|
81
|
+
return {
|
|
82
|
+
OR: condition.OR?.map(convertFilterKeysToSnakeCase)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
const converted = {};
|
|
86
|
+
for (const [field, value] of Object.entries(condition)) {
|
|
87
|
+
const snakeField = camelToSnake(field);
|
|
88
|
+
converted[snakeField] = value;
|
|
89
|
+
}
|
|
90
|
+
return converted;
|
|
91
|
+
}
|
|
70
92
|
function buildFilterQuery(condition) {
|
|
71
93
|
if (!condition) return "";
|
|
72
94
|
if ("AND" in condition) {
|
|
@@ -140,12 +162,14 @@ function encodeQueryValue(value) {
|
|
|
140
162
|
function buildQuery(options = {}) {
|
|
141
163
|
const params = {};
|
|
142
164
|
if (options.select && options.select.length > 0) {
|
|
143
|
-
|
|
165
|
+
const snakeFields = options.select.map(camelToSnake);
|
|
166
|
+
params.select = snakeFields.join(",");
|
|
144
167
|
} else {
|
|
145
168
|
params.select = "*";
|
|
146
169
|
}
|
|
147
170
|
if (options.where) {
|
|
148
|
-
const
|
|
171
|
+
const convertedWhere = convertFilterKeysToSnakeCase(options.where);
|
|
172
|
+
const filterQuery = buildFilterQuery(convertedWhere);
|
|
149
173
|
if (filterQuery) {
|
|
150
174
|
const filterParams = filterQuery.split("&");
|
|
151
175
|
for (const param of filterParams) {
|
|
@@ -160,7 +184,7 @@ function buildQuery(options = {}) {
|
|
|
160
184
|
if (typeof options.orderBy === "string") {
|
|
161
185
|
params.order = options.orderBy;
|
|
162
186
|
} else {
|
|
163
|
-
const orderClauses = Object.entries(options.orderBy).map(([field, direction]) => `${field}.${direction}`);
|
|
187
|
+
const orderClauses = Object.entries(options.orderBy).map(([field, direction]) => `${camelToSnake(field)}.${direction}`);
|
|
164
188
|
params.order = orderClauses.join(",");
|
|
165
189
|
}
|
|
166
190
|
}
|
|
@@ -177,6 +201,34 @@ function buildQuery(options = {}) {
|
|
|
177
201
|
}
|
|
178
202
|
|
|
179
203
|
// ../core/src/http-client.ts
|
|
204
|
+
function camelToSnake2(str) {
|
|
205
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
206
|
+
}
|
|
207
|
+
function snakeToCamel(str) {
|
|
208
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
209
|
+
}
|
|
210
|
+
function convertKeysToSnakeCase(obj) {
|
|
211
|
+
if (obj === null || obj === void 0) return obj;
|
|
212
|
+
if (typeof obj !== "object") return obj;
|
|
213
|
+
if (Array.isArray(obj)) return obj.map(convertKeysToSnakeCase);
|
|
214
|
+
const converted = {};
|
|
215
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
216
|
+
const snakeKey = camelToSnake2(key);
|
|
217
|
+
converted[snakeKey] = convertKeysToSnakeCase(value);
|
|
218
|
+
}
|
|
219
|
+
return converted;
|
|
220
|
+
}
|
|
221
|
+
function convertKeysToCamelCase(obj) {
|
|
222
|
+
if (obj === null || obj === void 0) return obj;
|
|
223
|
+
if (typeof obj !== "object") return obj;
|
|
224
|
+
if (Array.isArray(obj)) return obj.map(convertKeysToCamelCase);
|
|
225
|
+
const converted = {};
|
|
226
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
227
|
+
const camelKey = snakeToCamel(key);
|
|
228
|
+
converted[camelKey] = convertKeysToCamelCase(value);
|
|
229
|
+
}
|
|
230
|
+
return converted;
|
|
231
|
+
}
|
|
180
232
|
var HttpClient = class {
|
|
181
233
|
authUrl = "https://blink.new";
|
|
182
234
|
coreUrl = "https://core.blink.new";
|
|
@@ -260,45 +312,86 @@ var HttpClient = class {
|
|
|
260
312
|
*/
|
|
261
313
|
// Table operations (PostgREST-compatible)
|
|
262
314
|
async dbGet(table, searchParams) {
|
|
263
|
-
|
|
315
|
+
const response = await this.get(`/api/db/${this.projectId}/rest/v1/${table}`, searchParams);
|
|
316
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
317
|
+
return {
|
|
318
|
+
...response,
|
|
319
|
+
data: convertedData
|
|
320
|
+
};
|
|
264
321
|
}
|
|
265
322
|
async dbPost(table, body, options = {}) {
|
|
266
323
|
const headers = {};
|
|
267
324
|
if (options.returning) {
|
|
268
325
|
headers.Prefer = "return=representation";
|
|
269
326
|
}
|
|
270
|
-
|
|
327
|
+
const convertedBody = convertKeysToSnakeCase(body);
|
|
328
|
+
const response = await this.post(`/api/db/${this.projectId}/rest/v1/${table}`, convertedBody, headers);
|
|
329
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
330
|
+
return {
|
|
331
|
+
...response,
|
|
332
|
+
data: convertedData
|
|
333
|
+
};
|
|
271
334
|
}
|
|
272
335
|
async dbPatch(table, body, searchParams, options = {}) {
|
|
273
336
|
const headers = {};
|
|
274
337
|
if (options.returning) {
|
|
275
338
|
headers.Prefer = "return=representation";
|
|
276
339
|
}
|
|
277
|
-
|
|
340
|
+
const convertedBody = convertKeysToSnakeCase(body);
|
|
341
|
+
const response = await this.request(`/api/db/${this.projectId}/rest/v1/${table}`, {
|
|
278
342
|
method: "PATCH",
|
|
279
|
-
body,
|
|
343
|
+
body: convertedBody,
|
|
280
344
|
headers,
|
|
281
345
|
searchParams
|
|
282
346
|
});
|
|
347
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
348
|
+
return {
|
|
349
|
+
...response,
|
|
350
|
+
data: convertedData
|
|
351
|
+
};
|
|
283
352
|
}
|
|
284
353
|
async dbDelete(table, searchParams, options = {}) {
|
|
285
354
|
const headers = {};
|
|
286
355
|
if (options.returning) {
|
|
287
356
|
headers.Prefer = "return=representation";
|
|
288
357
|
}
|
|
289
|
-
|
|
358
|
+
const response = await this.request(`/api/db/${this.projectId}/rest/v1/${table}`, {
|
|
290
359
|
method: "DELETE",
|
|
291
360
|
headers,
|
|
292
361
|
searchParams
|
|
293
362
|
});
|
|
363
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
364
|
+
return {
|
|
365
|
+
...response,
|
|
366
|
+
data: convertedData
|
|
367
|
+
};
|
|
294
368
|
}
|
|
295
369
|
// Raw SQL operations
|
|
296
370
|
async dbSql(query, params) {
|
|
297
|
-
|
|
371
|
+
const response = await this.post(`/api/db/${this.projectId}/sql`, { query, params });
|
|
372
|
+
const convertedData = {
|
|
373
|
+
...response.data,
|
|
374
|
+
rows: convertKeysToCamelCase(response.data.rows)
|
|
375
|
+
};
|
|
376
|
+
return {
|
|
377
|
+
...response,
|
|
378
|
+
data: convertedData
|
|
379
|
+
};
|
|
298
380
|
}
|
|
299
381
|
// Batch SQL operations
|
|
300
382
|
async dbBatch(statements, mode = "write") {
|
|
301
|
-
|
|
383
|
+
const response = await this.post(`/api/db/${this.projectId}/batch`, { statements, mode });
|
|
384
|
+
const convertedData = {
|
|
385
|
+
...response.data,
|
|
386
|
+
results: response.data.results.map((result) => ({
|
|
387
|
+
...result,
|
|
388
|
+
rows: convertKeysToCamelCase(result.rows)
|
|
389
|
+
}))
|
|
390
|
+
};
|
|
391
|
+
return {
|
|
392
|
+
...response,
|
|
393
|
+
data: convertedData
|
|
394
|
+
};
|
|
302
395
|
}
|
|
303
396
|
/**
|
|
304
397
|
* Upload file with progress tracking
|
|
@@ -837,7 +930,17 @@ var BlinkAuth = class {
|
|
|
837
930
|
* Redirect to Blink auth page
|
|
838
931
|
*/
|
|
839
932
|
login(nextUrl) {
|
|
840
|
-
|
|
933
|
+
let redirectUrl = nextUrl || (typeof window !== "undefined" ? window.location.href : "");
|
|
934
|
+
if (redirectUrl && typeof window !== "undefined") {
|
|
935
|
+
try {
|
|
936
|
+
const url = new URL(redirectUrl);
|
|
937
|
+
url.searchParams.delete("redirect_url");
|
|
938
|
+
url.searchParams.delete("redirect");
|
|
939
|
+
redirectUrl = url.toString();
|
|
940
|
+
} catch (e) {
|
|
941
|
+
console.warn("Failed to parse redirect URL:", e);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
841
944
|
const authUrl = new URL("/auth", this.authUrl);
|
|
842
945
|
authUrl.searchParams.set("redirect_url", redirectUrl);
|
|
843
946
|
if (this.config.projectId) {
|
|
@@ -1164,8 +1267,15 @@ var BlinkAuth = class {
|
|
|
1164
1267
|
issuedAt: tokensWithTimestamp.issued_at
|
|
1165
1268
|
});
|
|
1166
1269
|
if (persist && typeof window !== "undefined") {
|
|
1167
|
-
|
|
1168
|
-
|
|
1270
|
+
try {
|
|
1271
|
+
localStorage.setItem("blink_tokens", JSON.stringify(tokensWithTimestamp));
|
|
1272
|
+
console.log("\u{1F4BE} Tokens persisted to localStorage");
|
|
1273
|
+
} catch (error) {
|
|
1274
|
+
console.log("\u{1F4A5} Error persisting tokens to localStorage:", error);
|
|
1275
|
+
if (error instanceof DOMException && error.name === "SecurityError") {
|
|
1276
|
+
console.log("\u{1F6AB} localStorage access blocked - running in cross-origin iframe");
|
|
1277
|
+
}
|
|
1278
|
+
}
|
|
1169
1279
|
}
|
|
1170
1280
|
let user = null;
|
|
1171
1281
|
try {
|
|
@@ -1208,7 +1318,11 @@ var BlinkAuth = class {
|
|
|
1208
1318
|
}
|
|
1209
1319
|
clearTokens() {
|
|
1210
1320
|
if (typeof window !== "undefined") {
|
|
1211
|
-
|
|
1321
|
+
try {
|
|
1322
|
+
localStorage.removeItem("blink_tokens");
|
|
1323
|
+
} catch (error) {
|
|
1324
|
+
console.log("\u{1F4A5} Error clearing tokens from localStorage:", error);
|
|
1325
|
+
}
|
|
1212
1326
|
}
|
|
1213
1327
|
this.updateAuthState({
|
|
1214
1328
|
user: null,
|
|
@@ -1223,7 +1337,9 @@ var BlinkAuth = class {
|
|
|
1223
1337
|
const stored = localStorage.getItem("blink_tokens");
|
|
1224
1338
|
console.log("\u{1F50D} Checking localStorage for tokens:", {
|
|
1225
1339
|
hasStoredData: !!stored,
|
|
1226
|
-
storedLength: stored?.length || 0
|
|
1340
|
+
storedLength: stored?.length || 0,
|
|
1341
|
+
origin: window.location.origin,
|
|
1342
|
+
isIframe: window.self !== window.top
|
|
1227
1343
|
});
|
|
1228
1344
|
if (stored) {
|
|
1229
1345
|
const tokens = JSON.parse(stored);
|
|
@@ -1237,8 +1353,10 @@ var BlinkAuth = class {
|
|
|
1237
1353
|
}
|
|
1238
1354
|
return null;
|
|
1239
1355
|
} catch (error) {
|
|
1240
|
-
console.log("\u{1F4A5} Error
|
|
1241
|
-
|
|
1356
|
+
console.log("\u{1F4A5} Error accessing localStorage:", error);
|
|
1357
|
+
if (error instanceof DOMException && error.name === "SecurityError") {
|
|
1358
|
+
console.log("\u{1F6AB} localStorage access blocked - likely due to cross-origin iframe restrictions");
|
|
1359
|
+
}
|
|
1242
1360
|
return null;
|
|
1243
1361
|
}
|
|
1244
1362
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -65,6 +65,28 @@ var BlinkNotificationsError = class extends BlinkError {
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
// ../core/src/query-builder.ts
|
|
68
|
+
function camelToSnake(str) {
|
|
69
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
70
|
+
}
|
|
71
|
+
function convertFilterKeysToSnakeCase(condition) {
|
|
72
|
+
if (!condition) return condition;
|
|
73
|
+
if ("AND" in condition) {
|
|
74
|
+
return {
|
|
75
|
+
AND: condition.AND?.map(convertFilterKeysToSnakeCase)
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
if ("OR" in condition) {
|
|
79
|
+
return {
|
|
80
|
+
OR: condition.OR?.map(convertFilterKeysToSnakeCase)
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const converted = {};
|
|
84
|
+
for (const [field, value] of Object.entries(condition)) {
|
|
85
|
+
const snakeField = camelToSnake(field);
|
|
86
|
+
converted[snakeField] = value;
|
|
87
|
+
}
|
|
88
|
+
return converted;
|
|
89
|
+
}
|
|
68
90
|
function buildFilterQuery(condition) {
|
|
69
91
|
if (!condition) return "";
|
|
70
92
|
if ("AND" in condition) {
|
|
@@ -138,12 +160,14 @@ function encodeQueryValue(value) {
|
|
|
138
160
|
function buildQuery(options = {}) {
|
|
139
161
|
const params = {};
|
|
140
162
|
if (options.select && options.select.length > 0) {
|
|
141
|
-
|
|
163
|
+
const snakeFields = options.select.map(camelToSnake);
|
|
164
|
+
params.select = snakeFields.join(",");
|
|
142
165
|
} else {
|
|
143
166
|
params.select = "*";
|
|
144
167
|
}
|
|
145
168
|
if (options.where) {
|
|
146
|
-
const
|
|
169
|
+
const convertedWhere = convertFilterKeysToSnakeCase(options.where);
|
|
170
|
+
const filterQuery = buildFilterQuery(convertedWhere);
|
|
147
171
|
if (filterQuery) {
|
|
148
172
|
const filterParams = filterQuery.split("&");
|
|
149
173
|
for (const param of filterParams) {
|
|
@@ -158,7 +182,7 @@ function buildQuery(options = {}) {
|
|
|
158
182
|
if (typeof options.orderBy === "string") {
|
|
159
183
|
params.order = options.orderBy;
|
|
160
184
|
} else {
|
|
161
|
-
const orderClauses = Object.entries(options.orderBy).map(([field, direction]) => `${field}.${direction}`);
|
|
185
|
+
const orderClauses = Object.entries(options.orderBy).map(([field, direction]) => `${camelToSnake(field)}.${direction}`);
|
|
162
186
|
params.order = orderClauses.join(",");
|
|
163
187
|
}
|
|
164
188
|
}
|
|
@@ -175,6 +199,34 @@ function buildQuery(options = {}) {
|
|
|
175
199
|
}
|
|
176
200
|
|
|
177
201
|
// ../core/src/http-client.ts
|
|
202
|
+
function camelToSnake2(str) {
|
|
203
|
+
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
204
|
+
}
|
|
205
|
+
function snakeToCamel(str) {
|
|
206
|
+
return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
207
|
+
}
|
|
208
|
+
function convertKeysToSnakeCase(obj) {
|
|
209
|
+
if (obj === null || obj === void 0) return obj;
|
|
210
|
+
if (typeof obj !== "object") return obj;
|
|
211
|
+
if (Array.isArray(obj)) return obj.map(convertKeysToSnakeCase);
|
|
212
|
+
const converted = {};
|
|
213
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
214
|
+
const snakeKey = camelToSnake2(key);
|
|
215
|
+
converted[snakeKey] = convertKeysToSnakeCase(value);
|
|
216
|
+
}
|
|
217
|
+
return converted;
|
|
218
|
+
}
|
|
219
|
+
function convertKeysToCamelCase(obj) {
|
|
220
|
+
if (obj === null || obj === void 0) return obj;
|
|
221
|
+
if (typeof obj !== "object") return obj;
|
|
222
|
+
if (Array.isArray(obj)) return obj.map(convertKeysToCamelCase);
|
|
223
|
+
const converted = {};
|
|
224
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
225
|
+
const camelKey = snakeToCamel(key);
|
|
226
|
+
converted[camelKey] = convertKeysToCamelCase(value);
|
|
227
|
+
}
|
|
228
|
+
return converted;
|
|
229
|
+
}
|
|
178
230
|
var HttpClient = class {
|
|
179
231
|
authUrl = "https://blink.new";
|
|
180
232
|
coreUrl = "https://core.blink.new";
|
|
@@ -258,45 +310,86 @@ var HttpClient = class {
|
|
|
258
310
|
*/
|
|
259
311
|
// Table operations (PostgREST-compatible)
|
|
260
312
|
async dbGet(table, searchParams) {
|
|
261
|
-
|
|
313
|
+
const response = await this.get(`/api/db/${this.projectId}/rest/v1/${table}`, searchParams);
|
|
314
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
315
|
+
return {
|
|
316
|
+
...response,
|
|
317
|
+
data: convertedData
|
|
318
|
+
};
|
|
262
319
|
}
|
|
263
320
|
async dbPost(table, body, options = {}) {
|
|
264
321
|
const headers = {};
|
|
265
322
|
if (options.returning) {
|
|
266
323
|
headers.Prefer = "return=representation";
|
|
267
324
|
}
|
|
268
|
-
|
|
325
|
+
const convertedBody = convertKeysToSnakeCase(body);
|
|
326
|
+
const response = await this.post(`/api/db/${this.projectId}/rest/v1/${table}`, convertedBody, headers);
|
|
327
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
328
|
+
return {
|
|
329
|
+
...response,
|
|
330
|
+
data: convertedData
|
|
331
|
+
};
|
|
269
332
|
}
|
|
270
333
|
async dbPatch(table, body, searchParams, options = {}) {
|
|
271
334
|
const headers = {};
|
|
272
335
|
if (options.returning) {
|
|
273
336
|
headers.Prefer = "return=representation";
|
|
274
337
|
}
|
|
275
|
-
|
|
338
|
+
const convertedBody = convertKeysToSnakeCase(body);
|
|
339
|
+
const response = await this.request(`/api/db/${this.projectId}/rest/v1/${table}`, {
|
|
276
340
|
method: "PATCH",
|
|
277
|
-
body,
|
|
341
|
+
body: convertedBody,
|
|
278
342
|
headers,
|
|
279
343
|
searchParams
|
|
280
344
|
});
|
|
345
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
346
|
+
return {
|
|
347
|
+
...response,
|
|
348
|
+
data: convertedData
|
|
349
|
+
};
|
|
281
350
|
}
|
|
282
351
|
async dbDelete(table, searchParams, options = {}) {
|
|
283
352
|
const headers = {};
|
|
284
353
|
if (options.returning) {
|
|
285
354
|
headers.Prefer = "return=representation";
|
|
286
355
|
}
|
|
287
|
-
|
|
356
|
+
const response = await this.request(`/api/db/${this.projectId}/rest/v1/${table}`, {
|
|
288
357
|
method: "DELETE",
|
|
289
358
|
headers,
|
|
290
359
|
searchParams
|
|
291
360
|
});
|
|
361
|
+
const convertedData = convertKeysToCamelCase(response.data);
|
|
362
|
+
return {
|
|
363
|
+
...response,
|
|
364
|
+
data: convertedData
|
|
365
|
+
};
|
|
292
366
|
}
|
|
293
367
|
// Raw SQL operations
|
|
294
368
|
async dbSql(query, params) {
|
|
295
|
-
|
|
369
|
+
const response = await this.post(`/api/db/${this.projectId}/sql`, { query, params });
|
|
370
|
+
const convertedData = {
|
|
371
|
+
...response.data,
|
|
372
|
+
rows: convertKeysToCamelCase(response.data.rows)
|
|
373
|
+
};
|
|
374
|
+
return {
|
|
375
|
+
...response,
|
|
376
|
+
data: convertedData
|
|
377
|
+
};
|
|
296
378
|
}
|
|
297
379
|
// Batch SQL operations
|
|
298
380
|
async dbBatch(statements, mode = "write") {
|
|
299
|
-
|
|
381
|
+
const response = await this.post(`/api/db/${this.projectId}/batch`, { statements, mode });
|
|
382
|
+
const convertedData = {
|
|
383
|
+
...response.data,
|
|
384
|
+
results: response.data.results.map((result) => ({
|
|
385
|
+
...result,
|
|
386
|
+
rows: convertKeysToCamelCase(result.rows)
|
|
387
|
+
}))
|
|
388
|
+
};
|
|
389
|
+
return {
|
|
390
|
+
...response,
|
|
391
|
+
data: convertedData
|
|
392
|
+
};
|
|
300
393
|
}
|
|
301
394
|
/**
|
|
302
395
|
* Upload file with progress tracking
|
|
@@ -835,7 +928,17 @@ var BlinkAuth = class {
|
|
|
835
928
|
* Redirect to Blink auth page
|
|
836
929
|
*/
|
|
837
930
|
login(nextUrl) {
|
|
838
|
-
|
|
931
|
+
let redirectUrl = nextUrl || (typeof window !== "undefined" ? window.location.href : "");
|
|
932
|
+
if (redirectUrl && typeof window !== "undefined") {
|
|
933
|
+
try {
|
|
934
|
+
const url = new URL(redirectUrl);
|
|
935
|
+
url.searchParams.delete("redirect_url");
|
|
936
|
+
url.searchParams.delete("redirect");
|
|
937
|
+
redirectUrl = url.toString();
|
|
938
|
+
} catch (e) {
|
|
939
|
+
console.warn("Failed to parse redirect URL:", e);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
839
942
|
const authUrl = new URL("/auth", this.authUrl);
|
|
840
943
|
authUrl.searchParams.set("redirect_url", redirectUrl);
|
|
841
944
|
if (this.config.projectId) {
|
|
@@ -1162,8 +1265,15 @@ var BlinkAuth = class {
|
|
|
1162
1265
|
issuedAt: tokensWithTimestamp.issued_at
|
|
1163
1266
|
});
|
|
1164
1267
|
if (persist && typeof window !== "undefined") {
|
|
1165
|
-
|
|
1166
|
-
|
|
1268
|
+
try {
|
|
1269
|
+
localStorage.setItem("blink_tokens", JSON.stringify(tokensWithTimestamp));
|
|
1270
|
+
console.log("\u{1F4BE} Tokens persisted to localStorage");
|
|
1271
|
+
} catch (error) {
|
|
1272
|
+
console.log("\u{1F4A5} Error persisting tokens to localStorage:", error);
|
|
1273
|
+
if (error instanceof DOMException && error.name === "SecurityError") {
|
|
1274
|
+
console.log("\u{1F6AB} localStorage access blocked - running in cross-origin iframe");
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1167
1277
|
}
|
|
1168
1278
|
let user = null;
|
|
1169
1279
|
try {
|
|
@@ -1206,7 +1316,11 @@ var BlinkAuth = class {
|
|
|
1206
1316
|
}
|
|
1207
1317
|
clearTokens() {
|
|
1208
1318
|
if (typeof window !== "undefined") {
|
|
1209
|
-
|
|
1319
|
+
try {
|
|
1320
|
+
localStorage.removeItem("blink_tokens");
|
|
1321
|
+
} catch (error) {
|
|
1322
|
+
console.log("\u{1F4A5} Error clearing tokens from localStorage:", error);
|
|
1323
|
+
}
|
|
1210
1324
|
}
|
|
1211
1325
|
this.updateAuthState({
|
|
1212
1326
|
user: null,
|
|
@@ -1221,7 +1335,9 @@ var BlinkAuth = class {
|
|
|
1221
1335
|
const stored = localStorage.getItem("blink_tokens");
|
|
1222
1336
|
console.log("\u{1F50D} Checking localStorage for tokens:", {
|
|
1223
1337
|
hasStoredData: !!stored,
|
|
1224
|
-
storedLength: stored?.length || 0
|
|
1338
|
+
storedLength: stored?.length || 0,
|
|
1339
|
+
origin: window.location.origin,
|
|
1340
|
+
isIframe: window.self !== window.top
|
|
1225
1341
|
});
|
|
1226
1342
|
if (stored) {
|
|
1227
1343
|
const tokens = JSON.parse(stored);
|
|
@@ -1235,8 +1351,10 @@ var BlinkAuth = class {
|
|
|
1235
1351
|
}
|
|
1236
1352
|
return null;
|
|
1237
1353
|
} catch (error) {
|
|
1238
|
-
console.log("\u{1F4A5} Error
|
|
1239
|
-
|
|
1354
|
+
console.log("\u{1F4A5} Error accessing localStorage:", error);
|
|
1355
|
+
if (error instanceof DOMException && error.name === "SecurityError") {
|
|
1356
|
+
console.log("\u{1F6AB} localStorage access blocked - likely due to cross-origin iframe restrictions");
|
|
1357
|
+
}
|
|
1240
1358
|
return null;
|
|
1241
1359
|
}
|
|
1242
1360
|
}
|
package/package.json
CHANGED