@howaboua/opencode-usage-plugin 0.0.2 → 0.0.3

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.
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAkD5D"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAI1C,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,CAAC,CAwD5D"}
@@ -38,7 +38,10 @@ export async function loadProxyConfig() {
38
38
  }
39
39
  try {
40
40
  const content = await file.text();
41
- const cleanJson = content.replace(/(\".*?\"|\'.*?\')|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g1) => g1 ?? "");
41
+ // Remove comments first (both // and /* */)
42
+ const withoutComments = content.replace(/(\".*?\"|\'.*?\')|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g1) => g1 ?? "");
43
+ // Remove trailing commas before closing brackets/braces
44
+ const cleanJson = withoutComments.replace(/,(\s*[}\]])/g, "$1");
42
45
  const config = JSON.parse(cleanJson);
43
46
  if (!config.endpoint) {
44
47
  throw new Error('Config must contain "endpoint" field');
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA0B,MAAM,SAAS,CAAA;AAiFpE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAiC7D"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/format.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA8B,MAAM,SAAS,CAAA;AAsGxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,aAAa,GAAG,MAAM,CAkC7D"}
@@ -48,26 +48,44 @@ function aggregateCredentialsByTier(credentials) {
48
48
  };
49
49
  for (const cred of credentials) {
50
50
  const tier = normalizeTier(cred.tier);
51
- const groups = cred.model_groups ?? {};
52
- for (const [name, group] of Object.entries(groups)) {
51
+ const groupUsage = cred.group_usage ?? {};
52
+ for (const [name, groupData] of Object.entries(groupUsage)) {
53
53
  if (!(name in GROUP_MAPPING))
54
54
  continue;
55
55
  const mappedName = GROUP_MAPPING[name];
56
+ // Find the best window from group_usage
57
+ const windows = groupData.windows || {};
58
+ let bestWindow = null;
59
+ // Priority order for windows
60
+ const windowPriority = ["daily", "5h", "1h", "15m"];
61
+ for (const windowName of windowPriority) {
62
+ if (windows[windowName]) {
63
+ bestWindow = windows[windowName];
64
+ break;
65
+ }
66
+ }
67
+ // Fallback to any available window
68
+ if (!bestWindow && Object.keys(windows).length > 0) {
69
+ bestWindow = Object.values(windows)[0];
70
+ }
71
+ if (!bestWindow)
72
+ continue;
56
73
  const existing = result[tier].get(mappedName);
57
74
  if (existing) {
58
- existing.remaining += group.requests_remaining;
59
- existing.max += group.requests_max;
60
- if (group.reset_time_iso) {
61
- if (!existing.resetTime || new Date(group.reset_time_iso) > new Date(existing.resetTime)) {
62
- existing.resetTime = group.reset_time_iso;
75
+ existing.remaining += bestWindow.remaining;
76
+ existing.max += bestWindow.limit || 0;
77
+ if (bestWindow.reset_at) {
78
+ const newResetTime = new Date(bestWindow.reset_at * 1000).toISOString();
79
+ if (!existing.resetTime || new Date(newResetTime) > new Date(existing.resetTime)) {
80
+ existing.resetTime = newResetTime;
63
81
  }
64
82
  }
65
83
  }
66
84
  else {
67
85
  result[tier].set(mappedName, {
68
- remaining: group.requests_remaining,
69
- max: group.requests_max,
70
- resetTime: group.reset_time_iso,
86
+ remaining: bestWindow.remaining,
87
+ max: bestWindow.limit || bestWindow.remaining,
88
+ resetTime: bestWindow.reset_at ? new Date(bestWindow.reset_at * 1000).toISOString() : null,
71
89
  });
72
90
  }
73
91
  }
@@ -84,7 +102,8 @@ export function formatProxyLimits(data) {
84
102
  }
85
103
  for (const [providerName, provider] of Object.entries(data.providers)) {
86
104
  lines.push(`${providerName}:`);
87
- const tierData = aggregateCredentialsByTier(provider.credentials ?? []);
105
+ const credentialsArray = Object.values(provider.credentials ?? {});
106
+ const tierData = aggregateCredentialsByTier(credentialsArray);
88
107
  for (const [tierName, quotas] of Object.entries(tierData)) {
89
108
  if (quotas.size === 0)
90
109
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAM5C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA8F5C,eAAO,MAAM,aAAa,EAAE,aAwB3B,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAM5C,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAC1C,OAAO,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAC1C,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA+I5C,eAAO,MAAM,aAAa,EAAE,aAwB3B,CAAA"}
@@ -11,31 +11,70 @@ const GROUP_MAPPING = {
11
11
  "claude": "claude",
12
12
  "g3-pro": "g3-pro",
13
13
  "g3-flash": "g3-fla",
14
+ "g25-flash": "25-flash",
15
+ "g25-lite": "25-lite",
14
16
  "pro": "g3-pro",
15
- "3-flash": "g3-fla"
17
+ "3-flash": "g3-fla",
18
+ "25-flash": "25-flash",
19
+ "25-lite": "25-lite"
16
20
  };
17
21
  function normalizeTier(tier) {
18
22
  if (!tier)
19
23
  return "free";
20
24
  return tier.includes("free") ? "free" : "paid";
21
25
  }
22
- function parseQuotaGroupsFromCredential(modelGroups) {
23
- if (!modelGroups)
26
+ /**
27
+ * Extract quota groups from group_usage data
28
+ * New API structure: group_usage[groupName].windows[windowName]
29
+ */
30
+ function parseQuotaGroupsFromCredential(groupUsage) {
31
+ if (!groupUsage)
24
32
  return [];
25
- return Object.entries(modelGroups)
26
- .filter(([name]) => name in GROUP_MAPPING)
27
- .map(([name, group]) => {
28
- const realRemainingPct = group.requests_max > 0
29
- ? Math.round((group.requests_remaining / group.requests_max) * 100)
30
- : 0;
31
- return {
32
- name: GROUP_MAPPING[name],
33
- remaining: group.requests_remaining,
34
- max: group.requests_max,
35
- remainingPct: realRemainingPct,
36
- resetTime: group.reset_time_iso,
37
- };
38
- });
33
+ const result = new Map();
34
+ for (const [groupName, groupData] of Object.entries(groupUsage)) {
35
+ const mappedName = GROUP_MAPPING[groupName];
36
+ if (!mappedName)
37
+ continue;
38
+ // Find the window with the best data (prefer daily, then 5h, then any)
39
+ const windows = groupData.windows || {};
40
+ let bestWindow = null;
41
+ // Priority order for windows
42
+ const windowPriority = ["daily", "5h", "1h", "15m"];
43
+ for (const windowName of windowPriority) {
44
+ if (windows[windowName]) {
45
+ bestWindow = windows[windowName];
46
+ break;
47
+ }
48
+ }
49
+ // Fallback to any available window
50
+ if (!bestWindow && Object.keys(windows).length > 0) {
51
+ bestWindow = Object.values(windows)[0];
52
+ }
53
+ if (!bestWindow)
54
+ continue;
55
+ const existing = result.get(mappedName);
56
+ if (existing) {
57
+ existing.remaining += bestWindow.remaining;
58
+ existing.max += bestWindow.limit || 0;
59
+ // Use the latest reset time
60
+ if (bestWindow.reset_at) {
61
+ const newResetTime = new Date(bestWindow.reset_at * 1000).toISOString();
62
+ if (!existing.resetTime || new Date(newResetTime) > new Date(existing.resetTime)) {
63
+ existing.resetTime = newResetTime;
64
+ }
65
+ }
66
+ }
67
+ else {
68
+ result.set(mappedName, {
69
+ name: mappedName,
70
+ remaining: bestWindow.remaining,
71
+ max: bestWindow.limit || bestWindow.remaining,
72
+ remainingPct: bestWindow.limit ? Math.round((bestWindow.remaining / bestWindow.limit) * 100) : 0,
73
+ resetTime: bestWindow.reset_at ? new Date(bestWindow.reset_at * 1000).toISOString() : null,
74
+ });
75
+ }
76
+ }
77
+ return Array.from(result.values());
39
78
  }
40
79
  function aggregateByTier(credentials) {
41
80
  const tiers = {
@@ -44,7 +83,7 @@ function aggregateByTier(credentials) {
44
83
  };
45
84
  for (const cred of credentials) {
46
85
  const tier = normalizeTier(cred.tier);
47
- const groups = parseQuotaGroupsFromCredential(cred.model_groups);
86
+ const groups = parseQuotaGroupsFromCredential(cred.group_usage);
48
87
  for (const group of groups) {
49
88
  const existing = tiers[tier].get(group.name);
50
89
  if (existing) {
@@ -76,13 +115,17 @@ function aggregateByTier(credentials) {
76
115
  function parseProviders(data) {
77
116
  if (!data.providers)
78
117
  return [];
79
- return Object.entries(data.providers).map(([name, provider]) => ({
80
- name,
81
- tiers: aggregateByTier(provider.credentials ?? []),
82
- }));
118
+ return Object.entries(data.providers).map(([name, provider]) => {
119
+ // Convert credentials object to array
120
+ const credentialsArray = Object.values(provider.credentials || {});
121
+ return {
122
+ name,
123
+ tiers: aggregateByTier(credentialsArray),
124
+ };
125
+ });
83
126
  }
84
127
  function parseProxyQuota(data) {
85
- const summary = data.global_summary ?? data.summary;
128
+ const summary = data.summary;
86
129
  return {
87
130
  providers: parseProviders(data),
88
131
  totalCredentials: summary?.total_credentials ?? 0,
@@ -13,96 +13,116 @@ export type ProxyConfig = {
13
13
  };
14
14
  /** Token statistics from the proxy */
15
15
  export type TokenStats = {
16
- input_cached: number;
17
- input_uncached: number;
18
- input_cache_pct: number;
19
- output: number;
16
+ input_cached?: number;
17
+ input_uncached?: number;
18
+ input_cache_pct?: number;
19
+ output?: number;
20
+ prompt_tokens?: number;
21
+ completion_tokens?: number;
22
+ thinking_tokens?: number;
23
+ output_tokens?: number;
24
+ prompt_tokens_cache_read?: number;
25
+ prompt_tokens_cache_write?: number;
26
+ total_tokens?: number;
27
+ request_count?: number;
28
+ success_count?: number;
29
+ failure_count?: number;
30
+ approx_cost?: number;
20
31
  };
21
- /** Quota group aggregation */
22
- export type QuotaGroup = {
23
- avg_remaining_pct: number;
24
- credentials_exhausted: number;
25
- credentials_total: number;
26
- models: string[];
27
- tiers: Record<string, {
28
- active: number;
32
+ /** Window-based quota information */
33
+ export type WindowQuota = {
34
+ limit?: number;
35
+ remaining: number;
36
+ reset_at?: number | null;
37
+ request_count?: number;
38
+ success_count?: number;
39
+ failure_count?: number;
40
+ total_used?: number;
41
+ total_remaining?: number;
42
+ total_max?: number;
43
+ remaining_pct?: number;
44
+ };
45
+ /** Model group usage information */
46
+ export type GroupUsageWindow = {
47
+ [windowName: string]: WindowQuota;
48
+ };
49
+ export type GroupUsage = {
50
+ windows: GroupUsageWindow;
51
+ totals: TokenStats;
52
+ fair_cycle_exhausted?: boolean;
53
+ fair_cycle_reason?: string | null;
54
+ cooldown_remaining?: number | null;
55
+ cooldown_source?: string | null;
56
+ custom_cap?: number | null;
57
+ };
58
+ /** Model usage information */
59
+ export type ModelUsage = {
60
+ windows: GroupUsageWindow;
61
+ totals: TokenStats;
62
+ };
63
+ /** Tier availability info */
64
+ export type TierAvailability = {
65
+ total: number;
66
+ available: number;
67
+ };
68
+ /** Tier window info */
69
+ export type TierWindow = {
70
+ total_used: number;
71
+ total_remaining: number;
72
+ total_max: number;
73
+ remaining_pct: number;
74
+ tier_availability: Record<string, TierAvailability>;
75
+ };
76
+ /** Model group tiers */
77
+ export type GroupTiers = {
78
+ [tierName: string]: {
29
79
  priority: number;
30
80
  total: number;
31
- }>;
32
- total_remaining_pct: number;
33
- total_requests_max: number;
34
- total_requests_remaining: number;
35
- total_requests_used: number;
81
+ };
36
82
  };
37
- /** Model quota information */
38
- export type ModelQuota = {
39
- requests: number;
40
- request_count: number;
41
- success_count: number;
42
- failure_count: number;
43
- prompt_tokens: number;
44
- prompt_tokens_cached: number;
45
- completion_tokens: number;
46
- approx_cost: number;
47
- window_start_ts: number | null;
48
- quota_reset_ts: number | null;
49
- baseline_remaining_fraction: number | null;
50
- baseline_fetched_at: number | null;
51
- quota_max_requests: number;
52
- quota_display: string;
83
+ /** Fair cycle summary */
84
+ export type FairCycleSummary = {
85
+ exhausted_count: number;
86
+ total_count: number;
53
87
  };
54
- /** Model group information */
55
- export type ModelGroup = {
56
- confidence: string;
57
- display: string;
58
- is_exhausted: boolean;
59
- models: string[];
60
- remaining_pct: number;
61
- requests_max: number;
62
- requests_remaining: number;
63
- requests_used: number;
64
- reset_time_iso: string | null;
88
+ /** Model group aggregation */
89
+ export type ModelGroupAggregation = {
90
+ tiers: GroupTiers;
91
+ windows: {
92
+ [windowName: string]: TierWindow;
93
+ };
94
+ fair_cycle_summary: FairCycleSummary;
65
95
  };
66
- /** Credential information */
67
- export type Credential = {
68
- identifier: string;
96
+ /** Credential information from new API */
97
+ export type CredentialData = {
98
+ stable_id: string;
99
+ accessor_masked?: string;
69
100
  full_path: string;
70
- status: string;
71
- last_used_ts: number;
101
+ identifier: string;
102
+ email?: string | null;
72
103
  tier?: string;
73
- requests: number;
74
- tokens: TokenStats;
75
- approx_cost: number | null;
76
- global: {
77
- requests: number;
78
- tokens: TokenStats;
79
- approx_cost: number | null;
80
- };
81
- models: Record<string, ModelQuota>;
82
- model_groups?: Record<string, ModelGroup>;
104
+ priority?: number;
105
+ active_requests?: number;
106
+ status: string;
107
+ totals: TokenStats;
108
+ model_usage?: Record<string, ModelUsage>;
109
+ group_usage?: Record<string, GroupUsage>;
110
+ last_used_at?: number;
111
+ first_used_at?: number;
83
112
  };
84
- /** Provider information */
113
+ /** Provider information from new API */
85
114
  export type Provider = {
115
+ provider: string;
86
116
  credential_count: number;
87
- active_count: number;
88
- on_cooldown_count: number;
89
- exhausted_count: number;
90
- total_requests: number;
91
- tokens: TokenStats;
92
- approx_cost: number | null;
93
- credentials: Credential[];
94
- quota_groups?: Record<string, QuotaGroup>;
95
- global?: {
96
- approx_cost: number | null;
97
- tokens: TokenStats;
98
- total_requests: number;
99
- };
117
+ rotation_mode?: string;
118
+ credentials: Record<string, CredentialData>;
119
+ quota_groups?: Record<string, ModelGroupAggregation>;
100
120
  };
101
- /** Summary statistics */
121
+ /** Summary statistics from new API */
102
122
  export type Summary = {
103
- total_providers: number;
123
+ total_providers?: number;
104
124
  total_credentials: number;
105
- active_credentials?: number;
125
+ active_credentials: number;
106
126
  exhausted_credentials?: number;
107
127
  total_requests: number;
108
128
  tokens: TokenStats;
@@ -112,7 +132,6 @@ export type Summary = {
112
132
  export type ProxyResponse = {
113
133
  providers: Record<string, Provider>;
114
134
  summary: Summary;
115
- global_summary?: Summary;
116
135
  data_source: string;
117
136
  timestamp: number;
118
137
  };
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/proxy/types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/ui/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,KAAK,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAExC,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBhB;AA0GD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,aAAa,EAAE,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhB"}
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/ui/status.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAA;AACtD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAE1C,KAAK,WAAW,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAExC,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;CACb,GAAG,OAAO,CAAC,IAAI,CAAC,CAwChB;AA0GD,wBAAsB,iBAAiB,CAAC,OAAO,EAAE;IAC/C,MAAM,EAAE,WAAW,CAAA;IACnB,KAAK,EAAE,UAAU,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,aAAa,EAAE,CAAA;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6BhB"}
package/dist/ui/status.js CHANGED
@@ -2,25 +2,45 @@
2
2
  * Renders usage snapshots into readable status text.
3
3
  */
4
4
  export async function sendStatusMessage(options) {
5
- const sent = await options.client.session
5
+ // 1. Send to Companion via Bus
6
+ // @ts-ignore
7
+ const bus = options.client.bus;
8
+ if (bus) {
9
+ try {
10
+ await bus.publish({
11
+ topic: "companion.projection",
12
+ body: {
13
+ key: "usage",
14
+ kind: "markdown",
15
+ content: options.text,
16
+ },
17
+ });
18
+ }
19
+ catch { }
20
+ }
21
+ // 2. Send plain message to TUI
22
+ await options.client.session
6
23
  .prompt({
7
24
  path: { id: options.sessionID },
8
25
  body: {
9
26
  noReply: true,
10
- agent: options.state.agent,
11
- model: options.state.model,
12
- parts: [{ type: "text", text: options.text, ignored: true }],
27
+ parts: [
28
+ {
29
+ type: "text",
30
+ text: options.text,
31
+ ignored: true,
32
+ },
33
+ ],
13
34
  },
14
35
  })
15
- .then(() => true)
16
- .catch(() => false);
17
- if (sent)
18
- return;
19
- await options.client.tui
20
- .showToast({
21
- body: { title: "Usage Status", message: options.text, variant: "info" },
22
- })
23
- .catch(() => { });
36
+ .catch(async () => {
37
+ // 3. Fallback: Toast
38
+ await options.client.tui
39
+ .showToast({
40
+ body: { title: "Usage Status", message: options.text, variant: "info" },
41
+ })
42
+ .catch(() => { });
43
+ });
24
44
  }
25
45
  function formatBar(remainingPercent) {
26
46
  const clamped = Math.max(0, Math.min(100, remainingPercent));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howaboua/opencode-usage-plugin",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "OpenCode plugin for tracking AI provider usage, rate limits, and quotas",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",