@amerged/ohmyhost-cli 0.1.39 → 0.1.41

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # @amerged/ohmyhost-cli
2
2
 
3
- ohmyho.st cli client, version 0.1.39.
3
+ ohmyho.st cli client, version 0.1.41.
4
4
 
5
5
  ```sh
6
6
  npm install --global @amerged/ohmyhost-cli
package/dist/bin.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import { createRequire as __ohmyhostCreateRequire } from "node:module"; const require = __ohmyhostCreateRequire(import.meta.url);
3
3
  import {
4
4
  runProductionCli
5
- } from "./chunk-R2BC42EW.js";
5
+ } from "./chunk-SB6RMO3M.js";
6
6
  import "./chunk-7D2RFLWM.js";
7
7
 
8
8
  // apps/product-cli/dist/bin.js
@@ -38593,7 +38593,7 @@ var FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
38593
38593
  },
38594
38594
  better_auth_version_required: {
38595
38595
  paths: ["manifest"],
38596
- template: '"{{path}}" must declare better-auth at exactly 1.7.1 in dependencies because ohmyhost.yaml sets auth.provider: better-auth. Pin that version or set auth.provider: none, commit and push the change, then plan the new commit.'
38596
+ template: '"{{path}}" must declare better-auth at exactly 1.7.7 in dependencies because ohmyhost.yaml sets auth.provider: better-auth. Pin that version or set auth.provider: none, commit and push the change, then plan the new commit.'
38597
38597
  },
38598
38598
  package_manifest_invalid: {
38599
38599
  paths: ["manifest"],
@@ -40064,31 +40064,41 @@ function assertOrganizationCreditUsage(value) {
40064
40064
  };
40065
40065
  const identifier2 = (input) => typeof input === "string" && /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u.test(input);
40066
40066
  const amount = (input) => typeof input === "string" && /^(0|[1-9][0-9]{0,37})$/u.test(input);
40067
- const report = record6(value, "organization_id,month,as_of,unit,data,next_cursor");
40068
- if (!identifier2(report["organization_id"]) || typeof report["month"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(report["month"]) || typeof report["as_of"] !== "string" || !Number.isFinite(Date.parse(report["as_of"])) || new Date(report["as_of"]).toISOString() !== report["as_of"] || report["unit"] !== "microcredits" || !Array.isArray(report["data"]) || report["data"].length > 20 || report["next_cursor"] !== null && !identifier2(report["next_cursor"]))
40067
+ const instant2 = (input) => typeof input === "string" && Number.isFinite(Date.parse(input)) && new Date(input).toISOString() === input;
40068
+ const report = record6(value, "organization_id,as_of,unit,period,from,projects,days");
40069
+ if (!identifier2(report["organization_id"]) || !instant2(report["as_of"]) || !instant2(report["from"]) || report["unit"] !== "microcredits" || typeof report["period"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(report["period"]) || !Array.isArray(report["projects"]) || report["projects"].length > 1e3 || !Array.isArray(report["days"]) || report["days"].length > 15)
40069
40070
  throw new TypeError("Invalid usage report");
40070
40071
  let previous = "";
40071
- for (const input of report["data"]) {
40072
- const project = record6(input, "project_id,reserved_micros,meters");
40073
- if (!identifier2(project["project_id"]) || String(project["project_id"]) <= previous || !amount(project["reserved_micros"]) || !Array.isArray(project["meters"]) || project["meters"].length > 1e3)
40072
+ for (const input of report["projects"]) {
40073
+ const project = record6(input, "project_id,used_micros");
40074
+ if (!identifier2(project["project_id"]) || String(project["project_id"]) <= previous || !amount(project["used_micros"]))
40074
40075
  throw new TypeError("Invalid usage project");
40075
40076
  previous = String(project["project_id"]);
40076
- for (const input2 of project["meters"]) {
40077
- const meter = record6(input2, "environment_id,meter,unit,rate_card_id,quantity,charged_micros,funded_micros,platform_overrun_micros");
40078
- if (meter["environment_id"] !== null && !identifier2(meter["environment_id"]))
40079
- throw new TypeError("Invalid usage environment");
40080
- for (const key of ["meter", "unit", "rate_card_id"])
40081
- if (typeof meter[key] !== "string" || !/^[A-Za-z0-9_.:/-]{1,128}$/u.test(meter[key]))
40082
- throw new TypeError("Invalid usage meter");
40083
- for (const key of ["quantity", "charged_micros", "funded_micros", "platform_overrun_micros"])
40084
- if (!amount(meter[key]))
40077
+ }
40078
+ let previousDay = "";
40079
+ for (const input of report["days"]) {
40080
+ const day = record6(input, "day,projects");
40081
+ if (typeof day["day"] !== "string" || !/^20[0-9]{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/u.test(day["day"]) || day["day"] <= previousDay || !Array.isArray(day["projects"]) || day["projects"].length > 1e3)
40082
+ throw new TypeError("Invalid usage day");
40083
+ previousDay = day["day"];
40084
+ previous = "";
40085
+ for (const projectInput of day["projects"]) {
40086
+ const project = record6(projectInput, "project_id,meters");
40087
+ if (!identifier2(project["project_id"]) || String(project["project_id"]) <= previous || !Array.isArray(project["meters"]) || project["meters"].length > 1e3)
40088
+ throw new TypeError("Invalid usage project");
40089
+ previous = String(project["project_id"]);
40090
+ for (const meterInput of project["meters"]) {
40091
+ const meter = record6(meterInput, "environment_id,meter,unit,rate_card_id,quantity,charged_micros");
40092
+ if (meter["environment_id"] !== null && !identifier2(meter["environment_id"]))
40093
+ throw new TypeError("Invalid usage environment");
40094
+ for (const key of ["meter", "unit", "rate_card_id"])
40095
+ if (typeof meter[key] !== "string" || !/^[A-Za-z0-9_.:/-]{1,128}$/u.test(meter[key]))
40096
+ throw new TypeError("Invalid usage meter");
40097
+ if (typeof meter["quantity"] !== "string" || !/^(0|[1-9][0-9]{0,29})(\.[0-9]{1,12})?$/u.test(meter["quantity"]) || !amount(meter["charged_micros"]))
40085
40098
  throw new TypeError("Invalid usage amount");
40086
- if (BigInt(String(meter["charged_micros"])) !== BigInt(String(meter["funded_micros"])) + BigInt(String(meter["platform_overrun_micros"])))
40087
- throw new TypeError("Inconsistent usage charge");
40099
+ }
40088
40100
  }
40089
40101
  }
40090
- if (report["next_cursor"] !== null && report["next_cursor"] !== previous)
40091
- throw new TypeError("Invalid usage cursor");
40092
40102
  }
40093
40103
  function assertPublishedCreditRateCards(value) {
40094
40104
  if (!Array.isArray(value) || value.length > 4)
@@ -40139,7 +40149,9 @@ function assertOrganizationAccount(value) {
40139
40149
  for (const field of ["available_micros", "monthly_micros", "one_time_micros", "reserved_micros"])
40140
40150
  if (typeof v[field] !== "string" || !/^(0|[1-9][0-9]{0,18})$/u.test(v[field]))
40141
40151
  throw new TypeError("Invalid account credits");
40142
- if (BigInt(String(v["monthly_micros"])) + BigInt(String(v["one_time_micros"])) !== BigInt(String(v["available_micros"])))
40152
+ const held = BigInt(String(v["reserved_micros"]));
40153
+ const balance = BigInt(String(v["monthly_micros"])) + BigInt(String(v["one_time_micros"]));
40154
+ if (BigInt(String(v["available_micros"])) !== (balance > held ? balance - held : 0n))
40143
40155
  throw new TypeError("Account credit buckets do not balance");
40144
40156
  for (const field of ["as_of", "paid_until", "next_expiry"]) {
40145
40157
  if (field !== "as_of" && v[field] === null)
@@ -40869,9 +40881,6 @@ function parseOrganizationCredits(value) {
40869
40881
  "as_of",
40870
40882
  "available_micros",
40871
40883
  "reserved_micros",
40872
- "spent_micros",
40873
- "expired_micros",
40874
- "platform_overrun_micros",
40875
40884
  "grace_started_at",
40876
40885
  "grace_expires_at",
40877
40886
  "active_meters",
@@ -40887,13 +40896,7 @@ function parseOrganizationCredits(value) {
40887
40896
  throw new ResponseContractError();
40888
40897
  if (!isUlid(input["organization_id"]) || input["unit"] !== "microcredits" || !isIsoInstant(input["as_of"]) || !Array.isArray(input["active_meters"]) || input["active_meters"].some((m) => typeof m !== "string" || !/^[a-z0-9_.-]{1,128}$/u.test(m)))
40889
40898
  throw new ResponseContractError();
40890
- for (const field of [
40891
- "available_micros",
40892
- "reserved_micros",
40893
- "spent_micros",
40894
- "expired_micros",
40895
- "platform_overrun_micros"
40896
- ]) {
40899
+ for (const field of ["available_micros", "reserved_micros"]) {
40897
40900
  const amount = input[field];
40898
40901
  if (typeof amount !== "string" || !/^(0|[1-9][0-9]{0,18})$/u.test(amount) || BigInt(amount) > 9223372036854775807n)
40899
40902
  throw new ResponseContractError();
@@ -43160,16 +43163,8 @@ var parseProductCliCommand = (argv) => {
43160
43163
  values.shift();
43161
43164
  if (yes || wait || follow || stdin)
43162
43165
  throw new InvalidCommandError();
43163
- const options = parseOptionalOptions(values, ["--organization", "--month", "--cursor"]);
43164
- if (!options["--organization"] || !options["--month"] || !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(options["--month"]))
43165
- throw new InvalidCommandError();
43166
- return {
43167
- kind: "credits-usage",
43168
- organizationId: options["--organization"],
43169
- month: options["--month"],
43170
- ...options["--cursor"] ? { cursor: options["--cursor"] } : {},
43171
- credentialStore
43172
- };
43166
+ const options = parseOptions(values, ["--organization"]);
43167
+ return { kind: "credits-usage", organizationId: options["--organization"], credentialStore };
43173
43168
  }
43174
43169
  if (first === "credits" && values[0] === "account") {
43175
43170
  values.shift();
@@ -44714,7 +44709,7 @@ function exact3(v, keys) {
44714
44709
  // apps/product-cli/package.json
44715
44710
  var package_default = {
44716
44711
  name: "@ohmyhost/product-cli",
44717
- version: "0.1.39",
44712
+ version: "0.1.41",
44718
44713
  private: true,
44719
44714
  ohmyhost: {
44720
44715
  deployment: "production",
@@ -45023,7 +45018,7 @@ var HELP_USAGE = Object.freeze({
45023
45018
  "billing checkout": "ohmyhost billing checkout --organization ULID --offer topup|paid [--packs 1] --idempotency-key KEY --json (returns a human payment URL; never auto-pays)",
45024
45019
  "billing status": "ohmyhost billing status --organization ULID --checkout ULID --json",
45025
45020
  "billing portal": "ohmyhost billing portal --organization ULID --json (short-lived human URL; request fresh after expiry)",
45026
- "credits usage": "ohmyhost credits usage --organization ULID --month YYYY-MM [--cursor ULID] --json",
45021
+ "credits usage": "ohmyhost credits usage --organization ULID --json (billed usage of the last up to 14 UTC days by day, project and meter, and each project's use this UTC month)",
45027
45022
  "budget get": "ohmyhost budget get --project ULID --json",
45028
45023
  "budget set": "ohmyhost budget set --project ULID --credits NUMBER|none [--mode continue|stop] --idempotency-key KEY --json",
45029
45024
  "organization create": "ohmyhost organization create --name NAME --idempotency-key KEY [--source SOURCE] --json (SOURCE is optional attribution from a link's r value; a login without organization is bound to the new workspace, another login keeps its own)",
@@ -45312,7 +45307,7 @@ var ProductCli = class {
45312
45307
  }
45313
45308
  if (command.kind === "credits-usage") {
45314
45309
  const api = await this.authenticatedApi(command.credentialStore, signal);
45315
- const usage = await api.getOrganizationCreditUsage(command);
45310
+ const usage = await api.getOrganizationCreditUsage(command.organizationId);
45316
45311
  try {
45317
45312
  assertOrganizationCreditUsage(usage);
45318
45313
  } catch {
@@ -48563,9 +48558,7 @@ var getOrganizationCreditUsage = (parameters, options) => {
48563
48558
  {
48564
48559
  args: [
48565
48560
  { in: "headers", key: "X-Request-Id" },
48566
- { in: "path", key: "organization_id" },
48567
- { in: "query", key: "month" },
48568
- { in: "query", key: "cursor" }
48561
+ { in: "path", key: "organization_id" }
48569
48562
  ]
48570
48563
  }
48571
48564
  ]);
@@ -50897,12 +50890,8 @@ var GeneratedSdkProductApi = class {
50897
50890
  createBillingPortal(organizationId) {
50898
50891
  return createBillingPortal({ organization_id: organizationId, body: {} }, { client: this.#client });
50899
50892
  }
50900
- getOrganizationCreditUsage(input) {
50901
- return getOrganizationCreditUsage({
50902
- organization_id: input.organizationId,
50903
- month: input.month,
50904
- ...input.cursor ? { cursor: input.cursor } : {}
50905
- }, { client: this.#client });
50893
+ getOrganizationCreditUsage(organizationId) {
50894
+ return getOrganizationCreditUsage({ organization_id: organizationId }, { client: this.#client });
50906
50895
  }
50907
50896
  getProjectCreditBudget(projectId) {
50908
50897
  return getProjectCreditBudget({ project_id: projectId }, { client: this.#client });
@@ -51956,7 +51945,7 @@ function classifyFrameworkFamily(dependencies) {
51956
51945
  }
51957
51946
 
51958
51947
  // packages/contracts/dist/framework-source-rules.js
51959
- var MANAGED_BETTER_AUTH_VERSION = "1.7.1";
51948
+ var MANAGED_BETTER_AUTH_VERSION = "1.7.7";
51960
51949
  var MAXIMUM_FRAMEWORK_CONFIG_BYTES = 256 * 1024;
51961
51950
  var WORKER_MODULE_PATH = "src/ohmyhost/worker.ts";
51962
51951
  var VITE_COMPANION_ENTRY_PATH = "src/ohmyhost/companion.ts";
package/dist/index.js CHANGED
@@ -99,7 +99,7 @@ import {
99
99
  selectWorkspace,
100
100
  verifiedUserId,
101
101
  workspaceOf
102
- } from "./chunk-R2BC42EW.js";
102
+ } from "./chunk-SB6RMO3M.js";
103
103
  import {
104
104
  CredentialStoreIntegrityError,
105
105
  CredentialStoreUnavailableError,
@@ -1 +1 @@
1
- PostgreSQL WebSocket bridge and authentication prelude handling adapted from cloudflare-postgres packages/cli, commit e05d9102c840e283602272ed0e16a95be3e3b8ea. Upstream license: Apache-2.0.
1
+ PostgreSQL WebSocket bridge and authentication prelude handling adapted from cloudflare-postgres (https://github.com/amerged-org/cloudflare-postgres) packages/cli, commit e05d9102c840e283602272ed0e16a95be3e3b8ea. Upstream license: Apache-2.0.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amerged/ohmyhost-cli",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "node": ">=22"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohmyhost/product-cli",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "private": true,
5
5
  "ohmyhost": {
6
6
  "deployment": "production",
@@ -351,7 +351,7 @@ const HELP_USAGE = Object.freeze({
351
351
  "billing portal":
352
352
  "ohmyhost billing portal --organization ULID --json (short-lived human URL; request fresh after expiry)",
353
353
  "credits usage":
354
- "ohmyhost credits usage --organization ULID --month YYYY-MM [--cursor ULID] --json",
354
+ "ohmyhost credits usage --organization ULID --json (billed usage of the last up to 14 UTC days by day, project and meter, and each project's use this UTC month)",
355
355
  "budget get": "ohmyhost budget get --project ULID --json",
356
356
  "budget set":
357
357
  "ohmyhost budget set --project ULID --credits NUMBER|none [--mode continue|stop] --idempotency-key KEY --json",
@@ -844,7 +844,7 @@ export class ProductCli {
844
844
  }
845
845
  if (command.kind === "credits-usage") {
846
846
  const api = await this.authenticatedApi(command.credentialStore, signal);
847
- const usage = await api.getOrganizationCreditUsage(command);
847
+ const usage = await api.getOrganizationCreditUsage(command.organizationId);
848
848
  try {
849
849
  assertOrganizationCreditUsage(usage);
850
850
  } catch {
@@ -199,8 +199,6 @@ export type ProductCliCommand =
199
199
  | {
200
200
  readonly kind: "credits-usage";
201
201
  readonly organizationId: string;
202
- readonly month: string;
203
- readonly cursor?: string;
204
202
  readonly credentialStore: "native";
205
203
  }
206
204
  | {
@@ -1407,20 +1405,8 @@ export const parseProductCliCommand = (argv: readonly string[]): ProductCliComma
1407
1405
  if (first === "credits" && values[0] === "usage") {
1408
1406
  values.shift();
1409
1407
  if (yes || wait || follow || stdin) throw new InvalidCommandError();
1410
- const options = parseOptionalOptions(values, ["--organization", "--month", "--cursor"]);
1411
- if (
1412
- !options["--organization"] ||
1413
- !options["--month"] ||
1414
- !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(options["--month"])
1415
- )
1416
- throw new InvalidCommandError();
1417
- return {
1418
- kind: "credits-usage",
1419
- organizationId: options["--organization"],
1420
- month: options["--month"],
1421
- ...(options["--cursor"] ? { cursor: options["--cursor"] } : {}),
1422
- credentialStore,
1423
- };
1408
+ const options = parseOptions(values, ["--organization"]);
1409
+ return { kind: "credits-usage", organizationId: options["--organization"], credentialStore };
1424
1410
  }
1425
1411
  if (first === "credits" && values[0] === "account") {
1426
1412
  values.shift();
@@ -230,11 +230,7 @@ export interface ProductApi {
230
230
  organizationId: string,
231
231
  ): Promise<import("@ohmyhost/sdk-ts").OrganizationReferral>;
232
232
  getOrganizationCredits(organizationId: string): Promise<OrganizationCredits>;
233
- getOrganizationCreditUsage(input: {
234
- organizationId: string;
235
- month: string;
236
- cursor?: string;
237
- }): Promise<OrganizationCreditUsage>;
233
+ getOrganizationCreditUsage(organizationId: string): Promise<OrganizationCreditUsage>;
238
234
  getProjectCreditBudget(projectId: string): Promise<ProjectCreditBudget>;
239
235
  setProjectCreditBudget(input: {
240
236
  projectId: string;
@@ -614,15 +610,9 @@ export class GeneratedSdkProductApi implements ProductApi {
614
610
  { client: this.#client },
615
611
  );
616
612
  }
617
- public getOrganizationCreditUsage(
618
- input: Parameters<ProductApi["getOrganizationCreditUsage"]>[0],
619
- ) {
613
+ public getOrganizationCreditUsage(organizationId: string) {
620
614
  return getOrganizationCreditUsage(
621
- {
622
- organization_id: input.organizationId,
623
- month: input.month,
624
- ...(input.cursor ? { cursor: input.cursor } : {}),
625
- },
615
+ { organization_id: organizationId },
626
616
  { client: this.#client },
627
617
  );
628
618
  }
@@ -552,9 +552,6 @@ export function parseOrganizationCredits(value: unknown): OrganizationCredits {
552
552
  "as_of",
553
553
  "available_micros",
554
554
  "reserved_micros",
555
- "spent_micros",
556
- "expired_micros",
557
- "platform_overrun_micros",
558
555
  "grace_started_at",
559
556
  "grace_expires_at",
560
557
  "active_meters",
@@ -586,13 +583,7 @@ export function parseOrganizationCredits(value: unknown): OrganizationCredits {
586
583
  )
587
584
  )
588
585
  throw new ResponseContractError();
589
- for (const field of [
590
- "available_micros",
591
- "reserved_micros",
592
- "spent_micros",
593
- "expired_micros",
594
- "platform_overrun_micros",
595
- ]) {
586
+ for (const field of ["available_micros", "reserved_micros"]) {
596
587
  const amount = input[field];
597
588
  if (
598
589
  typeof amount !== "string" ||
@@ -1,23 +1,28 @@
1
1
  export interface OrganizationCreditUsage {
2
2
  organization_id: string;
3
- month: string;
4
3
  as_of: string;
5
4
  unit: "microcredits";
6
- data: {
7
- project_id: string;
8
- reserved_micros: string;
9
- meters: {
10
- environment_id: string | null;
11
- meter: string;
12
- unit: string;
13
- rate_card_id: string;
14
- quantity: string;
15
- charged_micros: string;
16
- funded_micros: string;
17
- platform_overrun_micros: string;
5
+ /** The UTC month (`YYYY-MM`) that `projects[].used_micros` counts. */
6
+ period: string;
7
+ /** The first instant of the daily lines: the start of the oldest UTC day that is reported. */
8
+ from: string;
9
+ /** What each project has used so far in `period`. */
10
+ projects: { project_id: string; used_micros: string }[];
11
+ /** The credit-log lines of the last up to 14 UTC days, grouped by day, project and meter, oldest day first. */
12
+ days: {
13
+ day: string;
14
+ projects: {
15
+ project_id: string;
16
+ meters: {
17
+ environment_id: string | null;
18
+ meter: string;
19
+ unit: string;
20
+ rate_card_id: string;
21
+ quantity: string;
22
+ charged_micros: string;
23
+ }[];
18
24
  }[];
19
25
  }[];
20
- next_cursor: string | null;
21
26
  }
22
27
 
23
28
  /** A bounded read model, not a new source of accounting or billing authorization. */
@@ -38,53 +43,77 @@ export function assertOrganizationCreditUsage(
38
43
  typeof input === "string" && /^[0-7][0-9A-HJKMNP-TV-Z]{25}$/u.test(input);
39
44
  const amount = (input: unknown) =>
40
45
  typeof input === "string" && /^(0|[1-9][0-9]{0,37})$/u.test(input);
41
- const report = record(value, "organization_id,month,as_of,unit,data,next_cursor");
46
+ const instant = (input: unknown) =>
47
+ typeof input === "string" &&
48
+ Number.isFinite(Date.parse(input)) &&
49
+ new Date(input).toISOString() === input;
50
+ const report = record(value, "organization_id,as_of,unit,period,from,projects,days");
42
51
  if (
43
52
  !identifier(report["organization_id"]) ||
44
- typeof report["month"] !== "string" ||
45
- !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(report["month"]) ||
46
- typeof report["as_of"] !== "string" ||
47
- !Number.isFinite(Date.parse(report["as_of"])) ||
48
- new Date(report["as_of"]).toISOString() !== report["as_of"] ||
53
+ !instant(report["as_of"]) ||
54
+ !instant(report["from"]) ||
49
55
  report["unit"] !== "microcredits" ||
50
- !Array.isArray(report["data"]) ||
51
- report["data"].length > 20 ||
52
- (report["next_cursor"] !== null && !identifier(report["next_cursor"]))
56
+ typeof report["period"] !== "string" ||
57
+ !/^20[0-9]{2}-(0[1-9]|1[0-2])$/u.test(report["period"]) ||
58
+ !Array.isArray(report["projects"]) ||
59
+ report["projects"].length > 1000 ||
60
+ !Array.isArray(report["days"]) ||
61
+ report["days"].length > 15
53
62
  )
54
63
  throw new TypeError("Invalid usage report");
55
64
  let previous = "";
56
- for (const input of report["data"]) {
57
- const project = record(input, "project_id,reserved_micros,meters");
65
+ for (const input of report["projects"]) {
66
+ const project = record(input, "project_id,used_micros");
58
67
  if (
59
68
  !identifier(project["project_id"]) ||
60
69
  String(project["project_id"]) <= previous ||
61
- !amount(project["reserved_micros"]) ||
62
- !Array.isArray(project["meters"]) ||
63
- project["meters"].length > 1000
70
+ !amount(project["used_micros"])
64
71
  )
65
72
  throw new TypeError("Invalid usage project");
66
73
  previous = String(project["project_id"]);
67
- for (const input of project["meters"]) {
68
- const meter = record(
69
- input,
70
- "environment_id,meter,unit,rate_card_id,quantity,charged_micros,funded_micros,platform_overrun_micros",
71
- );
72
- if (meter["environment_id"] !== null && !identifier(meter["environment_id"]))
73
- throw new TypeError("Invalid usage environment");
74
- for (const key of ["meter", "unit", "rate_card_id"])
75
- if (typeof meter[key] !== "string" || !/^[A-Za-z0-9_.:/-]{1,128}$/u.test(meter[key]))
76
- throw new TypeError("Invalid usage meter");
77
- for (const key of ["quantity", "charged_micros", "funded_micros", "platform_overrun_micros"])
78
- if (!amount(meter[key])) throw new TypeError("Invalid usage amount");
74
+ }
75
+ let previousDay = "";
76
+ for (const input of report["days"]) {
77
+ const day = record(input, "day,projects");
78
+ if (
79
+ typeof day["day"] !== "string" ||
80
+ !/^20[0-9]{2}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])$/u.test(day["day"]) ||
81
+ day["day"] <= previousDay ||
82
+ !Array.isArray(day["projects"]) ||
83
+ day["projects"].length > 1000
84
+ )
85
+ throw new TypeError("Invalid usage day");
86
+ previousDay = day["day"];
87
+ previous = "";
88
+ for (const projectInput of day["projects"]) {
89
+ const project = record(projectInput, "project_id,meters");
79
90
  if (
80
- BigInt(String(meter["charged_micros"])) !==
81
- BigInt(String(meter["funded_micros"])) + BigInt(String(meter["platform_overrun_micros"]))
91
+ !identifier(project["project_id"]) ||
92
+ String(project["project_id"]) <= previous ||
93
+ !Array.isArray(project["meters"]) ||
94
+ project["meters"].length > 1000
82
95
  )
83
- throw new TypeError("Inconsistent usage charge");
96
+ throw new TypeError("Invalid usage project");
97
+ previous = String(project["project_id"]);
98
+ for (const meterInput of project["meters"]) {
99
+ const meter = record(
100
+ meterInput,
101
+ "environment_id,meter,unit,rate_card_id,quantity,charged_micros",
102
+ );
103
+ if (meter["environment_id"] !== null && !identifier(meter["environment_id"]))
104
+ throw new TypeError("Invalid usage environment");
105
+ for (const key of ["meter", "unit", "rate_card_id"])
106
+ if (typeof meter[key] !== "string" || !/^[A-Za-z0-9_.:/-]{1,128}$/u.test(meter[key]))
107
+ throw new TypeError("Invalid usage meter");
108
+ if (
109
+ typeof meter["quantity"] !== "string" ||
110
+ !/^(0|[1-9][0-9]{0,29})(\.[0-9]{1,12})?$/u.test(meter["quantity"]) ||
111
+ !amount(meter["charged_micros"])
112
+ )
113
+ throw new TypeError("Invalid usage amount");
114
+ }
84
115
  }
85
116
  }
86
- if (report["next_cursor"] !== null && report["next_cursor"] !== previous)
87
- throw new TypeError("Invalid usage cursor");
88
117
  }
89
118
 
90
119
  export interface PublishedCreditRateCard {
@@ -177,7 +206,7 @@ export function assertPublishedCreditRateCards(
177
206
  }
178
207
  }
179
208
 
180
- /** Effective feature access and credit buckets from the existing ledger. */
209
+ /** Effective feature access and the credit account: the monthly and one-time credit and what the open reservations hold. */
181
210
  export function assertOrganizationAccount(value: unknown): void {
182
211
  if (
183
212
  !value ||
@@ -203,10 +232,9 @@ export function assertOrganizationAccount(value: unknown): void {
203
232
  for (const field of ["available_micros", "monthly_micros", "one_time_micros", "reserved_micros"])
204
233
  if (typeof v[field] !== "string" || !/^(0|[1-9][0-9]{0,18})$/u.test(v[field] as string))
205
234
  throw new TypeError("Invalid account credits");
206
- if (
207
- BigInt(String(v["monthly_micros"])) + BigInt(String(v["one_time_micros"])) !==
208
- BigInt(String(v["available_micros"]))
209
- )
235
+ const held = BigInt(String(v["reserved_micros"]));
236
+ const balance = BigInt(String(v["monthly_micros"])) + BigInt(String(v["one_time_micros"]));
237
+ if (BigInt(String(v["available_micros"])) !== (balance > held ? balance - held : 0n))
210
238
  throw new TypeError("Account credit buckets do not balance");
211
239
  for (const field of ["as_of", "paid_until", "next_expiry"]) {
212
240
  if (field !== "as_of" && v[field] === null) continue;
@@ -214,11 +214,6 @@ export function parseFeedbackStatus(value: unknown): FeedbackStatus {
214
214
  return v as unknown as FeedbackStatus;
215
215
  }
216
216
 
217
- /** Bounded, trimmed text without control characters other than tab and line breaks. */
218
- export function validFeedbackText(value: unknown, max: number): value is string {
219
- return validText(value, max, true);
220
- }
221
-
222
217
  function validUpdate(value: unknown): boolean {
223
218
  if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
224
219
  const v = value as Record<string, unknown>;
@@ -450,7 +450,7 @@ const FRAMEWORK_CONVERSION_DETAILS = Object.freeze({
450
450
  better_auth_version_required: {
451
451
  paths: ["manifest"],
452
452
  template:
453
- '"{{path}}" must declare better-auth at exactly 1.7.1 in dependencies because ohmyhost.yaml sets auth.provider: better-auth. Pin that version or set auth.provider: none, commit and push the change, then plan the new commit.',
453
+ '"{{path}}" must declare better-auth at exactly 1.7.7 in dependencies because ohmyhost.yaml sets auth.provider: better-auth. Pin that version or set auth.provider: none, commit and push the change, then plan the new commit.',
454
454
  },
455
455
  package_manifest_invalid: {
456
456
  paths: ["manifest"],
@@ -32,7 +32,7 @@ import { classifyFrameworkFamily } from "./framework-family.js";
32
32
  import { parseOhmyhostConfigYaml, type OhmyhostConfig } from "./index.js";
33
33
 
34
34
  /** The only better-auth release the managed auth bridge installs. */
35
- export const MANAGED_BETTER_AUTH_VERSION = "1.7.1" as const;
35
+ export const MANAGED_BETTER_AUTH_VERSION = "1.7.7" as const;
36
36
  /** The largest framework config the rules inspect, in UTF-8 bytes. */
37
37
  export const MAXIMUM_FRAMEWORK_CONFIG_BYTES = 256 * 1024;
38
38
  /** The customer Worker module of the functions runtime and of Next.js or TanStack Start crons. */
@@ -1 +1 @@
1
- PostgreSQL WebSocket bridge and authentication prelude handling adapted from cloudflare-postgres packages/cli, commit e05d9102c840e283602272ed0e16a95be3e3b8ea. Upstream license: Apache-2.0.
1
+ PostgreSQL WebSocket bridge and authentication prelude handling adapted from cloudflare-postgres (https://github.com/amerged-org/cloudflare-postgres) packages/cli, commit e05d9102c840e283602272ed0e16a95be3e3b8ea. Upstream license: Apache-2.0.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ohmyhost/sdk-ts",
3
- "version": "0.1.39",
3
+ "version": "0.1.41",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "exports": {
@@ -1930,7 +1930,7 @@ export const createOrganization = <ThrowOnError extends boolean = true>(
1930
1930
  /**
1931
1931
  * Create or resume an owner's hosted Stripe Checkout
1932
1932
  *
1933
- * Returns a human payment URL, never charges a saved card. Paid is USD 10/month; each top-up pack is USD 10 before tax; a purchase grants 100 credits per dollar up to USD 100 and 125 credits per dollar for the part above, so 10 packs grant 10000 and 20 packs grant 22500 credits. Top-ups require active Paid access and have no time limit during uninterrupted Paid membership; remaining top-ups expire when the workspace returns to Free. Monthly Paid credits expire at billing-period end without rollover. Retry the same offer, packs and Idempotency-Key after uncertainty. Browser return is not payment proof; read this checkout and the organization balance. A conflicting or existing subscription returns billing_purchase_conflict (409); read the original checkout or request an owner billing portal URL instead of another purchase. Works at zero credits.
1933
+ * Returns a human payment URL, never charges a saved card. Paid is USD 10/month; each top-up pack is USD 10 before tax; a purchase grants 100 credits per dollar up to USD 100 and 125 credits per dollar for the part above, so 10 packs grant 10000 and 20 packs grant 22500 credits. Top-ups require active Paid access and never expire, also after the workspace returns to Free. Monthly Paid credits expire at billing-period end without rollover. Retry the same offer, packs and Idempotency-Key after uncertainty. Browser return is not payment proof; read this checkout and the organization balance. A conflicting or existing subscription returns billing_purchase_conflict (409); read the original checkout or request an owner billing portal URL instead of another purchase. Works at zero credits.
1934
1934
  */
1935
1935
  export const createBillingCheckout = <ThrowOnError extends boolean = true>(
1936
1936
  parameters: {
@@ -1983,7 +1983,7 @@ export const createBillingCheckout = <ThrowOnError extends boolean = true>(
1983
1983
  /**
1984
1984
  * Observe and reconcile an owner's original checkout
1985
1985
  *
1986
- * Reads Stripe and reconciles confirmed credits/refunds idempotently. payment_confirmed describes the original Checkout, not spendable credit or current Paid entitlement. Read organization credits for available funding and the organization account's effective plan for Paid coverage; paid_until is the paid Stripe period end, not the end of renewal grace. No new purchase intent or payment is created; an uncertain original Checkout can resume using its stored identity.
1986
+ * Reads Stripe and reconciles confirmed credits/refunds idempotently. payment_confirmed describes the original Checkout, not spendable credit or current Paid entitlement. Read organization credits for available funding and the organization account's effective plan for Paid coverage; paid_until is the end of paid coverage, the paid Stripe period end plus its 14-day renewal grace. No new purchase intent or payment is created; an uncertain original Checkout can resume using its stored identity.
1987
1987
  */
1988
1988
  export const getBillingCheckout = <ThrowOnError extends boolean = true>(
1989
1989
  parameters: {
@@ -2105,7 +2105,7 @@ export const getBillingRecharge = <ThrowOnError extends boolean = true>(
2105
2105
  /**
2106
2106
  * Enable or disable explicitly authorized auto-recharge
2107
2107
  *
2108
- * Owner-only. An agent must obtain explicit approval for off-session charges and the gross monthly spending cap before enabling. Each refill costs USD 9 before tax for 1000 top-up credits when available credits fall below 100. Active Paid access is required to enable recharge and initiate a payment; remaining refill credits expire on downgrade to Free. A saved Stripe card is required; follow setup_url if returned. Current revision prevents stale edits; retry the original Idempotency-Key and payload after uncertainty. Disable prevents new charge initiation; already initiated payments may complete. No subscription or Paid features are created.
2108
+ * Owner-only. An agent must obtain explicit approval for off-session charges and the gross monthly spending cap before enabling. Each refill costs USD 9 before tax for 1000 top-up credits when available credits fall below 100. Active Paid access is required to enable recharge and initiate a payment; bought credits never expire, also after a downgrade to Free. A saved Stripe card is required; follow setup_url if returned. Current revision prevents stale edits; retry the original Idempotency-Key and payload after uncertainty. Disable prevents new charge initiation; already initiated payments may complete. No subscription or Paid features are created.
2109
2109
  */
2110
2110
  export const configureBillingRecharge = <ThrowOnError extends boolean = true>(
2111
2111
  parameters: {
@@ -2162,7 +2162,7 @@ export const configureBillingRecharge = <ThrowOnError extends boolean = true>(
2162
2162
  /**
2163
2163
  * Read the owner's shared organization credit pool
2164
2164
  *
2165
- * Returns posted credits and reservations, in microcredits (one credit is 1000000 microcredits). Monthly entitlement posting is idempotent. Only the organization Owner may read this balance. active_meters names the currently billed sources; unreported usage is not included. platform_overrun_micros is recorded platform exposure, not customer debt. Remains available at zero credit.
2165
+ * Returns the spendable credit and the open reservations, in microcredits (one credit is 1000000 microcredits). available_micros is the monthly credit plus the one-time credit minus the reservations, never below zero. Only the organization Owner may read this balance. active_meters names the currently billed sources; usage that is not billed yet is not included. When the credit is used up, grace_started_at and grace_expires_at name the seven days that keep existing services running. Remains available at zero credit.
2166
2166
  */
2167
2167
  export const getOrganizationCredits = <ThrowOnError extends boolean = true>(
2168
2168
  parameters: {
@@ -2202,16 +2202,14 @@ export const getOrganizationCredits = <ThrowOnError extends boolean = true>(
2202
2202
  };
2203
2203
 
2204
2204
  /**
2205
- * Read monthly measured usage by project and meter
2205
+ * Read recent measured usage by day, project and meter
2206
2206
  *
2207
- * Owner-only event-month ledger totals, including signed corrections posted by as_of. Returns up to 20 projects per page in ID order; use next_cursor with the same month. Current unresolved reservations are separate from measured consumption. Null environment_id means project-shared cost, never guessed Dev allocation. Only posted measurements are included; this is not a complete provider invoice or zero-usage guarantee. Billing may arrive later. No credit is granted or charged by this read; it remains usable at zero credits.
2207
+ * Owner-only. days holds the credit-log charges of the last up to 14 UTC days (today included, oldest first), grouped by day, project and meter. projects holds what each project has used so far in the current UTC month. A null environment_id means a project-shared cost, never a guessed Dev allocation. Only billed usage is included; charges may arrive later, so this is not a complete provider invoice or a zero-usage guarantee. No credit is granted or charged by this read; it remains usable at zero credits.
2208
2208
  */
2209
2209
  export const getOrganizationCreditUsage = <ThrowOnError extends boolean = true>(
2210
2210
  parameters: {
2211
2211
  "X-Request-Id"?: string;
2212
2212
  organization_id: Ulid;
2213
- month: string;
2214
- cursor?: Ulid;
2215
2213
  },
2216
2214
  options?: Options<never, ThrowOnError>,
2217
2215
  ): RequestResult<
@@ -2227,8 +2225,6 @@ export const getOrganizationCreditUsage = <ThrowOnError extends boolean = true>(
2227
2225
  args: [
2228
2226
  { in: "headers", key: "X-Request-Id" },
2229
2227
  { in: "path", key: "organization_id" },
2230
- { in: "query", key: "month" },
2231
- { in: "query", key: "cursor" },
2232
2228
  ],
2233
2229
  },
2234
2230
  ],
@@ -321,15 +321,12 @@ export type OrganizationCredits = {
321
321
  as_of: string;
322
322
  available_micros: CreditMicros;
323
323
  reserved_micros: CreditMicros;
324
- spent_micros: CreditMicros;
325
- expired_micros: CreditMicros;
326
- platform_overrun_micros: CreditMicros;
327
324
  /**
328
- * First confirmed exhaustion in this continuous period; null while funded.
325
+ * When the credit was used up; null while funded or after the monthly credit renewed.
329
326
  */
330
327
  grace_started_at: string | null;
331
328
  /**
332
- * Seven days after first confirmed exhaustion. Existing services and domains are retained during this grace; no automatic data deletion. Explicit project stop budgets are separate.
329
+ * Seven days after the credit was used up. Existing services and domains are retained during this grace; no automatic data deletion. Explicit project stop budgets are separate.
333
330
  */
334
331
  grace_expires_at: string | null;
335
332
  active_meters: Array<string>;
@@ -346,22 +343,38 @@ export type UsageTotal = string;
346
343
 
347
344
  export type OrganizationCreditUsage = {
348
345
  organization_id: Ulid;
349
- month: string;
350
346
  as_of: string;
351
347
  unit: "microcredits";
352
- next_cursor: Ulid | null;
353
- data: Array<{
348
+ /**
349
+ * The UTC month that projects[].used_micros counts.
350
+ */
351
+ period: string;
352
+ /**
353
+ * The start of the oldest UTC day in days.
354
+ */
355
+ from: string;
356
+ /**
357
+ * What each project has used so far in period, in ID order; projects without use are left out.
358
+ */
359
+ projects: Array<{
354
360
  project_id: Ulid;
355
- reserved_micros: UsageTotal;
356
- meters: Array<{
357
- environment_id: Ulid | null;
358
- meter: string;
359
- unit: string;
360
- rate_card_id: string;
361
- quantity: UsageTotal;
362
- charged_micros: UsageTotal;
363
- funded_micros: UsageTotal;
364
- platform_overrun_micros: UsageTotal;
361
+ used_micros: UsageTotal;
362
+ }>;
363
+ /**
364
+ * Billed charges of the last up to 14 UTC days, oldest first.
365
+ */
366
+ days: Array<{
367
+ day: string;
368
+ projects: Array<{
369
+ project_id: Ulid;
370
+ meters: Array<{
371
+ environment_id: Ulid | null;
372
+ meter: string;
373
+ unit: string;
374
+ rate_card_id: string;
375
+ quantity: string;
376
+ charged_micros: UsageTotal;
377
+ }>;
365
378
  }>;
366
379
  }>;
367
380
  };
@@ -384,6 +397,9 @@ export type PublishedCreditRateCard = {
384
397
  };
385
398
 
386
399
  export type SetProjectCreditBudgetRequest = {
400
+ /**
401
+ * The monthly budget, at most 9007199254740991 microcredits (about 9 billion credits); null removes it.
402
+ */
387
403
  amount_micros: CreditMicros | null;
388
404
  mode: "continue" | "stop";
389
405
  };
@@ -1264,13 +1280,28 @@ export type OrganizationAccount = {
1264
1280
  plan: "free" | "paid";
1265
1281
  plan_source: "free" | "stripe" | "granted" | "manual";
1266
1282
  /**
1267
- * End of the paid Stripe billing period or the applicable grant; null on Free or for an unbounded grant. During an unpaid renewal the effective Paid plan may remain available for up to 14 days after this Stripe period end, without new monthly credits.
1283
+ * End of the paid coverage: the Stripe billing period plus its 14-day renewal grace, or the end of the grant; null on Free. Paid features stay available until this instant.
1268
1284
  */
1269
1285
  paid_until: string | null;
1286
+ /**
1287
+ * Spendable credit: monthly plus one-time credit minus the open reservations, never below zero.
1288
+ */
1270
1289
  available_micros: CreditMicros;
1290
+ /**
1291
+ * The monthly credit, which ends at next_expiry; the Free allowance is 200 credits and the Paid allowance 1000 credits per period.
1292
+ */
1271
1293
  monthly_micros: CreditMicros;
1294
+ /**
1295
+ * Top-up, bonus and referral credit. It does not expire.
1296
+ */
1272
1297
  one_time_micros: CreditMicros;
1298
+ /**
1299
+ * Credit held for open builds; it is part of the monthly and one-time credit until the build settles.
1300
+ */
1273
1301
  reserved_micros: CreditMicros;
1302
+ /**
1303
+ * When the monthly credit ends and renews; null when none is left.
1304
+ */
1274
1305
  next_expiry: string | null;
1275
1306
  as_of: string;
1276
1307
  };
@@ -4396,10 +4427,7 @@ export type GetOrganizationCreditUsageData = {
4396
4427
  path: {
4397
4428
  organization_id: Ulid;
4398
4429
  };
4399
- query: {
4400
- month: string;
4401
- cursor?: Ulid;
4402
- };
4430
+ query?: never;
4403
4431
  url: "/v1/organizations/{organization_id}/credit-usage";
4404
4432
  };
4405
4433
 
@@ -4431,7 +4459,7 @@ export type GetOrganizationCreditUsageError =
4431
4459
 
4432
4460
  export type GetOrganizationCreditUsageResponses = {
4433
4461
  /**
4434
- * Current posted usage for the selected UTC month and project page.
4462
+ * Recent billed usage of the organization.
4435
4463
  */
4436
4464
  200: OrganizationCreditUsage;
4437
4465
  };