@maxceem/agw 0.14.0 → 0.15.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.
Files changed (2) hide show
  1. package/dist/agw.mjs +105 -63
  2. package/package.json +3 -1
package/dist/agw.mjs CHANGED
@@ -6,7 +6,7 @@ var __export = (target, all) => {
6
6
  };
7
7
 
8
8
  // <define:__AGW_MANIFEST__>
9
- var define_AGW_MANIFEST_default = { version: "0.14.0", wrangler: "4.96.0", upgradeFrom: ["0.14.0", "0.13.1", "0.13.0", "0.12.1", "0.12.0", "0.11.2", "0.11.1", "0.11.0", "0.10.11", "0.10.10", "0.10.9", "0.10.8", "0.10.7", "0.10.6", "0.10.5", "0.10.4", "0.10.3", "0.10.2", "0.10.1", "0.10.0", "0.9.3", "0.9.2", "0.9.1", "0.9.0", "0.8.3", "0.8.2", "0.8.1", "0.8.0", "0.7.2", "0.7.1", "0.7.0", "0.6.4", "0.6.3", "0.6.2", "0.6.1", "0.6.0", "0.5.2", "0.5.1", "0.5.0", "0.4.0"], release: { url: "https://github.com/maxceem/app-ai-gateway/releases/download/v0.14.0/gateway-0.14.0.tar.gz", sha256: "5aa7d75f4a2570fcb92a34fba3735561d9bacbfad6ea109aedfb020521482793", manifest: "93881984b069a1bb21654753c2c7c221897e406afe32781feb146f3501ad7c79" } };
9
+ var define_AGW_MANIFEST_default = { version: "0.15.1", wrangler: "4.96.0", upgradeFrom: ["0.15.1", "0.15.0", "0.14.0", "0.13.1", "0.13.0", "0.12.1", "0.12.0", "0.11.2", "0.11.1", "0.11.0", "0.10.11", "0.10.10", "0.10.9", "0.10.8", "0.10.7", "0.10.6", "0.10.5", "0.10.4", "0.10.3", "0.10.2", "0.10.1", "0.10.0", "0.9.3", "0.9.2", "0.9.1", "0.9.0", "0.8.3", "0.8.2", "0.8.1", "0.8.0", "0.7.2", "0.7.1", "0.7.0", "0.6.4", "0.6.3", "0.6.2", "0.6.1", "0.6.0", "0.5.2", "0.5.1", "0.5.0", "0.4.0"], release: { url: "https://github.com/maxceem/app-ai-gateway/releases/download/v0.15.1/gateway-0.15.1.tar.gz", sha256: "b5938517a50f09ea3ce3f966efd949dde8e9f0f2c195d47bb0dfdcbc7ec8eda0", manifest: "888f171f040d7547b37c40b41c01a53d1f284c9671e0bdc98083e9474c4ecdab" } };
10
10
 
11
11
  // src/main.ts
12
12
  import { Writable as Writable2 } from "node:stream";
