@vibeiao/sdk 0.1.9 → 0.1.10

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
@@ -126,6 +126,75 @@ The onboarding CLI injects this automatically; keep it intact.
126
126
 
127
127
  When funds are critical, **pause paid work but keep memory updates on**. Survival depends on preserving state.
128
128
 
129
+ ## Multi-API Survival Checks
130
+ Self-reliance can now monitor multiple API credit pools, not only OpenRouter.
131
+
132
+ Use `apiCreditProviders` to report any provider balance into `snapshot.apiCredits`, then enforce policy thresholds with `apiMinCredits` / `apiWarnCredits`.
133
+
134
+ Important:
135
+ - Provider keys are optional overall (agents can run non-LLM services without them).
136
+ - If a listing/runtime depends on a provider and no key is present, ask the human owner to provision that provider key.
137
+ - The SDK cannot auto-discover third-party balances unless you configure adapters/endpoints.
138
+
139
+ ```ts
140
+ import { SelfReliance, createSelfReliancePolicy, getResourceSnapshot } from '@vibeiao/sdk';
141
+
142
+ const survival = new SelfReliance({
143
+ policy: createSelfReliancePolicy({
144
+ apiMinCredits: { openrouter: 1, anthropic: 2, customproxy: 10 },
145
+ apiWarnCredits: { openrouter: 5, anthropic: 8, customproxy: 25 },
146
+ }),
147
+ });
148
+
149
+ const snapshot = await getResourceSnapshot({
150
+ connection,
151
+ wallet,
152
+ openRouterApiKey: process.env.OPENROUTER_API_KEY,
153
+ apiCreditProviders: [
154
+ { name: 'anthropic', fetchCredits: async () => Number(await readAnthropicCredits()) },
155
+ { name: 'customproxy', fetchCredits: async () => Number(await readProxyCredits()) },
156
+ ],
157
+ });
158
+
159
+ survival.update(snapshot);
160
+ const allowed = await survival.guard();
161
+ ```
162
+
163
+ ### Manifest-driven provider adapters
164
+ You can declare providers in manifest and build adapters automatically:
165
+
166
+ ```json
167
+ {
168
+ "resourceProviders": [
169
+ { "provider": "openrouter", "apiKeyEnv": "OPENROUTER_API_KEY" },
170
+ { "provider": "anthropic", "apiKeyEnv": "ANTHROPIC_API_KEY", "endpoint": "https://your-billing-proxy.example.com/credits", "creditsPath": "data.remaining" }
171
+ ]
172
+ }
173
+ ```
174
+
175
+ ```ts
176
+ import {
177
+ createApiCreditProvidersFromManifest,
178
+ assertSurvivalProvidersConfigured,
179
+ getResourceSnapshot,
180
+ } from '@vibeiao/sdk';
181
+
182
+ const providers = await createApiCreditProvidersFromManifest(manifest, {
183
+ resolveSecret: async (name) => process.env[name],
184
+ });
185
+
186
+ assertSurvivalProvidersConfigured(policy, providers, {
187
+ hasOpenRouterApiKey: Boolean(process.env.OPENROUTER_API_KEY),
188
+ });
189
+
190
+ const snapshot = await getResourceSnapshot({
191
+ connection,
192
+ wallet,
193
+ apiCreditProviders: providers,
194
+ openRouterApiKey: process.env.OPENROUTER_API_KEY,
195
+ });
196
+ ```
197
+
129
198
  ## Memory Versioning & Upgrades
130
199
  Memory layout is versioned to allow future improvements without breaking older agents.
131
200
  - Current schema: `v1`
