stellarium-ts 0.14.0 → 0.15.0
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/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js +3 -2
- package/dist/resource/invoker.d.ts +2 -2
- package/dist/resource/invoker.d.ts.map +1 -1
- package/dist/resource/invoker.js +6 -6
- package/dist/resource/repository.d.ts +1 -1
- package/dist/resource/repository.d.ts.map +1 -1
- package/dist/resource/repository.js +2 -2
- package/dist/routes.js +2 -2
- package/dist/server.d.ts +3 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +4 -4
- package/dist/service.d.ts +1 -1
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +1 -1
- package/dist/tests/db/db.test.js +1 -1
- package/dist/tests/helpers.js +2 -2
- package/dist/tests/integration/network.test.js +4 -3
- package/dist/tests/resource/invoker.test.js +2 -2
- package/dist/tests/resource/repository.test.js +5 -5
- package/dist/tests/routes.test.js +3 -3
- package/dist/tests/server.test.js +7 -7
- package/package.json +1 -1
package/dist/db/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE7C,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db/db.ts"],"names":[],"mappings":"AACA,OAAO,EAAQ,KAAK,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAE7C,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAW1D,wGAAwG;AACxG,wBAAsB,YAAY,CAAC,QAAQ,GAAE,MAA8B,GAAG,OAAO,CAAC,QAAQ,CAAC,CAI9F;AAED,wBAAsB,YAAY,CAAC,EAAE,EAAE,QAAQ,iBA0I9C"}
|
package/dist/db/db.js
CHANGED
|
@@ -6,8 +6,9 @@ export const DEFAULT_DATABASE_PATH = './requestscript.db';
|
|
|
6
6
|
* Version 1 dropped `UNIQUE (base_url)` from `resource` and added uniqueness to the function tables.
|
|
7
7
|
* Version 2 added `resource_function.restricted`.
|
|
8
8
|
* Version 3 added `resource.website` and the `description` columns of the resource tables.
|
|
9
|
+
* Version 4 renamed `resource_function_payment_manifest.cost_lamports` to `cost_micro_usdc` (payments moved to USDC).
|
|
9
10
|
*/
|
|
10
|
-
const SCHEMA_VERSION =
|
|
11
|
+
const SCHEMA_VERSION = 4;
|
|
11
12
|
/** Opens (or creates) the node database and brings its schema up to date. Pass ':memory:' for tests. */
|
|
12
13
|
export async function openDatabase(filename = DEFAULT_DATABASE_PATH) {
|
|
13
14
|
const db = await open({ filename, driver: sqlite3.Database });
|
|
@@ -88,7 +89,7 @@ export async function createTables(db) {
|
|
|
88
89
|
CREATE TABLE IF NOT EXISTS resource_function_payment_manifest (
|
|
89
90
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
90
91
|
resource_function_id INTEGER NOT NULL,
|
|
91
|
-
|
|
92
|
+
cost_micro_usdc INTEGER NOT NULL,
|
|
92
93
|
recipient_address TEXT NOT NULL,
|
|
93
94
|
created_at TEXT NOT NULL,
|
|
94
95
|
updated_at TEXT NOT NULL,
|
|
@@ -36,12 +36,12 @@ export declare const EXTERNAL_INVOKE_BASE_DELAY_MS = 500;
|
|
|
36
36
|
export declare const EXTERNAL_INVOKE_TIMEOUT_MS = 30000;
|
|
37
37
|
export declare class CombinationResourceInvoker implements ResourceInvoker {
|
|
38
38
|
private readonly resourceRepository;
|
|
39
|
-
private readonly
|
|
39
|
+
private readonly costLimitMicroUsdc;
|
|
40
40
|
private readonly publicKey;
|
|
41
41
|
private readonly privateKey;
|
|
42
42
|
private readonly grantService?;
|
|
43
43
|
/** Without a `grantService`, calls to restricted remote functions fail. */
|
|
44
|
-
constructor(resourceRepository: ResourceRepository,
|
|
44
|
+
constructor(resourceRepository: ResourceRepository, costLimitMicroUsdc: number, publicKey: string, privateKey: string, grantService?: GrantService | undefined);
|
|
45
45
|
/**
|
|
46
46
|
* Invoke a function on a resource.
|
|
47
47
|
* If the resource has a baseUrl, it will be invoked as a remote function.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"invoker.d.ts","sourceRoot":"","sources":["../../src/resource/invoker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC1B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,6BAA6B,EAAE,GAC5C,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC;;;;;;;;EAG/E;AAED,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAC7C,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,wEAAwE;AACxE,eAAO,MAAM,0BAA0B,QAAS,CAAC;AA2BjD,qBAAa,0BAA2B,YAAW,eAAe;IAGlD,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAAsB,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"invoker.d.ts","sourceRoot":"","sources":["../../src/resource/invoker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,6BAA6B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEzF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAC1B,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,6BAA6B,EAAE,GAC5C,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,EAAE,WAAW,CAAC;;;;;;;;EAG/E;AAED,eAAO,MAAM,2BAA2B,IAAI,CAAC;AAC7C,eAAO,MAAM,6BAA6B,MAAM,CAAC;AACjD,wEAAwE;AACxE,eAAO,MAAM,0BAA0B,QAAS,CAAC;AA2BjD,qBAAa,0BAA2B,YAAW,eAAe;IAGlD,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAAsB,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAAU,OAAO,CAAC,QAAQ,CAAC,SAAS;IAAU,OAAO,CAAC,QAAQ,CAAC,UAAU;IAAU,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;IADzN,2EAA2E;IAC3E,YAA6B,kBAAkB,EAAE,kBAAkB,EAAmB,kBAAkB,EAAE,MAAM,EAAmB,SAAS,EAAE,MAAM,EAAmB,UAAU,EAAE,MAAM,EAAmB,YAAY,CAAC,EAAE,YAAY,YAAA,EAAI;IAC3O;;;;;;;;;;;OAWG;IACG,MAAM,CAAC,QAAQ,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,6BAA6B,EAAE,GAAG,OAAO,CAAC;QAAE,KAAK,EAAE,GAAG,CAAC;QAAC,KAAK,EAAE;YAAE,OAAO,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAA;KAAC,CAAC,CAgE7J;IAED,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,UAAU,EAAE,6BAA6B,EAAE,GAAG,cAAc,CAQ5L;CACJ"}
|
package/dist/resource/invoker.js
CHANGED
|
@@ -46,14 +46,14 @@ async function fetchWithRetry(url, init) {
|
|
|
46
46
|
}
|
|
47
47
|
export class CombinationResourceInvoker {
|
|
48
48
|
resourceRepository;
|
|
49
|
-
|
|
49
|
+
costLimitMicroUsdc;
|
|
50
50
|
publicKey;
|
|
51
51
|
privateKey;
|
|
52
52
|
grantService;
|
|
53
53
|
/** Without a `grantService`, calls to restricted remote functions fail. */
|
|
54
|
-
constructor(resourceRepository,
|
|
54
|
+
constructor(resourceRepository, costLimitMicroUsdc, publicKey, privateKey, grantService) {
|
|
55
55
|
this.resourceRepository = resourceRepository;
|
|
56
|
-
this.
|
|
56
|
+
this.costLimitMicroUsdc = costLimitMicroUsdc;
|
|
57
57
|
this.publicKey = publicKey;
|
|
58
58
|
this.privateKey = privateKey;
|
|
59
59
|
this.grantService = grantService;
|
|
@@ -95,10 +95,10 @@ export class CombinationResourceInvoker {
|
|
|
95
95
|
let paymentVoucher;
|
|
96
96
|
if (resourceFunction.paymentManifest) {
|
|
97
97
|
console.log(`Resource function ${resource.name}.${functionName} has a payment manifest, creating payment voucher...`);
|
|
98
|
-
if (resourceFunction.paymentManifest.
|
|
99
|
-
throw new Error(`Function ${functionName} cost ${resourceFunction.paymentManifest.
|
|
98
|
+
if (resourceFunction.paymentManifest.costMicroUsdc > this.costLimitMicroUsdc) {
|
|
99
|
+
throw new Error(`Function ${functionName} cost ${resourceFunction.paymentManifest.costMicroUsdc} micro-USDC, which exceeds the cost limit of ${this.costLimitMicroUsdc} micro-USDC`);
|
|
100
100
|
}
|
|
101
|
-
paymentVoucher = this.createPaymentVoucher(resourceFunction.paymentManifest.recipientAddress, resourceFunction.paymentManifest.
|
|
101
|
+
paymentVoucher = this.createPaymentVoucher(resourceFunction.paymentManifest.recipientAddress, resourceFunction.paymentManifest.costMicroUsdc, resource.path, resource.name, functionName, parameters);
|
|
102
102
|
requestBody.paymentVoucher = paymentVoucher;
|
|
103
103
|
}
|
|
104
104
|
// The voucher is created once and reused on every attempt, so the operator's
|
|
@@ -3,7 +3,7 @@ import { Database } from "sqlite";
|
|
|
3
3
|
import type { StoredPeer } from "../peer/repository.js";
|
|
4
4
|
export interface StellariumResourceFunctionPaymentManifest {
|
|
5
5
|
id?: number;
|
|
6
|
-
|
|
6
|
+
costMicroUsdc: number;
|
|
7
7
|
recipientAddress: string;
|
|
8
8
|
}
|
|
9
9
|
export interface StellariumResourceFunctionParameter extends ResourceFunctionParameter {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/resource/repository.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AAClC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,WAAW,yCAAyC;IACtD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/resource/repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -120,7 +120,7 @@ export class ResourceRepository {
|
|
|
120
120
|
await this.db.run('INSERT INTO resource_function_parameter (resource_function_id, name, parameter_type, description, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?)', [functionId, parameter.name, parameter.type, optionalText(parameter.description), createdAt, createdAt]);
|
|
121
121
|
}
|
|
122
122
|
if (fn.paymentManifest) {
|
|
123
|
-
await this.db.run('INSERT INTO resource_function_payment_manifest (resource_function_id,
|
|
123
|
+
await this.db.run('INSERT INTO resource_function_payment_manifest (resource_function_id, cost_micro_usdc, recipient_address, created_at, updated_at) VALUES (?, ?, ?, ?, ?)', [functionId, fn.paymentManifest.costMicroUsdc, fn.paymentManifest.recipientAddress, createdAt, createdAt]);
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
}
|
|
@@ -220,7 +220,7 @@ export class ResourceRepository {
|
|
|
220
220
|
}
|
|
221
221
|
return {
|
|
222
222
|
id: result.id,
|
|
223
|
-
|
|
223
|
+
costMicroUsdc: result.cost_micro_usdc,
|
|
224
224
|
recipientAddress: result.recipient_address,
|
|
225
225
|
};
|
|
226
226
|
}
|
package/dist/routes.js
CHANGED
|
@@ -109,7 +109,7 @@ function isValidPaymentVoucher(voucher, manifest, request) {
|
|
|
109
109
|
if (voucher.invocationHash !== expectedHash) {
|
|
110
110
|
return false;
|
|
111
111
|
}
|
|
112
|
-
if (voucher.amount < manifest.
|
|
112
|
+
if (voucher.amount < manifest.costMicroUsdc) {
|
|
113
113
|
return false;
|
|
114
114
|
}
|
|
115
115
|
if (voucher.recipientAddress !== manifest.recipientAddress) {
|
|
@@ -188,7 +188,7 @@ const routes = async (fastify, options) => {
|
|
|
188
188
|
description: parameter.description,
|
|
189
189
|
})),
|
|
190
190
|
paymentManifest: fn.paymentManifest ? ({
|
|
191
|
-
|
|
191
|
+
costMicroUsdc: fn.paymentManifest.costMicroUsdc,
|
|
192
192
|
recipientAddress: fn.paymentManifest.recipientAddress,
|
|
193
193
|
}) : undefined,
|
|
194
194
|
restricted: fn.restricted || undefined,
|
package/dist/server.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { ApproveGrant, GrantOptions } from './grant/service.js';
|
|
|
6
6
|
import { StellariumResource } from './resource/repository.js';
|
|
7
7
|
import { RateLimitConfig } from './routes.js';
|
|
8
8
|
import { type NodeConfig } from './service.js';
|
|
9
|
-
export declare const
|
|
9
|
+
export declare const DEFAULT_COST_LIMIT_MICRO_USDC = 10000;
|
|
10
10
|
export declare const DEFAULT_GRANT_REFRESH_INTERVAL_MS: number;
|
|
11
11
|
export interface StellariumNodeOptions {
|
|
12
12
|
port?: number;
|
|
@@ -24,8 +24,8 @@ export interface StellariumNodeOptions {
|
|
|
24
24
|
apiKey?: string;
|
|
25
25
|
/** Defaults to `OPERATOR_URL`. */
|
|
26
26
|
operatorUrl?: string;
|
|
27
|
-
/** Most this node pays for one remote call. Defaults to `
|
|
28
|
-
|
|
27
|
+
/** Most this node pays for one remote call. Defaults to `COST_LIMIT_MICRO_USDC`, then 10,000 ($0.01). */
|
|
28
|
+
costLimitMicroUsdc?: number;
|
|
29
29
|
/** SQLite file. Defaults to `./requestscript.db`; use ':memory:' for tests. */
|
|
30
30
|
databasePath?: string;
|
|
31
31
|
/**
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE1C,OAAO,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAC9D,OAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAiB,KAAK,UAAU,EAAgB,MAAM,cAAc,CAAC;AAG5E,eAAO,MAAM,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -3,7 +3,7 @@ import { DEFAULT_DATABASE_PATH, openDatabase } from './db/db.js';
|
|
|
3
3
|
import routes from './routes.js';
|
|
4
4
|
import { createService } from './service.js';
|
|
5
5
|
import { StartupService } from './startup.js';
|
|
6
|
-
export const
|
|
6
|
+
export const DEFAULT_COST_LIMIT_MICRO_USDC = 10_000;
|
|
7
7
|
export const DEFAULT_GRANT_REFRESH_INTERVAL_MS = 1000 * 60 * 5;
|
|
8
8
|
function required(name, value) {
|
|
9
9
|
if (!value) {
|
|
@@ -15,9 +15,9 @@ function hostsPaidFunctions(resources) {
|
|
|
15
15
|
return resources.some(resource => resource.functions.some(fn => fn.paymentManifest));
|
|
16
16
|
}
|
|
17
17
|
export function resolveConfig(options, resources = []) {
|
|
18
|
-
const costLimit = options.
|
|
18
|
+
const costLimit = options.costLimitMicroUsdc ?? (process.env.COST_LIMIT_MICRO_USDC ? Number(process.env.COST_LIMIT_MICRO_USDC) : DEFAULT_COST_LIMIT_MICRO_USDC);
|
|
19
19
|
if (!Number.isSafeInteger(costLimit) || costLimit < 0) {
|
|
20
|
-
throw new Error('
|
|
20
|
+
throw new Error('costLimitMicroUsdc must be a nonnegative integer');
|
|
21
21
|
}
|
|
22
22
|
return {
|
|
23
23
|
baseUrl: required('BASE_URL', options.baseUrl ?? process.env.BASE_URL),
|
|
@@ -28,7 +28,7 @@ export function resolveConfig(options, resources = []) {
|
|
|
28
28
|
operatorUrl: hostsPaidFunctions(resources)
|
|
29
29
|
? required('OPERATOR_URL', options.operatorUrl ?? process.env.OPERATOR_URL)
|
|
30
30
|
: options.operatorUrl ?? process.env.OPERATOR_URL,
|
|
31
|
-
|
|
31
|
+
costLimitMicroUsdc: costLimit,
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
export class StellariumNode {
|
package/dist/service.d.ts
CHANGED
|
@@ -17,7 +17,7 @@ export interface NodeConfig {
|
|
|
17
17
|
/** Operator base URL, including `/v1`. Required when the node hosts paid functions. */
|
|
18
18
|
operatorUrl?: string;
|
|
19
19
|
/** Most this node will pay for one remote call. */
|
|
20
|
-
|
|
20
|
+
costLimitMicroUsdc: number;
|
|
21
21
|
}
|
|
22
22
|
export interface Service {
|
|
23
23
|
config: NodeConfig;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,EAAE,KAAK,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAErE,4GAA4G;AAC5G,MAAM,WAAW,UAAU;IACvB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAClE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,kBAAkB,EAAE,KAAK,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEvF,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAE5D,OAAO,EAAE,KAAK,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAErE,4GAA4G;AAC5G,MAAM,WAAW,UAAU;IACvB,4DAA4D;IAC5D,OAAO,EAAE,MAAM,CAAC;IAChB,mCAAmC;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,oFAAoF;IACpF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uFAAuF;IACvF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mDAAmD;IACnD,kBAAkB,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,OAAO;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,EAAE,YAAY,CAAC;CAC9B;AAED,MAAM,WAAW,cAAc;IAC3B,+EAA+E;IAC/E,YAAY,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAoBtI"}
|
package/dist/service.js
CHANGED
|
@@ -9,7 +9,7 @@ export function createService(db, resources, config, options = {}) {
|
|
|
9
9
|
const resourceRepository = new ResourceRepository(db, resources, config.baseUrl);
|
|
10
10
|
const resourceResolver = new CombinationResourceResolver(resourceRepository);
|
|
11
11
|
const grantService = new GrantService(new GrantRepository(db), config, options.approveGrant);
|
|
12
|
-
const resourceInvoker = new CombinationResourceInvoker(resourceRepository, config.
|
|
12
|
+
const resourceInvoker = new CombinationResourceInvoker(resourceRepository, config.costLimitMicroUsdc, config.publicKey, config.privateKey, grantService);
|
|
13
13
|
const operatorClient = new OperatorClient(config.operatorUrl);
|
|
14
14
|
return {
|
|
15
15
|
config,
|
package/dist/tests/db/db.test.js
CHANGED
|
@@ -17,7 +17,7 @@ describe("openDatabase", () => {
|
|
|
17
17
|
const filename = path.join(dir, "node.db");
|
|
18
18
|
await (await openDatabase(filename)).close();
|
|
19
19
|
const db = await openDatabase(filename);
|
|
20
|
-
expect(await db.get("PRAGMA user_version")).toEqual({ user_version:
|
|
20
|
+
expect(await db.get("PRAGMA user_version")).toEqual({ user_version: 4 });
|
|
21
21
|
await db.close();
|
|
22
22
|
});
|
|
23
23
|
test("rebuilds resource tables from the old schema and keeps peers", async () => {
|
package/dist/tests/helpers.js
CHANGED
|
@@ -17,7 +17,7 @@ export function testConfig(overrides = {}) {
|
|
|
17
17
|
...generateBase64KeyPair(),
|
|
18
18
|
apiKey: "secret",
|
|
19
19
|
operatorUrl: "http://operator.invalid/v1",
|
|
20
|
-
|
|
20
|
+
costLimitMicroUsdc: 100_000,
|
|
21
21
|
...overrides,
|
|
22
22
|
};
|
|
23
23
|
}
|
|
@@ -35,7 +35,7 @@ export function weatherResource(baseUrl = "http://127.0.0.1:3002") {
|
|
|
35
35
|
parameters: [{ name: "city", type: "string" }],
|
|
36
36
|
returnType: "int32",
|
|
37
37
|
exec: async (args) => (args.find((arg) => arg.name === "city")?.value === "Oslo" ? 12 : 20),
|
|
38
|
-
paymentManifest: {
|
|
38
|
+
paymentManifest: { costMicroUsdc: COST, recipientAddress: RECIPIENT },
|
|
39
39
|
},
|
|
40
40
|
{
|
|
41
41
|
name: "humidity",
|
|
@@ -36,7 +36,8 @@ function freePort() {
|
|
|
36
36
|
* A provider node hosting the paid weather resource, a caller node that bootstraps from it,
|
|
37
37
|
* and a fake operator that records settlements. Everything runs in-process over real HTTP.
|
|
38
38
|
*/
|
|
39
|
-
|
|
39
|
+
// Each test starts real HTTP nodes on SQLite files, which can take several seconds on a loaded CI runner.
|
|
40
|
+
describe("two-node network", { timeout: 15_000 }, () => {
|
|
40
41
|
const servers = [];
|
|
41
42
|
const settlements = [];
|
|
42
43
|
const callerKeys = generateBase64KeyPair();
|
|
@@ -106,7 +107,7 @@ describe("two-node network", () => {
|
|
|
106
107
|
expect(callerResources.resources).toContainEqual(expect.objectContaining({
|
|
107
108
|
name: "Weather",
|
|
108
109
|
baseUrl: providerUrl,
|
|
109
|
-
functions: expect.arrayContaining([expect.objectContaining({ name: "temperature", paymentManifest: {
|
|
110
|
+
functions: expect.arrayContaining([expect.objectContaining({ name: "temperature", paymentManifest: { costMicroUsdc: COST, recipientAddress: RECIPIENT } })]),
|
|
110
111
|
}));
|
|
111
112
|
expect(await run(caller.url)).toEqual({ returnValue: { value: 12, error: null } });
|
|
112
113
|
await vi.waitFor(() => expect(settlements).toHaveLength(1));
|
|
@@ -179,7 +180,7 @@ describe("two-node network", () => {
|
|
|
179
180
|
});
|
|
180
181
|
});
|
|
181
182
|
test("the caller refuses a call that costs more than its limit", async () => {
|
|
182
|
-
const caller = await startCaller({
|
|
183
|
+
const caller = await startCaller({ costLimitMicroUsdc: COST - 1 });
|
|
183
184
|
const result = await run(caller.url);
|
|
184
185
|
expect(result.returnValue.value).toBeNull();
|
|
185
186
|
expect(result.returnValue.error.message).toContain("exceeds the cost limit");
|
|
@@ -93,7 +93,7 @@ describe("external invoke retries", () => {
|
|
|
93
93
|
});
|
|
94
94
|
test("reuses the same payment voucher on every attempt", async () => {
|
|
95
95
|
fetchMock.mockResolvedValueOnce(status(503)).mockResolvedValueOnce(status(503)).mockResolvedValueOnce(ok());
|
|
96
|
-
const invoker = createInvoker({
|
|
96
|
+
const invoker = createInvoker({ costMicroUsdc: 10000, recipientAddress: "4HkmXgXCJ8tw1ih5VFHetRt4kWdo1VLBVmV7B5p6ctK2" });
|
|
97
97
|
const pending = invoker.invoke(resource, "forecast", parameters);
|
|
98
98
|
await vi.runAllTimersAsync();
|
|
99
99
|
await pending;
|
|
@@ -139,7 +139,7 @@ describe("restricted functions", () => {
|
|
|
139
139
|
fetchMock.mockResolvedValueOnce(new Response(null, { status: 503 })).mockResolvedValueOnce(new Response(JSON.stringify({ value: 42, error: null }), { status: 200 }));
|
|
140
140
|
let nonce = 0;
|
|
141
141
|
const authorize = vi.fn(() => ({ nonce: `nonce-${nonce++}` }));
|
|
142
|
-
const invoker = createInvoker({ chainFor: async () => chain, authorize }, {
|
|
142
|
+
const invoker = createInvoker({ chainFor: async () => chain, authorize }, { costMicroUsdc: 10000, recipientAddress: "4HkmXgXCJ8tw1ih5VFHetRt4kWdo1VLBVmV7B5p6ctK2" });
|
|
143
143
|
const pending = invoker.invoke(resource, "forecast", parameters);
|
|
144
144
|
await vi.runAllTimersAsync();
|
|
145
145
|
await expect(pending).resolves.toEqual({ value: 42, error: null });
|
|
@@ -88,12 +88,12 @@ describe("ResourceRepository", () => {
|
|
|
88
88
|
test("returns each function's own payment manifest", async () => {
|
|
89
89
|
await repository.learn(resource("Forecast", [
|
|
90
90
|
{ name: "free" },
|
|
91
|
-
{ name: "paid", paymentManifest: {
|
|
91
|
+
{ name: "paid", paymentManifest: { costMicroUsdc: 250, recipientAddress: RECIPIENT } },
|
|
92
92
|
]));
|
|
93
93
|
const found = await repository.getResource("com.provider.Forecast");
|
|
94
94
|
expect(found.metadata).toEqual({ baseUrl: PROVIDER });
|
|
95
95
|
expect(found.functions.find(f => f.name === "free")?.paymentManifest).toBeUndefined();
|
|
96
|
-
expect(found.functions.find(f => f.name === "paid")?.paymentManifest).toMatchObject({
|
|
96
|
+
expect(found.functions.find(f => f.name === "paid")?.paymentManifest).toMatchObject({ costMicroUsdc: 250, recipientAddress: RECIPIENT });
|
|
97
97
|
});
|
|
98
98
|
test("prefers the internal resource", async () => {
|
|
99
99
|
const found = await repository.getResource("com.example.Weather");
|
|
@@ -119,13 +119,13 @@ describe("ResourceRepository", () => {
|
|
|
119
119
|
test("adds new functions, parameters and payment manifests to a known resource", async () => {
|
|
120
120
|
await save([resource("Forecast", [{ name: "today" }])]);
|
|
121
121
|
const result = await save([resource("Forecast", [
|
|
122
|
-
{ name: "today", parameters: [{ name: "city", type: "string" }], paymentManifest: {
|
|
122
|
+
{ name: "today", parameters: [{ name: "city", type: "string" }], paymentManifest: { costMicroUsdc: 100, recipientAddress: RECIPIENT } },
|
|
123
123
|
{ name: "tomorrow" },
|
|
124
124
|
])]);
|
|
125
125
|
expect(result).toEqual({ ok: true, rejected: [] });
|
|
126
126
|
const today = await repository.getResourceFunction("com.provider", "Forecast", "today");
|
|
127
127
|
expect(today?.parameters).toEqual([{ name: "city", type: "string" }]);
|
|
128
|
-
expect(today?.paymentManifest).toMatchObject({
|
|
128
|
+
expect(today?.paymentManifest).toMatchObject({ costMicroUsdc: 100 });
|
|
129
129
|
expect(await repository.getResourceFunction("com.provider", "Forecast", "tomorrow")).toBeDefined();
|
|
130
130
|
});
|
|
131
131
|
test("drops descriptions that aren't strings and websites that aren't http(s) URLs", async () => {
|
|
@@ -142,7 +142,7 @@ describe("ResourceRepository", () => {
|
|
|
142
142
|
expect([radar.website, radar.description]).toEqual(["https://radar.example", "Rain radar"]);
|
|
143
143
|
});
|
|
144
144
|
test("removes functions and payment manifests the peer no longer advertises", async () => {
|
|
145
|
-
await save([resource("Forecast", [{ name: "today", paymentManifest: {
|
|
145
|
+
await save([resource("Forecast", [{ name: "today", paymentManifest: { costMicroUsdc: 100, recipientAddress: RECIPIENT } }, { name: "old" }])]);
|
|
146
146
|
await save([resource("Forecast", [{ name: "today" }])]);
|
|
147
147
|
expect((await repository.getResourceFunction("com.provider", "Forecast", "today"))?.paymentManifest).toBeUndefined();
|
|
148
148
|
expect(await repository.getResourceFunction("com.provider", "Forecast", "old")).toBeUndefined();
|
|
@@ -270,7 +270,7 @@ describe("routes", () => {
|
|
|
270
270
|
parameters: [{ name: "city", type: "string" }],
|
|
271
271
|
returnType: "string",
|
|
272
272
|
exec: async () => "sunny",
|
|
273
|
-
paymentManifest: {
|
|
273
|
+
paymentManifest: { costMicroUsdc: 500, recipientAddress: RECIPIENT },
|
|
274
274
|
}],
|
|
275
275
|
});
|
|
276
276
|
function broadcast(resources, privateKey = keys.privateKey, publicKey = keys.publicKey) {
|
|
@@ -294,7 +294,7 @@ describe("routes", () => {
|
|
|
294
294
|
const resources = (await fastify.inject({ method: "GET", url: "/v1/resources" })).json().resources;
|
|
295
295
|
expect(resources.find((r) => r.name === "Forecast")).toMatchObject({
|
|
296
296
|
baseUrl: peer.baseUrl,
|
|
297
|
-
functions: [{ name: "tomorrow", paymentManifest: {
|
|
297
|
+
functions: [{ name: "tomorrow", paymentManifest: { costMicroUsdc: 500, recipientAddress: RECIPIENT } }],
|
|
298
298
|
});
|
|
299
299
|
});
|
|
300
300
|
test("rejects a broadcast from an unknown peer", async () => {
|
|
@@ -366,7 +366,7 @@ describe("restricted functions", () => {
|
|
|
366
366
|
name: "Vault",
|
|
367
367
|
functions: [
|
|
368
368
|
{ name: "open", parameters: [{ name: "city", type: "string" }], returnType: "int32", exec: async () => 7, restricted: true },
|
|
369
|
-
{ name: "premium", parameters: [{ name: "city", type: "string" }], returnType: "int32", exec: async () => 9, restricted: true, paymentManifest: {
|
|
369
|
+
{ name: "premium", parameters: [{ name: "city", type: "string" }], returnType: "int32", exec: async () => 9, restricted: true, paymentManifest: { costMicroUsdc: COST, recipientAddress: RECIPIENT } },
|
|
370
370
|
],
|
|
371
371
|
};
|
|
372
372
|
const call = (functionName) => ({ resourcePath: "com.example", resourceName: "Vault", functionName, parameters });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test, vi } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import { DEFAULT_COST_LIMIT_MICRO_USDC, resolveConfig } from "../server.js";
|
|
3
3
|
import { weatherResource } from "./helpers.js";
|
|
4
4
|
describe("resolveConfig", () => {
|
|
5
5
|
const keys = { baseUrl: "http://node.example", publicKey: "public", privateKey: "private" };
|
|
@@ -15,15 +15,15 @@ describe("resolveConfig", () => {
|
|
|
15
15
|
vi.stubEnv("BASE_URL", "http://env.example");
|
|
16
16
|
vi.stubEnv("SIGNING_PUBLIC_KEY", "env-public");
|
|
17
17
|
vi.stubEnv("SIGNING_PRIVATE_KEY", "env-private");
|
|
18
|
-
vi.stubEnv("
|
|
19
|
-
expect(resolveConfig({})).toMatchObject({ baseUrl: "http://env.example", publicKey: "env-public", privateKey: "env-private",
|
|
18
|
+
vi.stubEnv("COST_LIMIT_MICRO_USDC", "500");
|
|
19
|
+
expect(resolveConfig({})).toMatchObject({ baseUrl: "http://env.example", publicKey: "env-public", privateKey: "env-private", costLimitMicroUsdc: 500 });
|
|
20
20
|
});
|
|
21
21
|
test("defaults the cost limit", () => {
|
|
22
|
-
vi.stubEnv("
|
|
23
|
-
expect(resolveConfig(keys).
|
|
22
|
+
vi.stubEnv("COST_LIMIT_MICRO_USDC", undefined);
|
|
23
|
+
expect(resolveConfig(keys).costLimitMicroUsdc).toBe(DEFAULT_COST_LIMIT_MICRO_USDC);
|
|
24
24
|
});
|
|
25
|
-
test.each([-1, 1.5, Number.NaN])("rejects a cost limit of %s", (
|
|
26
|
-
expect(() => resolveConfig({ ...keys,
|
|
25
|
+
test.each([-1, 1.5, Number.NaN])("rejects a cost limit of %s", (costLimitMicroUsdc) => {
|
|
26
|
+
expect(() => resolveConfig({ ...keys, costLimitMicroUsdc })).toThrow("costLimitMicroUsdc");
|
|
27
27
|
});
|
|
28
28
|
test("requires the signing keys and base URL", () => {
|
|
29
29
|
vi.stubEnv("SIGNING_PRIVATE_KEY", undefined);
|