@forgezero/providers 0.1.2 → 0.1.4
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 +3 -1
- package/dist/binance.js +22 -3
- package/dist/chain.js +22 -3
- package/dist/database.js +22 -3
- package/dist/email.js +22 -3
- package/dist/http.js +22 -3
- package/dist/index.d.ts +6 -2
- package/dist/index.js +22 -3
- package/dist/pool.js +22 -3
- package/dist/storage.js +22 -3
- package/dist/translation.js +22 -3
- package/package.json +8 -7
package/README.md
CHANGED
|
@@ -30,7 +30,9 @@ const services = createRegistry({
|
|
|
30
30
|
providers: [jetemail, smtp]
|
|
31
31
|
});
|
|
32
32
|
|
|
33
|
-
|
|
33
|
+
const controller = new AbortController();
|
|
34
|
+
await services.call('email', { to, subject, html }, { signal: controller.signal });
|
|
35
|
+
// JetEmail first, then SMTP. Abort stops the chain and reaches provider I/O.
|
|
34
36
|
```
|
|
35
37
|
|
|
36
38
|
## Why a 400 stops the loop and a 401 does not
|
package/dist/binance.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/http.ts
|
|
131
150
|
class BudgetExhausted extends ProviderError {
|
package/dist/chain.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/chain.ts
|
|
131
150
|
var hexToNumber = (value) => Number(BigInt(value));
|
package/dist/database.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/database.ts
|
|
131
150
|
var pools = new Map;
|
package/dist/email.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/email.ts
|
|
131
150
|
var recipients = (to) => Array.isArray(to) ? [...to] : [to];
|
package/dist/http.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/http.ts
|
|
131
150
|
class BudgetExhausted extends ProviderError {
|
package/dist/index.d.ts
CHANGED
|
@@ -118,6 +118,10 @@ export interface CallResult<Result> {
|
|
|
118
118
|
attempts: readonly Attempt[];
|
|
119
119
|
error?: ProviderError;
|
|
120
120
|
}
|
|
121
|
+
export interface CallOptions {
|
|
122
|
+
/** Reaches provider fetch/socket code; cancellation never falls through to another vendor. */
|
|
123
|
+
signal?: AbortSignal;
|
|
124
|
+
}
|
|
121
125
|
export interface RegistryOptions {
|
|
122
126
|
credentials: CredentialSource;
|
|
123
127
|
config: ConfigSource;
|
|
@@ -141,7 +145,7 @@ export interface RegistryOptions {
|
|
|
141
145
|
}
|
|
142
146
|
export declare function nextHealth(current: ProviderHealth | undefined, kind: FailureKind | 'success'): ProviderHealth;
|
|
143
147
|
export declare function createRegistry(options: RegistryOptions): {
|
|
144
|
-
call: <Result>(serviceKey: string, args: unknown) => Promise<CallResult<Result>>;
|
|
148
|
+
call: <Result>(serviceKey: string, args: unknown, callOptions?: CallOptions) => Promise<CallResult<Result>>;
|
|
145
149
|
};
|
|
146
150
|
/** Passed to `registry.call('email', message)`. */
|
|
147
151
|
export interface EmailMessage {
|
|
@@ -152,4 +156,4 @@ export interface EmailMessage {
|
|
|
152
156
|
from?: string;
|
|
153
157
|
replyTo?: string;
|
|
154
158
|
}
|
|
155
|
-
export declare const VERSION = "0.1.
|
|
159
|
+
export declare const VERSION = "0.1.4";
|
package/dist/index.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
export {
|
|
130
149
|
staticConfig,
|
|
131
150
|
nextHealth,
|
package/dist/pool.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/http.ts
|
|
131
150
|
class BudgetExhausted extends ProviderError {
|
package/dist/storage.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/storage.ts
|
|
131
150
|
var encoder = new TextEncoder;
|
package/dist/translation.js
CHANGED
|
@@ -71,10 +71,19 @@ function nextHealth(current, kind) {
|
|
|
71
71
|
}
|
|
72
72
|
function createRegistry(options) {
|
|
73
73
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args) {
|
|
74
|
+
async function call(serviceKey, args, callOptions = {}) {
|
|
75
75
|
const configured = [...await options.config.list(serviceKey)].filter((provider) => provider.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
76
|
const attempts = [];
|
|
77
77
|
for (const entry of configured) {
|
|
78
|
+
if (callOptions.signal?.aborted) {
|
|
79
|
+
const cancelled = {
|
|
80
|
+
ok: false,
|
|
81
|
+
attempts,
|
|
82
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
83
|
+
};
|
|
84
|
+
options.after?.(cancelled);
|
|
85
|
+
return cancelled;
|
|
86
|
+
}
|
|
78
87
|
const spec = byId.get(entry.providerId);
|
|
79
88
|
if (!spec) {
|
|
80
89
|
attempts.push({ providerId: entry.providerId, outcome: "skipped", error: "not registered" });
|
|
@@ -88,7 +97,8 @@ function createRegistry(options) {
|
|
|
88
97
|
try {
|
|
89
98
|
const result = await spec.invoke({
|
|
90
99
|
config: entry.config,
|
|
91
|
-
secret: (field) => options.credentials.get(entry.secretRef, field)
|
|
100
|
+
secret: (field) => options.credentials.get(entry.secretRef, field),
|
|
101
|
+
signal: callOptions.signal
|
|
92
102
|
}, args);
|
|
93
103
|
attempts.push({ providerId: entry.providerId, outcome: "sent" });
|
|
94
104
|
await options.config.recordHealth(serviceKey, entry.providerId, nextHealth(entry.health, "success"));
|
|
@@ -96,6 +106,15 @@ function createRegistry(options) {
|
|
|
96
106
|
options.after?.(sent);
|
|
97
107
|
return sent;
|
|
98
108
|
} catch (error) {
|
|
109
|
+
if (callOptions.signal?.aborted) {
|
|
110
|
+
const cancelled = {
|
|
111
|
+
ok: false,
|
|
112
|
+
attempts,
|
|
113
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
114
|
+
};
|
|
115
|
+
options.after?.(cancelled);
|
|
116
|
+
return cancelled;
|
|
117
|
+
}
|
|
99
118
|
const kind = spec.classify(error);
|
|
100
119
|
attempts.push({
|
|
101
120
|
providerId: entry.providerId,
|
|
@@ -125,7 +144,7 @@ function createRegistry(options) {
|
|
|
125
144
|
}
|
|
126
145
|
return { call };
|
|
127
146
|
}
|
|
128
|
-
var VERSION = "0.1.
|
|
147
|
+
var VERSION = "0.1.4";
|
|
129
148
|
|
|
130
149
|
// src/translation.ts
|
|
131
150
|
var GOOGLE_ENDPOINT = "https://generativelanguage.googleapis.com/v1beta/models";
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"//": "Publishing happens from an operator's machine, not CI \u2014 CLAUDE.md records that the absence of CI is deliberate. npm's `provenance` attests a tarball was built by a recognised CI provider from a named commit, so it cannot be produced here: it was set, and the first publish failed with `Automatic provenance generation not supported for provider: null`. A setting that can never be satisfied is worse than none, because it reads as a guarantee nobody is getting. Restore it the day this publishes from CI, and not before.",
|
|
3
2
|
"name": "@forgezero/providers",
|
|
4
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
5
4
|
"type": "module",
|
|
6
5
|
"publishConfig": {
|
|
7
|
-
"access": "public"
|
|
6
|
+
"access": "public",
|
|
7
|
+
"provenance": true
|
|
8
8
|
},
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
@@ -44,8 +44,9 @@
|
|
|
44
44
|
"default": "./dist/translation.js"
|
|
45
45
|
}
|
|
46
46
|
},
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
"scripts": {
|
|
48
|
+
"check": "tsc --noEmit",
|
|
49
|
+
"prebuild": "rm -rf dist",
|
|
49
50
|
"build": "bun build src/index.ts src/email.ts src/chain.ts src/database.ts src/http.ts src/pool.ts src/storage.ts src/binance.ts src/translation.ts --root src --outdir dist --target browser --format esm --packages external && tsc --emitDeclarationOnly --declaration --noEmit false --outDir dist",
|
|
50
51
|
"prepublishOnly": "bun run check && bun run build"
|
|
51
52
|
},
|
|
@@ -70,7 +71,7 @@
|
|
|
70
71
|
"repository": {
|
|
71
72
|
"type": "git",
|
|
72
73
|
"url": "git+https://github.com/forgezero-net/packages.git",
|
|
73
|
-
"directory": "
|
|
74
|
+
"directory": "providers"
|
|
74
75
|
},
|
|
75
76
|
"bugs": "https://github.com/forgezero-net/packages/issues",
|
|
76
77
|
"sideEffects": false,
|
|
@@ -81,6 +82,6 @@
|
|
|
81
82
|
"LICENSE"
|
|
82
83
|
],
|
|
83
84
|
"dependencies": {
|
|
84
|
-
"@forgezero/runtime": "^0.1.
|
|
85
|
+
"@forgezero/runtime": "^0.1.4"
|
|
85
86
|
}
|
|
86
87
|
}
|