@blinkdotnew/sdk 0.12.5 → 0.13.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/README.md CHANGED
@@ -196,8 +196,9 @@ const unsubscribe = blink.auth.onAuthStateChanged((state) => {
196
196
  ### Database Operations
197
197
 
198
198
  ```typescript
199
- // Create
199
+ // Create (ID auto-generated if not provided)
200
200
  const todo = await blink.db.todos.create({
201
+ id: 'todo_12345', // Optional - auto-generated if not provided
201
202
  title: 'Learn Blink SDK',
202
203
  user_id: user.id
203
204
  })
@@ -215,14 +216,22 @@ const todos = await blink.db.todos.list({
215
216
  })
216
217
  // `todos` is a direct array: Todo[]
217
218
 
219
+ // Note: Boolean fields are returned as "0"/"1" strings from SQLite
220
+ // Check boolean values using Number(value) > 0
221
+ const completedTodos = todos.filter(todo => Number(todo.completed) > 0)
222
+ const incompleteTodos = todos.filter(todo => Number(todo.completed) === 0)
223
+
218
224
  // Update
219
225
  await blink.db.todos.update(todo.id, { completed: true })
220
226
 
221
227
  // Delete
222
228
  await blink.db.todos.delete(todo.id)
223
229
 
224
- // Bulk operations
225
- await blink.db.todos.createMany([...])
230
+ // Bulk operations (IDs auto-generated if not provided)
231
+ await blink.db.todos.createMany([
232
+ { title: 'Task 1', user_id: user.id }, // ID will be auto-generated
233
+ { id: 'custom_id', title: 'Task 2', user_id: user.id } // Custom ID provided
234
+ ])
226
235
  await blink.db.todos.upsertMany([...])
227
236
 
228
237
  // Raw SQL
@@ -292,6 +301,42 @@ const { object } = await blink.ai.generateObject({
292
301
  }
293
302
  })
294
303
 
304
+ // ⚠️ IMPORTANT: Schema Rule for generateObject()
305
+ // The top-level schema MUST use type: "object" - you cannot use type: "array" at the top level
306
+ // This ensures clear, robust, and extensible API calls with named parameters
307
+
308
+ // ✅ Correct: Array inside object
309
+ const { object: todoList } = await blink.ai.generateObject({
310
+ prompt: 'Generate a list of 5 daily tasks',
311
+ schema: {
312
+ type: 'object',
313
+ properties: {
314
+ tasks: {
315
+ type: 'array',
316
+ items: {
317
+ type: 'object',
318
+ properties: {
319
+ title: { type: 'string' },
320
+ priority: { type: 'string', enum: ['low', 'medium', 'high'] }
321
+ }
322
+ }
323
+ }
324
+ },
325
+ required: ['tasks']
326
+ }
327
+ })
328
+ // Result: { tasks: [{ title: "Exercise", priority: "high" }, ...] }
329
+
330
+ // ❌ Wrong: Top-level array (will fail)
331
+ // const { object } = await blink.ai.generateObject({
332
+ // prompt: 'Generate tasks',
333
+ // schema: {
334
+ // type: 'array', // ❌ This will throw an error
335
+ // items: { type: 'string' }
336
+ // }
337
+ // })
338
+ // Error: "schema must be a JSON Schema of 'type: \"object\"', got 'type: \"array\"'"
339
+
295
340
  // Image generation
296
341
  const { data } = await blink.ai.generateImage({
297
342
  prompt: 'A serene landscape',
@@ -1147,17 +1192,22 @@ The SDK is written in TypeScript and provides full type safety:
1147
1192
  interface Todo {
1148
1193
  id: string
1149
1194
  title: string
1150
- completed: boolean
1195
+ completed: boolean // Will be returned as "0" or "1" string from SQLite
1151
1196
  user_id: string
1152
1197
  created_at: string
1153
1198
  }
1154
1199
 
1155
- // Note: Boolean fields are stored as integers (0/1) in SQLite
1200
+ // Note: Boolean fields are returned as "0"/"1" strings from SQLite
1156
1201
  // Use Number(value) > 0 to check boolean values
1157
- const completed = Number(todo.completed) > 0
1202
+ const todos = await blink.db.todos.list<Todo>()
1203
+
1204
+ // Check boolean values properly
1205
+ const completedTodos = todos.filter(todo => Number(todo.completed) > 0)
1206
+ const incompleteTodos = todos.filter(todo => Number(todo.completed) === 0)
1158
1207
 
1159
- const todos = await blink.db.todos.list<Todo>({
1160
- where: { completed: false }
1208
+ // When filtering by boolean values in queries, use "0"/"1" strings
1209
+ const onlyCompleted = await blink.db.todos.list<Todo>({
1210
+ where: { completed: "1" } // Use string "1" for true, "0" for false
1161
1211
  })
1162
1212
  // todos is fully typed as Todo[]
1163
1213
  ```
package/dist/index.js CHANGED
@@ -1314,6 +1314,24 @@ var BlinkAuth = class {
1314
1314
  };
1315
1315
 
1316
1316
  // src/database.ts
1317
+ function generateSecureId() {
1318
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
1319
+ const array = new Uint8Array(16);
1320
+ crypto.getRandomValues(array);
1321
+ return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
1322
+ } else {
1323
+ const timestamp = Date.now().toString(36);
1324
+ const randomPart = Math.random().toString(36).substring(2, 15);
1325
+ const extraRandom = Math.random().toString(36).substring(2, 15);
1326
+ return `${timestamp}_${randomPart}_${extraRandom}`;
1327
+ }
1328
+ }
1329
+ function ensureRecordId(record) {
1330
+ if (!record.id) {
1331
+ return { ...record, id: generateSecureId() };
1332
+ }
1333
+ return record;
1334
+ }
1317
1335
  var BlinkTable = class {
1318
1336
  constructor(tableName, httpClient) {
1319
1337
  this.tableName = tableName;
@@ -1323,9 +1341,10 @@ var BlinkTable = class {
1323
1341
  * Create a single record
1324
1342
  */
1325
1343
  async create(data, options = {}) {
1344
+ const record = ensureRecordId(data);
1326
1345
  const response = await this.httpClient.dbPost(
1327
1346
  this.tableName,
1328
- data,
1347
+ record,
1329
1348
  { returning: options.returning !== false }
1330
1349
  );
1331
1350
  const result = Array.isArray(response.data) ? response.data[0] : response.data;
@@ -1338,13 +1357,14 @@ var BlinkTable = class {
1338
1357
  * Create multiple records
1339
1358
  */
1340
1359
  async createMany(data, options = {}) {
1360
+ const records = data.map(ensureRecordId);
1341
1361
  const response = await this.httpClient.dbPost(
1342
1362
  this.tableName,
1343
- data,
1363
+ records,
1344
1364
  { returning: options.returning !== false }
1345
1365
  );
1346
- const records = Array.isArray(response.data) ? response.data : [response.data];
1347
- return records;
1366
+ const results = Array.isArray(response.data) ? response.data : [response.data];
1367
+ return results;
1348
1368
  }
1349
1369
  /**
1350
1370
  * Upsert a single record (insert or update on conflict)
@@ -1357,11 +1377,12 @@ var BlinkTable = class {
1357
1377
  if (options.onConflict) {
1358
1378
  headers["Prefer"] = `${headers["Prefer"] || ""} resolution=merge-duplicates`.trim();
1359
1379
  }
1380
+ const record = ensureRecordId(data);
1360
1381
  const response = await this.httpClient.request(
1361
1382
  `/api/db/${this.httpClient.projectId}/rest/v1/${this.tableName}?on_conflict=${options.onConflict || "id"}`,
1362
1383
  {
1363
1384
  method: "POST",
1364
- body: data,
1385
+ body: record,
1365
1386
  headers
1366
1387
  }
1367
1388
  );
@@ -1375,6 +1396,7 @@ var BlinkTable = class {
1375
1396
  * Upsert multiple records
1376
1397
  */
1377
1398
  async upsertMany(data, options = {}) {
1399
+ const records = data.map(ensureRecordId);
1378
1400
  const headers = {};
1379
1401
  if (options.returning !== false) {
1380
1402
  headers.Prefer = "return=representation";
@@ -1386,12 +1408,12 @@ var BlinkTable = class {
1386
1408
  `/api/db/${this.httpClient.projectId}/rest/v1/${this.tableName}?on_conflict=${options.onConflict || "id"}`,
1387
1409
  {
1388
1410
  method: "POST",
1389
- body: data,
1411
+ body: records,
1390
1412
  headers
1391
1413
  }
1392
1414
  );
1393
- const records = Array.isArray(response.data) ? response.data : [response.data];
1394
- return records;
1415
+ const results = Array.isArray(response.data) ? response.data : [response.data];
1416
+ return results;
1395
1417
  }
1396
1418
  /**
1397
1419
  * Get a single record by ID
package/dist/index.mjs CHANGED
@@ -1312,6 +1312,24 @@ var BlinkAuth = class {
1312
1312
  };
1313
1313
 
1314
1314
  // src/database.ts
1315
+ function generateSecureId() {
1316
+ if (typeof crypto !== "undefined" && crypto.getRandomValues) {
1317
+ const array = new Uint8Array(16);
1318
+ crypto.getRandomValues(array);
1319
+ return Array.from(array, (byte) => byte.toString(16).padStart(2, "0")).join("");
1320
+ } else {
1321
+ const timestamp = Date.now().toString(36);
1322
+ const randomPart = Math.random().toString(36).substring(2, 15);
1323
+ const extraRandom = Math.random().toString(36).substring(2, 15);
1324
+ return `${timestamp}_${randomPart}_${extraRandom}`;
1325
+ }
1326
+ }
1327
+ function ensureRecordId(record) {
1328
+ if (!record.id) {
1329
+ return { ...record, id: generateSecureId() };
1330
+ }
1331
+ return record;
1332
+ }
1315
1333
  var BlinkTable = class {
1316
1334
  constructor(tableName, httpClient) {
1317
1335
  this.tableName = tableName;
@@ -1321,9 +1339,10 @@ var BlinkTable = class {
1321
1339
  * Create a single record
1322
1340
  */
1323
1341
  async create(data, options = {}) {
1342
+ const record = ensureRecordId(data);
1324
1343
  const response = await this.httpClient.dbPost(
1325
1344
  this.tableName,
1326
- data,
1345
+ record,
1327
1346
  { returning: options.returning !== false }
1328
1347
  );
1329
1348
  const result = Array.isArray(response.data) ? response.data[0] : response.data;
@@ -1336,13 +1355,14 @@ var BlinkTable = class {
1336
1355
  * Create multiple records
1337
1356
  */
1338
1357
  async createMany(data, options = {}) {
1358
+ const records = data.map(ensureRecordId);
1339
1359
  const response = await this.httpClient.dbPost(
1340
1360
  this.tableName,
1341
- data,
1361
+ records,
1342
1362
  { returning: options.returning !== false }
1343
1363
  );
1344
- const records = Array.isArray(response.data) ? response.data : [response.data];
1345
- return records;
1364
+ const results = Array.isArray(response.data) ? response.data : [response.data];
1365
+ return results;
1346
1366
  }
1347
1367
  /**
1348
1368
  * Upsert a single record (insert or update on conflict)
@@ -1355,11 +1375,12 @@ var BlinkTable = class {
1355
1375
  if (options.onConflict) {
1356
1376
  headers["Prefer"] = `${headers["Prefer"] || ""} resolution=merge-duplicates`.trim();
1357
1377
  }
1378
+ const record = ensureRecordId(data);
1358
1379
  const response = await this.httpClient.request(
1359
1380
  `/api/db/${this.httpClient.projectId}/rest/v1/${this.tableName}?on_conflict=${options.onConflict || "id"}`,
1360
1381
  {
1361
1382
  method: "POST",
1362
- body: data,
1383
+ body: record,
1363
1384
  headers
1364
1385
  }
1365
1386
  );
@@ -1373,6 +1394,7 @@ var BlinkTable = class {
1373
1394
  * Upsert multiple records
1374
1395
  */
1375
1396
  async upsertMany(data, options = {}) {
1397
+ const records = data.map(ensureRecordId);
1376
1398
  const headers = {};
1377
1399
  if (options.returning !== false) {
1378
1400
  headers.Prefer = "return=representation";
@@ -1384,12 +1406,12 @@ var BlinkTable = class {
1384
1406
  `/api/db/${this.httpClient.projectId}/rest/v1/${this.tableName}?on_conflict=${options.onConflict || "id"}`,
1385
1407
  {
1386
1408
  method: "POST",
1387
- body: data,
1409
+ body: records,
1388
1410
  headers
1389
1411
  }
1390
1412
  );
1391
- const records = Array.isArray(response.data) ? response.data : [response.data];
1392
- return records;
1413
+ const results = Array.isArray(response.data) ? response.data : [response.data];
1414
+ return results;
1393
1415
  }
1394
1416
  /**
1395
1417
  * Get a single record by ID
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blinkdotnew/sdk",
3
- "version": "0.12.5",
3
+ "version": "0.13.2",
4
4
  "description": "Blink TypeScript SDK for client-side applications - Zero-boilerplate CRUD + auth + AI + analytics + notifications for modern SaaS/AI apps",
5
5
  "keywords": [
6
6
  "blink",