@sinch/functions-runtime 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/sinch-runtime.js +346 -48
- package/dist/bin/sinch-runtime.js.map +1 -1
- package/dist/index.d.ts +1101 -65
- package/dist/index.js +1268 -152
- package/dist/index.js.map +1 -1
- package/package.json +1 -4
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/bin/sinch-runtime.ts
|
|
4
|
-
import
|
|
4
|
+
import path6 from "path";
|
|
5
5
|
import { createRequire as createRequire3 } from "module";
|
|
6
6
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
7
|
-
import
|
|
7
|
+
import fs5 from "fs";
|
|
8
8
|
|
|
9
9
|
// ../runtime-shared/dist/ai/connect-agent.js
|
|
10
10
|
var AgentProvider;
|
|
@@ -247,11 +247,11 @@ function isVoiceCallback(functionName) {
|
|
|
247
247
|
function isNotificationEvent(functionName) {
|
|
248
248
|
return NOTIFICATION_EVENTS.includes(functionName);
|
|
249
249
|
}
|
|
250
|
-
function extractFunctionName(
|
|
250
|
+
function extractFunctionName(path7, body) {
|
|
251
251
|
if (body?.event && isVoiceCallback(body.event)) {
|
|
252
252
|
return body.event;
|
|
253
253
|
}
|
|
254
|
-
const pathname =
|
|
254
|
+
const pathname = path7.split("?")[0];
|
|
255
255
|
const segments = pathname.split("/").filter((s) => s && s !== "*");
|
|
256
256
|
if (segments.length === 1 && isVoiceCallback(segments[0])) {
|
|
257
257
|
return segments[0];
|
|
@@ -268,10 +268,10 @@ function generateRequestId() {
|
|
|
268
268
|
return `req_${Date.now()}_${Math.random().toString(36).substring(7)}`;
|
|
269
269
|
}
|
|
270
270
|
function findFunctionPath() {
|
|
271
|
-
const
|
|
271
|
+
const fs6 = requireCjs2("fs");
|
|
272
272
|
const distPath = nodePath.join(process.cwd(), "dist", "function.js");
|
|
273
273
|
const rootPath = nodePath.join(process.cwd(), "function.js");
|
|
274
|
-
if (
|
|
274
|
+
if (fs6.existsSync(distPath)) {
|
|
275
275
|
return distPath;
|
|
276
276
|
}
|
|
277
277
|
return rootPath;
|
|
@@ -349,6 +349,15 @@ var noOpCache = {
|
|
|
349
349
|
keys: async () => [],
|
|
350
350
|
getMany: async () => ({})
|
|
351
351
|
};
|
|
352
|
+
var noOpStorage = {
|
|
353
|
+
write: async () => {
|
|
354
|
+
},
|
|
355
|
+
read: async () => Buffer.alloc(0),
|
|
356
|
+
list: async () => [],
|
|
357
|
+
exists: async () => false,
|
|
358
|
+
delete: async () => {
|
|
359
|
+
}
|
|
360
|
+
};
|
|
352
361
|
function buildBaseContext(req, config = {}) {
|
|
353
362
|
return {
|
|
354
363
|
requestId: req.headers["x-request-id"] || generateRequestId(),
|
|
@@ -361,6 +370,8 @@ function buildBaseContext(req, config = {}) {
|
|
|
361
370
|
variables: config.variables
|
|
362
371
|
},
|
|
363
372
|
cache: noOpCache,
|
|
373
|
+
storage: noOpStorage,
|
|
374
|
+
database: "",
|
|
364
375
|
assets: (filename) => {
|
|
365
376
|
const filePath = nodePath.join(process.cwd(), "assets", filename);
|
|
366
377
|
return nodeFs.promises.readFile(filePath, "utf-8");
|
|
@@ -763,10 +774,306 @@ function createCacheClient(_projectId, _functionName) {
|
|
|
763
774
|
return new LocalCache();
|
|
764
775
|
}
|
|
765
776
|
|
|
777
|
+
// src/storage/local.ts
|
|
778
|
+
import * as fs3 from "fs/promises";
|
|
779
|
+
import * as path4 from "path";
|
|
780
|
+
var LocalStorage = class {
|
|
781
|
+
baseDir;
|
|
782
|
+
constructor(baseDir) {
|
|
783
|
+
this.baseDir = baseDir ?? path4.join(process.cwd(), "storage");
|
|
784
|
+
}
|
|
785
|
+
resolvePath(key) {
|
|
786
|
+
const sanitized = key.replace(/^\/+/, "").replace(/\.\./g, "_");
|
|
787
|
+
return path4.join(this.baseDir, sanitized);
|
|
788
|
+
}
|
|
789
|
+
async write(key, data) {
|
|
790
|
+
const filePath = this.resolvePath(key);
|
|
791
|
+
await fs3.mkdir(path4.dirname(filePath), { recursive: true });
|
|
792
|
+
await fs3.writeFile(filePath, data);
|
|
793
|
+
}
|
|
794
|
+
async read(key) {
|
|
795
|
+
const filePath = this.resolvePath(key);
|
|
796
|
+
return fs3.readFile(filePath);
|
|
797
|
+
}
|
|
798
|
+
async list(prefix) {
|
|
799
|
+
const results = [];
|
|
800
|
+
await this.walkDir(this.baseDir, "", results);
|
|
801
|
+
if (prefix) {
|
|
802
|
+
return results.filter((f) => f.startsWith(prefix));
|
|
803
|
+
}
|
|
804
|
+
return results;
|
|
805
|
+
}
|
|
806
|
+
async exists(key) {
|
|
807
|
+
const filePath = this.resolvePath(key);
|
|
808
|
+
try {
|
|
809
|
+
await fs3.access(filePath);
|
|
810
|
+
return true;
|
|
811
|
+
} catch {
|
|
812
|
+
return false;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
async delete(key) {
|
|
816
|
+
const filePath = this.resolvePath(key);
|
|
817
|
+
await fs3.rm(filePath, { force: true });
|
|
818
|
+
}
|
|
819
|
+
async walkDir(dir, relative, results) {
|
|
820
|
+
let entries;
|
|
821
|
+
try {
|
|
822
|
+
entries = await fs3.readdir(dir, { withFileTypes: true });
|
|
823
|
+
} catch {
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
826
|
+
for (const entry of entries) {
|
|
827
|
+
const rel = relative ? `${relative}/${entry.name}` : entry.name;
|
|
828
|
+
if (entry.isDirectory()) {
|
|
829
|
+
await this.walkDir(path4.join(dir, entry.name), rel, results);
|
|
830
|
+
} else {
|
|
831
|
+
results.push(rel);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
};
|
|
836
|
+
function createStorageClient(baseDir) {
|
|
837
|
+
return new LocalStorage(baseDir);
|
|
838
|
+
}
|
|
839
|
+
|
|
766
840
|
// src/secrets/index.ts
|
|
767
|
-
import
|
|
768
|
-
import
|
|
841
|
+
import fs4 from "fs";
|
|
842
|
+
import path5 from "path";
|
|
769
843
|
import os from "os";
|
|
844
|
+
|
|
845
|
+
// src/secrets/keychain.ts
|
|
846
|
+
import { execFile, spawn } from "child_process";
|
|
847
|
+
import { promisify } from "util";
|
|
848
|
+
var execFileAsync = promisify(execFile);
|
|
849
|
+
function b64(value) {
|
|
850
|
+
return Buffer.from(value, "utf8").toString("base64");
|
|
851
|
+
}
|
|
852
|
+
function psParam(name, value) {
|
|
853
|
+
return `$${name} = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${b64(value)}'));`;
|
|
854
|
+
}
|
|
855
|
+
var WIN32_CRED_READ_SCRIPT = `
|
|
856
|
+
Add-Type -TypeDefinition @'
|
|
857
|
+
using System;
|
|
858
|
+
using System.Runtime.InteropServices;
|
|
859
|
+
public class CredManager {
|
|
860
|
+
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
|
|
861
|
+
private struct CREDENTIAL {
|
|
862
|
+
public int Flags;
|
|
863
|
+
public int Type;
|
|
864
|
+
public IntPtr TargetName;
|
|
865
|
+
public IntPtr Comment;
|
|
866
|
+
public long LastWritten;
|
|
867
|
+
public int CredentialBlobSize;
|
|
868
|
+
public IntPtr CredentialBlob;
|
|
869
|
+
public int Persist;
|
|
870
|
+
public int AttributeCount;
|
|
871
|
+
public IntPtr Attributes;
|
|
872
|
+
public IntPtr TargetAlias;
|
|
873
|
+
public IntPtr UserName;
|
|
874
|
+
}
|
|
875
|
+
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
|
|
876
|
+
private static extern bool CredReadW(string target, int type, int flags, out IntPtr cred);
|
|
877
|
+
[DllImport("advapi32.dll")]
|
|
878
|
+
private static extern void CredFree(IntPtr cred);
|
|
879
|
+
public static string Read(string target) {
|
|
880
|
+
IntPtr credPtr;
|
|
881
|
+
if (!CredReadW(target, 1, 0, out credPtr)) return null;
|
|
882
|
+
try {
|
|
883
|
+
CREDENTIAL c = (CREDENTIAL)Marshal.PtrToStructure(credPtr, typeof(CREDENTIAL));
|
|
884
|
+
if (c.CredentialBlobSize > 0 && c.CredentialBlob != IntPtr.Zero)
|
|
885
|
+
return Marshal.PtrToStringUni(c.CredentialBlob, c.CredentialBlobSize / 2);
|
|
886
|
+
return "";
|
|
887
|
+
} finally { CredFree(credPtr); }
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
'@
|
|
891
|
+
$r = [CredManager]::Read($target)
|
|
892
|
+
if ($r -ne $null) { [Console]::Write($r) }
|
|
893
|
+
else { exit 1 }
|
|
894
|
+
`;
|
|
895
|
+
var WIN32_CRED_WRITE_SCRIPT = `
|
|
896
|
+
Add-Type -TypeDefinition @'
|
|
897
|
+
using System;
|
|
898
|
+
using System.Runtime.InteropServices;
|
|
899
|
+
using System.Text;
|
|
900
|
+
public class CredWriter {
|
|
901
|
+
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
|
|
902
|
+
private struct CREDENTIAL {
|
|
903
|
+
public int Flags;
|
|
904
|
+
public int Type;
|
|
905
|
+
public string TargetName;
|
|
906
|
+
public string Comment;
|
|
907
|
+
public long LastWritten;
|
|
908
|
+
public int CredentialBlobSize;
|
|
909
|
+
public IntPtr CredentialBlob;
|
|
910
|
+
public int Persist;
|
|
911
|
+
public int AttributeCount;
|
|
912
|
+
public IntPtr Attributes;
|
|
913
|
+
public string TargetAlias;
|
|
914
|
+
public string UserName;
|
|
915
|
+
}
|
|
916
|
+
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
|
|
917
|
+
private static extern bool CredWriteW(ref CREDENTIAL cred, int flags);
|
|
918
|
+
public static bool Write(string target, string password) {
|
|
919
|
+
byte[] blob = Encoding.Unicode.GetBytes(password);
|
|
920
|
+
CREDENTIAL c = new CREDENTIAL();
|
|
921
|
+
c.Type = 1;
|
|
922
|
+
c.TargetName = target;
|
|
923
|
+
c.CredentialBlobSize = blob.Length;
|
|
924
|
+
c.CredentialBlob = Marshal.AllocHGlobal(blob.Length);
|
|
925
|
+
Marshal.Copy(blob, 0, c.CredentialBlob, blob.Length);
|
|
926
|
+
c.Persist = 2;
|
|
927
|
+
try { return CredWriteW(ref c, 0); }
|
|
928
|
+
finally { Marshal.FreeHGlobal(c.CredentialBlob); }
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
'@
|
|
932
|
+
if (-not [CredWriter]::Write($target, $password)) { exit 1 }
|
|
933
|
+
`;
|
|
934
|
+
var WIN32_CRED_DELETE_SCRIPT = `
|
|
935
|
+
Add-Type -TypeDefinition @'
|
|
936
|
+
using System;
|
|
937
|
+
using System.Runtime.InteropServices;
|
|
938
|
+
public class CredDeleter {
|
|
939
|
+
[DllImport("advapi32.dll", SetLastError=true, CharSet=CharSet.Unicode)]
|
|
940
|
+
private static extern bool CredDeleteW(string target, int type, int flags);
|
|
941
|
+
public static bool Delete(string target) { return CredDeleteW(target, 1, 0); }
|
|
942
|
+
}
|
|
943
|
+
'@
|
|
944
|
+
if (-not [CredDeleter]::Delete($target)) { exit 1 }
|
|
945
|
+
`;
|
|
946
|
+
function winTarget(service, account) {
|
|
947
|
+
return `${service}/${account}`;
|
|
948
|
+
}
|
|
949
|
+
var windowsKeychain = {
|
|
950
|
+
async getPassword(service, account) {
|
|
951
|
+
try {
|
|
952
|
+
const params = psParam("target", winTarget(service, account));
|
|
953
|
+
const { stdout } = await execFileAsync(
|
|
954
|
+
"powershell.exe",
|
|
955
|
+
["-NoProfile", "-NonInteractive", "-Command", params + WIN32_CRED_READ_SCRIPT],
|
|
956
|
+
{ timeout: 15e3, windowsHide: true }
|
|
957
|
+
);
|
|
958
|
+
return stdout;
|
|
959
|
+
} catch {
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
},
|
|
963
|
+
async setPassword(service, account, password) {
|
|
964
|
+
const params = psParam("target", winTarget(service, account)) + psParam("password", password);
|
|
965
|
+
await execFileAsync(
|
|
966
|
+
"powershell.exe",
|
|
967
|
+
["-NoProfile", "-NonInteractive", "-Command", params + WIN32_CRED_WRITE_SCRIPT],
|
|
968
|
+
{ timeout: 15e3, windowsHide: true }
|
|
969
|
+
);
|
|
970
|
+
},
|
|
971
|
+
async deletePassword(service, account) {
|
|
972
|
+
try {
|
|
973
|
+
const params = psParam("target", winTarget(service, account));
|
|
974
|
+
await execFileAsync(
|
|
975
|
+
"powershell.exe",
|
|
976
|
+
["-NoProfile", "-NonInteractive", "-Command", params + WIN32_CRED_DELETE_SCRIPT],
|
|
977
|
+
{ timeout: 15e3, windowsHide: true }
|
|
978
|
+
);
|
|
979
|
+
return true;
|
|
980
|
+
} catch {
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
var macKeychain = {
|
|
986
|
+
async getPassword(service, account) {
|
|
987
|
+
try {
|
|
988
|
+
const { stdout } = await execFileAsync(
|
|
989
|
+
"security",
|
|
990
|
+
["find-generic-password", "-s", service, "-a", account, "-w"],
|
|
991
|
+
{ timeout: 15e3 }
|
|
992
|
+
);
|
|
993
|
+
return stdout.trimEnd();
|
|
994
|
+
} catch {
|
|
995
|
+
return null;
|
|
996
|
+
}
|
|
997
|
+
},
|
|
998
|
+
async setPassword(service, account, password) {
|
|
999
|
+
await execFileAsync(
|
|
1000
|
+
"security",
|
|
1001
|
+
["add-generic-password", "-U", "-s", service, "-a", account, "-w", password],
|
|
1002
|
+
{ timeout: 15e3 }
|
|
1003
|
+
);
|
|
1004
|
+
},
|
|
1005
|
+
async deletePassword(service, account) {
|
|
1006
|
+
try {
|
|
1007
|
+
await execFileAsync(
|
|
1008
|
+
"security",
|
|
1009
|
+
["delete-generic-password", "-s", service, "-a", account],
|
|
1010
|
+
{ timeout: 15e3 }
|
|
1011
|
+
);
|
|
1012
|
+
return true;
|
|
1013
|
+
} catch {
|
|
1014
|
+
return false;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
1018
|
+
var linuxKeychain = {
|
|
1019
|
+
async getPassword(service, account) {
|
|
1020
|
+
try {
|
|
1021
|
+
const { stdout } = await execFileAsync(
|
|
1022
|
+
"secret-tool",
|
|
1023
|
+
["lookup", "service", service, "account", account],
|
|
1024
|
+
{ timeout: 15e3 }
|
|
1025
|
+
);
|
|
1026
|
+
return stdout.trimEnd();
|
|
1027
|
+
} catch {
|
|
1028
|
+
return null;
|
|
1029
|
+
}
|
|
1030
|
+
},
|
|
1031
|
+
// secret-tool reads password from stdin (avoids exposing it in process args)
|
|
1032
|
+
async setPassword(service, account, password) {
|
|
1033
|
+
const child = spawn(
|
|
1034
|
+
"secret-tool",
|
|
1035
|
+
["store", "--label", `${service}/${account}`, "service", service, "account", account],
|
|
1036
|
+
{ stdio: ["pipe", "pipe", "pipe"] }
|
|
1037
|
+
);
|
|
1038
|
+
child.stdin.write(password);
|
|
1039
|
+
child.stdin.end();
|
|
1040
|
+
await new Promise((resolve, reject) => {
|
|
1041
|
+
child.on(
|
|
1042
|
+
"close",
|
|
1043
|
+
(code) => code === 0 ? resolve() : reject(new Error("secret-tool store failed"))
|
|
1044
|
+
);
|
|
1045
|
+
child.on("error", reject);
|
|
1046
|
+
});
|
|
1047
|
+
},
|
|
1048
|
+
async deletePassword(service, account) {
|
|
1049
|
+
try {
|
|
1050
|
+
await execFileAsync(
|
|
1051
|
+
"secret-tool",
|
|
1052
|
+
["clear", "service", service, "account", account],
|
|
1053
|
+
{ timeout: 15e3 }
|
|
1054
|
+
);
|
|
1055
|
+
return true;
|
|
1056
|
+
} catch {
|
|
1057
|
+
return false;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
};
|
|
1061
|
+
function getBackend() {
|
|
1062
|
+
switch (process.platform) {
|
|
1063
|
+
case "win32":
|
|
1064
|
+
return windowsKeychain;
|
|
1065
|
+
case "darwin":
|
|
1066
|
+
return macKeychain;
|
|
1067
|
+
default:
|
|
1068
|
+
return linuxKeychain;
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
var backend = getBackend();
|
|
1072
|
+
async function getPassword(service, account) {
|
|
1073
|
+
return backend.getPassword(service, account);
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
// src/secrets/index.ts
|
|
770
1077
|
var SecretsLoader = class {
|
|
771
1078
|
// Same service name as CLI uses
|
|
772
1079
|
SERVICE_NAME = "sinch-functions-cli";
|
|
@@ -780,24 +1087,12 @@ var SecretsLoader = class {
|
|
|
780
1087
|
return false;
|
|
781
1088
|
}
|
|
782
1089
|
try {
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
keytar = await import("keytar");
|
|
786
|
-
} catch (error) {
|
|
787
|
-
if (error.code === "MODULE_NOT_FOUND" || error.code === "ERR_MODULE_NOT_FOUND") {
|
|
788
|
-
console.debug("[Secrets] Keytar not available - secrets not loaded");
|
|
789
|
-
return false;
|
|
790
|
-
} else {
|
|
791
|
-
console.error("[Secrets] Error loading keytar:", error.message);
|
|
792
|
-
}
|
|
793
|
-
return false;
|
|
794
|
-
}
|
|
795
|
-
const envPath = path4.join(process.cwd(), ".env");
|
|
796
|
-
if (!fs3.existsSync(envPath)) {
|
|
1090
|
+
const envPath = path5.join(process.cwd(), ".env");
|
|
1091
|
+
if (!fs4.existsSync(envPath)) {
|
|
797
1092
|
console.debug("[Secrets] No .env file found, skipping keychain load");
|
|
798
1093
|
return false;
|
|
799
1094
|
}
|
|
800
|
-
const envContent =
|
|
1095
|
+
const envContent = fs4.readFileSync(envPath, "utf8");
|
|
801
1096
|
const envLines = envContent.replace(/\r\n/g, "\n").split("\n");
|
|
802
1097
|
const secretsToLoad = [];
|
|
803
1098
|
envLines.forEach((line) => {
|
|
@@ -819,7 +1114,7 @@ var SecretsLoader = class {
|
|
|
819
1114
|
}
|
|
820
1115
|
let secretsLoaded = 0;
|
|
821
1116
|
if (secretsToLoad.includes("PROJECT_ID_API_SECRET")) {
|
|
822
|
-
const apiSecret = await
|
|
1117
|
+
const apiSecret = await getPassword(this.SERVICE_NAME, `${this.username}-keySecret`);
|
|
823
1118
|
if (apiSecret) {
|
|
824
1119
|
process.env.PROJECT_ID_API_SECRET = apiSecret;
|
|
825
1120
|
console.log("\u2705 Loaded PROJECT_ID_API_SECRET from secure storage");
|
|
@@ -829,7 +1124,7 @@ var SecretsLoader = class {
|
|
|
829
1124
|
if (secretsToLoad.includes("VOICE_APPLICATION_SECRET")) {
|
|
830
1125
|
const applicationKey = process.env.VOICE_APPLICATION_KEY || this.getApplicationKeyFromConfig();
|
|
831
1126
|
if (applicationKey) {
|
|
832
|
-
const appSecret = await
|
|
1127
|
+
const appSecret = await getPassword(this.SERVICE_NAME, applicationKey);
|
|
833
1128
|
if (appSecret) {
|
|
834
1129
|
process.env.VOICE_APPLICATION_SECRET = appSecret;
|
|
835
1130
|
console.log("\u2705 Loaded VOICE_APPLICATION_SECRET from secure storage");
|
|
@@ -843,7 +1138,7 @@ var SecretsLoader = class {
|
|
|
843
1138
|
continue;
|
|
844
1139
|
}
|
|
845
1140
|
if (functionName) {
|
|
846
|
-
const value = await
|
|
1141
|
+
const value = await getPassword(
|
|
847
1142
|
this.SERVICE_NAME,
|
|
848
1143
|
`${functionName}-${secretName}`
|
|
849
1144
|
);
|
|
@@ -871,9 +1166,9 @@ var SecretsLoader = class {
|
|
|
871
1166
|
*/
|
|
872
1167
|
getApplicationKeyFromConfig() {
|
|
873
1168
|
try {
|
|
874
|
-
const sinchJsonPath =
|
|
875
|
-
if (
|
|
876
|
-
const sinchConfig = JSON.parse(
|
|
1169
|
+
const sinchJsonPath = path5.join(process.cwd(), "sinch.json");
|
|
1170
|
+
if (fs4.existsSync(sinchJsonPath)) {
|
|
1171
|
+
const sinchConfig = JSON.parse(fs4.readFileSync(sinchJsonPath, "utf8"));
|
|
877
1172
|
return sinchConfig.voiceAppId || sinchConfig.applicationKey || null;
|
|
878
1173
|
}
|
|
879
1174
|
} catch (error) {
|
|
@@ -886,9 +1181,9 @@ var SecretsLoader = class {
|
|
|
886
1181
|
*/
|
|
887
1182
|
getFunctionNameFromConfig() {
|
|
888
1183
|
try {
|
|
889
|
-
const sinchJsonPath =
|
|
890
|
-
if (
|
|
891
|
-
const sinchConfig = JSON.parse(
|
|
1184
|
+
const sinchJsonPath = path5.join(process.cwd(), "sinch.json");
|
|
1185
|
+
if (fs4.existsSync(sinchJsonPath)) {
|
|
1186
|
+
const sinchConfig = JSON.parse(fs4.readFileSync(sinchJsonPath, "utf8"));
|
|
892
1187
|
return sinchConfig.name || null;
|
|
893
1188
|
}
|
|
894
1189
|
} catch (error) {
|
|
@@ -902,14 +1197,13 @@ var SecretsLoader = class {
|
|
|
902
1197
|
async loadCustomSecrets(secretNames = []) {
|
|
903
1198
|
const secrets = {};
|
|
904
1199
|
try {
|
|
905
|
-
const keytar = await import("keytar");
|
|
906
1200
|
const functionName = this.getFunctionNameFromConfig();
|
|
907
1201
|
if (!functionName) {
|
|
908
1202
|
console.debug("[Secrets] Could not determine function name for custom secrets");
|
|
909
1203
|
return secrets;
|
|
910
1204
|
}
|
|
911
1205
|
for (const secretName of secretNames) {
|
|
912
|
-
const value = await
|
|
1206
|
+
const value = await getPassword(this.SERVICE_NAME, `${functionName}-${secretName}`);
|
|
913
1207
|
if (value) {
|
|
914
1208
|
secrets[secretName] = value;
|
|
915
1209
|
process.env[secretName] = value;
|
|
@@ -921,15 +1215,13 @@ var SecretsLoader = class {
|
|
|
921
1215
|
return secrets;
|
|
922
1216
|
}
|
|
923
1217
|
/**
|
|
924
|
-
* Check if
|
|
1218
|
+
* Check if the native keychain is available.
|
|
1219
|
+
* Always true — no native npm deps required. The underlying OS tool
|
|
1220
|
+
* (secret-tool, security, CredManager) may still be absent, in which
|
|
1221
|
+
* case getPassword() silently returns null per credential.
|
|
925
1222
|
*/
|
|
926
1223
|
async isAvailable() {
|
|
927
|
-
|
|
928
|
-
await import("keytar");
|
|
929
|
-
return true;
|
|
930
|
-
} catch {
|
|
931
|
-
return false;
|
|
932
|
-
}
|
|
1224
|
+
return true;
|
|
933
1225
|
}
|
|
934
1226
|
};
|
|
935
1227
|
var secretsLoader = new SecretsLoader();
|
|
@@ -1320,9 +1612,9 @@ var TunnelClient = class {
|
|
|
1320
1612
|
// src/bin/sinch-runtime.ts
|
|
1321
1613
|
var requireCjs3 = createRequire3(import.meta.url);
|
|
1322
1614
|
function findFunctionPath3() {
|
|
1323
|
-
const distPath =
|
|
1324
|
-
const rootPath =
|
|
1325
|
-
if (
|
|
1615
|
+
const distPath = path6.join(process.cwd(), "dist", "function.js");
|
|
1616
|
+
const rootPath = path6.join(process.cwd(), "function.js");
|
|
1617
|
+
if (fs5.existsSync(distPath)) {
|
|
1326
1618
|
return distPath;
|
|
1327
1619
|
}
|
|
1328
1620
|
return rootPath;
|
|
@@ -1334,6 +1626,8 @@ function loadRuntimeConfig() {
|
|
|
1334
1626
|
functionId: process.env.FUNCTION_ID || process.env.SINCH_FUNCTION_ID || "local-dev"
|
|
1335
1627
|
};
|
|
1336
1628
|
}
|
|
1629
|
+
var storage = createStorageClient();
|
|
1630
|
+
var databasePath = path6.join(process.cwd(), "data", "app.db");
|
|
1337
1631
|
function buildLocalContext(req, runtimeConfig) {
|
|
1338
1632
|
const baseContext = buildBaseContext(req);
|
|
1339
1633
|
const cache = createCacheClient();
|
|
@@ -1341,6 +1635,8 @@ function buildLocalContext(req, runtimeConfig) {
|
|
|
1341
1635
|
return {
|
|
1342
1636
|
...baseContext,
|
|
1343
1637
|
cache,
|
|
1638
|
+
storage,
|
|
1639
|
+
database: databasePath,
|
|
1344
1640
|
...sinchClients,
|
|
1345
1641
|
env: process.env,
|
|
1346
1642
|
config: {
|
|
@@ -1367,12 +1663,12 @@ function displayStartupInfo(config, verbose, _port) {
|
|
|
1367
1663
|
function displayEnvironmentVariables() {
|
|
1368
1664
|
console.log("\nEnvironment Variables:");
|
|
1369
1665
|
try {
|
|
1370
|
-
const envPath =
|
|
1371
|
-
if (!
|
|
1666
|
+
const envPath = path6.join(process.cwd(), ".env");
|
|
1667
|
+
if (!fs5.existsSync(envPath)) {
|
|
1372
1668
|
console.log(" (no .env file found)");
|
|
1373
1669
|
return;
|
|
1374
1670
|
}
|
|
1375
|
-
const envContent =
|
|
1671
|
+
const envContent = fs5.readFileSync(envPath, "utf8");
|
|
1376
1672
|
const envLines = envContent.split("\n");
|
|
1377
1673
|
const variables = [];
|
|
1378
1674
|
const secrets = [];
|
|
@@ -1432,7 +1728,7 @@ function displayApplicationCredentials() {
|
|
|
1432
1728
|
async function displayDetectedFunctions() {
|
|
1433
1729
|
try {
|
|
1434
1730
|
const functionPath = findFunctionPath3();
|
|
1435
|
-
if (!
|
|
1731
|
+
if (!fs5.existsSync(functionPath)) return;
|
|
1436
1732
|
const functionUrl = pathToFileURL2(functionPath).href;
|
|
1437
1733
|
const module = await import(functionUrl);
|
|
1438
1734
|
const userFunction = module.default || module;
|
|
@@ -1459,6 +1755,8 @@ async function main() {
|
|
|
1459
1755
|
} catch {
|
|
1460
1756
|
}
|
|
1461
1757
|
await secretsLoader.loadFromKeychain();
|
|
1758
|
+
fs5.mkdirSync(path6.join(process.cwd(), "storage"), { recursive: true });
|
|
1759
|
+
fs5.mkdirSync(path6.join(process.cwd(), "data"), { recursive: true });
|
|
1462
1760
|
const config = loadRuntimeConfig();
|
|
1463
1761
|
const staticDir = process.env.STATIC_DIR;
|
|
1464
1762
|
const landingPageEnabled = process.env.LANDING_PAGE_ENABLED !== "false";
|