@@ -0,0 +1,202 @@
1
+ // src/selfReliance.ts
2
+ var now = () => Date.now();
3
+ var OPENROUTER_RESOURCE_KEY = "openrouter";
4
+ var sanitizeCreditMap = (value) => {
5
+ if (!value) return void 0;
6
+ const entries = Object.entries(value).map(([name, amount]) => [name.trim().toLowerCase(), Number(amount)]).filter(([name, amount]) => Boolean(name) && Number.isFinite(amount));
7
+ if (!entries.length) return void 0;
8
+ return Object.fromEntries(entries);
9
+ };
10
+ var SelfReliance = class {
11
+ policy;
12
+ events;
13
+ state;
14
+ constructor(config) {
15
+ this.policy = config.policy;
16
+ this.events = config.events || {};
17
+ this.state = {};
18
+ }
19
+ update(snapshot) {
20
+ const currentApiCredits = this.state.apiCredits || {};
21
+ const incomingApiCredits = sanitizeCreditMap(snapshot.apiCredits) || {};
22
+ if (snapshot.openRouterCredits !== void 0) {
23
+ incomingApiCredits[OPENROUTER_RESOURCE_KEY] = snapshot.openRouterCredits;
24
+ }
25
+ const mergedApiCredits = {
26
+ ...currentApiCredits,
27
+ ...incomingApiCredits
28
+ };
29
+ const nextOpenRouterCredits = snapshot.openRouterCredits ?? mergedApiCredits[OPENROUTER_RESOURCE_KEY] ?? this.state.openRouterCredits;
30
+ this.state = {
31
+ ...this.state,
32
+ solBalance: snapshot.solBalance ?? this.state.solBalance,
33
+ openRouterCredits: nextOpenRouterCredits,
34
+ apiCredits: Object.keys(mergedApiCredits).length ? mergedApiCredits : this.state.apiCredits,
35
+ lastUpdatedAt: snapshot.updatedAt ?? now()
36
+ };
37
+ return this.state;
38
+ }
39
+ getState() {
40
+ return { ...this.state };
41
+ }
42
+ isLow() {
43
+ return this.shouldDeny();
44
+ }
45
+ shouldDeny() {
46
+ const { solMinBalance, openRouterMinCredits, denyMode = "all", solHardMin } = this.policy;
47
+ const solBalance = this.state.solBalance;
48
+ if (solHardMin !== void 0 && solBalance !== void 0 && solBalance < solHardMin) {
49
+ return true;
50
+ }
51
+ const signals = [];
52
+ const solTracked = solBalance !== void 0 && Number.isFinite(solMinBalance);
53
+ if (solTracked) {
54
+ signals.push(solBalance < solMinBalance);
55
+ }
56
+ const creditsTracked = openRouterMinCredits !== void 0 && this.state.openRouterCredits !== void 0;
57
+ if (creditsTracked) {
58
+ signals.push(this.state.openRouterCredits < openRouterMinCredits);
59
+ }
60
+ const apiMinCredits = sanitizeCreditMap(this.policy.apiMinCredits);
61
+ if (apiMinCredits && this.state.apiCredits) {
62
+ for (const [resource, min] of Object.entries(apiMinCredits)) {
63
+ const current = this.state.apiCredits[resource];
64
+ if (current !== void 0) {
65
+ signals.push(current < min);
66
+ }
67
+ }
68
+ }
69
+ if (!signals.length) return false;
70
+ return denyMode === "all" ? signals.every(Boolean) : signals.some(Boolean);
71
+ }
72
+ shouldWarn() {
73
+ const { solWarnBalance, openRouterWarnCredits, warnIntervalMs = 3e5 } = this.policy;
74
+ const solWarn = this.state.solBalance !== void 0 && Number.isFinite(solWarnBalance) && this.state.solBalance < solWarnBalance;
75
+ const creditsWarn = openRouterWarnCredits !== void 0 && this.state.openRouterCredits !== void 0 && this.state.openRouterCredits < openRouterWarnCredits;
76
+ let apiWarn = false;
77
+ const apiWarnCredits = sanitizeCreditMap(this.policy.apiWarnCredits);
78
+ if (apiWarnCredits && this.state.apiCredits) {
79
+ for (const [resource, min] of Object.entries(apiWarnCredits)) {
80
+ const current = this.state.apiCredits[resource];
81
+ if (current !== void 0 && current < min) {
82
+ apiWarn = true;
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ if (!solWarn && !creditsWarn && !apiWarn) return false;
88
+ const lastWarnAt = this.state.lastWarnAt ?? 0;
89
+ return now() - lastWarnAt > warnIntervalMs;
90
+ }
91
+ async enforce() {
92
+ if (this.isLow()) {
93
+ if (this.events.onCritical) {
94
+ this.events.onCritical(this.getState());
95
+ }
96
+ if (this.events.onPersist) {
97
+ await this.events.onPersist(this.getState());
98
+ }
99
+ return this.policy.allowIfLow ? "allow" : "deny";
100
+ }
101
+ if (this.shouldWarn()) {
102
+ this.state.lastWarnAt = now();
103
+ if (this.events.onWarn) {
104
+ this.events.onWarn(this.getState());
105
+ }
106
+ }
107
+ return "allow";
108
+ }
109
+ guard = async () => {
110
+ const decision = await this.enforce();
111
+ return decision === "allow";
112
+ };
113
+ };
114
+ var createSelfReliancePolicy = (overrides = {}) => ({
115
+ solMinBalance: 0.01,
116
+ solWarnBalance: 0.05,
117
+ openRouterMinCredits: 1,
118
+ openRouterWarnCredits: 5,
119
+ apiMinCredits: { openrouter: 1 },
120
+ apiWarnCredits: { openrouter: 5 },
121
+ allowIfLow: false,
122
+ denyMode: "all",
123
+ warnIntervalMs: 3e5,
124
+ criticalOnly: false,
125
+ ...overrides
126
+ });
127
+ var createSurvivalMiddleware = (survival, options = {}) => {
128
+ const errorStatus = options.errorStatus ?? 402;
129
+ const errorPayload = options.errorPayload ?? { error: "survival_low_funds" };
130
+ return async (req, res, next) => {
131
+ const allowed = await survival.guard();
132
+ const state = survival.getState();
133
+ if (!allowed) {
134
+ if (options.onDeny) {
135
+ options.onDeny(state);
136
+ }
137
+ res.status(errorStatus).json(errorPayload);
138
+ return;
139
+ }
140
+ next();
141
+ };
142
+ };
143
+ var withSurvival = async (survival, handler, options = {}) => {
144
+ const allowed = await survival.guard();
145
+ if (!allowed) {
146
+ if (options.onDeny) {
147
+ options.onDeny(survival.getState());
148
+ }
149
+ throw new Error("survival_low_funds");
150
+ }
151
+ return handler();
152
+ };
153
+ var createSelfRelianceMonitor = (survival, fetchSnapshot, config = {}) => {
154
+ const intervalMs = config.intervalMs ?? 3e4;
155
+ let timer = null;
156
+ let stopped = false;
157
+ const runOnce = async () => {
158
+ try {
159
+ const snapshot = await fetchSnapshot();
160
+ const state = survival.update(snapshot);
161
+ if (config.onUpdate) {
162
+ config.onUpdate(snapshot, state);
163
+ }
164
+ await survival.enforce();
165
+ } catch (err) {
166
+ if (config.onError) {
167
+ config.onError(err instanceof Error ? err : new Error("monitor_failed"));
168
+ }
169
+ }
170
+ };
171
+ const start = async () => {
172
+ if (timer) return;
173
+ await runOnce();
174
+ if (stopped) return;
175
+ timer = setInterval(runOnce, intervalMs);
176
+ };
177
+ const stop = () => {
178
+ stopped = true;
179
+ if (timer) {
180
+ clearInterval(timer);
181
+ timer = null;
182
+ }
183
+ };
184
+ return { start, stop, runOnce };
185
+ };
186
+ var createAutoSelfReliance = (options) => {
187
+ const { survival, fetchSnapshot, intervalMs, onUpdate, onError } = options;
188
+ return createSelfRelianceMonitor(survival, fetchSnapshot, {
189
+ intervalMs,
190
+ onUpdate,
191
+ onError
192
+ });
193
+ };
194
+
195
+ export {
196
+ SelfReliance,
197
+ createSelfReliancePolicy,
198
+ createSurvivalMiddleware,
199
+ withSurvival,
200
+ createSelfRelianceMonitor,
201
+ createAutoSelfReliance
202
+ };
@@ -0,0 +1,204 @@
1
+ // src/selfReliance.ts
2
+ var now = () => Date.now();
3
+ var OPENROUTER_RESOURCE_KEY = "openrouter";
4
+ var sanitizeCreditMap = (value) => {
5
+ if (!value) return void 0;
6
+ const entries = Object.entries(value).map(([name, amount]) => [name.trim().toLowerCase(), Number(amount)]).filter(([name, amount]) => Boolean(name) && Number.isFinite(amount));
7
+ if (!entries.length) return void 0;
8
+ return Object.fromEntries(entries);
9
+ };
10
+ var SelfReliance = class {
11
+ policy;
12
+ events;
13
+ state;
14
+ constructor(config) {
15
+ this.policy = config.policy;
16
+ this.events = config.events || {};
17
+ this.state = {};
18
+ }
19
+ update(snapshot) {
20
+ const currentApiCredits = this.state.apiCredits || {};
21
+ const incomingApiCredits = sanitizeCreditMap(snapshot.apiCredits) || {};
22
+ if (snapshot.openRouterCredits !== void 0) {
23
+ incomingApiCredits[OPENROUTER_RESOURCE_KEY] = snapshot.openRouterCredits;
24
+ }
25
+ const mergedApiCredits = {
26
+ ...currentApiCredits,
27
+ ...incomingApiCredits
28
+ };
29
+ const nextOpenRouterCredits = snapshot.openRouterCredits ?? mergedApiCredits[OPENROUTER_RESOURCE_KEY] ?? this.state.openRouterCredits;
30
+ this.state = {
31
+ ...this.state,
32
+ solBalance: snapshot.solBalance ?? this.state.solBalance,
33
+ openRouterCredits: nextOpenRouterCredits,
34
+ apiCredits: Object.keys(mergedApiCredits).length ? mergedApiCredits : this.state.apiCredits,
35
+ lastUpdatedAt: snapshot.updatedAt ?? now()
36
+ };
37
+ return this.state;
38
+ }
39
+ getState() {
40
+ return { ...this.state };
41
+ }
42
+ isLow() {
43
+ return this.shouldDeny();
44
+ }
45
+ shouldDeny() {
46
+ const { solMinBalance, openRouterMinCredits, denyMode = "all", solHardMin } = this.policy;
47
+ const solBalance = this.state.solBalance;
48
+ if (solHardMin !== void 0 && solBalance !== void 0 && solBalance < solHardMin) {
49
+ return true;
50
+ }
51
+ const signals = [];
52
+ const solTracked = solBalance !== void 0 && Number.isFinite(solMinBalance);
53
+ if (solTracked) {
54
+ signals.push(solBalance < solMinBalance);
55
+ }
56
+ const apiMinCredits = sanitizeCreditMap(this.policy.apiMinCredits);
57
+ const shouldUseLegacyOpenRouterMin = openRouterMinCredits !== void 0 && (!apiMinCredits || apiMinCredits[OPENROUTER_RESOURCE_KEY] === void 0);
58
+ const creditsTracked = shouldUseLegacyOpenRouterMin && this.state.openRouterCredits !== void 0;
59
+ if (creditsTracked) {
60
+ signals.push(this.state.openRouterCredits < openRouterMinCredits);
61
+ }
62
+ if (apiMinCredits && this.state.apiCredits) {
63
+ for (const [resource, min] of Object.entries(apiMinCredits)) {
64
+ const current = this.state.apiCredits[resource];
65
+ if (current !== void 0) {
66
+ signals.push(current < min);
67
+ }
68
+ }
69
+ }
70
+ if (!signals.length) return false;
71
+ return denyMode === "all" ? signals.every(Boolean) : signals.some(Boolean);
72
+ }
73
+ shouldWarn() {
74
+ const { solWarnBalance, openRouterWarnCredits, warnIntervalMs = 3e5 } = this.policy;
75
+ const solWarn = this.state.solBalance !== void 0 && Number.isFinite(solWarnBalance) && this.state.solBalance < solWarnBalance;
76
+ const apiWarnCredits = sanitizeCreditMap(this.policy.apiWarnCredits);
77
+ const shouldUseLegacyOpenRouterWarn = openRouterWarnCredits !== void 0 && (!apiWarnCredits || apiWarnCredits[OPENROUTER_RESOURCE_KEY] === void 0);
78
+ const creditsWarn = shouldUseLegacyOpenRouterWarn && this.state.openRouterCredits !== void 0 && this.state.openRouterCredits < openRouterWarnCredits;
79
+ let apiWarn = false;
80
+ if (apiWarnCredits && this.state.apiCredits) {
81
+ for (const [resource, min] of Object.entries(apiWarnCredits)) {
82
+ const current = this.state.apiCredits[resource];
83
+ if (current !== void 0 && current < min) {
84
+ apiWarn = true;
85
+ break;
86
+ }
87
+ }
88
+ }
89
+ if (!solWarn && !creditsWarn && !apiWarn) return false;
90
+ const lastWarnAt = this.state.lastWarnAt ?? 0;
91
+ return now() - lastWarnAt > warnIntervalMs;
92
+ }
93
+ async enforce() {
94
+ if (this.isLow()) {
95
+ if (this.events.onCritical) {
96
+ this.events.onCritical(this.getState());
97
+ }
98
+ if (this.events.onPersist) {
99
+ await this.events.onPersist(this.getState());
100
+ }
101
+ return this.policy.allowIfLow ? "allow" : "deny";
102
+ }
103
+ if (this.shouldWarn()) {
104
+ this.state.lastWarnAt = now();
105
+ if (this.events.onWarn) {
106
+ this.events.onWarn(this.getState());
107
+ }
108
+ }
109
+ return "allow";
110
+ }
111
+ guard = async () => {
112
+ const decision = await this.enforce();
113
+ return decision === "allow";
114
+ };
115
+ };
116
+ var createSelfReliancePolicy = (overrides = {}) => ({
117
+ solMinBalance: 0.01,
118
+ solWarnBalance: 0.05,
119
+ openRouterMinCredits: 1,
120
+ openRouterWarnCredits: 5,
121
+ apiMinCredits: { openrouter: 1 },
122
+ apiWarnCredits: { openrouter: 5 },
123
+ allowIfLow: false,
124
+ denyMode: "all",
125
+ warnIntervalMs: 3e5,
126
+ criticalOnly: false,
127
+ ...overrides
128
+ });
129
+ var createSurvivalMiddleware = (survival, options = {}) => {
130
+ const errorStatus = options.errorStatus ?? 402;
131
+ const errorPayload = options.errorPayload ?? { error: "survival_low_funds" };
132
+ return async (req, res, next) => {
133
+ const allowed = await survival.guard();
134
+ const state = survival.getState();
135
+ if (!allowed) {
136
+ if (options.onDeny) {
137
+ options.onDeny(state);
138
+ }
139
+ res.status(errorStatus).json(errorPayload);
140
+ return;
141
+ }
142
+ next();
143
+ };
144
+ };
145
+ var withSurvival = async (survival, handler, options = {}) => {
146
+ const allowed = await survival.guard();
147
+ if (!allowed) {
148
+ if (options.onDeny) {
149
+ options.onDeny(survival.getState());
150
+ }
151
+ throw new Error("survival_low_funds");
152
+ }
153
+ return handler();
154
+ };
155
+ var createSelfRelianceMonitor = (survival, fetchSnapshot, config = {}) => {
156
+ const intervalMs = config.intervalMs ?? 3e4;
157
+ let timer = null;
158
+ let stopped = false;
159
+ const runOnce = async () => {
160
+ try {
161
+ const snapshot = await fetchSnapshot();
162
+ const state = survival.update(snapshot);
163
+ if (config.onUpdate) {
164
+ config.onUpdate(snapshot, state);
165
+ }
166
+ await survival.enforce();
167
+ } catch (err) {
168
+ if (config.onError) {
169
+ config.onError(err instanceof Error ? err : new Error("monitor_failed"));
170
+ }
171
+ }
172
+ };
173
+ const start = async () => {
174
+ if (timer) return;
175
+ await runOnce();
176
+ if (stopped) return;
177
+ timer = setInterval(runOnce, intervalMs);
178
+ };
179
+ const stop = () => {
180
+ stopped = true;
181
+ if (timer) {
182
+ clearInterval(timer);
183
+ timer = null;
184
+ }
185
+ };
186
+ return { start, stop, runOnce };
187
+ };
188
+ var createAutoSelfReliance = (options) => {
189
+ const { survival, fetchSnapshot, intervalMs, onUpdate, onError } = options;
190
+ return createSelfRelianceMonitor(survival, fetchSnapshot, {
191
+ intervalMs,
192
+ onUpdate,
193
+ onError
194
+ });
195
+ };
196
+
197
+ export {
198
+ SelfReliance,
199
+ createSelfReliancePolicy,
200
+ createSurvivalMiddleware,
201
+ withSurvival,
202
+ createSelfRelianceMonitor,
203
+ createAutoSelfReliance
204
+ };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as _solana_web3_js from '@solana/web3.js';
2
2
  import { L as ListingRecord, a as ListingType, b as ListingStatus, C as ClaimPurpose, c as ClaimResponse, V as VerifiedClaimResponse, d as ListingInput, e as ListingReviewRecord, T as TicketVerifyResponse } from './solana-3VMnBZH6.js';
3
3
  export { f as fetchSolBalance, g as fetchTokenBalance, h as fetchTokenBalances } from './solana-3VMnBZH6.js';
4
+ import { SelfReliancePolicy } from './selfReliance.js';
4
5
  export { SelfReliance, createAutoSelfReliance, createSelfRelianceMonitor, createSelfReliancePolicy, createSurvivalMiddleware, withSurvival } from './selfReliance.js';
5
6
  import '@coral-xyz/anchor';
6
7
 
@@ -737,9 +738,43 @@ type OpenRouterCredits = {
737
738
  type ResourceSnapshot = {
738
739
  solBalance?: number;
739
740
  openRouterCredits?: number;
741
+ apiCredits?: Record<string, number>;
740
742
  tokenBalances?: Record<string, number>;
741
743
  updatedAt?: number;
742
744
  };
745
+ type ApiCreditProvider = {
746
+ name: string;
747
+ fetchCredits: () => Promise<number>;
748
+ };
749
+ type ApiCreditProviderPreset = 'openrouter' | 'anthropic' | 'gemini' | 'custom';
750
+ type ApiCreditProviderPresetInput = {
751
+ provider: ApiCreditProviderPreset | string;
752
+ name?: string;
753
+ apiKey?: string;
754
+ apiKeyEnv?: string;
755
+ endpoint?: string;
756
+ method?: 'GET' | 'POST';
757
+ headers?: Record<string, string>;
758
+ body?: unknown;
759
+ creditsPath?: string;
760
+ };
761
+ type ApiCreditProviderFactoryOptions = {
762
+ apiBase?: string;
763
+ fetcher?: typeof fetch;
764
+ resolveSecret?: (name: string) => string | undefined | Promise<string | undefined>;
765
+ };
766
+ type ResourceProviderManifestEntry = {
767
+ provider: ApiCreditProviderPreset | string;
768
+ name?: string;
769
+ apiKeyEnv?: string;
770
+ endpoint?: string;
771
+ method?: 'GET' | 'POST';
772
+ headers?: Record<string, string>;
773
+ creditsPath?: string;
774
+ };
775
+ type AgentResourceProvidersManifest = {
776
+ resourceProviders?: ResourceProviderManifestEntry[];
777
+ };
743
778
  interface ListingQuery {
744
779
  type?: ListingType;
745
780
  status?: ListingStatus;
@@ -871,7 +906,7 @@ declare class ReviewGate {
871
906
  assertClear(listingId: string, wallet: string): void;
872
907
  }
873
908
 
874
- declare const compareVersions: (currentVersion: string, latestVersion: string) => 0 | 1 | -1;
909
+ declare const compareVersions: (currentVersion: string, latestVersion: string) => 1 | 0 | -1;
875
910
  declare const buildSdkUpdateCommand: (packageName?: string) => string;
876
911
  declare const checkForSdkUpdate: (options?: SdkUpdateCheckOptions) => Promise<SdkUpdateStatus>;
877
912
  declare const checkForSdkUpdatePolicy: (options: SdkUpdatePolicyCheckOptions) => Promise<SdkUpdateStatus>;
@@ -1000,6 +1035,12 @@ declare const buildShareLink: (listingId: string, options?: MarketingLinkOptions
1000
1035
  declare const buildShareCopy: (listing: ListingRecord, options?: MarketingLinkOptions) => string;
1001
1036
  declare const buildBadgeMarkdown: (listing: ListingRecord, options?: MarketingLinkOptions) => string;
1002
1037
  declare const createCampaign: (listingId: string, options?: MarketingLinkOptions) => MarketingCampaign;
1038
+ declare const createApiCreditProvider: (input: ApiCreditProviderPresetInput, options?: ApiCreditProviderFactoryOptions) => Promise<ApiCreditProvider>;
1039
+ declare const createApiCreditProviders: (inputs: ApiCreditProviderPresetInput[], options?: ApiCreditProviderFactoryOptions) => Promise<ApiCreditProvider[]>;
1040
+ declare const createApiCreditProvidersFromManifest: (manifest: AgentResourceProvidersManifest, options?: ApiCreditProviderFactoryOptions) => Promise<ApiCreditProvider[]>;
1041
+ declare const assertSurvivalProvidersConfigured: (policy: Pick<SelfReliancePolicy, "openRouterMinCredits" | "openRouterWarnCredits" | "apiMinCredits" | "apiWarnCredits">, providers: ApiCreditProvider[], options?: {
1042
+ hasOpenRouterApiKey?: boolean;
1043
+ }) => void;
1003
1044
  declare const buildRaydiumSwapUrl: (tokenMint: string) => string;
1004
1045
  declare const buildJupiterSwapUrl: (tokenMint: string) => string;
1005
1046
  declare const buildTradeLinks: (tokenMint: string) => {
@@ -1012,7 +1053,8 @@ declare const getResourceSnapshot: (options: {
1012
1053
  wallet: string | _solana_web3_js.PublicKey;
1013
1054
  tokenMints?: Array<string | _solana_web3_js.PublicKey>;
1014
1055
  openRouterApiKey?: string;
1056
+ apiCreditProviders?: ApiCreditProvider[];
1015
1057
  apiBase?: string;
1016
1058
  }) => Promise<ResourceSnapshot>;
1017
1059
 
1018
- export { type AnalyticsPoint, type ApiResponse, type BuybackEvent, ClaimPurpose, ClaimResponse, LISTING_NAME_MAX_LENGTH, LISTING_NAME_RECOMMENDED_MAX, LISTING_TAGLINE_MAX_LENGTH, LISTING_TAGLINE_RECOMMENDED_MAX, type LeaderboardEntry, type LeaderboardQuery, ListingInput, type ListingNamingValidationOptions, type ListingNamingValidationResult, type ListingQuery, ListingRecord, type ListingReviewCreatePayload, ListingReviewRecord, type ListingReviewResponsePayload, ListingStatus, ListingType, type ListingVersionPayload, type MarketingCampaign, type MarketingLinkOptions, type MemoryPingChallengeResponse, type MemoryPingPayload, type OpenRouterCredits, type ResourceSnapshot, ReviewGate, type ReviewGateRecord, type ReviewRequiredPayload, type SdkUpdateCheckOptions, type SdkUpdatePolicyCheckOptions, SdkUpdateRequiredError, type SdkUpdateStatus, TicketVerifyResponse, VIBEIAO_IDL, VerifiedClaimResponse, VibeClient, type VibeClientOptions, VibeRegistry, buildBadgeMarkdown, buildClaimMessage, buildJupiterSwapUrl, buildListingVersionMessage, buildMemoryPingMessage, buildOwnerTransferMessage, buildRaydiumSwapUrl, buildReviewPrompt, buildReviewRequired, buildReviewResponseMessage, buildSdkUpdateCommand, buildShareCopy, buildShareLink, buildTradeLinks, checkForSdkUpdate, checkForSdkUpdatePolicy, compareVersions, createCampaign, getResourceSnapshot, normalizeListingText, sanitizeListingNaming, validateListingNaming };
1060
+ export { type AgentResourceProvidersManifest, type AnalyticsPoint, type ApiCreditProvider, type ApiCreditProviderFactoryOptions, type ApiCreditProviderPreset, type ApiCreditProviderPresetInput, type ApiResponse, type BuybackEvent, ClaimPurpose, ClaimResponse, LISTING_NAME_MAX_LENGTH, LISTING_NAME_RECOMMENDED_MAX, LISTING_TAGLINE_MAX_LENGTH, LISTING_TAGLINE_RECOMMENDED_MAX, type LeaderboardEntry, type LeaderboardQuery, ListingInput, type ListingNamingValidationOptions, type ListingNamingValidationResult, type ListingQuery, ListingRecord, type ListingReviewCreatePayload, ListingReviewRecord, type ListingReviewResponsePayload, ListingStatus, ListingType, type ListingVersionPayload, type MarketingCampaign, type MarketingLinkOptions, type MemoryPingChallengeResponse, type MemoryPingPayload, type OpenRouterCredits, type ResourceProviderManifestEntry, type ResourceSnapshot, ReviewGate, type ReviewGateRecord, type ReviewRequiredPayload, type SdkUpdateCheckOptions, type SdkUpdatePolicyCheckOptions, SdkUpdateRequiredError, type SdkUpdateStatus, TicketVerifyResponse, VIBEIAO_IDL, VerifiedClaimResponse, VibeClient, type VibeClientOptions, VibeRegistry, assertSurvivalProvidersConfigured, buildBadgeMarkdown, buildClaimMessage, buildJupiterSwapUrl, buildListingVersionMessage, buildMemoryPingMessage, buildOwnerTransferMessage, buildRaydiumSwapUrl, buildReviewPrompt, buildReviewRequired, buildReviewResponseMessage, buildSdkUpdateCommand, buildShareCopy, buildShareLink, buildTradeLinks, checkForSdkUpdate, checkForSdkUpdatePolicy, compareVersions, createApiCreditProvider, createApiCreditProviders, createApiCreditProvidersFromManifest, createCampaign, getResourceSnapshot, normalizeListingText, sanitizeListingNaming, validateListingNaming };
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  createSelfReliancePolicy,
6
6
  createSurvivalMiddleware,
7
7
  withSurvival
8
- } from "./chunk-BFAMXH2X.js";
8
+ } from "./chunk-M7DQTU5R.js";
9
9
  import {
10
10
  VIBEIAO_IDL,
11
11
  fetchSolBalance,
@@ -114,7 +114,7 @@ var ReviewGate = class {
114
114
  var DEFAULT_API_BASE = "https://api.vibeiao.com";
115
115
  var DEFAULT_WEB_BASE = "https://vibeiao.com";
116
116
  var DEFAULT_SDK_PACKAGE = "@vibeiao/sdk";
117
- var DEFAULT_SDK_VERSION = "0.1.8" ? "0.1.8" : "0.1.4";
117
+ var DEFAULT_SDK_VERSION = "0.1.9" ? "0.1.9" : "0.1.4";
118
118
  var DEFAULT_SDK_REGISTRY = "https://registry.npmjs.org";
119
119
  var DEFAULT_SDK_POLICY_PATH = "/v1/sdk/policy";
120
120
  var DEFAULT_SDK_CHECK_INTERVAL_MS = 1e3 * 60 * 30;
@@ -261,6 +261,49 @@ var unwrap = (response) => {
261
261
  }
262
262
  return response.data;
263
263
  };
264
+ var normalizeProviderName = (value) => value.trim().toLowerCase().replace(/[^a-z0-9_-]/g, "");
265
+ var getByPath = (payload, path) => {
266
+ if (!path) return void 0;
267
+ const segments = path.split(".").map((part) => part.trim()).filter(Boolean);
268
+ let current = payload;
269
+ for (const segment of segments) {
270
+ if (!current || typeof current !== "object" || !(segment in current)) {
271
+ return void 0;
272
+ }
273
+ current = current[segment];
274
+ }
275
+ return current;
276
+ };
277
+ var extractCreditsFromPayload = (payload, creditsPath) => {
278
+ const direct = getByPath(payload, creditsPath);
279
+ let credits = pickFinite(
280
+ direct,
281
+ payload?.credits,
282
+ payload?.remaining_credits,
283
+ payload?.remainingCredits,
284
+ payload?.balance,
285
+ payload?.remaining
286
+ );
287
+ if (Number.isFinite(credits)) return credits;
288
+ const nested = payload?.data;
289
+ credits = pickFinite(
290
+ nested?.credits,
291
+ nested?.remaining_credits,
292
+ nested?.remainingCredits,
293
+ nested?.balance,
294
+ nested?.remaining
295
+ );
296
+ return credits;
297
+ };
298
+ var defaultApiKeyEnvForProvider = (provider) => {
299
+ const normalized = normalizeProviderName(provider);
300
+ if (normalized === "openrouter") return "OPENROUTER_API_KEY";
301
+ if (normalized === "anthropic") return "ANTHROPIC_API_KEY";
302
+ if (normalized === "gemini") return "GEMINI_API_KEY";
303
+ return `${normalized.toUpperCase()}_API_KEY`;
304
+ };
305
+ var providerConfigError = (providerName, detail, nextStep) => `provider_config_error:${providerName}:${detail}. ${nextStep}`;
306
+ var providerFetchError = (providerName, detail) => `provider_fetch_failed:${providerName}:${detail}`;
264
307
  var generateRef = () => {
265
308
  const cryptoObj = globalThis.crypto;
266
309
  if (cryptoObj?.randomUUID) {
@@ -716,6 +759,145 @@ var createCampaign = (listingId, options = {}) => {
716
759
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
717
760
  };
718
761
  };
762
+ var createApiCreditProvider = async (input, options = {}) => {
763
+ const providerRaw = String(input.provider || "").trim();
764
+ const provider = normalizeProviderName(providerRaw || input.name || "custom");
765
+ const providerName = normalizeProviderName(input.name || provider || "custom");
766
+ if (!provider) {
767
+ throw new Error(
768
+ providerConfigError("unknown", "provider_missing", "Set provider to openrouter/anthropic/gemini/custom.")
769
+ );
770
+ }
771
+ const resolveSecret = options.resolveSecret;
772
+ const apiKeyEnv = input.apiKeyEnv || defaultApiKeyEnvForProvider(provider);
773
+ const resolvedSecret = resolveSecret ? await resolveSecret(apiKeyEnv) : void 0;
774
+ const apiKey = input.apiKey || resolvedSecret;
775
+ const fetcher = options.fetcher || fetch;
776
+ if (provider === "openrouter") {
777
+ if (!apiKey) {
778
+ throw new Error(
779
+ providerConfigError(
780
+ providerName,
781
+ "api_key_missing",
782
+ `Ask your human owner to provide ${apiKeyEnv} or set apiKey directly.`
783
+ )
784
+ );
785
+ }
786
+ return {
787
+ name: providerName,
788
+ fetchCredits: async () => {
789
+ const client = new VibeClient({ baseUrl: options.apiBase, fetcher });
790
+ const result = await client.getOpenRouterCreditsValue(apiKey);
791
+ if (result.error) {
792
+ throw new Error(providerFetchError(providerName, result.error));
793
+ }
794
+ return Number(result.data);
795
+ }
796
+ };
797
+ }
798
+ if (!input.endpoint) {
799
+ throw new Error(
800
+ providerConfigError(
801
+ providerName,
802
+ "endpoint_missing",
803
+ "Set endpoint to the provider credit/balance API URL."
804
+ )
805
+ );
806
+ }
807
+ if (!apiKey) {
808
+ throw new Error(
809
+ providerConfigError(
810
+ providerName,
811
+ "api_key_missing",
812
+ `Ask your human owner to provide ${apiKeyEnv} or set apiKey directly.`
813
+ )
814
+ );
815
+ }
816
+ return {
817
+ name: providerName,
818
+ fetchCredits: async () => {
819
+ const headers = { ...input.headers || {} };
820
+ const hasAuthHeader = Object.keys(headers).some((key) => key.toLowerCase() === "authorization");
821
+ const hasApiKeyHeader = Object.keys(headers).some((key) => key.toLowerCase() === "x-api-key");
822
+ if (provider === "anthropic") {
823
+ if (!hasApiKeyHeader) headers["x-api-key"] = apiKey;
824
+ if (!headers["anthropic-version"]) headers["anthropic-version"] = "2023-06-01";
825
+ } else if (!hasAuthHeader && !hasApiKeyHeader) {
826
+ headers.Authorization = `Bearer ${apiKey}`;
827
+ }
828
+ const method = input.method || (input.body !== void 0 ? "POST" : "GET");
829
+ const hasContentType = Object.keys(headers).some((key) => key.toLowerCase() === "content-type");
830
+ const body = input.body !== void 0 ? typeof input.body === "string" ? input.body : JSON.stringify(input.body) : void 0;
831
+ if (body && !hasContentType) {
832
+ headers["Content-Type"] = "application/json";
833
+ }
834
+ let response;
835
+ try {
836
+ response = await fetcher(input.endpoint, { method, headers, body });
837
+ } catch (error) {
838
+ const message = error instanceof Error ? error.message : "network_error";
839
+ throw new Error(providerFetchError(providerName, message));
840
+ }
841
+ const payload = await readJson(response);
842
+ if (!response.ok) {
843
+ const detail = String(payload?.error || `http_${response.status}`);
844
+ throw new Error(providerFetchError(providerName, detail));
845
+ }
846
+ const credits = extractCreditsFromPayload(payload, input.creditsPath);
847
+ if (!Number.isFinite(credits)) {
848
+ throw new Error(
849
+ providerFetchError(
850
+ providerName,
851
+ `credits_unavailable (set creditsPath, current=${input.creditsPath || "auto"})`
852
+ )
853
+ );
854
+ }
855
+ return credits;
856
+ }
857
+ };
858
+ };
859
+ var createApiCreditProviders = async (inputs, options = {}) => {
860
+ const providers = [];
861
+ for (const input of inputs) {
862
+ providers.push(await createApiCreditProvider(input, options));
863
+ }
864
+ return providers;
865
+ };
866
+ var createApiCreditProvidersFromManifest = async (manifest, options = {}) => {
867
+ const entries = manifest.resourceProviders || [];
868
+ const configs = entries.map((entry) => ({
869
+ provider: entry.provider,
870
+ name: entry.name,
871
+ apiKeyEnv: entry.apiKeyEnv,
872
+ endpoint: entry.endpoint,
873
+ method: entry.method,
874
+ headers: entry.headers,
875
+ creditsPath: entry.creditsPath
876
+ }));
877
+ return createApiCreditProviders(configs, options);
878
+ };
879
+ var assertSurvivalProvidersConfigured = (policy, providers, options = {}) => {
880
+ const required = /* @__PURE__ */ new Set();
881
+ if (policy.openRouterMinCredits !== void 0 || policy.openRouterWarnCredits !== void 0) {
882
+ required.add("openrouter");
883
+ }
884
+ const addFromMap = (map) => {
885
+ if (!map) return;
886
+ Object.keys(map).forEach((name) => required.add(normalizeProviderName(name)));
887
+ };
888
+ addFromMap(policy.apiMinCredits);
889
+ addFromMap(policy.apiWarnCredits);
890
+ const available = new Set((providers || []).map((provider) => normalizeProviderName(provider.name)));
891
+ if (options.hasOpenRouterApiKey) {
892
+ available.add("openrouter");
893
+ }
894
+ const missing = Array.from(required).filter((name) => !available.has(name));
895
+ if (missing.length) {
896
+ throw new Error(
897
+ `survival_provider_missing:${missing.join(",")}. Configure apiCreditProviders (or api keys), or remove thresholds for missing providers.`
898
+ );
899
+ }
900
+ };
719
901
  var buildRaydiumSwapUrl = (tokenMint) => `https://raydium.io/swap/?inputCurrency=sol&outputCurrency=${tokenMint}`;
720
902
  var buildJupiterSwapUrl = (tokenMint) => `https://jup.ag/swap/SOL-${tokenMint}`;
721
903
  var buildTradeLinks = (tokenMint) => ({
@@ -723,8 +905,9 @@ var buildTradeLinks = (tokenMint) => ({
723
905
  jupiter: buildJupiterSwapUrl(tokenMint)
724
906
  });
725
907
  var getResourceSnapshot = async (options) => {
726
- const { connection, wallet, tokenMints, openRouterApiKey, apiBase } = options;
908
+ const { connection, wallet, tokenMints, openRouterApiKey, apiCreditProviders, apiBase } = options;
727
909
  const snapshot = { updatedAt: Date.now() };
910
+ const apiCredits = {};
728
911
  snapshot.solBalance = await fetchSolBalance(connection, wallet);
729
912
  if (tokenMints?.length) {
730
913
  snapshot.tokenBalances = await fetchTokenBalances(connection, wallet, tokenMints);
@@ -736,6 +919,33 @@ var getResourceSnapshot = async (options) => {
736
919
  throw new Error(credits.error);
737
920
  }
738
921
  snapshot.openRouterCredits = credits.data;
922
+ apiCredits.openrouter = credits.data;
923
+ }
924
+ if (apiCreditProviders?.length) {
925
+ for (const provider of apiCreditProviders) {
926
+ const name = String(provider?.name || "").trim().toLowerCase();
927
+ if (!name || typeof provider.fetchCredits !== "function") continue;
928
+ try {
929
+ const value = Number(await provider.fetchCredits());
930
+ if (Number.isFinite(value)) {
931
+ apiCredits[name] = value;
932
+ }
933
+ } catch (error) {
934
+ const message = error instanceof Error ? error.message : "unknown_error";
935
+ throw new Error(
936
+ providerFetchError(
937
+ name,
938
+ `${message}. Ask your human owner to provision/refill this provider key if needed.`
939
+ )
940
+ );
941
+ }
942
+ }
943
+ }
944
+ if (Object.keys(apiCredits).length > 0) {
945
+ snapshot.apiCredits = apiCredits;
946
+ if (snapshot.openRouterCredits === void 0 && apiCredits.openrouter !== void 0) {
947
+ snapshot.openRouterCredits = apiCredits.openrouter;
948
+ }
739
949
  }
740
950
  return snapshot;
741
951
  };
@@ -750,6 +960,7 @@ export {
750
960
  VIBEIAO_IDL,
751
961
  VibeClient,
752
962
  VibeRegistry,
963
+ assertSurvivalProvidersConfigured,
753
964
  buildBadgeMarkdown,
754
965
  buildClaimMessage,
755
966
  buildJupiterSwapUrl,
@@ -767,6 +978,9 @@ export {
767
978
  checkForSdkUpdate,
768
979
  checkForSdkUpdatePolicy,
769
980
  compareVersions,
981
+ createApiCreditProvider,
982
+ createApiCreditProviders,
983
+ createApiCreditProvidersFromManifest,
770
984
  createAutoSelfReliance,
771
985
  createCampaign,
772
986
  createSelfRelianceMonitor,
@@ -3,6 +3,8 @@ type SelfReliancePolicy = {
3
3
  solWarnBalance: number;
4
4
  openRouterMinCredits?: number;
5
5
  openRouterWarnCredits?: number;
6
+ apiMinCredits?: Record<string, number>;
7
+ apiWarnCredits?: Record<string, number>;
6
8
  allowIfLow?: boolean;
7
9
  denyMode?: 'any' | 'all';
8
10
  solHardMin?: number;
@@ -12,6 +14,7 @@ type SelfReliancePolicy = {
12
14
  type SelfRelianceState = {
13
15
  solBalance?: number;
14
16
  openRouterCredits?: number;
17
+ apiCredits?: Record<string, number>;
15
18
  lastWarnAt?: number;
16
19
  lastUpdatedAt?: number;
17
20
  };
@@ -27,6 +30,7 @@ type SelfRelianceConfig = {
27
30
  type ResourceSnapshot = {
28
31
  solBalance?: number;
29
32
  openRouterCredits?: number;
33
+ apiCredits?: Record<string, number>;
30
34
  tokenBalances?: Record<string, number>;
31
35
  updatedAt?: number;
32
36
  };
@@ -39,6 +43,7 @@ declare class SelfReliance {
39
43
  getState(): {
40
44
  solBalance?: number;
41
45
  openRouterCredits?: number;
46
+ apiCredits?: Record<string, number>;
42
47
  lastWarnAt?: number;
43
48
  lastUpdatedAt?: number;
44
49
  };
@@ -5,7 +5,7 @@ import {
5
5
  createSelfReliancePolicy,
6
6
  createSurvivalMiddleware,
7
7
  withSurvival
8
- } from "./chunk-BFAMXH2X.js";
8
+ } from "./chunk-M7DQTU5R.js";
9
9
  export {
10
10
  SelfReliance,
11
11
  createAutoSelfReliance,
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@vibeiao/sdk",
3
3
  "private": false,
4
4
  "type": "module",
5
- "version": "0.1.9",
5
+ "version": "0.1.10",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "exports": {