@cortexkit/opencode-claustrum-auth 0.1.0 → 0.1.2

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.js CHANGED
@@ -94,6 +94,26 @@ function transitionActivation(previous, event) {
94
94
  }
95
95
  return result;
96
96
  }
97
+ // ../core/src/balance.ts
98
+ var balanceProbeMs = 5 * 60 * 1000;
99
+ function isBalanceFailure(service, body) {
100
+ if (service === "deepseek")
101
+ return true;
102
+ if (service !== "openrouter")
103
+ return false;
104
+ try {
105
+ const value = JSON.parse(body ?? "");
106
+ if (typeof value !== "object" || value === null || !("error" in value))
107
+ return false;
108
+ const error = value.error;
109
+ if (typeof error !== "object" || error === null || !("metadata" in error))
110
+ return false;
111
+ const metadata = error.metadata;
112
+ return typeof metadata === "object" && metadata !== null && "limit_source" in metadata && metadata.limit_source === "openrouter_credits" && (!("reason" in metadata) || metadata.reason !== "weight_exceeds_budget");
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
97
117
  // ../../node_modules/.bun/@cortexkit+common-auth@0.29.1+e881539e648aba62/node_modules/@cortexkit/common-auth/dist/redaction/index.js
98
118
  import { types } from "node:util";
99
119
 
@@ -1076,7 +1096,7 @@ function retryExpiry(response, now) {
1076
1096
  if (Number.isFinite(date) && date > now)
1077
1097
  return date;
1078
1098
  }
1079
- return now + 60000;
1099
+ return now + (response.status === 402 ? balanceProbeMs : 60000);
1080
1100
  }
1081
1101
  function limited(marks, now) {
1082
1102
  const expiries = [...marks.values()].filter((expiry) => expiry > now);
@@ -1109,6 +1129,7 @@ function createFetch(options) {
1109
1129
  const tried = new Set;
1110
1130
  const secrets = [];
1111
1131
  let saw429 = false;
1132
+ let saw402 = false;
1112
1133
  try {
1113
1134
  for (;; ) {
1114
1135
  signal.throwIfAborted();
@@ -1119,6 +1140,7 @@ function createFetch(options) {
1119
1140
  throw new ClaustrumAuthError("no-vault-account");
1120
1141
  }
1121
1142
  tried.add(route);
1143
+ const previousMark = rateLimitMarks.get(route);
1122
1144
  let target = url;
1123
1145
  let method = template.method;
1124
1146
  let bytes = body;
@@ -1168,11 +1190,26 @@ function createFetch(options) {
1168
1190
  }
1169
1191
  target = next;
1170
1192
  }
1171
- if (response.status !== 429 && response.status !== 401)
1193
+ let balance402 = false;
1194
+ if (response.status === 402) {
1195
+ let text;
1196
+ if (options.entry.service === "openrouter") {
1197
+ try {
1198
+ text = await response.clone().text();
1199
+ } catch {}
1200
+ }
1201
+ balance402 = isBalanceFailure(options.entry.service, text);
1202
+ }
1203
+ if ((response.ok || response.status === 402 && !balance402) && previousMark !== undefined && previousMark <= now() && rateLimitMarks.get(route) === previousMark)
1204
+ rateLimitMarks.delete(route);
1205
+ if (response.status !== 401 && response.status !== 429 && !balance402)
1172
1206
  return await redactResponse(response, secrets);
1173
1207
  signal.throwIfAborted();
1174
- if (response.status === 429) {
1175
- saw429 = true;
1208
+ if (response.status === 429 || balance402) {
1209
+ if (response.status === 429)
1210
+ saw429 = true;
1211
+ else
1212
+ saw402 = true;
1176
1213
  rateLimitMarks.set(route, retryExpiry(response, now()));
1177
1214
  }
1178
1215
  const next = orderedRoutes(routing, tried)[0];
@@ -1180,7 +1217,7 @@ function createFetch(options) {
1180
1217
  await response.body?.cancel().catch(() => {});
1181
1218
  continue;
1182
1219
  }
1183
- if (response.status === 401 && saw429) {
1220
+ if (saw429 && (response.status === 401 || saw402)) {
1184
1221
  await response.body?.cancel().catch(() => {});
1185
1222
  return limited(rateLimitMarks, now());
1186
1223
  }
@@ -7185,6 +7222,13 @@ var supportedProviders = [
7185
7222
  class: "A",
7186
7223
  origins: ["https://api.kimi.com", "https://api.kimi.ai"]
7187
7224
  },
7225
+ {
7226
+ service: "minimax-coding-plan",
7227
+ ids: ["minimax-coding-plan"],
7228
+ hosts: { opencode2: "minimax-coding-plan" },
7229
+ class: "A",
7230
+ origins: ["https://api.minimax.io"]
7231
+ },
7188
7232
  {
7189
7233
  service: "openrouter",
7190
7234
  ids: ["openrouter"],
@@ -7196,6 +7240,13 @@ var supportedProviders = [
7196
7240
  class: "A",
7197
7241
  origins: ["https://openrouter.ai"]
7198
7242
  },
7243
+ {
7244
+ service: "synthetic",
7245
+ ids: ["synthetic"],
7246
+ hosts: { opencode1: "synthetic", opencode2: "synthetic" },
7247
+ class: "A",
7248
+ origins: ["https://api.synthetic.new"]
7249
+ },
7199
7250
  {
7200
7251
  service: "typesafe",
7201
7252
  ids: ["typesafe"],
@@ -7456,12 +7507,21 @@ function configIdentity(configDir) {
7456
7507
  }
7457
7508
  }
7458
7509
  function resolveOpencodeStateDir(env = process.env, home = homedir()) {
7510
+ const override = env.OPENCODE_CLAUSTRUM_AUTH_STATE_DIR?.trim();
7511
+ if (override)
7512
+ return path.resolve(override);
7459
7513
  const configDir = opencodeConfigDir(env, home);
7460
7514
  const identity = configIdentity(configDir);
7461
7515
  const key = identity === configIdentity(path.resolve(home, ".config", "opencode")) ? "opencode" : `opencode-${createHash3("sha256").update(identity).digest("hex").slice(0, 16)}`;
7462
7516
  return path.resolve(env.XDG_STATE_HOME || path.join(home, ".local", "state"), "cortexkit", "claustrum-auth", key);
7463
7517
  }
7464
7518
  async function opencodeStateDir(env = process.env, home = homedir()) {
7519
+ if (env.OPENCODE_CLAUSTRUM_AUTH_STATE_DIR?.trim()) {
7520
+ const stateDir = resolveOpencodeStateDir(env, home);
7521
+ if (!stateDir || !path.isAbsolute(stateDir))
7522
+ throw startupRefusal("opencode-start");
7523
+ return stateDir;
7524
+ }
7465
7525
  const identity = configIdentity(opencodeConfigDir(env, home));
7466
7526
  const stateDir = resolveOpencodeStateDir(env, home);
7467
7527
  const manifest = path.join(stateDir, "config-dir.json");
package/dist/server.js CHANGED
@@ -94,6 +94,26 @@ function transitionActivation(previous, event) {
94
94
  }
95
95
  return result;
96
96
  }
97
+ // ../core/src/balance.ts
98
+ var balanceProbeMs = 5 * 60 * 1000;
99
+ function isBalanceFailure(service, body) {
100
+ if (service === "deepseek")
101
+ return true;
102
+ if (service !== "openrouter")
103
+ return false;
104
+ try {
105
+ const value = JSON.parse(body ?? "");
106
+ if (typeof value !== "object" || value === null || !("error" in value))
107
+ return false;
108
+ const error = value.error;
109
+ if (typeof error !== "object" || error === null || !("metadata" in error))
110
+ return false;
111
+ const metadata = error.metadata;
112
+ return typeof metadata === "object" && metadata !== null && "limit_source" in metadata && metadata.limit_source === "openrouter_credits" && (!("reason" in metadata) || metadata.reason !== "weight_exceeds_budget");
113
+ } catch {
114
+ return false;
115
+ }
116
+ }
97
117
  // ../../node_modules/.bun/@cortexkit+common-auth@0.29.1+e881539e648aba62/node_modules/@cortexkit/common-auth/dist/redaction/index.js
98
118
  import { types } from "node:util";
99
119
 
@@ -1110,7 +1130,7 @@ function retryExpiry(response, now) {
1110
1130
  if (Number.isFinite(date) && date > now)
1111
1131
  return date;
1112
1132
  }
1113
- return now + 60000;
1133
+ return now + (response.status === 402 ? balanceProbeMs : 60000);
1114
1134
  }
1115
1135
  function limited(marks, now) {
1116
1136
  const expiries = [...marks.values()].filter((expiry) => expiry > now);
@@ -1143,6 +1163,7 @@ function createFetch(options) {
1143
1163
  const tried = new Set;
1144
1164
  const secrets = [];
1145
1165
  let saw429 = false;
1166
+ let saw402 = false;
1146
1167
  try {
1147
1168
  for (;; ) {
1148
1169
  signal.throwIfAborted();
@@ -1153,6 +1174,7 @@ function createFetch(options) {
1153
1174
  throw new ClaustrumAuthError("no-vault-account");
1154
1175
  }
1155
1176
  tried.add(route);
1177
+ const previousMark = rateLimitMarks.get(route);
1156
1178
  let target = url;
1157
1179
  let method = template.method;
1158
1180
  let bytes = body;
@@ -1202,11 +1224,26 @@ function createFetch(options) {
1202
1224
  }
1203
1225
  target = next;
1204
1226
  }
1205
- if (response.status !== 429 && response.status !== 401)
1227
+ let balance402 = false;
1228
+ if (response.status === 402) {
1229
+ let text;
1230
+ if (options.entry.service === "openrouter") {
1231
+ try {
1232
+ text = await response.clone().text();
1233
+ } catch {}
1234
+ }
1235
+ balance402 = isBalanceFailure(options.entry.service, text);
1236
+ }
1237
+ if ((response.ok || response.status === 402 && !balance402) && previousMark !== undefined && previousMark <= now() && rateLimitMarks.get(route) === previousMark)
1238
+ rateLimitMarks.delete(route);
1239
+ if (response.status !== 401 && response.status !== 429 && !balance402)
1206
1240
  return await redactResponse(response, secrets);
1207
1241
  signal.throwIfAborted();
1208
- if (response.status === 429) {
1209
- saw429 = true;
1242
+ if (response.status === 429 || balance402) {
1243
+ if (response.status === 429)
1244
+ saw429 = true;
1245
+ else
1246
+ saw402 = true;
1210
1247
  rateLimitMarks.set(route, retryExpiry(response, now()));
1211
1248
  }
1212
1249
  const next = orderedRoutes(routing, tried)[0];
@@ -1214,7 +1251,7 @@ function createFetch(options) {
1214
1251
  await response.body?.cancel().catch(() => {});
1215
1252
  continue;
1216
1253
  }
1217
- if (response.status === 401 && saw429) {
1254
+ if (saw429 && (response.status === 401 || saw402)) {
1218
1255
  await response.body?.cancel().catch(() => {});
1219
1256
  return limited(rateLimitMarks, now());
1220
1257
  }
@@ -7219,6 +7256,13 @@ var supportedProviders = [
7219
7256
  class: "A",
7220
7257
  origins: ["https://api.kimi.com", "https://api.kimi.ai"]
7221
7258
  },
7259
+ {
7260
+ service: "minimax-coding-plan",
7261
+ ids: ["minimax-coding-plan"],
7262
+ hosts: { opencode2: "minimax-coding-plan" },
7263
+ class: "A",
7264
+ origins: ["https://api.minimax.io"]
7265
+ },
7222
7266
  {
7223
7267
  service: "openrouter",
7224
7268
  ids: ["openrouter"],
@@ -7230,6 +7274,13 @@ var supportedProviders = [
7230
7274
  class: "A",
7231
7275
  origins: ["https://openrouter.ai"]
7232
7276
  },
7277
+ {
7278
+ service: "synthetic",
7279
+ ids: ["synthetic"],
7280
+ hosts: { opencode1: "synthetic", opencode2: "synthetic" },
7281
+ class: "A",
7282
+ origins: ["https://api.synthetic.new"]
7283
+ },
7233
7284
  {
7234
7285
  service: "typesafe",
7235
7286
  ids: ["typesafe"],
@@ -7490,12 +7541,21 @@ function configIdentity(configDir) {
7490
7541
  }
7491
7542
  }
7492
7543
  function resolveOpencodeStateDir(env = process.env, home = homedir()) {
7544
+ const override = env.OPENCODE_CLAUSTRUM_AUTH_STATE_DIR?.trim();
7545
+ if (override)
7546
+ return path.resolve(override);
7493
7547
  const configDir = opencodeConfigDir(env, home);
7494
7548
  const identity = configIdentity(configDir);
7495
7549
  const key = identity === configIdentity(path.resolve(home, ".config", "opencode")) ? "opencode" : `opencode-${createHash3("sha256").update(identity).digest("hex").slice(0, 16)}`;
7496
7550
  return path.resolve(env.XDG_STATE_HOME || path.join(home, ".local", "state"), "cortexkit", "claustrum-auth", key);
7497
7551
  }
7498
7552
  async function opencodeStateDir(env = process.env, home = homedir()) {
7553
+ if (env.OPENCODE_CLAUSTRUM_AUTH_STATE_DIR?.trim()) {
7554
+ const stateDir = resolveOpencodeStateDir(env, home);
7555
+ if (!stateDir || !path.isAbsolute(stateDir))
7556
+ throw startupRefusal("opencode-start");
7557
+ return stateDir;
7558
+ }
7499
7559
  const identity = configIdentity(opencodeConfigDir(env, home));
7500
7560
  const stateDir = resolveOpencodeStateDir(env, home);
7501
7561
  const manifest = path.join(stateDir, "config-dir.json");
@@ -9345,34 +9405,32 @@ function frameCode(event) {
9345
9405
  const code = event.code ?? nested?.code ?? nested?.type;
9346
9406
  return typeof code === "string" ? code : undefined;
9347
9407
  }
9348
- function inspectResponsesFrame(data, attempt) {
9408
+ function inspectResponsesFrame(data, attempt, service) {
9349
9409
  let event;
9350
9410
  try {
9351
9411
  event = JSON.parse(data);
9352
9412
  } catch {
9353
- return;
9413
+ return { outputStarted: true };
9354
9414
  }
9355
9415
  if (!isRecord6(event))
9356
- return;
9416
+ return { outputStarted: true };
9357
9417
  const type = typeof event.type === "string" ? event.type : event.error != null ? "error" : undefined;
9358
- if (type === undefined)
9418
+ if (type === "response.created" || type === "response.in_progress" || type?.startsWith("codex."))
9359
9419
  return;
9360
9420
  if (type === "response.completed" || type === "response.incomplete")
9361
- return { done: true };
9421
+ return { done: true, outputStarted: true };
9362
9422
  if (type === "error" || type === "response.failed") {
9363
9423
  const status = frameStatus(event);
9364
9424
  if (attempt && status !== undefined)
9365
9425
  attempt.frameStatus = status;
9366
9426
  const code = frameCode(event);
9367
- const limited = status === 429 || code !== undefined && /rate.?limit/iu.test(code);
9427
+ const limited = status !== 402 && (status === 429 || code !== undefined && /rate.?limit/iu.test(code));
9368
9428
  return {
9369
9429
  error: "the provider answered with an error frame",
9370
- ...limited ? { limit: { reason: "rate-limit", status: status ?? 429 } } : {}
9430
+ ...status === 402 && isBalanceFailure(service, data) ? { limit: { reason: "payment-required", status } } : limited ? { limit: { reason: "rate-limit", status: status ?? 429 } } : {}
9371
9431
  };
9372
9432
  }
9373
- if (type.startsWith("response.") && type.endsWith(".delta"))
9374
- return { outputStarted: true };
9375
- return;
9433
+ return { outputStarted: true };
9376
9434
  }
9377
9435
  var defaultMarkMs = 60000;
9378
9436
  function retryAfterMs(headers, now) {
@@ -9386,7 +9444,7 @@ function retryAfterMs(headers, now) {
9386
9444
  return Number.isFinite(date) && date > now ? date - now : undefined;
9387
9445
  }
9388
9446
  function markUntil(limit, now) {
9389
- return now + (limit.retryAfterMs ?? defaultMarkMs);
9447
+ return now + (limit.retryAfterMs ?? (limit.status === 402 ? balanceProbeMs : defaultMarkMs));
9390
9448
  }
9391
9449
  async function rebuild(request, url, headers) {
9392
9450
  const body = request.body === null ? undefined : await request.clone().arrayBuffer();
@@ -9413,7 +9471,7 @@ function createVaultAdapter(options) {
9413
9471
  now,
9414
9472
  rateLimitMarks: marks
9415
9473
  }, tried);
9416
- const inspectEvent = options.entry.handshakeOrigins?.length ? ({ transport, data, attempt }) => transport === "ws" ? inspectResponsesFrame(data, attempt.data) : undefined : undefined;
9474
+ const inspectEvent = options.entry.handshakeOrigins?.length ? ({ transport, data, attempt }) => transport === "ws" ? inspectResponsesFrame(data, attempt.data, options.entry.service) : undefined : undefined;
9417
9475
  const noAccount = async () => {
9418
9476
  let mode;
9419
9477
  try {
@@ -9529,12 +9587,22 @@ function createVaultAdapter(options) {
9529
9587
  return;
9530
9588
  return redactResponse(response, [secret]);
9531
9589
  },
9532
- limitFromResponse({ status, headers }) {
9533
- if (status !== 429)
9590
+ async limitFromResponse({ status, headers, body }) {
9591
+ if (status !== 429 && status !== 402)
9534
9592
  return;
9593
+ if (status === 402) {
9594
+ let text;
9595
+ if (options.entry.service === "openrouter") {
9596
+ try {
9597
+ text = await body();
9598
+ } catch {}
9599
+ }
9600
+ if (!isBalanceFailure(options.entry.service, text))
9601
+ return;
9602
+ }
9535
9603
  const wait = retryAfterMs(headers, now());
9536
9604
  return {
9537
- reason: "rate-limit",
9605
+ reason: status === 402 ? "payment-required" : "rate-limit",
9538
9606
  status,
9539
9607
  ...wait === undefined ? {} : { retryAfterMs: wait }
9540
9608
  };
package/dist/setup-bin.js CHANGED
@@ -7,6 +7,8 @@ import { pathToFileURL } from "node:url";
7
7
  // src/setup.ts
8
8
  import { homedir as homedir2 } from "node:os";
9
9
  import path2 from "node:path";
10
+ // ../core/src/balance.ts
11
+ var balanceProbeMs = 5 * 60 * 1000;
10
12
  // ../../node_modules/.bun/@cortexkit+common-auth@0.29.1+e881539e648aba62/node_modules/@cortexkit/common-auth/dist/logger/redact.js
11
13
  var SECRET_KEY_EXACT = /^(authorization|x-api-key|cookie|set-cookie|refresh|access|token)$/i;
12
14
  var TOKEN_VALUE = /\b(Bearer\s+[\w.-]+|sk-[\w-]+|eyJ[\w.-]+)\b|ckh_[A-Za-z0-9_-]{20,}/g;
@@ -5787,6 +5789,13 @@ var supportedProviders = [
5787
5789
  class: "A",
5788
5790
  origins: ["https://api.kimi.com", "https://api.kimi.ai"]
5789
5791
  },
5792
+ {
5793
+ service: "minimax-coding-plan",
5794
+ ids: ["minimax-coding-plan"],
5795
+ hosts: { opencode2: "minimax-coding-plan" },
5796
+ class: "A",
5797
+ origins: ["https://api.minimax.io"]
5798
+ },
5790
5799
  {
5791
5800
  service: "openrouter",
5792
5801
  ids: ["openrouter"],
@@ -5798,6 +5807,13 @@ var supportedProviders = [
5798
5807
  class: "A",
5799
5808
  origins: ["https://openrouter.ai"]
5800
5809
  },
5810
+ {
5811
+ service: "synthetic",
5812
+ ids: ["synthetic"],
5813
+ hosts: { opencode1: "synthetic", opencode2: "synthetic" },
5814
+ class: "A",
5815
+ origins: ["https://api.synthetic.new"]
5816
+ },
5801
5817
  {
5802
5818
  service: "typesafe",
5803
5819
  ids: ["typesafe"],
@@ -6014,7 +6030,7 @@ import {
6014
6030
  // ../pi/package.json
6015
6031
  var package_default = {
6016
6032
  name: "@cortexkit/pi-claustrum-auth",
6017
- version: "0.1.0",
6033
+ version: "0.1.2",
6018
6034
  description: "Claustrum vault credentials for Pi",
6019
6035
  type: "module",
6020
6036
  license: "MIT",
@@ -6063,7 +6079,7 @@ var package_default = {
6063
6079
  // package.json
6064
6080
  var package_default2 = {
6065
6081
  name: "@cortexkit/opencode-claustrum-auth",
6066
- version: "0.1.0",
6082
+ version: "0.1.2",
6067
6083
  description: "Claustrum vault credentials for OpenCode 1 and OpenCode 2",
6068
6084
  type: "module",
6069
6085
  license: "MIT",
@@ -6143,12 +6159,21 @@ function configIdentity(configDir) {
6143
6159
  }
6144
6160
  }
6145
6161
  function resolveOpencodeStateDir(env = process.env, home = homedir()) {
6162
+ const override = env.OPENCODE_CLAUSTRUM_AUTH_STATE_DIR?.trim();
6163
+ if (override)
6164
+ return path.resolve(override);
6146
6165
  const configDir = opencodeConfigDir(env, home);
6147
6166
  const identity = configIdentity(configDir);
6148
6167
  const key = identity === configIdentity(path.resolve(home, ".config", "opencode")) ? "opencode" : `opencode-${createHash3("sha256").update(identity).digest("hex").slice(0, 16)}`;
6149
6168
  return path.resolve(env.XDG_STATE_HOME || path.join(home, ".local", "state"), "cortexkit", "claustrum-auth", key);
6150
6169
  }
6151
6170
  async function opencodeStateDir(env = process.env, home = homedir()) {
6171
+ if (env.OPENCODE_CLAUSTRUM_AUTH_STATE_DIR?.trim()) {
6172
+ const stateDir = resolveOpencodeStateDir(env, home);
6173
+ if (!stateDir || !path.isAbsolute(stateDir))
6174
+ throw startupRefusal("opencode-start");
6175
+ return stateDir;
6176
+ }
6152
6177
  const identity = configIdentity(opencodeConfigDir(env, home));
6153
6178
  const stateDir = resolveOpencodeStateDir(env, home);
6154
6179
  const manifest = path.join(stateDir, "config-dir.json");
@@ -6234,8 +6259,11 @@ async function runClaustrumSetup(rawArgv = [], io = {}, options = { table: suppo
6234
6259
  beforeSignIn: async (host, context) => {
6235
6260
  if (context.mode !== "claustrum")
6236
6261
  throw new Error(vaultOnlyMessage);
6237
- if (host === "opencode")
6262
+ if (host === "opencode") {
6238
6263
  await opencodeStateDir(env, home);
6264
+ if (env.OPENCODE_CLAUSTRUM_AUTH_STATE_DIR?.trim() && argv.includes("--enroll-only"))
6265
+ print(`State directory: ${states.opencode}`);
6266
+ }
6239
6267
  },
6240
6268
  signInLocal: async () => {
6241
6269
  throw new Error(vaultOnlyMessage);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-claustrum-auth",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Claustrum vault credentials for OpenCode 1 and OpenCode 2",
5
5
  "type": "module",
6
6
  "license": "MIT",