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