learn-secrets-sdk 1.9.0 → 1.11.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/cli/index.mjs +11 -327
- package/package.json +2 -2
package/dist/cli/index.mjs
CHANGED
|
@@ -362,7 +362,7 @@ Log in on ${this.baseUrl}`);
|
|
|
362
362
|
/**
|
|
363
363
|
* Make authenticated request
|
|
364
364
|
*/
|
|
365
|
-
async request(method,
|
|
365
|
+
async request(method, path2, body) {
|
|
366
366
|
const token = this.getAccessToken();
|
|
367
367
|
const options = {
|
|
368
368
|
method,
|
|
@@ -374,7 +374,7 @@ Log in on ${this.baseUrl}`);
|
|
|
374
374
|
if (body) {
|
|
375
375
|
options.body = JSON.stringify(body);
|
|
376
376
|
}
|
|
377
|
-
const response = await fetch(`${this.baseUrl}${
|
|
377
|
+
const response = await fetch(`${this.baseUrl}${path2}`, options);
|
|
378
378
|
if (!response.ok) {
|
|
379
379
|
const errorData = await response.json().catch(() => ({}));
|
|
380
380
|
throw new SecretsSDKError(
|
|
@@ -675,107 +675,6 @@ function summarizeDetectedSecrets(secrets) {
|
|
|
675
675
|
return lines.join("\n");
|
|
676
676
|
}
|
|
677
677
|
|
|
678
|
-
// src/cli/commands/connect-cloudflare.ts
|
|
679
|
-
function getApiUrl(baseUrl) {
|
|
680
|
-
return baseUrl || "https://cloudprototype.org";
|
|
681
|
-
}
|
|
682
|
-
async function connectCloudflare(apiToken, baseUrl) {
|
|
683
|
-
if (!apiToken.match(/^[A-Za-z0-9_-]{40,}$/)) {
|
|
684
|
-
return {
|
|
685
|
-
success: false,
|
|
686
|
-
error: "Invalid API token format. Token should be 40+ alphanumeric characters"
|
|
687
|
-
};
|
|
688
|
-
}
|
|
689
|
-
const validation = await validateCloudflareToken(apiToken);
|
|
690
|
-
if (!validation.valid) {
|
|
691
|
-
return {
|
|
692
|
-
success: false,
|
|
693
|
-
error: validation.error || "Token validation failed"
|
|
694
|
-
};
|
|
695
|
-
}
|
|
696
|
-
try {
|
|
697
|
-
const apiUrl = getApiUrl(baseUrl);
|
|
698
|
-
const response = await fetch(`${apiUrl}/api/cloudflare/connect`, {
|
|
699
|
-
method: "POST",
|
|
700
|
-
headers: {
|
|
701
|
-
"Content-Type": "application/json"
|
|
702
|
-
},
|
|
703
|
-
credentials: "include",
|
|
704
|
-
body: JSON.stringify({
|
|
705
|
-
apiToken,
|
|
706
|
-
accountId: validation.accountId,
|
|
707
|
-
accountName: validation.accountName
|
|
708
|
-
})
|
|
709
|
-
});
|
|
710
|
-
if (!response.ok) {
|
|
711
|
-
const error = await response.json();
|
|
712
|
-
return {
|
|
713
|
-
success: false,
|
|
714
|
-
error: error.message || "Failed to store token"
|
|
715
|
-
};
|
|
716
|
-
}
|
|
717
|
-
return {
|
|
718
|
-
success: true,
|
|
719
|
-
accountId: validation.accountId,
|
|
720
|
-
accountName: validation.accountName
|
|
721
|
-
};
|
|
722
|
-
} catch (error) {
|
|
723
|
-
return {
|
|
724
|
-
success: false,
|
|
725
|
-
error: error.message || "Failed to connect Cloudflare account"
|
|
726
|
-
};
|
|
727
|
-
}
|
|
728
|
-
}
|
|
729
|
-
async function validateCloudflareToken(token) {
|
|
730
|
-
try {
|
|
731
|
-
const response = await fetch("https://api.cloudflare.com/client/v4/user", {
|
|
732
|
-
headers: {
|
|
733
|
-
Authorization: `Bearer ${token}`,
|
|
734
|
-
"Content-Type": "application/json"
|
|
735
|
-
}
|
|
736
|
-
});
|
|
737
|
-
if (!response.ok) {
|
|
738
|
-
const error = await response.json();
|
|
739
|
-
return {
|
|
740
|
-
valid: false,
|
|
741
|
-
error: error.errors?.[0]?.message || "Invalid token"
|
|
742
|
-
};
|
|
743
|
-
}
|
|
744
|
-
const data = await response.json();
|
|
745
|
-
const accountsResponse = await fetch("https://api.cloudflare.com/client/v4/accounts", {
|
|
746
|
-
headers: {
|
|
747
|
-
Authorization: `Bearer ${token}`,
|
|
748
|
-
"Content-Type": "application/json"
|
|
749
|
-
}
|
|
750
|
-
});
|
|
751
|
-
if (!accountsResponse.ok) {
|
|
752
|
-
return {
|
|
753
|
-
valid: false,
|
|
754
|
-
error: "Token does not have access to accounts"
|
|
755
|
-
};
|
|
756
|
-
}
|
|
757
|
-
const accountsData = await accountsResponse.json();
|
|
758
|
-
const accounts = accountsData.result || [];
|
|
759
|
-
if (accounts.length === 0) {
|
|
760
|
-
return {
|
|
761
|
-
valid: false,
|
|
762
|
-
error: "No accounts found for this token"
|
|
763
|
-
};
|
|
764
|
-
}
|
|
765
|
-
const account = accounts[0];
|
|
766
|
-
return {
|
|
767
|
-
valid: true,
|
|
768
|
-
accountId: account.id,
|
|
769
|
-
accountName: account.name
|
|
770
|
-
};
|
|
771
|
-
} catch (error) {
|
|
772
|
-
return {
|
|
773
|
-
valid: false,
|
|
774
|
-
error: error.message || "Failed to validate token"
|
|
775
|
-
};
|
|
776
|
-
}
|
|
777
|
-
}
|
|
778
|
-
|
|
779
678
|
// src/cli/commands/init.ts
|
|
780
679
|
async function initCommand(options) {
|
|
781
680
|
if (!hasValidCredentials()) {
|
|
@@ -865,67 +764,16 @@ Onboarding site for project: ${projectId}`);
|
|
|
865
764
|
console.log(` - ${failure.name}: ${failure.error}`);
|
|
866
765
|
}
|
|
867
766
|
}
|
|
767
|
+
const dashboardUrl = options.baseUrl || "https://cloudprototype.org";
|
|
868
768
|
console.log("\nYour site is ready!");
|
|
869
769
|
console.log("\nAdd to your static site code:");
|
|
870
770
|
console.log(" const sdk = new SecretsSDK();");
|
|
871
771
|
console.log(" // Uses origin-based auth - no token needed!");
|
|
872
|
-
console.log("\n--- Cloudflare Worker Setup ---");
|
|
873
|
-
const dashboardUrl = options.baseUrl || "https://cloudprototype.org";
|
|
874
|
-
let cloudflareConnected = false;
|
|
875
|
-
try {
|
|
876
|
-
const statusResponse = await fetch(`${dashboardUrl}/api/cloudflare/status`, {
|
|
877
|
-
credentials: "include"
|
|
878
|
-
});
|
|
879
|
-
cloudflareConnected = statusResponse.ok;
|
|
880
|
-
} catch {
|
|
881
|
-
cloudflareConnected = false;
|
|
882
|
-
}
|
|
883
|
-
if (cloudflareConnected) {
|
|
884
|
-
console.log("Cloudflare account is already connected.");
|
|
885
|
-
} else {
|
|
886
|
-
console.log("To deploy secrets via Cloudflare Worker, we need your Cloudflare API token.");
|
|
887
|
-
console.log("\nRequired permissions:");
|
|
888
|
-
console.log(" - Workers Scripts: Edit");
|
|
889
|
-
console.log(" - Workers Routes: Edit");
|
|
890
|
-
console.log(" - Account Settings: Read");
|
|
891
|
-
console.log("\nCreate token at: https://dash.cloudflare.com/profile/api-tokens");
|
|
892
|
-
const readline = await import("readline");
|
|
893
|
-
const rl = readline.createInterface({
|
|
894
|
-
input: process.stdin,
|
|
895
|
-
output: process.stdout
|
|
896
|
-
});
|
|
897
|
-
const apiToken = await new Promise((resolve2) => {
|
|
898
|
-
rl.question("\nCloudflare API Token (or press Enter to skip): ", (answer) => {
|
|
899
|
-
rl.close();
|
|
900
|
-
resolve2(answer.trim());
|
|
901
|
-
});
|
|
902
|
-
});
|
|
903
|
-
if (apiToken) {
|
|
904
|
-
console.log("\nValidating token...");
|
|
905
|
-
const result2 = await connectCloudflare(apiToken, options.baseUrl);
|
|
906
|
-
if (result2.success) {
|
|
907
|
-
console.log("Cloudflare account connected");
|
|
908
|
-
console.log(` Account: ${result2.accountName}`);
|
|
909
|
-
cloudflareConnected = true;
|
|
910
|
-
} else {
|
|
911
|
-
console.log(`
|
|
912
|
-
Warning: Failed to connect Cloudflare: ${result2.error}`);
|
|
913
|
-
console.log("You can connect later by running: learn-secrets deploy");
|
|
914
|
-
}
|
|
915
|
-
} else {
|
|
916
|
-
console.log("\nSkipped Cloudflare connection.");
|
|
917
|
-
console.log("You can connect later when you run: learn-secrets deploy");
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
772
|
console.log(`
|
|
921
773
|
Next steps:`);
|
|
922
|
-
console.log(` 1. Run: learn-secrets deploy`);
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
} else {
|
|
926
|
-
console.log(` (Connect Cloudflare and deploy Worker with your secrets)`);
|
|
927
|
-
}
|
|
928
|
-
console.log(` 2. Visit: ${dashboardUrl}/dashboard to manage secrets`);
|
|
774
|
+
console.log(` 1. Run: learn-secrets deploy (to update secrets)`);
|
|
775
|
+
console.log(` 2. Visit: ${dashboardUrl}/dashboard/secrets to manage secrets`);
|
|
776
|
+
console.log(` 3. View usage at: ${dashboardUrl}/dashboard/settings/usage`);
|
|
929
777
|
const config = {
|
|
930
778
|
project: projectId,
|
|
931
779
|
origins,
|
|
@@ -994,87 +842,6 @@ Configuration saved to: ${configFile}`);
|
|
|
994
842
|
|
|
995
843
|
// src/cli/commands/deploy.ts
|
|
996
844
|
import fs5 from "fs";
|
|
997
|
-
|
|
998
|
-
// src/cli/commands/provision-worker.ts
|
|
999
|
-
import path2 from "path";
|
|
1000
|
-
import { fileURLToPath } from "url";
|
|
1001
|
-
var __filename = fileURLToPath(import.meta.url);
|
|
1002
|
-
var __dirname = path2.dirname(__filename);
|
|
1003
|
-
function getApiUrl2(baseUrl) {
|
|
1004
|
-
return baseUrl || "https://cloudprototype.org";
|
|
1005
|
-
}
|
|
1006
|
-
async function provisionWorker(workerName, origins, envVars, baseUrl) {
|
|
1007
|
-
const publicVars = [];
|
|
1008
|
-
const secretVars = [];
|
|
1009
|
-
for (const { key, value } of envVars) {
|
|
1010
|
-
if (isPublicConfig(key)) {
|
|
1011
|
-
publicVars.push({ key, value });
|
|
1012
|
-
} else {
|
|
1013
|
-
secretVars.push({ key, value });
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
try {
|
|
1017
|
-
const apiUrl = getApiUrl2(baseUrl);
|
|
1018
|
-
const deployResponse = await fetch(`${apiUrl}/api/cloudflare/provision-worker`, {
|
|
1019
|
-
method: "POST",
|
|
1020
|
-
headers: {
|
|
1021
|
-
"Content-Type": "application/json"
|
|
1022
|
-
},
|
|
1023
|
-
credentials: "include",
|
|
1024
|
-
body: JSON.stringify({
|
|
1025
|
-
workerName,
|
|
1026
|
-
allowedOrigins: origins,
|
|
1027
|
-
publicVars: publicVars.map((v) => ({
|
|
1028
|
-
key: `PUBLIC_${v.key}`,
|
|
1029
|
-
value: v.value
|
|
1030
|
-
})),
|
|
1031
|
-
secrets: secretVars.map((v) => ({
|
|
1032
|
-
key: `SECRET_${v.key}`,
|
|
1033
|
-
value: v.value
|
|
1034
|
-
}))
|
|
1035
|
-
})
|
|
1036
|
-
});
|
|
1037
|
-
if (!deployResponse.ok) {
|
|
1038
|
-
const error = await deployResponse.json();
|
|
1039
|
-
return {
|
|
1040
|
-
success: false,
|
|
1041
|
-
error: error.message || "Failed to deploy Worker"
|
|
1042
|
-
};
|
|
1043
|
-
}
|
|
1044
|
-
const result = await deployResponse.json();
|
|
1045
|
-
return {
|
|
1046
|
-
success: true,
|
|
1047
|
-
workerUrl: result.workerUrl,
|
|
1048
|
-
workerName: result.workerName
|
|
1049
|
-
};
|
|
1050
|
-
} catch (error) {
|
|
1051
|
-
return {
|
|
1052
|
-
success: false,
|
|
1053
|
-
error: error.message || "Failed to provision Worker"
|
|
1054
|
-
};
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
function isPublicConfig(key) {
|
|
1058
|
-
const publicPatterns = [
|
|
1059
|
-
/_DOMAIN$/,
|
|
1060
|
-
/_CLIENT_ID$/,
|
|
1061
|
-
/_AUDIENCE$/,
|
|
1062
|
-
/_CALLBACK_URL$/,
|
|
1063
|
-
/_ISSUER$/,
|
|
1064
|
-
/_TEAM_ID$/,
|
|
1065
|
-
/_KEY_ID$/,
|
|
1066
|
-
/^API_BASE_URL$/,
|
|
1067
|
-
/^PUBLIC_/
|
|
1068
|
-
];
|
|
1069
|
-
for (const pattern of publicPatterns) {
|
|
1070
|
-
if (pattern.test(key)) {
|
|
1071
|
-
return true;
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
return false;
|
|
1075
|
-
}
|
|
1076
|
-
|
|
1077
|
-
// src/cli/commands/deploy.ts
|
|
1078
845
|
async function deployCommand(options = {}) {
|
|
1079
846
|
if (!hasValidCredentials()) {
|
|
1080
847
|
console.error('Error: Not authenticated. Run "learn-secrets login" first.');
|
|
@@ -1156,93 +923,10 @@ Deploying secrets to project: ${config.project}`);
|
|
|
1156
923
|
}
|
|
1157
924
|
const dashboardUrl = options.baseUrl || "https://cloudprototype.org";
|
|
1158
925
|
console.log(`
|
|
1159
|
-
Secrets deployed
|
|
1160
|
-
console.log(
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
const statusResponse = await fetch(`${dashboardUrl}/api/cloudflare/status`, {
|
|
1164
|
-
credentials: "include"
|
|
1165
|
-
});
|
|
1166
|
-
cloudflareConnected = statusResponse.ok;
|
|
1167
|
-
} catch {
|
|
1168
|
-
cloudflareConnected = false;
|
|
1169
|
-
}
|
|
1170
|
-
if (!cloudflareConnected) {
|
|
1171
|
-
console.log("Cloudflare account not connected.");
|
|
1172
|
-
console.log("\nTo deploy Worker, we need your Cloudflare API token.");
|
|
1173
|
-
console.log("Required permissions:");
|
|
1174
|
-
console.log(" - Workers Scripts: Edit");
|
|
1175
|
-
console.log(" - Workers Routes: Edit");
|
|
1176
|
-
console.log(" - Account Settings: Read");
|
|
1177
|
-
console.log("\nCreate token at: https://dash.cloudflare.com/profile/api-tokens");
|
|
1178
|
-
const readline = await import("readline");
|
|
1179
|
-
const rl = readline.createInterface({
|
|
1180
|
-
input: process.stdin,
|
|
1181
|
-
output: process.stdout
|
|
1182
|
-
});
|
|
1183
|
-
const apiToken = await new Promise((resolve2) => {
|
|
1184
|
-
rl.question("\nCloudflare API Token (or press Enter to skip): ", (answer) => {
|
|
1185
|
-
rl.close();
|
|
1186
|
-
resolve2(answer.trim());
|
|
1187
|
-
});
|
|
1188
|
-
});
|
|
1189
|
-
if (apiToken) {
|
|
1190
|
-
console.log("\nValidating token...");
|
|
1191
|
-
const result2 = await connectCloudflare(apiToken, options.baseUrl);
|
|
1192
|
-
if (result2.success) {
|
|
1193
|
-
console.log("Cloudflare account connected");
|
|
1194
|
-
console.log(` Account: ${result2.accountName}`);
|
|
1195
|
-
cloudflareConnected = true;
|
|
1196
|
-
} else {
|
|
1197
|
-
console.log(`
|
|
1198
|
-
Error: Failed to connect Cloudflare: ${result2.error}`);
|
|
1199
|
-
console.log("Worker deployment skipped.");
|
|
1200
|
-
}
|
|
1201
|
-
} else {
|
|
1202
|
-
console.log("\nSkipped Cloudflare connection. Worker deployment skipped.");
|
|
1203
|
-
}
|
|
1204
|
-
} else {
|
|
1205
|
-
console.log("Cloudflare account is connected.");
|
|
1206
|
-
}
|
|
1207
|
-
if (cloudflareConnected) {
|
|
1208
|
-
const readline = await import("readline");
|
|
1209
|
-
const rl = readline.createInterface({
|
|
1210
|
-
input: process.stdin,
|
|
1211
|
-
output: process.stdout
|
|
1212
|
-
});
|
|
1213
|
-
const shouldProvision = await new Promise((resolve2) => {
|
|
1214
|
-
rl.question("\nDeploy/update Worker to Cloudflare? (y/N): ", (answer) => {
|
|
1215
|
-
rl.close();
|
|
1216
|
-
resolve2(answer.trim());
|
|
1217
|
-
});
|
|
1218
|
-
});
|
|
1219
|
-
if (shouldProvision.toLowerCase() === "y" || shouldProvision.toLowerCase() === "yes") {
|
|
1220
|
-
console.log("\nDeploying Worker to Cloudflare...");
|
|
1221
|
-
const workerName = `learn-secrets-${config.project.toLowerCase()}`;
|
|
1222
|
-
const provisionResult = await provisionWorker(
|
|
1223
|
-
workerName,
|
|
1224
|
-
config.origins,
|
|
1225
|
-
envVars,
|
|
1226
|
-
options.baseUrl
|
|
1227
|
-
);
|
|
1228
|
-
if (provisionResult.success) {
|
|
1229
|
-
console.log("\nWorker deployed successfully");
|
|
1230
|
-
console.log(` Name: ${provisionResult.workerName}`);
|
|
1231
|
-
console.log(` URL: ${provisionResult.workerUrl}`);
|
|
1232
|
-
config.workerUrl = provisionResult.workerUrl;
|
|
1233
|
-
fs5.writeFileSync(configFile, JSON.stringify(config, null, 2));
|
|
1234
|
-
console.log("\nNext steps:");
|
|
1235
|
-
console.log(` 1. Test Worker: curl ${provisionResult.workerUrl}/health`);
|
|
1236
|
-
console.log(` 2. Update your frontend to use Worker URL`);
|
|
1237
|
-
console.log(` 3. Test origin validation from your site`);
|
|
1238
|
-
} else {
|
|
1239
|
-
console.log(`
|
|
1240
|
-
Error: Worker deployment failed: ${provisionResult.error}`);
|
|
1241
|
-
}
|
|
1242
|
-
} else {
|
|
1243
|
-
console.log("\nSkipped Worker deployment.");
|
|
1244
|
-
}
|
|
1245
|
-
}
|
|
926
|
+
Secrets deployed to Learn dashboard!`);
|
|
927
|
+
console.log(`View at: ${dashboardUrl}/dashboard/collections/secrets`);
|
|
928
|
+
console.log(`
|
|
929
|
+
Your secrets are now accessible via the Learn Secrets API.`);
|
|
1246
930
|
} catch (error) {
|
|
1247
931
|
console.error("\nDeploy failed:", error.message);
|
|
1248
932
|
if (error.status === 401) {
|
|
@@ -1257,7 +941,7 @@ Error: Worker deployment failed: ${provisionResult.error}`);
|
|
|
1257
941
|
|
|
1258
942
|
// src/cli/index.ts
|
|
1259
943
|
var program = new Command();
|
|
1260
|
-
program.name("learn-secrets").description("CLI tool for managing
|
|
944
|
+
program.name("learn-secrets").description("CLI tool for managing secrets with the Learn platform").version("1.11.1");
|
|
1261
945
|
program.command("login").description("Authenticate with Learn Secrets via browser").option("--base-url <url>", "Custom base URL for API").action(async (options) => {
|
|
1262
946
|
await loginCommand(options);
|
|
1263
947
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "learn-secrets-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.11.1",
|
|
4
|
+
"description": "Secrets management SDK for static sites with Learn platform",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|