@@ -20509,25 +20509,76 @@ var ENDPOINT_PROVIDER_TYPES = PROVIDER_TYPES.filter(
20509
20509
  var APP_STATUSES = ["active", "disabled"];
20510
20510
 
20511
20511
  // ../src/shared/token-rates.ts
20512
- var TOKEN_RATE_FIELDS = [
20513
- "input",
20514
- "output",
20515
- "cached_input",
20516
- "cache_write",
20517
- "cache_write_1h",
20518
- "image_input",
20519
- "audio_input",
20520
- "video_input",
20521
- "image_output",
20522
- "long_input",
20523
- "long_output",
20524
- "long_cached_input",
20525
- "long_cache_write",
20526
- "long_cache_write_1h"
20527
- ];
20528
- var LONG_RATE_FIELDS = TOKEN_RATE_FIELDS.filter(
20529
- (field) => field.startsWith("long_")
20512
+ var TOKEN_VARIANTS = {
20513
+ cache_write: {
20514
+ // Anthropic: a write kept for an hour bills at 2x input, against 1.25x for
20515
+ // the default five minutes. `usage.cache_creation` splits the write by TTL.
20516
+ "1h": {
20517
+ label: "1h cache write",
20518
+ description: "USD per 1M tokens written to a one-hour cache, where it costs more than the default cache write.",
20519
+ reportedAt: ["cache_creation", "ephemeral_1h_input_tokens"]
20520
+ },
20521
+ // OpenAI (Responses API): a write kept for 12 hours bills at 2.5x input,
20522
+ // against 1.25x for the default 30 minutes.
20523
+ "12h": {
20524
+ label: "12h cache write",
20525
+ description: "USD per 1M tokens written to a 12-hour cache, where it costs more than the default cache write.",
20526
+ reportedAt: ["input_tokens_details", "cache_write_tokens_details", "ttl_12h_tokens"]
20527
+ }
20528
+ }
20529
+ };
20530
+ var VARIANTS = Object.entries(TOKEN_VARIANTS).flatMap(
20531
+ ([bucket, variants]) => Object.entries(variants).map(([name, spec]) => ({
20532
+ ...spec,
20533
+ bucket,
20534
+ name,
20535
+ field: `${bucket}_${name}`
20536
+ }))
20537
+ );
20538
+ var BUCKETS = ["input", "cached_input", "cache_write", "output"];
20539
+ var MODALITY_RATES = ["image_input", "audio_input", "video_input", "image_output"];
20540
+ var BASE_RATES = {
20541
+ input: { label: "input" },
20542
+ cached_input: { label: "cached" },
20543
+ cache_write: { label: "cache write" },
20544
+ output: { label: "output" },
20545
+ image_input: {
20546
+ label: "image input",
20547
+ description: "USD per 1M image input tokens, where they are priced apart from text input."
20548
+ },
20549
+ audio_input: {
20550
+ label: "audio input",
20551
+ description: "USD per 1M audio input tokens, where they are priced apart from text input."
20552
+ },
20553
+ video_input: {
20554
+ label: "video input",
20555
+ description: "USD per 1M video input tokens, where they are priced apart from text input."
20556
+ },
20557
+ image_output: {
20558
+ label: "image output",
20559
+ description: "USD per 1M generated image tokens, where they cost more than text output."
20560
+ }
20561
+ };
20562
+ var BUCKET_FIELDS = BUCKETS.flatMap((bucket) => [
20563
+ bucket,
20564
+ ...VARIANTS.filter((variant) => variant.bucket === bucket).map((variant) => variant.field)
20565
+ ]);
20566
+ var LONG_RATE_FIELDS = BUCKET_FIELDS.map((field) => `long_${field}`);
20567
+ var TOKEN_RATE_FIELDS = [...BUCKET_FIELDS, ...MODALITY_RATES, ...LONG_RATE_FIELDS];
20568
+ var SHORT_INFO = new Map([
20569
+ ...Object.entries(BASE_RATES),
20570
+ ...VARIANTS.map((variant) => [variant.field, variant])
20571
+ ]);
20572
+ var RATE_LABELS = Object.fromEntries(
20573
+ TOKEN_RATE_FIELDS.map((field) => {
20574
+ const short = field.startsWith("long_") ? field.slice("long_".length) : field;
20575
+ const label = SHORT_INFO.get(short)?.label ?? short;
20576
+ return [field, short === field ? label : `long ${label}`];
20577
+ })
20530
20578
  );
20579
+ function rateDescription(field) {
20580
+ return SHORT_INFO.get(field)?.description;
20581
+ }
20531
20582
 
20532
20583
  // ../src/contracts/schemas.ts
20533
20584
  var ISSUER_PROVIDERS = ["firebase", "supabase", "auth0", "clerk", "custom"];
@@ -22622,7 +22673,7 @@ function snippetRemedy(code, appId, language) {
22622
22673
 
22623
22674
  // src/conversations.ts
22624
22675
  import { mkdir as mkdir2, readFile as readFile3, stat, writeFile } from "node:fs/promises";
22625
- import { dirname, join as join2, resolve as resolve2 } from "node:path";
22676
+ import { dirname, isAbsolute, relative, resolve as resolve2 } from "node:path";
22626
22677
  import { gunzipSync } from "node:zlib";
22627
22678
 
22628
22679
  // src/usage.ts
@@ -22686,6 +22737,14 @@ async function sizeOf(path) {
22686
22737
  return null;
22687
22738
  }
22688
22739
  }
22740
+ function inside(output2, name) {
22741
+ const path = resolve2(output2, name);
22742
+ const rel = relative(output2, path);
22743
+ if (rel === "" || rel.startsWith("..") || isAbsolute(rel)) {
22744
+ fail("invalid_response", "The deployment named a conversation file outside the export folder.", void 0, 3);
22745
+ }
22746
+ return path;
22747
+ }
22689
22748
  async function save(path, bytes) {
22690
22749
  await mkdir2(dirname(path), { recursive: true });
22691
22750
  await writeFile(path, bytes);
@@ -22715,7 +22774,7 @@ async function conversationsCommand(ctx, appId, flags) {
22715
22774
  })).data;
22716
22775
  for (const file2 of page2.files) {
22717
22776
  result.files += 1;
22718
- const path = join2(output2, file2.name);
22777
+ const path = inside(output2, file2.name);
22719
22778
  batches.push(path);
22720
22779
  if (await sizeOf(path) === file2.size) continue;
22721
22780
  const bytes = await ctx.client.download("getAppConversationFile", {
@@ -22735,7 +22794,7 @@ async function conversationsCommand(ctx, appId, flags) {
22735
22794
  for (const match of text2.matchAll(MEDIA_REFERENCE)) names.add(match[1]);
22736
22795
  }
22737
22796
  for (const name of names) {
22738
- const path = join2(output2, name);
22797
+ const path = inside(output2, name);
22739
22798
  if (await sizeOf(path) !== null) continue;
22740
22799
  const bytes = await ctx.client.download("getAppConversationFile", {
22741
22800
  params: { app: appId },
@@ -23685,40 +23744,23 @@ var UsageRepriceResponseSchema = external_exports.object({
23685
23744
  recalculated_cost_usd: external_exports.number(),
23686
23745
  delta_usd: external_exports.number()
23687
23746
  });
23747
+ var CATALOG_TOKEN_RATES = Object.fromEntries(
23748
+ TOKEN_RATE_FIELDS.map((field) => {
23749
+ const description = rateDescription(field);
23750
+ return [field, description ? external_exports.number().optional().meta({ description }) : external_exports.number().optional()];
23751
+ })
23752
+ );
23688
23753
  var ModelPriceSchema = external_exports.object({
23689
23754
  kind: external_exports.enum(MODEL_KINDS).meta({
23690
23755
  description: "What the model does: text, image (generation), speech (text to speech), transcription (speech to text), embedding, or realtime (served only over a realtime session). A custom endpoint serves models of its own kind only."
23691
23756
  }),
23692
- input: external_exports.number().optional(),
23693
- output: external_exports.number().optional(),
23694
- image_input: external_exports.number().optional().meta({
23695
- description: "USD per 1M image input tokens, where they are priced apart from text input."
23696
- }),
23697
- audio_input: external_exports.number().optional().meta({
23698
- description: "USD per 1M audio input tokens, where they are priced apart from text input."
23699
- }),
23700
- video_input: external_exports.number().optional().meta({
23701
- description: "USD per 1M video input tokens, where they are priced apart from text input."
23702
- }),
23703
- image_output: external_exports.number().optional().meta({
23704
- description: "USD per 1M generated image tokens, where they cost more than text output."
23705
- }),
23706
- cached_input: external_exports.number().optional(),
23707
- cache_write: external_exports.number().optional(),
23708
- cache_write_1h: external_exports.number().optional().meta({
23709
- description: "USD per 1M tokens written to a one-hour cache, where it costs more than the default cache write."
23710
- }),
23757
+ ...CATALOG_TOKEN_RATES,
23711
23758
  per_minute: external_exports.number().optional(),
23712
23759
  per_hour: external_exports.number().optional(),
23713
23760
  per_image: external_exports.number().optional().meta({
23714
23761
  description: "USD per generated image, for a model billed per image rather than per token."
23715
23762
  }),
23716
23763
  long_context_threshold: external_exports.number().optional(),
23717
- long_input: external_exports.number().optional(),
23718
- long_output: external_exports.number().optional(),
23719
- long_cached_input: external_exports.number().optional(),
23720
- long_cache_write: external_exports.number().optional(),
23721
- long_cache_write_1h: external_exports.number().optional(),
23722
23764
  retirement_date: external_exports.string().optional().meta({
23723
23765
  description: "The day (YYYY-MM-DD) the provider stops, or stopped, serving this model. The model stays priced after it."
23724
23766
  })
@@ -26322,11 +26364,11 @@ async function openBrowser(url2) {
26322
26364
  // src/deployment.ts
26323
26365
  import { createHash as createHash4, randomUUID } from "node:crypto";
26324
26366
  import { writeFile as writeFile4, unlink as unlink2 } from "node:fs/promises";
26325
- import { join as join5 } from "node:path";
26367
+ import { join as join4 } from "node:path";
26326
26368
 
26327
26369
  // src/release.ts
26328
26370
  import { readFile as readFile4, lstat as lstat2, mkdir as mkdir3, rename as rename2, rm, writeFile as writeFile2 } from "node:fs/promises";
26329
- import { join as join3, dirname as dirname2 } from "node:path";
26371
+ import { join as join2, dirname as dirname2 } from "node:path";
26330
26372
  import { fileURLToPath } from "node:url";
26331
26373
  import { createHash as createHash3, randomBytes as randomBytes3 } from "node:crypto";
26332
26374
 
@@ -26451,7 +26493,7 @@ async function fetchArchive(url2) {
26451
26493
  async function extract(archive, directory) {
26452
26494
  await mkdir3(directory, { recursive: true, mode: 448 });
26453
26495
  for (const entry of readArchive(archive)) {
26454
- const path = join3(directory, entry.path);
26496
+ const path = join2(directory, entry.path);
26455
26497
  if (entry.directory) {
26456
26498
  await mkdir3(path, { recursive: true, mode: 448 });
26457
26499
  continue;
@@ -26461,9 +26503,9 @@ async function extract(archive, directory) {
26461
26503
  }
26462
26504
  }
26463
26505
  async function cachedRelease(version2, integrity, source) {
26464
- const root = source.cache ?? join3(cacheDirectory(), "releases");
26465
- const directory = join3(root, version2);
26466
- const cached2 = await readFile4(join3(directory, "manifest.json")).catch(() => null);
26506
+ const root = source.cache ?? join2(cacheDirectory(), "releases");
26507
+ const directory = join2(root, version2);
26508
+ const cached2 = await readFile4(join2(directory, "manifest.json")).catch(() => null);
26467
26509
  if (cached2 && digest(cached2) === integrity.manifest) return directory;
26468
26510
  const supplied = source.archive ?? process.env["AGW_RELEASE_ARCHIVE"] ?? void 0;
26469
26511
  let archive;
@@ -26487,10 +26529,10 @@ async function cachedRelease(version2, integrity, source) {
26487
26529
  4
26488
26530
  );
26489
26531
  await protectedDirectory(root);
26490
- const staging = join3(root, `.${version2}-${randomBytes3(8).toString("hex")}`);
26532
+ const staging = join2(root, `.${version2}-${randomBytes3(8).toString("hex")}`);
26491
26533
  try {
26492
26534
  await extract(archive, staging);
26493
- const manifest2 = await readFile4(join3(staging, "manifest.json")).catch(() => null);
26535
+ const manifest2 = await readFile4(join2(staging, "manifest.json")).catch(() => null);
26494
26536
  if (!manifest2 || digest(manifest2) !== integrity.manifest)
26495
26537
  fail(
26496
26538
  "release_integrity",
@@ -26516,7 +26558,7 @@ async function release2(requested = VERSION, base = dirname2(fileURLToPath(impor
26516
26558
  if (major === void 0 || minor === void 0 || major < 22 || major === 22 && minor < 19)
26517
26559
  fail("unsupported_runtime", "Node.js 22.19.0 or newer is required.");
26518
26560
  const integrity = source.integrity === void 0 ? RELEASE : source.integrity;
26519
- const packaged = join3(base, "release", requested);
26561
+ const packaged = join2(base, "release", requested);
26520
26562
  const local = await lstat2(packaged).catch(() => null);
26521
26563
  let directory;
26522
26564
  if (local?.isDirectory()) directory = packaged;
@@ -26530,7 +26572,7 @@ async function release2(requested = VERSION, base = dirname2(fileURLToPath(impor
26530
26572
  );
26531
26573
  let serialized;
26532
26574
  try {
26533
- serialized = await readFile4(join3(directory, "manifest.json"), "utf8");
26575
+ serialized = await readFile4(join2(directory, "manifest.json"), "utf8");
26534
26576
  } catch {
26535
26577
  fail(
26536
26578
  "release_missing",
@@ -26550,7 +26592,7 @@ async function release2(requested = VERSION, base = dirname2(fileURLToPath(impor
26550
26592
  for (const [path, hash2] of Object.entries(manifest2.files)) {
26551
26593
  if (path.startsWith("/") || path.split(/[\\/]/).some((p) => p === ".." || p === ""))
26552
26594
  fail("release_integrity", "Release includes an unsafe path.");
26553
- const file2 = join3(directory, path);
26595
+ const file2 = join2(directory, path);
26554
26596
  const info = await lstat2(file2);
26555
26597
  if (!info.isFile() || info.isSymbolicLink() || digest(await readFile4(file2)) !== hash2)
26556
26598
  fail("release_integrity", "Release asset integrity check failed.");
@@ -26559,7 +26601,7 @@ async function release2(requested = VERSION, base = dirname2(fileURLToPath(impor
26559
26601
  directory,
26560
26602
  manifest: manifest2,
26561
26603
  config: JSON.parse(
26562
- await readFile4(join3(directory, "wrangler.json"), "utf8")
26604
+ await readFile4(join2(directory, "wrangler.json"), "utf8")
26563
26605
  )
26564
26606
  };
26565
26607
  }
@@ -26816,7 +26858,7 @@ async function whileWarming(run, sleep = delay3, report = (line) => process.stde
26816
26858
 
26817
26859
  // src/installation.ts
26818
26860
  import { cp, writeFile as writeFile3 } from "node:fs/promises";
26819
- import { join as join4 } from "node:path";
26861
+ import { join as join3 } from "node:path";
26820
26862
  import { setTimeout as delay4 } from "node:timers/promises";
26821
26863
  async function advance(ctx, journal, phase, patch = {}) {
26822
26864
  const fields = journal;
@@ -26843,9 +26885,9 @@ function selectedInstallation(ctx) {
26843
26885
  };
26844
26886
  }
26845
26887
  async function configFile(ctx, journal, artifact) {
26846
- const directory = join4(ctx.store.directory, "deployments", journal.id);
26888
+ const directory = join3(ctx.store.directory, "deployments", journal.id);
26847
26889
  await protectedDirectory(directory);
26848
- await cp(artifact.directory, join4(directory, "release"), { recursive: true });
26890
+ await cp(artifact.directory, join3(directory, "release"), { recursive: true });
26849
26891
  const config2 = {
26850
26892
  ...artifact.config,
26851
26893
  name: journal.name,
@@ -26873,7 +26915,7 @@ async function configFile(ctx, journal, artifact) {
26873
26915
  }))
26874
26916
  } : {}
26875
26917
  };
26876
- const path = join4(directory, "wrangler.json");
26918
+ const path = join3(directory, "wrangler.json");
26877
26919
  await writeFile3(path, JSON.stringify(config2, null, 2), { mode: 384 });
26878
26920
  return { path, directory, config: config2 };
26879
26921
  }
@@ -27220,7 +27262,7 @@ async function install(ctx, cf, journal, artifact, url2, domain2) {
27220
27262
  // the account is this CLI's however soon anyone else finds the address.
27221
27263
  CLI_BOOTSTRAP_TOKEN_DIGEST: createHash4("sha256").update(journal.bootstrap.token).digest("hex")
27222
27264
  };
27223
- const secretPath = join5(file2.directory, "secrets.json");
27265
+ const secretPath = join4(file2.directory, "secrets.json");
27224
27266
  await writeFile4(secretPath, JSON.stringify(secrets), {
27225
27267
  mode: 384
27226
27268
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maxceem/agw",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "type": "module",
5
5
  "description": "Manage App AI Gateway from a terminal or coding agent: providers, iOS and server apps, usage, and self-hosted deployment on Cloudflare",
6
6
  "keywords": [
@@ -26,6 +26,8 @@
26
26
  },
27
27
  "bugs": "https://github.com/maxceem/app-ai-gateway/issues",
28
28
  "upgradeFrom": [
29
+ "0.15.0",
30
+ "0.14.0",
29
31
  "0.13.1",
30
32
  "0.13.0",
31
33
  "0.12.1",