@blinkdotnew/dev-sdk 0.0.1 → 2.1.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/dist/index.d.mts +97 -9
- package/dist/index.d.ts +97 -9
- package/dist/index.js +297 -157
- package/dist/index.mjs +296 -158
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -7,6 +7,33 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
|
|
|
7
7
|
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
8
8
|
});
|
|
9
9
|
|
|
10
|
+
// ../core/src/platform.ts
|
|
11
|
+
function detectPlatform() {
|
|
12
|
+
if (typeof Deno !== "undefined") {
|
|
13
|
+
return "deno";
|
|
14
|
+
}
|
|
15
|
+
if (typeof process !== "undefined" && process.versions?.node) {
|
|
16
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
17
|
+
return "react-native";
|
|
18
|
+
}
|
|
19
|
+
return "node";
|
|
20
|
+
}
|
|
21
|
+
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
22
|
+
return "react-native";
|
|
23
|
+
}
|
|
24
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
25
|
+
return "web";
|
|
26
|
+
}
|
|
27
|
+
return "node";
|
|
28
|
+
}
|
|
29
|
+
var platform = detectPlatform();
|
|
30
|
+
var isWeb = platform === "web";
|
|
31
|
+
var isReactNative = platform === "react-native";
|
|
32
|
+
var isNode = platform === "node";
|
|
33
|
+
var isDeno = platform === "deno";
|
|
34
|
+
var isBrowser = isWeb || isReactNative;
|
|
35
|
+
var isServer = isNode || isDeno;
|
|
36
|
+
|
|
10
37
|
// ../core/src/storage-adapter.ts
|
|
11
38
|
var WebStorageAdapter = class {
|
|
12
39
|
getItem(key) {
|
|
@@ -92,6 +119,9 @@ var NoOpStorageAdapter = class {
|
|
|
92
119
|
}
|
|
93
120
|
};
|
|
94
121
|
function getDefaultStorageAdapter() {
|
|
122
|
+
if (isDeno) {
|
|
123
|
+
return new NoOpStorageAdapter();
|
|
124
|
+
}
|
|
95
125
|
if (typeof window !== "undefined" && typeof localStorage !== "undefined") {
|
|
96
126
|
try {
|
|
97
127
|
localStorage.setItem("__test__", "test");
|
|
@@ -103,28 +133,6 @@ function getDefaultStorageAdapter() {
|
|
|
103
133
|
return new NoOpStorageAdapter();
|
|
104
134
|
}
|
|
105
135
|
|
|
106
|
-
// ../core/src/platform.ts
|
|
107
|
-
function detectPlatform() {
|
|
108
|
-
if (typeof process !== "undefined" && process.versions?.node) {
|
|
109
|
-
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
110
|
-
return "react-native";
|
|
111
|
-
}
|
|
112
|
-
return "node";
|
|
113
|
-
}
|
|
114
|
-
if (typeof navigator !== "undefined" && navigator.product === "ReactNative") {
|
|
115
|
-
return "react-native";
|
|
116
|
-
}
|
|
117
|
-
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
118
|
-
return "web";
|
|
119
|
-
}
|
|
120
|
-
return "node";
|
|
121
|
-
}
|
|
122
|
-
var platform = detectPlatform();
|
|
123
|
-
var isWeb = platform === "web";
|
|
124
|
-
var isReactNative = platform === "react-native";
|
|
125
|
-
var isNode = platform === "node";
|
|
126
|
-
var isBrowser = isWeb || isReactNative;
|
|
127
|
-
|
|
128
136
|
// ../core/src/types.ts
|
|
129
137
|
var BlinkError = class extends Error {
|
|
130
138
|
constructor(message, code, status, details) {
|
|
@@ -391,32 +399,65 @@ var HttpClient = class {
|
|
|
391
399
|
authUrl = "https://blink.new";
|
|
392
400
|
coreUrl = "https://core.blink.new";
|
|
393
401
|
projectId;
|
|
402
|
+
publishableKey;
|
|
403
|
+
secretKey;
|
|
404
|
+
// Permanent, non-expiring key (like Stripe's sk_live_...)
|
|
394
405
|
getToken;
|
|
395
406
|
getValidToken;
|
|
396
407
|
constructor(config, getToken, getValidToken) {
|
|
397
408
|
this.projectId = config.projectId;
|
|
409
|
+
this.publishableKey = config.publishableKey;
|
|
410
|
+
this.secretKey = config.secretKey || config.serviceToken;
|
|
398
411
|
this.getToken = getToken;
|
|
399
412
|
this.getValidToken = getValidToken;
|
|
400
413
|
}
|
|
414
|
+
shouldAttachPublishableKey(path, method) {
|
|
415
|
+
if (method !== "GET" && method !== "POST") return false;
|
|
416
|
+
if (path.includes("/api/analytics/")) return true;
|
|
417
|
+
if (path.includes("/api/storage/")) return true;
|
|
418
|
+
if (path.includes("/api/db/") && path.includes("/rest/v1/")) return method === "GET";
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
shouldSkipSecretKey(url) {
|
|
422
|
+
try {
|
|
423
|
+
const parsed = new URL(url);
|
|
424
|
+
return parsed.hostname.endsWith(".functions.blink.new");
|
|
425
|
+
} catch {
|
|
426
|
+
return false;
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
getAuthorizationHeader(url, token) {
|
|
430
|
+
if (this.secretKey && !this.shouldSkipSecretKey(url)) {
|
|
431
|
+
return `Bearer ${this.secretKey}`;
|
|
432
|
+
}
|
|
433
|
+
if (token) {
|
|
434
|
+
return `Bearer ${token}`;
|
|
435
|
+
}
|
|
436
|
+
return null;
|
|
437
|
+
}
|
|
401
438
|
/**
|
|
402
439
|
* Make an authenticated request to the Blink API
|
|
403
440
|
*/
|
|
404
441
|
async request(path, options = {}) {
|
|
405
442
|
const url = this.buildUrl(path, options.searchParams);
|
|
406
443
|
const token = this.getValidToken ? await this.getValidToken() : this.getToken();
|
|
444
|
+
const method = options.method || "GET";
|
|
407
445
|
const headers = {
|
|
408
446
|
"Content-Type": "application/json",
|
|
409
447
|
...options.headers
|
|
410
448
|
};
|
|
411
|
-
|
|
412
|
-
|
|
449
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
450
|
+
if (auth) {
|
|
451
|
+
headers.Authorization = auth;
|
|
452
|
+
} else if (this.publishableKey && !headers["x-blink-publishable-key"] && this.shouldAttachPublishableKey(path, method)) {
|
|
453
|
+
headers["x-blink-publishable-key"] = this.publishableKey;
|
|
413
454
|
}
|
|
414
455
|
const requestInit = {
|
|
415
|
-
method
|
|
456
|
+
method,
|
|
416
457
|
headers,
|
|
417
458
|
signal: options.signal
|
|
418
459
|
};
|
|
419
|
-
if (options.body &&
|
|
460
|
+
if (options.body && method !== "GET") {
|
|
420
461
|
requestInit.body = typeof options.body === "string" ? options.body : JSON.stringify(options.body);
|
|
421
462
|
}
|
|
422
463
|
try {
|
|
@@ -570,12 +611,12 @@ var HttpClient = class {
|
|
|
570
611
|
throw new BlinkValidationError("Unsupported file type");
|
|
571
612
|
}
|
|
572
613
|
formData.append("path", filePath);
|
|
573
|
-
if (options.upsert !== void 0) {
|
|
574
|
-
formData.append("options", JSON.stringify({ upsert: options.upsert }));
|
|
575
|
-
}
|
|
576
614
|
const headers = {};
|
|
577
|
-
|
|
578
|
-
|
|
615
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
616
|
+
if (auth) {
|
|
617
|
+
headers.Authorization = auth;
|
|
618
|
+
} else if (this.publishableKey && path.includes("/api/storage/") && !headers["x-blink-publishable-key"]) {
|
|
619
|
+
headers["x-blink-publishable-key"] = this.publishableKey;
|
|
579
620
|
}
|
|
580
621
|
try {
|
|
581
622
|
if (typeof XMLHttpRequest !== "undefined" && options.onProgress) {
|
|
@@ -676,7 +717,7 @@ var HttpClient = class {
|
|
|
676
717
|
});
|
|
677
718
|
}
|
|
678
719
|
/**
|
|
679
|
-
* Stream AI text generation
|
|
720
|
+
* Stream AI text generation - uses Vercel AI SDK's pipeUIMessageStreamToResponse (Data Stream Protocol)
|
|
680
721
|
*/
|
|
681
722
|
async streamAiText(prompt, options = {}, onChunk) {
|
|
682
723
|
const url = this.buildUrl(`/api/ai/${this.projectId}/text`);
|
|
@@ -684,9 +725,8 @@ var HttpClient = class {
|
|
|
684
725
|
const headers = {
|
|
685
726
|
"Content-Type": "application/json"
|
|
686
727
|
};
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
728
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
729
|
+
if (auth) headers.Authorization = auth;
|
|
690
730
|
const body = {
|
|
691
731
|
prompt,
|
|
692
732
|
stream: true,
|
|
@@ -706,7 +746,7 @@ var HttpClient = class {
|
|
|
706
746
|
if (!response.body) {
|
|
707
747
|
throw new BlinkNetworkError("No response body for streaming");
|
|
708
748
|
}
|
|
709
|
-
return this.
|
|
749
|
+
return this.parseDataStreamProtocol(response.body, onChunk);
|
|
710
750
|
} catch (error) {
|
|
711
751
|
if (error instanceof BlinkError) {
|
|
712
752
|
throw error;
|
|
@@ -731,7 +771,7 @@ var HttpClient = class {
|
|
|
731
771
|
});
|
|
732
772
|
}
|
|
733
773
|
/**
|
|
734
|
-
* Stream AI object generation
|
|
774
|
+
* Stream AI object generation - uses Vercel AI SDK's pipeTextStreamToResponse
|
|
735
775
|
*/
|
|
736
776
|
async streamAiObject(prompt, options = {}, onPartial) {
|
|
737
777
|
const url = this.buildUrl(`/api/ai/${this.projectId}/object`);
|
|
@@ -739,9 +779,8 @@ var HttpClient = class {
|
|
|
739
779
|
const headers = {
|
|
740
780
|
"Content-Type": "application/json"
|
|
741
781
|
};
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
}
|
|
782
|
+
const auth = this.getAuthorizationHeader(url, token);
|
|
783
|
+
if (auth) headers.Authorization = auth;
|
|
745
784
|
const body = {
|
|
746
785
|
prompt,
|
|
747
786
|
stream: true,
|
|
@@ -761,7 +800,35 @@ var HttpClient = class {
|
|
|
761
800
|
if (!response.body) {
|
|
762
801
|
throw new BlinkNetworkError("No response body for streaming");
|
|
763
802
|
}
|
|
764
|
-
|
|
803
|
+
const reader = response.body.getReader();
|
|
804
|
+
const decoder = new TextDecoder();
|
|
805
|
+
let buffer = "";
|
|
806
|
+
let latestObject = {};
|
|
807
|
+
try {
|
|
808
|
+
while (true) {
|
|
809
|
+
const { done, value } = await reader.read();
|
|
810
|
+
if (done) break;
|
|
811
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
812
|
+
buffer += chunk;
|
|
813
|
+
try {
|
|
814
|
+
const parsed = JSON.parse(buffer);
|
|
815
|
+
latestObject = parsed;
|
|
816
|
+
if (onPartial) {
|
|
817
|
+
onPartial(parsed);
|
|
818
|
+
}
|
|
819
|
+
} catch {
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
if (buffer) {
|
|
823
|
+
try {
|
|
824
|
+
latestObject = JSON.parse(buffer);
|
|
825
|
+
} catch {
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
return { object: latestObject };
|
|
829
|
+
} finally {
|
|
830
|
+
reader.releaseLock();
|
|
831
|
+
}
|
|
765
832
|
} catch (error) {
|
|
766
833
|
if (error instanceof BlinkError) {
|
|
767
834
|
throw error;
|
|
@@ -956,93 +1023,94 @@ var HttpClient = class {
|
|
|
956
1023
|
}
|
|
957
1024
|
}
|
|
958
1025
|
/**
|
|
959
|
-
* Parse Vercel AI SDK
|
|
960
|
-
*
|
|
1026
|
+
* Parse Vercel AI SDK v5 Data Stream Protocol (Server-Sent Events)
|
|
1027
|
+
* Supports all event types from the UI Message Stream protocol
|
|
961
1028
|
*/
|
|
962
|
-
async
|
|
1029
|
+
async parseDataStreamProtocol(body, onChunk) {
|
|
963
1030
|
const reader = body.getReader();
|
|
964
1031
|
const decoder = new TextDecoder();
|
|
1032
|
+
const finalResult = {
|
|
1033
|
+
text: "",
|
|
1034
|
+
toolCalls: [],
|
|
1035
|
+
toolResults: [],
|
|
1036
|
+
sources: [],
|
|
1037
|
+
files: [],
|
|
1038
|
+
reasoning: []
|
|
1039
|
+
};
|
|
965
1040
|
let buffer = "";
|
|
966
|
-
let finalResult = {};
|
|
967
1041
|
try {
|
|
968
1042
|
while (true) {
|
|
969
1043
|
const { done, value } = await reader.read();
|
|
970
1044
|
if (done) break;
|
|
971
1045
|
buffer += decoder.decode(value, { stream: true });
|
|
972
|
-
const lines = buffer.split(
|
|
1046
|
+
const lines = buffer.split("\n");
|
|
973
1047
|
buffer = lines.pop() || "";
|
|
974
1048
|
for (const line of lines) {
|
|
975
1049
|
if (!line.trim()) continue;
|
|
1050
|
+
if (line === "[DONE]") {
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
if (!line.startsWith("data: ")) continue;
|
|
976
1054
|
try {
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
} else if (line.startsWith("2:")) {
|
|
987
|
-
const data = JSON.parse(line.slice(2));
|
|
988
|
-
if (Array.isArray(data) && data.length > 0) {
|
|
989
|
-
const item = data[0];
|
|
990
|
-
if (typeof item === "string") {
|
|
991
|
-
finalResult.status = item;
|
|
992
|
-
} else if (typeof item === "object") {
|
|
993
|
-
if (onPartial) {
|
|
994
|
-
onPartial(item);
|
|
995
|
-
}
|
|
996
|
-
finalResult.object = item;
|
|
1055
|
+
const jsonStr = line.slice(6);
|
|
1056
|
+
const part = JSON.parse(jsonStr);
|
|
1057
|
+
switch (part.type) {
|
|
1058
|
+
case "text-start":
|
|
1059
|
+
break;
|
|
1060
|
+
case "text-delta":
|
|
1061
|
+
if (part.delta) {
|
|
1062
|
+
finalResult.text += part.delta;
|
|
1063
|
+
if (onChunk) onChunk(part.delta);
|
|
997
1064
|
}
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
if (metadata.usage) {
|
|
1002
|
-
finalResult.usage = metadata.usage;
|
|
1003
|
-
}
|
|
1004
|
-
if (metadata.finishReason) {
|
|
1005
|
-
finalResult.finishReason = metadata.finishReason;
|
|
1006
|
-
}
|
|
1007
|
-
} else if (line.startsWith("e:")) {
|
|
1008
|
-
const errorData = JSON.parse(line.slice(2));
|
|
1009
|
-
finalResult.error = errorData;
|
|
1010
|
-
}
|
|
1011
|
-
} catch (error) {
|
|
1012
|
-
console.warn("Failed to parse stream line:", line, error);
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
if (buffer.trim()) {
|
|
1017
|
-
try {
|
|
1018
|
-
if (buffer.startsWith("0:")) {
|
|
1019
|
-
const textChunk = JSON.parse(buffer.slice(2));
|
|
1020
|
-
if (onChunk) {
|
|
1021
|
-
onChunk(textChunk);
|
|
1022
|
-
}
|
|
1023
|
-
finalResult.text = (finalResult.text || "") + textChunk;
|
|
1024
|
-
} else if (buffer.startsWith("2:")) {
|
|
1025
|
-
const data = JSON.parse(buffer.slice(2));
|
|
1026
|
-
if (Array.isArray(data) && data.length > 0) {
|
|
1027
|
-
const item = data[0];
|
|
1028
|
-
if (typeof item === "object") {
|
|
1029
|
-
if (onPartial) {
|
|
1030
|
-
onPartial(item);
|
|
1065
|
+
if (part.textDelta) {
|
|
1066
|
+
finalResult.text += part.textDelta;
|
|
1067
|
+
if (onChunk) onChunk(part.textDelta);
|
|
1031
1068
|
}
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1069
|
+
break;
|
|
1070
|
+
case "text-end":
|
|
1071
|
+
break;
|
|
1072
|
+
case "tool-call":
|
|
1073
|
+
finalResult.toolCalls.push({
|
|
1074
|
+
toolCallId: part.toolCallId,
|
|
1075
|
+
toolName: part.toolName,
|
|
1076
|
+
args: part.args
|
|
1077
|
+
});
|
|
1078
|
+
break;
|
|
1079
|
+
case "tool-result":
|
|
1080
|
+
finalResult.toolResults.push({
|
|
1081
|
+
toolCallId: part.toolCallId,
|
|
1082
|
+
toolName: part.toolName,
|
|
1083
|
+
result: part.result
|
|
1084
|
+
});
|
|
1085
|
+
break;
|
|
1086
|
+
case "source-url":
|
|
1087
|
+
finalResult.sources.push({
|
|
1088
|
+
id: part.id,
|
|
1089
|
+
url: part.url,
|
|
1090
|
+
title: part.title
|
|
1091
|
+
});
|
|
1092
|
+
break;
|
|
1093
|
+
case "file":
|
|
1094
|
+
finalResult.files.push(part.file);
|
|
1095
|
+
break;
|
|
1096
|
+
case "reasoning":
|
|
1097
|
+
finalResult.reasoning.push(part.content);
|
|
1098
|
+
break;
|
|
1099
|
+
case "finish":
|
|
1100
|
+
finalResult.finishReason = part.finishReason;
|
|
1101
|
+
finalResult.usage = part.usage;
|
|
1102
|
+
if (part.response) finalResult.response = part.response;
|
|
1103
|
+
break;
|
|
1104
|
+
case "error":
|
|
1105
|
+
finalResult.error = part.error;
|
|
1106
|
+
throw new Error(part.error);
|
|
1107
|
+
case "data":
|
|
1108
|
+
if (!finalResult.customData) finalResult.customData = [];
|
|
1109
|
+
finalResult.customData.push(part.value);
|
|
1110
|
+
break;
|
|
1042
1111
|
}
|
|
1112
|
+
} catch (e) {
|
|
1043
1113
|
}
|
|
1044
|
-
} catch (error) {
|
|
1045
|
-
console.warn("Failed to parse final buffer:", buffer, error);
|
|
1046
1114
|
}
|
|
1047
1115
|
}
|
|
1048
1116
|
return finalResult;
|
|
@@ -1933,22 +2001,33 @@ var BlinkAuth = class {
|
|
|
1933
2001
|
if (!hasWindow()) {
|
|
1934
2002
|
throw new BlinkAuthError("NETWORK_ERROR" /* NETWORK_ERROR */, "signInWithProvider requires a browser environment");
|
|
1935
2003
|
}
|
|
2004
|
+
const shouldPreferRedirect = isWeb && this.isIframe || typeof window !== "undefined" && window.crossOriginIsolated === true;
|
|
2005
|
+
const state = this.generateState();
|
|
2006
|
+
try {
|
|
2007
|
+
const sessionStorage = getSessionStorage();
|
|
2008
|
+
if (sessionStorage) {
|
|
2009
|
+
sessionStorage.setItem("blink_oauth_state", state);
|
|
2010
|
+
}
|
|
2011
|
+
} catch {
|
|
2012
|
+
}
|
|
2013
|
+
const redirectUrl = options?.redirectUrl || getLocationOrigin() || "";
|
|
2014
|
+
const buildAuthUrl = (mode) => {
|
|
2015
|
+
const url = new URL("/auth", this.authUrl);
|
|
2016
|
+
url.searchParams.set("provider", provider);
|
|
2017
|
+
url.searchParams.set("project_id", this.config.projectId);
|
|
2018
|
+
url.searchParams.set("state", state);
|
|
2019
|
+
url.searchParams.set("mode", mode);
|
|
2020
|
+
url.searchParams.set("redirect_url", redirectUrl);
|
|
2021
|
+
url.searchParams.set("opener_origin", getLocationOrigin() || "");
|
|
2022
|
+
return url;
|
|
2023
|
+
};
|
|
2024
|
+
if (shouldPreferRedirect) {
|
|
2025
|
+
window.location.href = buildAuthUrl("redirect").toString();
|
|
2026
|
+
return new Promise(() => {
|
|
2027
|
+
});
|
|
2028
|
+
}
|
|
1936
2029
|
return new Promise((resolve, reject) => {
|
|
1937
|
-
const
|
|
1938
|
-
try {
|
|
1939
|
-
const sessionStorage = getSessionStorage();
|
|
1940
|
-
if (sessionStorage) {
|
|
1941
|
-
sessionStorage.setItem("blink_oauth_state", state);
|
|
1942
|
-
}
|
|
1943
|
-
} catch {
|
|
1944
|
-
}
|
|
1945
|
-
const redirectUrl = options?.redirectUrl || getLocationOrigin() || "";
|
|
1946
|
-
const popupUrl = new URL("/auth", this.authUrl);
|
|
1947
|
-
popupUrl.searchParams.set("provider", provider);
|
|
1948
|
-
popupUrl.searchParams.set("project_id", this.config.projectId);
|
|
1949
|
-
popupUrl.searchParams.set("state", state);
|
|
1950
|
-
popupUrl.searchParams.set("mode", "popup");
|
|
1951
|
-
popupUrl.searchParams.set("redirect_url", redirectUrl);
|
|
2030
|
+
const popupUrl = buildAuthUrl("popup");
|
|
1952
2031
|
const popup = window.open(
|
|
1953
2032
|
popupUrl.toString(),
|
|
1954
2033
|
"blink-auth",
|
|
@@ -1959,6 +2038,15 @@ var BlinkAuth = class {
|
|
|
1959
2038
|
return;
|
|
1960
2039
|
}
|
|
1961
2040
|
let timeoutId;
|
|
2041
|
+
let closedIntervalId;
|
|
2042
|
+
let cleanedUp = false;
|
|
2043
|
+
const cleanup = () => {
|
|
2044
|
+
if (cleanedUp) return;
|
|
2045
|
+
cleanedUp = true;
|
|
2046
|
+
clearTimeout(timeoutId);
|
|
2047
|
+
if (closedIntervalId) clearInterval(closedIntervalId);
|
|
2048
|
+
window.removeEventListener("message", messageListener);
|
|
2049
|
+
};
|
|
1962
2050
|
const messageListener = (event) => {
|
|
1963
2051
|
let allowed = false;
|
|
1964
2052
|
try {
|
|
@@ -1995,29 +2083,34 @@ var BlinkAuth = class {
|
|
|
1995
2083
|
}, true).then(() => {
|
|
1996
2084
|
resolve(this.authState.user);
|
|
1997
2085
|
}).catch(reject);
|
|
1998
|
-
|
|
1999
|
-
window.removeEventListener("message", messageListener);
|
|
2086
|
+
cleanup();
|
|
2000
2087
|
popup.close();
|
|
2001
2088
|
} else if (event.data?.type === "BLINK_AUTH_ERROR") {
|
|
2002
2089
|
const errorCode = this.mapErrorCodeFromResponse(event.data.code);
|
|
2003
2090
|
reject(new BlinkAuthError(errorCode, event.data.message || "Authentication failed"));
|
|
2004
|
-
|
|
2005
|
-
window.removeEventListener("message", messageListener);
|
|
2091
|
+
cleanup();
|
|
2006
2092
|
popup.close();
|
|
2007
2093
|
}
|
|
2008
2094
|
};
|
|
2095
|
+
if (popup.opener === null) {
|
|
2096
|
+
try {
|
|
2097
|
+
popup.close();
|
|
2098
|
+
} catch {
|
|
2099
|
+
}
|
|
2100
|
+
cleanup();
|
|
2101
|
+
window.location.href = buildAuthUrl("redirect").toString();
|
|
2102
|
+
return;
|
|
2103
|
+
}
|
|
2009
2104
|
timeoutId = setTimeout(() => {
|
|
2010
|
-
|
|
2105
|
+
cleanup();
|
|
2011
2106
|
if (!popup.closed) {
|
|
2012
2107
|
popup.close();
|
|
2013
2108
|
}
|
|
2014
2109
|
reject(new BlinkAuthError("AUTH_TIMEOUT" /* AUTH_TIMEOUT */, "Authentication timed out"));
|
|
2015
2110
|
}, 3e5);
|
|
2016
|
-
|
|
2111
|
+
closedIntervalId = setInterval(() => {
|
|
2017
2112
|
if (popup.closed) {
|
|
2018
|
-
|
|
2019
|
-
clearTimeout(timeoutId);
|
|
2020
|
-
window.removeEventListener("message", messageListener);
|
|
2113
|
+
cleanup();
|
|
2021
2114
|
reject(new BlinkAuthError("POPUP_CANCELED" /* POPUP_CANCELED */, "Authentication was canceled"));
|
|
2022
2115
|
}
|
|
2023
2116
|
}, 1e3);
|
|
@@ -2944,6 +3037,11 @@ var BlinkAuth = class {
|
|
|
2944
3037
|
};
|
|
2945
3038
|
|
|
2946
3039
|
// src/database.ts
|
|
3040
|
+
function assertServerOnly(methodName) {
|
|
3041
|
+
if (typeof window !== "undefined") {
|
|
3042
|
+
throw new Error(`${methodName} is server-only. Use Blink CRUD methods (blink.db.<table>.*) instead.`);
|
|
3043
|
+
}
|
|
3044
|
+
}
|
|
2947
3045
|
function camelToSnake3(str) {
|
|
2948
3046
|
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
2949
3047
|
}
|
|
@@ -3162,6 +3260,7 @@ var BlinkTable = class {
|
|
|
3162
3260
|
* Raw SQL query on this table (for advanced use cases)
|
|
3163
3261
|
*/
|
|
3164
3262
|
async sql(query, params) {
|
|
3263
|
+
assertServerOnly("blink.db.<table>.sql");
|
|
3165
3264
|
const response = await this.httpClient.dbSql(query, params);
|
|
3166
3265
|
return response.data;
|
|
3167
3266
|
}
|
|
@@ -3210,6 +3309,7 @@ var BlinkDatabase = class {
|
|
|
3210
3309
|
* Execute raw SQL query
|
|
3211
3310
|
*/
|
|
3212
3311
|
async sql(query, params) {
|
|
3312
|
+
assertServerOnly("blink.db.sql");
|
|
3213
3313
|
const response = await this.httpClient.dbSql(query, params);
|
|
3214
3314
|
return response.data;
|
|
3215
3315
|
}
|
|
@@ -3217,6 +3317,7 @@ var BlinkDatabase = class {
|
|
|
3217
3317
|
* Execute batch SQL operations
|
|
3218
3318
|
*/
|
|
3219
3319
|
async batch(statements, mode = "write") {
|
|
3320
|
+
assertServerOnly("blink.db.batch");
|
|
3220
3321
|
const response = await this.httpClient.dbBatch(statements, mode);
|
|
3221
3322
|
return response.data;
|
|
3222
3323
|
}
|
|
@@ -3279,7 +3380,6 @@ var BlinkStorageImpl = class {
|
|
|
3279
3380
|
correctedPath,
|
|
3280
3381
|
// Use corrected path with proper extension
|
|
3281
3382
|
{
|
|
3282
|
-
upsert: options.upsert,
|
|
3283
3383
|
onProgress: options.onProgress,
|
|
3284
3384
|
contentType: detectedContentType
|
|
3285
3385
|
// Pass detected content type
|
|
@@ -3299,7 +3399,7 @@ var BlinkStorageImpl = class {
|
|
|
3299
3399
|
if (error instanceof Error && "status" in error) {
|
|
3300
3400
|
const status = error.status;
|
|
3301
3401
|
if (status === 409) {
|
|
3302
|
-
throw new BlinkStorageError("File already exists.
|
|
3402
|
+
throw new BlinkStorageError("File already exists.", 409);
|
|
3303
3403
|
}
|
|
3304
3404
|
if (status === 400) {
|
|
3305
3405
|
throw new BlinkStorageError("Invalid request parameters", 400);
|
|
@@ -3344,7 +3444,6 @@ var BlinkStorageImpl = class {
|
|
|
3344
3444
|
detectedContentType
|
|
3345
3445
|
};
|
|
3346
3446
|
} catch (error) {
|
|
3347
|
-
console.warn("File type detection failed, using original path:", error);
|
|
3348
3447
|
return {
|
|
3349
3448
|
correctedPath: originalPath,
|
|
3350
3449
|
detectedContentType: "application/octet-stream"
|
|
@@ -3734,13 +3833,7 @@ var BlinkAIImpl = class {
|
|
|
3734
3833
|
options.prompt || "",
|
|
3735
3834
|
requestBody
|
|
3736
3835
|
);
|
|
3737
|
-
|
|
3738
|
-
return response.data.result;
|
|
3739
|
-
} else if (response.data?.text) {
|
|
3740
|
-
return response.data;
|
|
3741
|
-
} else {
|
|
3742
|
-
throw new BlinkAIError("Invalid response format: missing text");
|
|
3743
|
-
}
|
|
3836
|
+
return response.data;
|
|
3744
3837
|
} catch (error) {
|
|
3745
3838
|
if (error instanceof BlinkAIError) {
|
|
3746
3839
|
throw error;
|
|
@@ -3809,9 +3902,14 @@ var BlinkAIImpl = class {
|
|
|
3809
3902
|
);
|
|
3810
3903
|
return {
|
|
3811
3904
|
text: result.text || "",
|
|
3812
|
-
finishReason: "stop",
|
|
3905
|
+
finishReason: result.finishReason || "stop",
|
|
3813
3906
|
usage: result.usage,
|
|
3814
|
-
|
|
3907
|
+
toolCalls: result.toolCalls,
|
|
3908
|
+
toolResults: result.toolResults,
|
|
3909
|
+
sources: result.sources,
|
|
3910
|
+
files: result.files,
|
|
3911
|
+
reasoningDetails: result.reasoning,
|
|
3912
|
+
response: result.response
|
|
3815
3913
|
};
|
|
3816
3914
|
} catch (error) {
|
|
3817
3915
|
if (error instanceof BlinkAIError) {
|
|
@@ -3890,13 +3988,7 @@ var BlinkAIImpl = class {
|
|
|
3890
3988
|
signal: options.signal
|
|
3891
3989
|
}
|
|
3892
3990
|
);
|
|
3893
|
-
|
|
3894
|
-
return response.data.result;
|
|
3895
|
-
} else if (response.data?.object) {
|
|
3896
|
-
return response.data;
|
|
3897
|
-
} else {
|
|
3898
|
-
throw new BlinkAIError("Invalid response format: missing object");
|
|
3899
|
-
}
|
|
3991
|
+
return response.data;
|
|
3900
3992
|
} catch (error) {
|
|
3901
3993
|
if (error instanceof BlinkAIError) {
|
|
3902
3994
|
throw error;
|
|
@@ -3958,8 +4050,7 @@ var BlinkAIImpl = class {
|
|
|
3958
4050
|
return {
|
|
3959
4051
|
object: result.object || {},
|
|
3960
4052
|
finishReason: "stop",
|
|
3961
|
-
usage: result.usage
|
|
3962
|
-
...result
|
|
4053
|
+
usage: result.usage
|
|
3963
4054
|
};
|
|
3964
4055
|
} catch (error) {
|
|
3965
4056
|
if (error instanceof BlinkAIError) {
|
|
@@ -5278,7 +5369,6 @@ var BlinkAnalyticsImpl = class {
|
|
|
5278
5369
|
} catch (error) {
|
|
5279
5370
|
this.queue = [...events, ...this.queue];
|
|
5280
5371
|
this.persistQueue();
|
|
5281
|
-
console.error("Failed to send analytics events:", error);
|
|
5282
5372
|
}
|
|
5283
5373
|
if (this.queue.length > 0) {
|
|
5284
5374
|
this.timer = setTimeout(() => this.flush(), BATCH_TIMEOUT);
|
|
@@ -5488,6 +5578,45 @@ var BlinkConnectorsImpl = class {
|
|
|
5488
5578
|
}
|
|
5489
5579
|
};
|
|
5490
5580
|
|
|
5581
|
+
// src/functions.ts
|
|
5582
|
+
var BlinkFunctionsImpl = class {
|
|
5583
|
+
httpClient;
|
|
5584
|
+
projectId;
|
|
5585
|
+
constructor(httpClient, projectId, _getToken) {
|
|
5586
|
+
this.httpClient = httpClient;
|
|
5587
|
+
this.projectId = projectId;
|
|
5588
|
+
}
|
|
5589
|
+
/**
|
|
5590
|
+
* Get the project suffix from the full project ID.
|
|
5591
|
+
* Project IDs are formatted as: prj_xxxxx
|
|
5592
|
+
* The suffix is the last 8 characters used in function URLs.
|
|
5593
|
+
*/
|
|
5594
|
+
getProjectSuffix() {
|
|
5595
|
+
return this.projectId.slice(-8);
|
|
5596
|
+
}
|
|
5597
|
+
/**
|
|
5598
|
+
* Build the full function URL
|
|
5599
|
+
*/
|
|
5600
|
+
buildFunctionUrl(functionSlug, searchParams) {
|
|
5601
|
+
const suffix = this.getProjectSuffix();
|
|
5602
|
+
const baseUrl = `https://${suffix}--${functionSlug}.functions.blink.new`;
|
|
5603
|
+
if (!searchParams || Object.keys(searchParams).length === 0) {
|
|
5604
|
+
return baseUrl;
|
|
5605
|
+
}
|
|
5606
|
+
const url = new URL(baseUrl);
|
|
5607
|
+
Object.entries(searchParams).forEach(([key, value]) => {
|
|
5608
|
+
url.searchParams.set(key, value);
|
|
5609
|
+
});
|
|
5610
|
+
return url.toString();
|
|
5611
|
+
}
|
|
5612
|
+
async invoke(functionSlug, options = {}) {
|
|
5613
|
+
const { method = "POST", body, headers = {}, searchParams } = options;
|
|
5614
|
+
const url = this.buildFunctionUrl(functionSlug, searchParams);
|
|
5615
|
+
const res = await this.httpClient.request(url, { method, body, headers });
|
|
5616
|
+
return { data: res.data, status: res.status, headers: res.headers };
|
|
5617
|
+
}
|
|
5618
|
+
};
|
|
5619
|
+
|
|
5491
5620
|
// src/client.ts
|
|
5492
5621
|
var BlinkClientImpl = class {
|
|
5493
5622
|
auth;
|
|
@@ -5499,8 +5628,12 @@ var BlinkClientImpl = class {
|
|
|
5499
5628
|
notifications;
|
|
5500
5629
|
analytics;
|
|
5501
5630
|
connectors;
|
|
5631
|
+
functions;
|
|
5502
5632
|
httpClient;
|
|
5503
5633
|
constructor(config) {
|
|
5634
|
+
if ((config.secretKey || config.serviceToken) && isBrowser) {
|
|
5635
|
+
throw new Error("secretKey/serviceToken is server-only. Do not provide it in browser/React Native clients.");
|
|
5636
|
+
}
|
|
5504
5637
|
this.auth = new BlinkAuth(config);
|
|
5505
5638
|
this.httpClient = new HttpClient(
|
|
5506
5639
|
config,
|
|
@@ -5515,6 +5648,11 @@ var BlinkClientImpl = class {
|
|
|
5515
5648
|
this.notifications = new BlinkNotificationsImpl(this.httpClient);
|
|
5516
5649
|
this.analytics = new BlinkAnalyticsImpl(this.httpClient, config.projectId);
|
|
5517
5650
|
this.connectors = new BlinkConnectorsImpl(this.httpClient);
|
|
5651
|
+
this.functions = new BlinkFunctionsImpl(
|
|
5652
|
+
this.httpClient,
|
|
5653
|
+
config.projectId,
|
|
5654
|
+
() => this.auth.getValidToken()
|
|
5655
|
+
);
|
|
5518
5656
|
this.auth.onAuthStateChanged((state) => {
|
|
5519
5657
|
if (state.isAuthenticated && state.user) {
|
|
5520
5658
|
this.analytics.setUserId(state.user.id);
|
|
@@ -5548,8 +5686,10 @@ exports.WebStorageAdapter = WebStorageAdapter;
|
|
|
5548
5686
|
exports.createClient = createClient;
|
|
5549
5687
|
exports.getDefaultStorageAdapter = getDefaultStorageAdapter;
|
|
5550
5688
|
exports.isBrowser = isBrowser;
|
|
5689
|
+
exports.isDeno = isDeno;
|
|
5551
5690
|
exports.isNode = isNode;
|
|
5552
5691
|
exports.isReactNative = isReactNative;
|
|
5692
|
+
exports.isServer = isServer;
|
|
5553
5693
|
exports.isWeb = isWeb;
|
|
5554
5694
|
exports.platform = platform;
|
|
5555
5695
|
//# sourceMappingURL=index.js.map
|