@granular-software/sdk 0.4.10 → 0.4.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/cli/index.js +31 -9
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +17 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -48,6 +48,8 @@ CLI overrides:
|
|
|
48
48
|
- `granular --prod <command>`
|
|
49
49
|
- `granular --env local|production <command>`
|
|
50
50
|
|
|
51
|
+
When the resolved API URL points at `localhost` or `127.0.0.1`, the SDK and CLI automatically swap opaque `sk_...` WorkOS keys for the local dev key `gn_sk_tenant_default_principal_local_e2e_00000000` so local runs work without server-side WorkOS validation. Override with `GRANULAR_LOCAL_API_KEY=...` or disable with `GRANULAR_DISABLE_LOCAL_API_KEY_FALLBACK=true`.
|
|
52
|
+
|
|
51
53
|
## Agent documentation (CLI)
|
|
52
54
|
|
|
53
55
|
Projects created with `granular init` can include Markdown for coding agents (optional `AGENTS.md` plus generated guides):
|
package/dist/cli/index.js
CHANGED
|
@@ -5388,6 +5388,7 @@ var import_dotenv = __toESM(require_main());
|
|
|
5388
5388
|
// src/endpoints.ts
|
|
5389
5389
|
var LOCAL_API_URL = "ws://localhost:8787/granular";
|
|
5390
5390
|
var PRODUCTION_API_URL = "wss://cf-api-gateway.arthur6084.workers.dev/granular";
|
|
5391
|
+
var DEFAULT_LOCAL_API_KEY = "gn_sk_tenant_default_principal_local_e2e_00000000";
|
|
5391
5392
|
var LOCAL_AUTH_URL = "http://localhost:3000";
|
|
5392
5393
|
var PRODUCTION_AUTH_URL = "https://app.granular.software";
|
|
5393
5394
|
function readEnv(name) {
|
|
@@ -5407,6 +5408,21 @@ function isTruthy(value) {
|
|
|
5407
5408
|
const normalized = value.trim().toLowerCase();
|
|
5408
5409
|
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
5409
5410
|
}
|
|
5411
|
+
function isLocalApiUrl(url) {
|
|
5412
|
+
try {
|
|
5413
|
+
const parsed = new URL(url);
|
|
5414
|
+
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
5415
|
+
} catch {
|
|
5416
|
+
return false;
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
function resolveAuthTokenForApiUrl(authToken, apiUrl) {
|
|
5420
|
+
if (!authToken.startsWith("sk_") || !isLocalApiUrl(apiUrl) || isTruthy(readEnv("GRANULAR_DISABLE_LOCAL_API_KEY_FALLBACK"))) {
|
|
5421
|
+
return authToken;
|
|
5422
|
+
}
|
|
5423
|
+
const override = readEnv("GRANULAR_LOCAL_API_KEY")?.trim();
|
|
5424
|
+
return override || DEFAULT_LOCAL_API_KEY;
|
|
5425
|
+
}
|
|
5410
5426
|
function resolveEndpointMode(explicitMode) {
|
|
5411
5427
|
const explicit = normalizeMode(explicitMode);
|
|
5412
5428
|
if (explicit === "local" || explicit === "production") {
|
|
@@ -6762,7 +6778,7 @@ var ApiClient = class {
|
|
|
6762
6778
|
apiKey;
|
|
6763
6779
|
baseUrl;
|
|
6764
6780
|
constructor(apiKey, apiUrl) {
|
|
6765
|
-
this.apiKey = apiKey;
|
|
6781
|
+
this.apiKey = resolveAuthTokenForApiUrl(apiKey, apiUrl);
|
|
6766
6782
|
this.baseUrl = apiUrl.replace("wss://", "https://").replace("ws://", "http://").replace(/\/ws$/, "");
|
|
6767
6783
|
}
|
|
6768
6784
|
async request(path4, options = {}) {
|
|
@@ -9722,7 +9738,7 @@ async function initCommand(projectName, options) {
|
|
|
9722
9738
|
dim(" The seed script shows how records enter the graph. The effects script shows how external systems plug in.");
|
|
9723
9739
|
console.log();
|
|
9724
9740
|
}
|
|
9725
|
-
var
|
|
9741
|
+
var DEFAULT_LOCAL_API_KEY2 = "gn_sk_tenant_default_principal_local_e2e_00000000";
|
|
9726
9742
|
function promptSecret(question) {
|
|
9727
9743
|
const rl = readline__namespace.createInterface({ input: process.stdin, output: process.stdout });
|
|
9728
9744
|
return new Promise((resolve) => {
|
|
@@ -9748,7 +9764,7 @@ function maskApiKey(apiKey) {
|
|
|
9748
9764
|
if (apiKey.length < 10) return `${apiKey}...`;
|
|
9749
9765
|
return `${apiKey.substring(0, 10)}...`;
|
|
9750
9766
|
}
|
|
9751
|
-
function
|
|
9767
|
+
function isLocalApiUrl2(apiUrl) {
|
|
9752
9768
|
return apiUrl.startsWith("ws://localhost:") || apiUrl.startsWith("wss://localhost:") || apiUrl.startsWith("ws://127.0.0.1:") || apiUrl.startsWith("wss://127.0.0.1:") || apiUrl.startsWith("http://localhost:") || apiUrl.startsWith("https://localhost:") || apiUrl.startsWith("http://127.0.0.1:") || apiUrl.startsWith("https://127.0.0.1:");
|
|
9753
9769
|
}
|
|
9754
9770
|
async function loginCommand(options = {}) {
|
|
@@ -9762,8 +9778,8 @@ async function loginCommand(options = {}) {
|
|
|
9762
9778
|
const apiUrl = loadApiUrl();
|
|
9763
9779
|
let apiKey = options.apiKey?.trim();
|
|
9764
9780
|
if (!apiKey) {
|
|
9765
|
-
if (!options.manual &&
|
|
9766
|
-
apiKey = existing?.trim() || process.env.GRANULAR_LOCAL_API_KEY?.trim() ||
|
|
9781
|
+
if (!options.manual && isLocalApiUrl2(apiUrl)) {
|
|
9782
|
+
apiKey = existing?.trim() || process.env.GRANULAR_LOCAL_API_KEY?.trim() || DEFAULT_LOCAL_API_KEY2;
|
|
9767
9783
|
info("Using local Granular API key for localhost development.");
|
|
9768
9784
|
} else if (options.manual) {
|
|
9769
9785
|
dim("Get your API key at https://app.granular.software/w/default/api-keys");
|
|
@@ -10324,13 +10340,19 @@ function openUrl(url) {
|
|
|
10324
10340
|
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
|
|
10325
10341
|
child_process.spawn(cmd, [url], { stdio: "ignore", shell: platform === "win32" });
|
|
10326
10342
|
}
|
|
10327
|
-
async function simulateCommand(sandboxIdArg) {
|
|
10343
|
+
async function simulateCommand(sandboxIdArg, options) {
|
|
10328
10344
|
const sandboxId = sandboxIdArg ?? resolveConfig().sandboxId;
|
|
10329
10345
|
if (!sandboxId) {
|
|
10330
10346
|
error("No sandbox ID. Run from a project with `granular init` or pass a sandbox ID: granular simulate <sandbox-id>");
|
|
10331
10347
|
process.exit(1);
|
|
10332
10348
|
}
|
|
10333
|
-
const
|
|
10349
|
+
const params = new URLSearchParams({
|
|
10350
|
+
sandboxId
|
|
10351
|
+
});
|
|
10352
|
+
if (options?.subjectId) {
|
|
10353
|
+
params.set("subject_id", options.subjectId);
|
|
10354
|
+
}
|
|
10355
|
+
const url = `${SIMULATOR_BASE}?${params.toString()}`;
|
|
10334
10356
|
info(`Opening simulator: ${url}`);
|
|
10335
10357
|
openUrl(url);
|
|
10336
10358
|
}
|
|
@@ -10470,9 +10492,9 @@ program2.command("document").description("Generate GRANULAR_SANDBOX.md (agent re
|
|
|
10470
10492
|
process.exit(1);
|
|
10471
10493
|
}
|
|
10472
10494
|
});
|
|
10473
|
-
program2.command("simulate [sandbox-id]").description("Open the Granular simulator in the browser for the current (or given) sandbox").action(async (sandboxId) => {
|
|
10495
|
+
program2.command("simulate [sandbox-id]").description("Open the Granular simulator in the browser for the current (or given) sandbox").option("--subject-id <subjectId>", "Open the simulator preloaded for a specific subject").action(async (sandboxId, options) => {
|
|
10474
10496
|
try {
|
|
10475
|
-
await simulateCommand(sandboxId);
|
|
10497
|
+
await simulateCommand(sandboxId, options);
|
|
10476
10498
|
} catch (err) {
|
|
10477
10499
|
error(err.message);
|
|
10478
10500
|
process.exit(1);
|
package/dist/index.js
CHANGED
|
@@ -5316,6 +5316,7 @@ var JobImplementation = class {
|
|
|
5316
5316
|
// src/endpoints.ts
|
|
5317
5317
|
var LOCAL_API_URL = "ws://localhost:8787/granular";
|
|
5318
5318
|
var PRODUCTION_API_URL = "wss://cf-api-gateway.arthur6084.workers.dev/granular";
|
|
5319
|
+
var DEFAULT_LOCAL_API_KEY = "gn_sk_tenant_default_principal_local_e2e_00000000";
|
|
5319
5320
|
function readEnv(name) {
|
|
5320
5321
|
if (typeof process === "undefined" || !process.env) return void 0;
|
|
5321
5322
|
return process.env[name];
|
|
@@ -5333,6 +5334,21 @@ function isTruthy(value) {
|
|
|
5333
5334
|
const normalized = value.trim().toLowerCase();
|
|
5334
5335
|
return normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on";
|
|
5335
5336
|
}
|
|
5337
|
+
function isLocalApiUrl(url) {
|
|
5338
|
+
try {
|
|
5339
|
+
const parsed = new URL(url);
|
|
5340
|
+
return parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
5341
|
+
} catch {
|
|
5342
|
+
return false;
|
|
5343
|
+
}
|
|
5344
|
+
}
|
|
5345
|
+
function resolveAuthTokenForApiUrl(authToken, apiUrl) {
|
|
5346
|
+
if (!authToken.startsWith("sk_") || !isLocalApiUrl(apiUrl) || isTruthy(readEnv("GRANULAR_DISABLE_LOCAL_API_KEY_FALLBACK"))) {
|
|
5347
|
+
return authToken;
|
|
5348
|
+
}
|
|
5349
|
+
const override = readEnv("GRANULAR_LOCAL_API_KEY")?.trim();
|
|
5350
|
+
return override || DEFAULT_LOCAL_API_KEY;
|
|
5351
|
+
}
|
|
5336
5352
|
function resolveEndpointMode(explicitMode) {
|
|
5337
5353
|
const explicit = normalizeMode(explicitMode);
|
|
5338
5354
|
if (explicit === "local" || explicit === "production") {
|
|
@@ -6251,8 +6267,8 @@ var Granular = class {
|
|
|
6251
6267
|
if (!auth) {
|
|
6252
6268
|
throw new Error("Granular client requires either apiKey or token. Set GRANULAR_API_KEY or GRANULAR_TOKEN, or pass one in options.");
|
|
6253
6269
|
}
|
|
6254
|
-
this.apiKey = auth;
|
|
6255
6270
|
this.apiUrl = resolveApiUrl(options.apiUrl, options.endpointMode);
|
|
6271
|
+
this.apiKey = resolveAuthTokenForApiUrl(auth, this.apiUrl);
|
|
6256
6272
|
this.tokenProvider = options.tokenProvider;
|
|
6257
6273
|
this.WebSocketCtor = options.WebSocketCtor;
|
|
6258
6274
|
this.onUnexpectedClose = options.onUnexpectedClose;
|