@forgezero/providers 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 +160 -52
- package/dist/binance.js +95 -38
- package/dist/chain.d.ts +1 -1
- package/dist/chain.js +95 -38
- package/dist/database.d.ts +2 -2
- package/dist/database.js +95 -38
- package/dist/email.d.ts +26 -44
- package/dist/email.js +160 -127
- package/dist/http.d.ts +2 -2
- package/dist/http.js +95 -38
- package/dist/index.d.ts +80 -17
- package/dist/index.js +97 -36
- package/dist/pool.js +95 -38
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +95 -38
- package/dist/translation.d.ts +6 -4
- package/dist/translation.js +95 -38
- package/package.json +5 -5
package/dist/chain.js
CHANGED
|
@@ -38,25 +38,45 @@ function chainCredentials(...sources) {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
function staticConfig(
|
|
41
|
+
function staticConfig(config) {
|
|
42
42
|
const health = new Map;
|
|
43
43
|
return {
|
|
44
44
|
name: "static",
|
|
45
|
-
async
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
async provider(instanceKey) {
|
|
46
|
+
const provider = config.providers[instanceKey];
|
|
47
|
+
return provider ? { instanceKey, ...provider, config: { ...provider.config } } : undefined;
|
|
48
|
+
},
|
|
49
|
+
async list(serviceKey, methodKey) {
|
|
50
|
+
return (config.services[serviceKey]?.[methodKey] ?? []).map((attachment) => ({
|
|
51
|
+
...attachment,
|
|
52
|
+
health: health.get(`${serviceKey}:${methodKey}:${attachment.instanceKey}:${attachment.providerMethod}`) ?? attachment.health
|
|
49
53
|
}));
|
|
50
54
|
},
|
|
51
|
-
async recordHealth(serviceKey,
|
|
52
|
-
health.set(`${serviceKey}:${
|
|
55
|
+
async recordHealth(serviceKey, methodKey, instanceKey, providerMethod, next) {
|
|
56
|
+
health.set(`${serviceKey}:${methodKey}:${instanceKey}:${providerMethod}`, next);
|
|
53
57
|
}
|
|
54
58
|
};
|
|
55
59
|
}
|
|
60
|
+
function defineProviderMethod(method) {
|
|
61
|
+
return method;
|
|
62
|
+
}
|
|
56
63
|
function defineProvider(spec) {
|
|
57
64
|
return spec;
|
|
58
65
|
}
|
|
66
|
+
function defineSingleMethodProvider(spec) {
|
|
67
|
+
const { method, invoke, classify, ...identity } = spec;
|
|
68
|
+
return defineProvider({
|
|
69
|
+
...identity,
|
|
70
|
+
methods: { [method]: defineProviderMethod({ invoke, classify }) }
|
|
71
|
+
});
|
|
72
|
+
}
|
|
59
73
|
var STRIKES_TO_OFFLINE = 3;
|
|
74
|
+
function serviceMethod() {
|
|
75
|
+
return Object.freeze({});
|
|
76
|
+
}
|
|
77
|
+
function defineService(definition) {
|
|
78
|
+
return definition;
|
|
79
|
+
}
|
|
60
80
|
function nextHealth(current, kind) {
|
|
61
81
|
if (kind === "success")
|
|
62
82
|
return { strikes: 0, status: "ok" };
|
|
@@ -71,80 +91,117 @@ function nextHealth(current, kind) {
|
|
|
71
91
|
}
|
|
72
92
|
function createRegistry(options) {
|
|
73
93
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args, callOptions = {}) {
|
|
75
|
-
const configured = [...await options.config.list(serviceKey)].filter((
|
|
94
|
+
async function call(serviceKey, methodKey, args, callOptions = {}) {
|
|
95
|
+
const configured = [...await options.config.list(serviceKey, methodKey)].filter((attachment) => attachment.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
96
|
const attempts = [];
|
|
77
|
-
for (const
|
|
97
|
+
for (const attachment of configured) {
|
|
78
98
|
if (callOptions.signal?.aborted) {
|
|
79
99
|
const cancelled = {
|
|
80
100
|
ok: false,
|
|
101
|
+
fallbackUsed: attempts.length > 0,
|
|
81
102
|
attempts,
|
|
82
|
-
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
103
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}.${methodKey}" call was cancelled.`)
|
|
83
104
|
};
|
|
84
|
-
options.after?.(cancelled);
|
|
105
|
+
await options.after?.(cancelled);
|
|
85
106
|
return cancelled;
|
|
86
107
|
}
|
|
87
|
-
const
|
|
88
|
-
if (!
|
|
89
|
-
attempts.push({ providerId:
|
|
108
|
+
const instance = await options.config.provider(attachment.instanceKey);
|
|
109
|
+
if (!instance) {
|
|
110
|
+
attempts.push({ providerId: "unknown", instanceKey: attachment.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: "instance not registered" });
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const spec = byId.get(instance.providerId);
|
|
114
|
+
const method = spec?.methods[attachment.providerMethod];
|
|
115
|
+
if (!spec || !method) {
|
|
116
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: !spec ? "provider not registered" : "method not supported" });
|
|
90
117
|
continue;
|
|
91
118
|
}
|
|
92
|
-
if (
|
|
93
|
-
attempts.push({ providerId:
|
|
119
|
+
if (!instance.enabled) {
|
|
120
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: "instance disabled" });
|
|
94
121
|
continue;
|
|
95
122
|
}
|
|
96
|
-
|
|
123
|
+
if (attachment.health?.status === "offline") {
|
|
124
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: "offline" });
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
await options.before?.({ service: serviceKey, method: methodKey, provider: instance.providerId, instance: instance.instanceKey });
|
|
128
|
+
const startedAt = performance.now();
|
|
97
129
|
try {
|
|
98
|
-
const result = await
|
|
99
|
-
config:
|
|
100
|
-
secret: (field) => options.credentials.get(
|
|
130
|
+
const result = await method.invoke({
|
|
131
|
+
config: instance.config,
|
|
132
|
+
secret: (field) => options.credentials.get(instance.secretRef, field),
|
|
101
133
|
signal: callOptions.signal
|
|
102
134
|
}, args);
|
|
103
|
-
attempts.push({ providerId:
|
|
104
|
-
await options.config.recordHealth(serviceKey,
|
|
105
|
-
const sent = {
|
|
106
|
-
|
|
135
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "sent", durationMs: performance.now() - startedAt });
|
|
136
|
+
await options.config.recordHealth(serviceKey, methodKey, instance.instanceKey, attachment.providerMethod, nextHealth(attachment.health, "success"));
|
|
137
|
+
const sent = {
|
|
138
|
+
ok: true,
|
|
139
|
+
result,
|
|
140
|
+
provider: instance.providerId,
|
|
141
|
+
instance: instance.instanceKey,
|
|
142
|
+
method: attachment.providerMethod,
|
|
143
|
+
selected: { providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod },
|
|
144
|
+
fallbackUsed: attempts.length > 1,
|
|
145
|
+
attempts
|
|
146
|
+
};
|
|
147
|
+
await options.after?.(sent);
|
|
107
148
|
return sent;
|
|
108
149
|
} catch (error) {
|
|
109
150
|
if (callOptions.signal?.aborted) {
|
|
110
151
|
const cancelled = {
|
|
111
152
|
ok: false,
|
|
153
|
+
fallbackUsed: attempts.length > 0,
|
|
112
154
|
attempts,
|
|
113
|
-
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
155
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}.${methodKey}" call was cancelled.`)
|
|
114
156
|
};
|
|
115
|
-
options.after?.(cancelled);
|
|
157
|
+
await options.after?.(cancelled);
|
|
116
158
|
return cancelled;
|
|
117
159
|
}
|
|
118
|
-
const kind =
|
|
160
|
+
const kind = method.classify(error);
|
|
161
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
162
|
+
const code = error instanceof ProviderError ? error.code : typeof error?.code === "string" ? error.code : undefined;
|
|
119
163
|
attempts.push({
|
|
120
|
-
providerId:
|
|
164
|
+
providerId: instance.providerId,
|
|
165
|
+
instanceKey: instance.instanceKey,
|
|
166
|
+
providerMethod: attachment.providerMethod,
|
|
121
167
|
outcome: "failed",
|
|
122
168
|
kind,
|
|
123
|
-
|
|
169
|
+
durationMs: performance.now() - startedAt,
|
|
170
|
+
failure: { kind, ...code ? { code } : {}, message },
|
|
171
|
+
error: message
|
|
124
172
|
});
|
|
125
|
-
await options.config.recordHealth(serviceKey,
|
|
173
|
+
await options.config.recordHealth(serviceKey, methodKey, instance.instanceKey, attachment.providerMethod, nextHealth(attachment.health, kind));
|
|
126
174
|
if (kind === "terminal") {
|
|
127
175
|
const refused = {
|
|
128
176
|
ok: false,
|
|
177
|
+
fallbackUsed: attempts.length > 1,
|
|
129
178
|
attempts,
|
|
130
179
|
error: new ProviderError("PAYLOAD_REJECTED", "The request was refused as malformed; no provider will accept it.")
|
|
131
180
|
};
|
|
132
|
-
options.after?.(refused);
|
|
181
|
+
await options.after?.(refused);
|
|
133
182
|
return refused;
|
|
134
183
|
}
|
|
135
184
|
}
|
|
136
185
|
}
|
|
137
186
|
const failed = {
|
|
138
187
|
ok: false,
|
|
188
|
+
fallbackUsed: attempts.length > 1,
|
|
139
189
|
attempts,
|
|
140
|
-
error: new ProviderError(attempts.length === 0 ? "NO_PROVIDER" : "ALL_PROVIDERS_FAILED", attempts.length === 0 ? `No provider is configured for "${serviceKey}".` : `Every provider for "${serviceKey}" failed or was skipped.`)
|
|
190
|
+
error: new ProviderError(attempts.length === 0 ? "NO_PROVIDER" : "ALL_PROVIDERS_FAILED", attempts.length === 0 ? `No provider method is configured for "${serviceKey}.${methodKey}".` : `Every provider method for "${serviceKey}.${methodKey}" failed or was skipped.`)
|
|
141
191
|
};
|
|
142
|
-
options.after?.(failed);
|
|
192
|
+
await options.after?.(failed);
|
|
143
193
|
return failed;
|
|
144
194
|
}
|
|
145
|
-
|
|
195
|
+
function service(definition) {
|
|
196
|
+
return {
|
|
197
|
+
call(method, args, callOptions) {
|
|
198
|
+
return call(definition.key, method, args, callOptions);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return { call, service };
|
|
146
203
|
}
|
|
147
|
-
var VERSION = "0.1.
|
|
204
|
+
var VERSION = "0.1.10";
|
|
148
205
|
|
|
149
206
|
// src/chain.ts
|
|
150
207
|
var hexToNumber = (value) => Number(BigInt(value));
|
|
@@ -159,9 +216,9 @@ var TERMINAL_PATTERNS = [
|
|
|
159
216
|
"invalid sender",
|
|
160
217
|
"execution reverted"
|
|
161
218
|
];
|
|
162
|
-
var evmRpc =
|
|
219
|
+
var evmRpc = defineSingleMethodProvider({
|
|
163
220
|
id: "evm-rpc",
|
|
164
|
-
|
|
221
|
+
method: "request",
|
|
165
222
|
label: "EVM JSON-RPC node",
|
|
166
223
|
multiInstance: true,
|
|
167
224
|
credentials: {
|
package/dist/database.d.ts
CHANGED
|
@@ -123,7 +123,7 @@ export declare const ARANGO_SERVER_MODE_PATH: "/_admin/server/mode";
|
|
|
123
123
|
* database routing authority.
|
|
124
124
|
*/
|
|
125
125
|
export declare function arangoCoordinatorUrls(config: Pick<ArangoConfig, 'url' | 'urls'>): readonly string[];
|
|
126
|
-
export declare const arangodb: import("./index").
|
|
126
|
+
export declare const arangodb: import("./index").ProviderDefinition<Record<"query", import("./index").ProviderMethodSpec<Query, unknown[]>>>;
|
|
127
127
|
/** Drop memoised connections. Tests, and after a credential rotation. */
|
|
128
128
|
export declare function resetPools(): void;
|
|
129
|
-
export declare const databaseProviders: readonly [import("./index").
|
|
129
|
+
export declare const databaseProviders: readonly [import("./index").ProviderDefinition<Record<"query", import("./index").ProviderMethodSpec<Query, unknown[]>>>];
|
package/dist/database.js
CHANGED
|
@@ -38,25 +38,45 @@ function chainCredentials(...sources) {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
function staticConfig(
|
|
41
|
+
function staticConfig(config) {
|
|
42
42
|
const health = new Map;
|
|
43
43
|
return {
|
|
44
44
|
name: "static",
|
|
45
|
-
async
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
async provider(instanceKey) {
|
|
46
|
+
const provider = config.providers[instanceKey];
|
|
47
|
+
return provider ? { instanceKey, ...provider, config: { ...provider.config } } : undefined;
|
|
48
|
+
},
|
|
49
|
+
async list(serviceKey, methodKey) {
|
|
50
|
+
return (config.services[serviceKey]?.[methodKey] ?? []).map((attachment) => ({
|
|
51
|
+
...attachment,
|
|
52
|
+
health: health.get(`${serviceKey}:${methodKey}:${attachment.instanceKey}:${attachment.providerMethod}`) ?? attachment.health
|
|
49
53
|
}));
|
|
50
54
|
},
|
|
51
|
-
async recordHealth(serviceKey,
|
|
52
|
-
health.set(`${serviceKey}:${
|
|
55
|
+
async recordHealth(serviceKey, methodKey, instanceKey, providerMethod, next) {
|
|
56
|
+
health.set(`${serviceKey}:${methodKey}:${instanceKey}:${providerMethod}`, next);
|
|
53
57
|
}
|
|
54
58
|
};
|
|
55
59
|
}
|
|
60
|
+
function defineProviderMethod(method) {
|
|
61
|
+
return method;
|
|
62
|
+
}
|
|
56
63
|
function defineProvider(spec) {
|
|
57
64
|
return spec;
|
|
58
65
|
}
|
|
66
|
+
function defineSingleMethodProvider(spec) {
|
|
67
|
+
const { method, invoke, classify, ...identity } = spec;
|
|
68
|
+
return defineProvider({
|
|
69
|
+
...identity,
|
|
70
|
+
methods: { [method]: defineProviderMethod({ invoke, classify }) }
|
|
71
|
+
});
|
|
72
|
+
}
|
|
59
73
|
var STRIKES_TO_OFFLINE = 3;
|
|
74
|
+
function serviceMethod() {
|
|
75
|
+
return Object.freeze({});
|
|
76
|
+
}
|
|
77
|
+
function defineService(definition) {
|
|
78
|
+
return definition;
|
|
79
|
+
}
|
|
60
80
|
function nextHealth(current, kind) {
|
|
61
81
|
if (kind === "success")
|
|
62
82
|
return { strikes: 0, status: "ok" };
|
|
@@ -71,80 +91,117 @@ function nextHealth(current, kind) {
|
|
|
71
91
|
}
|
|
72
92
|
function createRegistry(options) {
|
|
73
93
|
const byId = new Map(options.providers.map((provider) => [provider.id, provider]));
|
|
74
|
-
async function call(serviceKey, args, callOptions = {}) {
|
|
75
|
-
const configured = [...await options.config.list(serviceKey)].filter((
|
|
94
|
+
async function call(serviceKey, methodKey, args, callOptions = {}) {
|
|
95
|
+
const configured = [...await options.config.list(serviceKey, methodKey)].filter((attachment) => attachment.enabled).sort((a, b) => a.priority - b.priority);
|
|
76
96
|
const attempts = [];
|
|
77
|
-
for (const
|
|
97
|
+
for (const attachment of configured) {
|
|
78
98
|
if (callOptions.signal?.aborted) {
|
|
79
99
|
const cancelled = {
|
|
80
100
|
ok: false,
|
|
101
|
+
fallbackUsed: attempts.length > 0,
|
|
81
102
|
attempts,
|
|
82
|
-
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
103
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}.${methodKey}" call was cancelled.`)
|
|
83
104
|
};
|
|
84
|
-
options.after?.(cancelled);
|
|
105
|
+
await options.after?.(cancelled);
|
|
85
106
|
return cancelled;
|
|
86
107
|
}
|
|
87
|
-
const
|
|
88
|
-
if (!
|
|
89
|
-
attempts.push({ providerId:
|
|
108
|
+
const instance = await options.config.provider(attachment.instanceKey);
|
|
109
|
+
if (!instance) {
|
|
110
|
+
attempts.push({ providerId: "unknown", instanceKey: attachment.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: "instance not registered" });
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const spec = byId.get(instance.providerId);
|
|
114
|
+
const method = spec?.methods[attachment.providerMethod];
|
|
115
|
+
if (!spec || !method) {
|
|
116
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: !spec ? "provider not registered" : "method not supported" });
|
|
90
117
|
continue;
|
|
91
118
|
}
|
|
92
|
-
if (
|
|
93
|
-
attempts.push({ providerId:
|
|
119
|
+
if (!instance.enabled) {
|
|
120
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: "instance disabled" });
|
|
94
121
|
continue;
|
|
95
122
|
}
|
|
96
|
-
|
|
123
|
+
if (attachment.health?.status === "offline") {
|
|
124
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "skipped", error: "offline" });
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
await options.before?.({ service: serviceKey, method: methodKey, provider: instance.providerId, instance: instance.instanceKey });
|
|
128
|
+
const startedAt = performance.now();
|
|
97
129
|
try {
|
|
98
|
-
const result = await
|
|
99
|
-
config:
|
|
100
|
-
secret: (field) => options.credentials.get(
|
|
130
|
+
const result = await method.invoke({
|
|
131
|
+
config: instance.config,
|
|
132
|
+
secret: (field) => options.credentials.get(instance.secretRef, field),
|
|
101
133
|
signal: callOptions.signal
|
|
102
134
|
}, args);
|
|
103
|
-
attempts.push({ providerId:
|
|
104
|
-
await options.config.recordHealth(serviceKey,
|
|
105
|
-
const sent = {
|
|
106
|
-
|
|
135
|
+
attempts.push({ providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod, outcome: "sent", durationMs: performance.now() - startedAt });
|
|
136
|
+
await options.config.recordHealth(serviceKey, methodKey, instance.instanceKey, attachment.providerMethod, nextHealth(attachment.health, "success"));
|
|
137
|
+
const sent = {
|
|
138
|
+
ok: true,
|
|
139
|
+
result,
|
|
140
|
+
provider: instance.providerId,
|
|
141
|
+
instance: instance.instanceKey,
|
|
142
|
+
method: attachment.providerMethod,
|
|
143
|
+
selected: { providerId: instance.providerId, instanceKey: instance.instanceKey, providerMethod: attachment.providerMethod },
|
|
144
|
+
fallbackUsed: attempts.length > 1,
|
|
145
|
+
attempts
|
|
146
|
+
};
|
|
147
|
+
await options.after?.(sent);
|
|
107
148
|
return sent;
|
|
108
149
|
} catch (error) {
|
|
109
150
|
if (callOptions.signal?.aborted) {
|
|
110
151
|
const cancelled = {
|
|
111
152
|
ok: false,
|
|
153
|
+
fallbackUsed: attempts.length > 0,
|
|
112
154
|
attempts,
|
|
113
|
-
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}" call was cancelled.`)
|
|
155
|
+
error: new ProviderError("CALL_ABORTED", `The "${serviceKey}.${methodKey}" call was cancelled.`)
|
|
114
156
|
};
|
|
115
|
-
options.after?.(cancelled);
|
|
157
|
+
await options.after?.(cancelled);
|
|
116
158
|
return cancelled;
|
|
117
159
|
}
|
|
118
|
-
const kind =
|
|
160
|
+
const kind = method.classify(error);
|
|
161
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
162
|
+
const code = error instanceof ProviderError ? error.code : typeof error?.code === "string" ? error.code : undefined;
|
|
119
163
|
attempts.push({
|
|
120
|
-
providerId:
|
|
164
|
+
providerId: instance.providerId,
|
|
165
|
+
instanceKey: instance.instanceKey,
|
|
166
|
+
providerMethod: attachment.providerMethod,
|
|
121
167
|
outcome: "failed",
|
|
122
168
|
kind,
|
|
123
|
-
|
|
169
|
+
durationMs: performance.now() - startedAt,
|
|
170
|
+
failure: { kind, ...code ? { code } : {}, message },
|
|
171
|
+
error: message
|
|
124
172
|
});
|
|
125
|
-
await options.config.recordHealth(serviceKey,
|
|
173
|
+
await options.config.recordHealth(serviceKey, methodKey, instance.instanceKey, attachment.providerMethod, nextHealth(attachment.health, kind));
|
|
126
174
|
if (kind === "terminal") {
|
|
127
175
|
const refused = {
|
|
128
176
|
ok: false,
|
|
177
|
+
fallbackUsed: attempts.length > 1,
|
|
129
178
|
attempts,
|
|
130
179
|
error: new ProviderError("PAYLOAD_REJECTED", "The request was refused as malformed; no provider will accept it.")
|
|
131
180
|
};
|
|
132
|
-
options.after?.(refused);
|
|
181
|
+
await options.after?.(refused);
|
|
133
182
|
return refused;
|
|
134
183
|
}
|
|
135
184
|
}
|
|
136
185
|
}
|
|
137
186
|
const failed = {
|
|
138
187
|
ok: false,
|
|
188
|
+
fallbackUsed: attempts.length > 1,
|
|
139
189
|
attempts,
|
|
140
|
-
error: new ProviderError(attempts.length === 0 ? "NO_PROVIDER" : "ALL_PROVIDERS_FAILED", attempts.length === 0 ? `No provider is configured for "${serviceKey}".` : `Every provider for "${serviceKey}" failed or was skipped.`)
|
|
190
|
+
error: new ProviderError(attempts.length === 0 ? "NO_PROVIDER" : "ALL_PROVIDERS_FAILED", attempts.length === 0 ? `No provider method is configured for "${serviceKey}.${methodKey}".` : `Every provider method for "${serviceKey}.${methodKey}" failed or was skipped.`)
|
|
141
191
|
};
|
|
142
|
-
options.after?.(failed);
|
|
192
|
+
await options.after?.(failed);
|
|
143
193
|
return failed;
|
|
144
194
|
}
|
|
145
|
-
|
|
195
|
+
function service(definition) {
|
|
196
|
+
return {
|
|
197
|
+
call(method, args, callOptions) {
|
|
198
|
+
return call(definition.key, method, args, callOptions);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
return { call, service };
|
|
146
203
|
}
|
|
147
|
-
var VERSION = "0.1.
|
|
204
|
+
var VERSION = "0.1.10";
|
|
148
205
|
|
|
149
206
|
// src/database.ts
|
|
150
207
|
var pools = new Map;
|
|
@@ -296,9 +353,9 @@ function nodeForRequest(pool, request, fallback, excluded, now) {
|
|
|
296
353
|
}
|
|
297
354
|
return selectNode(pool, excluded, now, () => true);
|
|
298
355
|
}
|
|
299
|
-
var arangodb =
|
|
356
|
+
var arangodb = defineSingleMethodProvider({
|
|
300
357
|
id: "arangodb",
|
|
301
|
-
|
|
358
|
+
method: "query",
|
|
302
359
|
label: "ArangoDB",
|
|
303
360
|
credentials: {
|
|
304
361
|
type: "object",
|
package/dist/email.d.ts
CHANGED
|
@@ -6,25 +6,12 @@ export interface JetEmailConfig {
|
|
|
6
6
|
batchEndpoint?: string;
|
|
7
7
|
fetch?: typeof globalThis.fetch;
|
|
8
8
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
* accept it, so trying the next one wastes a round trip
|
|
15
|
-
* and buries the real error
|
|
16
|
-
* 401 bad key → RETRYABLE: THIS key is wrong; the next provider's may
|
|
17
|
-
* be fine. This is the case people get wrong by treating
|
|
18
|
-
* any 4xx as fatal
|
|
19
|
-
* 409 idempotency → TERMINAL: the message already exists. Re-sending via
|
|
20
|
-
* another provider would deliver it twice
|
|
21
|
-
* 429 rate limited → BACKOFF: it is working, we are asking too fast
|
|
22
|
-
*/
|
|
23
|
-
export declare const jetemail: import("./index").ProviderSpec<EmailMessage, {
|
|
24
|
-
id: string;
|
|
9
|
+
export declare const jetemail: import("./index").ProviderDefinition<{
|
|
10
|
+
send: import("./index").ProviderMethodSpec<EmailMessage, {
|
|
11
|
+
id: string;
|
|
12
|
+
}>;
|
|
13
|
+
sendBatch: import("./index").ProviderMethodSpec<EmailBatch, EmailBatchResult>;
|
|
25
14
|
}>;
|
|
26
|
-
/** JetEmail's native POST /email-batch capability. */
|
|
27
|
-
export declare const jetemailBatch: import("./index").ProviderSpec<EmailBatch, EmailBatchResult>;
|
|
28
15
|
/**
|
|
29
16
|
* A transport, so this package holds no socket code and no nodemailer.
|
|
30
17
|
*
|
|
@@ -49,31 +36,26 @@ export interface SmtpTransport {
|
|
|
49
36
|
messageId: string;
|
|
50
37
|
}>;
|
|
51
38
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
*
|
|
57
|
-
* SMTP reply codes carry the same distinction as HTTP status:
|
|
58
|
-
*
|
|
59
|
-
* 5xx permanent → TERMINAL for 550/553 (bad recipient — every relay agrees)
|
|
60
|
-
* RETRYABLE for 535 (auth failed — THIS relay's credentials)
|
|
61
|
-
* 4xx transient → RETRYABLE, and 421/450/451 specifically mean try later
|
|
62
|
-
*/
|
|
63
|
-
export declare const smtp: import("./index").ProviderSpec<EmailMessage, {
|
|
64
|
-
id: string;
|
|
39
|
+
export declare const smtp: import("./index").ProviderDefinition<{
|
|
40
|
+
send: import("./index").ProviderMethodSpec<EmailMessage, {
|
|
41
|
+
id: string;
|
|
42
|
+
}>;
|
|
65
43
|
}>;
|
|
66
|
-
/**
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
id: string;
|
|
44
|
+
/** Ready to register for the email service's `send` method. */
|
|
45
|
+
export declare const emailProviders: readonly [import("./index").ProviderDefinition<{
|
|
46
|
+
send: import("./index").ProviderMethodSpec<EmailMessage, {
|
|
47
|
+
id: string;
|
|
48
|
+
}>;
|
|
49
|
+
sendBatch: import("./index").ProviderMethodSpec<EmailBatch, EmailBatchResult>;
|
|
50
|
+
}>, import("./index").ProviderDefinition<{
|
|
51
|
+
send: import("./index").ProviderMethodSpec<EmailMessage, {
|
|
52
|
+
id: string;
|
|
53
|
+
}>;
|
|
77
54
|
}>];
|
|
78
|
-
/**
|
|
79
|
-
export declare const
|
|
55
|
+
/** Provider-neutral service contract applications and SSOT handlers call. */
|
|
56
|
+
export declare const emailService: import("./index").ServiceDefinition<"email", {
|
|
57
|
+
send: import("./index").ServiceMethodContract<EmailMessage, {
|
|
58
|
+
id: string;
|
|
59
|
+
}>;
|
|
60
|
+
sendBatch: import("./index").ServiceMethodContract<EmailBatch, EmailBatchResult>;
|
|
61
|
+
}>;
|