stellarium-ts 0.16.0 → 0.17.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.
Files changed (39) hide show
  1. package/dist/client/operatorAuth.d.ts +19 -0
  2. package/dist/client/operatorAuth.d.ts.map +1 -0
  3. package/dist/client/operatorAuth.js +21 -0
  4. package/dist/client/operatorClient.d.ts +68 -31
  5. package/dist/client/operatorClient.d.ts.map +1 -1
  6. package/dist/client/operatorClient.js +82 -23
  7. package/dist/db/db.d.ts.map +1 -1
  8. package/dist/db/db.js +8 -5
  9. package/dist/index.d.ts +2 -1
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +2 -0
  12. package/dist/resource/inference.d.ts +3 -3
  13. package/dist/resource/inference.d.ts.map +1 -1
  14. package/dist/resource/inference.js +7 -7
  15. package/dist/resource/invoker.d.ts +13 -13
  16. package/dist/resource/invoker.d.ts.map +1 -1
  17. package/dist/resource/invoker.js +26 -23
  18. package/dist/resource/repository.d.ts +13 -7
  19. package/dist/resource/repository.d.ts.map +1 -1
  20. package/dist/resource/repository.js +23 -13
  21. package/dist/routes.d.ts.map +1 -1
  22. package/dist/routes.js +46 -37
  23. package/dist/server.d.ts +10 -5
  24. package/dist/server.d.ts.map +1 -1
  25. package/dist/server.js +20 -7
  26. package/dist/service.d.ts +7 -2
  27. package/dist/service.d.ts.map +1 -1
  28. package/dist/service.js +3 -3
  29. package/dist/tests/client/operatorClient.test.js +94 -36
  30. package/dist/tests/db/db.test.js +4 -4
  31. package/dist/tests/helpers.d.ts +4 -3
  32. package/dist/tests/helpers.d.ts.map +1 -1
  33. package/dist/tests/helpers.js +8 -6
  34. package/dist/tests/integration/network.test.js +56 -9
  35. package/dist/tests/resource/invoker.test.js +14 -9
  36. package/dist/tests/resource/repository.test.js +9 -9
  37. package/dist/tests/routes.test.js +71 -38
  38. package/dist/tests/server.test.js +15 -15
  39. package/package.json +1 -1
@@ -10,7 +10,7 @@ import { CombinationResourceInvoker, inferenceVoucherPayload, paymentVoucherPayl
10
10
  import { resourceAnnouncementPayload } from "../resource/repository.js";
11
11
  import routes from "../routes.js";
12
12
  import { createService } from "../service.js";
13
- import { COST, generateBase64KeyPair, INFERENCE_RATES, modelResource, RECIPIENT, temperatureSource, testConfig, weatherResource } from "./helpers.js";
13
+ import { COST, generateBase64KeyPair, INFERENCE_RATES, modelResource, ORGANIZATION, temperatureSource, testConfig, weatherResource } from "./helpers.js";
14
14
  const parameters = [{ name: "city", value: "Oslo" }];
15
15
  const inMinutes = (minutes) => new Date(Date.now() + minutes * 60_000).toISOString();
16
16
  describe("routes", () => {
@@ -22,12 +22,16 @@ describe("routes", () => {
22
22
  let config;
23
23
  let service;
24
24
  let fastify;
25
- let settlePayment;
25
+ let authorize;
26
+ let capture;
27
+ let release;
26
28
  beforeEach(async () => {
27
29
  db = await openDatabase(":memory:");
28
30
  config = testConfig();
29
31
  service = createService(db, [weather], config);
30
- settlePayment = vi.spyOn(service.operatorClient, "settlePayment").mockResolvedValue(undefined);
32
+ authorize = vi.spyOn(service.operatorClient, "authorize").mockResolvedValue({ ok: true });
33
+ capture = vi.spyOn(service.operatorClient, "capture").mockResolvedValue(undefined);
34
+ release = vi.spyOn(service.operatorClient, "release").mockResolvedValue(undefined);
31
35
  fastify = Fastify();
32
36
  await fastify.register(routes, { prefix: "/v1", service });
33
37
  await fastify.ready();
@@ -41,7 +45,7 @@ describe("routes", () => {
41
45
  const flushSettlement = () => new Promise((resolve) => setTimeout(resolve, 10));
42
46
  describe("POST /v1/run/resource", () => {
43
47
  function voucherFor(functionName = "temperature", overrides = {}) {
44
- const voucher = callerInvoker.createPaymentVoucher(RECIPIENT, COST, weather.path, weather.name, functionName, parameters);
48
+ const voucher = callerInvoker.createPaymentVoucher(ORGANIZATION, COST, weather.path, weather.name, functionName, parameters);
45
49
  if (Object.keys(overrides).length === 0) {
46
50
  return voucher;
47
51
  }
@@ -56,13 +60,30 @@ describe("routes", () => {
56
60
  payload: { resourcePath: weather.path, resourceName: weather.name, functionName: "temperature", parameters, ...body },
57
61
  });
58
62
  }
59
- test("runs a paid function with a valid voucher and settles it", async () => {
63
+ test("authorizes a paid function's voucher, runs it, then captures it", async () => {
60
64
  const paymentVoucher = voucherFor();
61
65
  const response = await runResource({ paymentVoucher });
62
66
  expect(response.statusCode).toBe(200);
63
67
  expect(response.json()).toEqual({ value: 12, error: null });
68
+ expect(authorize).toHaveBeenCalledExactlyOnceWith(paymentVoucher);
64
69
  await flushSettlement();
65
- expect(settlePayment).toHaveBeenCalledExactlyOnceWith({ voucher: paymentVoucher });
70
+ expect(capture).toHaveBeenCalledExactlyOnceWith({ voucher: paymentVoucher });
71
+ expect(release).not.toHaveBeenCalled();
72
+ });
73
+ test.each([
74
+ [402, "Insufficient balance"],
75
+ [403, "Payer organization is frozen"],
76
+ [503, "Payment operator is unavailable"],
77
+ ])("answers the operator's %i refusal without running the function", async (status, error) => {
78
+ authorize.mockResolvedValueOnce({ ok: false, status, error });
79
+ const exec = vi.spyOn(weather.functions[0], "exec");
80
+ const response = await runResource({ paymentVoucher: voucherFor() });
81
+ expect(response.statusCode).toBe(status);
82
+ expect(response.json()).toEqual({ error });
83
+ expect(exec).not.toHaveBeenCalled();
84
+ await flushSettlement();
85
+ expect(capture).not.toHaveBeenCalled();
86
+ expect(release).not.toHaveBeenCalled();
66
87
  });
67
88
  test("refuses a voucher from a blocked caller, even for an unrestricted function", async () => {
68
89
  await service.grantService.block(caller.publicKey);
@@ -70,7 +91,7 @@ describe("routes", () => {
70
91
  expect(response.statusCode).toBe(403);
71
92
  expect(response.json()).toEqual({ error: "Caller is blocked" });
72
93
  await flushSettlement();
73
- expect(settlePayment).not.toHaveBeenCalled();
94
+ expect(capture).not.toHaveBeenCalled();
74
95
  });
75
96
  test("accepts a voucher that pays more than the cost", async () => {
76
97
  const response = await runResource({ paymentVoucher: voucherFor("temperature", { amount: COST + 1 }) });
@@ -80,11 +101,11 @@ describe("routes", () => {
80
101
  const response = await runResource({});
81
102
  expect(response.statusCode).toBe(402);
82
103
  await flushSettlement();
83
- expect(settlePayment).not.toHaveBeenCalled();
104
+ expect(capture).not.toHaveBeenCalled();
84
105
  });
85
106
  test.each([
86
107
  ["pays less than the cost", { amount: COST - 1 }],
87
- ["pays a different recipient", { recipientAddress: "11111111111111111111111111111111" }],
108
+ ["pays a different recipient", { recipientOrganizationId: "org_other" }],
88
109
  ["has expired", { expiresAt: new Date(Date.now() - 1000).toISOString() }],
89
110
  ["has an unparseable expiry", { expiresAt: "not-a-date" }],
90
111
  ])("rejects a voucher that %s", async (_, overrides) => {
@@ -92,14 +113,14 @@ describe("routes", () => {
92
113
  expect(response.statusCode).toBe(400);
93
114
  expect(response.json()).toEqual({ error: "Invalid payment voucher" });
94
115
  await flushSettlement();
95
- expect(settlePayment).not.toHaveBeenCalled();
116
+ expect(capture).not.toHaveBeenCalled();
96
117
  });
97
118
  test("rejects a voucher whose parameters were tampered with", async () => {
98
119
  const response = await runResource({ paymentVoucher: voucherFor(), parameters: [{ name: "city", value: "Bergen" }] });
99
120
  expect(response.statusCode).toBe(400);
100
121
  });
101
122
  test("rejects a voucher issued for a different function", async () => {
102
- const paymentVoucher = callerInvoker.createPaymentVoucher(RECIPIENT, COST, weather.path, weather.name, "humidity", parameters);
123
+ const paymentVoucher = callerInvoker.createPaymentVoucher(ORGANIZATION, COST, weather.path, weather.name, "humidity", parameters);
103
124
  const response = await runResource({ paymentVoucher });
104
125
  expect(response.statusCode).toBe(400);
105
126
  });
@@ -122,21 +143,23 @@ describe("routes", () => {
122
143
  expect(response.statusCode).toBe(200);
123
144
  expect(response.json()).toEqual({ value: 80, error: null });
124
145
  await flushSettlement();
125
- expect(settlePayment).not.toHaveBeenCalled();
146
+ expect(capture).not.toHaveBeenCalled();
126
147
  });
127
148
  test("rejects an unknown function without settling the voucher", async () => {
128
149
  const response = await runResource({ functionName: "missing", paymentVoucher: voucherFor("missing") });
129
150
  expect(response.statusCode).toBe(400);
130
151
  expect(response.json()).toEqual({ error: "Function not found" });
131
152
  await flushSettlement();
132
- expect(settlePayment).not.toHaveBeenCalled();
153
+ expect(capture).not.toHaveBeenCalled();
133
154
  });
134
- test("does not settle when the invoke returns an error", async () => {
155
+ test("releases the hold when the invoke returns an error", async () => {
135
156
  vi.spyOn(service.resourceInvoker, "invoke").mockResolvedValueOnce({ value: null, error: { message: "boom" } });
136
- const response = await runResource({ paymentVoucher: voucherFor() });
157
+ const paymentVoucher = voucherFor();
158
+ const response = await runResource({ paymentVoucher });
137
159
  expect(response.statusCode).toBe(200);
138
160
  await flushSettlement();
139
- expect(settlePayment).not.toHaveBeenCalled();
161
+ expect(capture).not.toHaveBeenCalled();
162
+ expect(release).toHaveBeenCalledExactlyOnceWith(paymentVoucher);
140
163
  });
141
164
  test("rejects an unknown resource", async () => {
142
165
  const response = await runResource({ resourceName: "Missing" });
@@ -270,7 +293,7 @@ describe("routes", () => {
270
293
  parameters: [{ name: "city", type: "string" }],
271
294
  returnType: "string",
272
295
  exec: async () => "sunny",
273
- paymentManifest: { costMicroUsdc: 500, recipientAddress: RECIPIENT },
296
+ paymentManifest: { costMicroUsd: 500, recipientOrganizationId: ORGANIZATION },
274
297
  }],
275
298
  });
276
299
  function broadcast(resources, privateKey = keys.privateKey, publicKey = keys.publicKey) {
@@ -294,7 +317,7 @@ describe("routes", () => {
294
317
  const resources = (await fastify.inject({ method: "GET", url: "/v1/resources" })).json().resources;
295
318
  expect(resources.find((r) => r.name === "Forecast")).toMatchObject({
296
319
  baseUrl: peer.baseUrl,
297
- functions: [{ name: "tomorrow", paymentManifest: { costMicroUsdc: 500, recipientAddress: RECIPIENT } }],
320
+ functions: [{ name: "tomorrow", paymentManifest: { costMicroUsd: 500, recipientOrganizationId: ORGANIZATION } }],
298
321
  });
299
322
  });
300
323
  test("rejects a broadcast from an unknown peer", async () => {
@@ -366,7 +389,7 @@ describe("restricted functions", () => {
366
389
  name: "Vault",
367
390
  functions: [
368
391
  { 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: { costMicroUsdc: COST, recipientAddress: RECIPIENT } },
392
+ { name: "premium", parameters: [{ name: "city", type: "string" }], returnType: "int32", exec: async () => 9, restricted: true, paymentManifest: { costMicroUsd: COST, recipientOrganizationId: ORGANIZATION } },
370
393
  ],
371
394
  };
372
395
  const call = (functionName) => ({ resourcePath: "com.example", resourceName: "Vault", functionName, parameters });
@@ -379,7 +402,9 @@ describe("restricted functions", () => {
379
402
  beforeEach(async () => {
380
403
  db = await openDatabase(":memory:");
381
404
  service = createService(db, [restricted], testConfig());
382
- vi.spyOn(service.operatorClient, "settlePayment").mockResolvedValue(undefined);
405
+ vi.spyOn(service.operatorClient, "authorize").mockResolvedValue({ ok: true });
406
+ vi.spyOn(service.operatorClient, "capture").mockResolvedValue(undefined);
407
+ vi.spyOn(service.operatorClient, "release").mockResolvedValue(undefined);
383
408
  callerDb = await openDatabase(":memory:");
384
409
  callerGrants = new GrantService(new GrantRepository(callerDb), { baseUrl: "http://caller", ...caller });
385
410
  grant = await service.grantService.issue(caller.publicKey, [{ resourcePath: "com.example", resourceName: "Vault" }], { lifetimeMs: 3_600_000 });
@@ -491,11 +516,11 @@ describe("restricted functions", () => {
491
516
  expect(response.statusCode).toBe(403);
492
517
  });
493
518
  test("checks the authorization before the voucher, and needs both for a paid function", async () => {
494
- const paymentVoucher = callerInvoker.createPaymentVoucher(RECIPIENT, COST, "com.example", "Vault", "premium", parameters);
519
+ const paymentVoucher = callerInvoker.createPaymentVoucher(ORGANIZATION, COST, "com.example", "Vault", "premium", parameters);
495
520
  const unauthorized = await runResource({ ...call("premium"), paymentVoucher });
496
521
  expect(unauthorized.statusCode).toBe(403);
497
522
  await new Promise((resolve) => setTimeout(resolve, 10));
498
- expect(service.operatorClient.settlePayment).not.toHaveBeenCalled();
523
+ expect(service.operatorClient.authorize).not.toHaveBeenCalled();
499
524
  const unpaid = await runResource({ ...call("premium"), authorization: callerGrants.authorize(grant, call("premium")) });
500
525
  expect(unpaid.statusCode).toBe(402);
501
526
  const paid = await runResource({ ...call("premium"), paymentVoucher, authorization: callerGrants.authorize(grant, call("premium")) });
@@ -571,15 +596,19 @@ describe("inference functions", () => {
571
596
  // "Hello world!" is 3 input tokens by the fixture's estimator. 3 at $3/M plus 1,000 at $15/M, rounded up.
572
597
  const parameters = [{ name: "prompt", value: "Hello world!" }, { name: "maxTokens", value: 1000 }];
573
598
  const MAX_AMOUNT = 15_009;
574
- const manifest = { ...INFERENCE_RATES, recipientAddress: RECIPIENT };
599
+ const manifest = { ...INFERENCE_RATES, recipientOrganizationId: ORGANIZATION };
575
600
  let db;
576
601
  let service;
577
602
  let fastify;
578
- let settlePayment;
603
+ let authorize;
604
+ let capture;
605
+ let release;
579
606
  beforeEach(async () => {
580
607
  db = await openDatabase(":memory:");
581
608
  service = createService(db, [weather, model], testConfig());
582
- settlePayment = vi.spyOn(service.operatorClient, "settlePayment").mockResolvedValue(undefined);
609
+ authorize = vi.spyOn(service.operatorClient, "authorize").mockResolvedValue({ ok: true });
610
+ capture = vi.spyOn(service.operatorClient, "capture").mockResolvedValue(undefined);
611
+ release = vi.spyOn(service.operatorClient, "release").mockResolvedValue(undefined);
583
612
  fastify = Fastify();
584
613
  await fastify.register(routes, { prefix: "/v1", service });
585
614
  await fastify.ready();
@@ -639,7 +668,7 @@ describe("inference functions", () => {
639
668
  expect(response.statusCode).toBe(200);
640
669
  expect(response.json()).toEqual({ value: "echo: Hello world!", error: null, usage: { inputTokens: 3, outputTokens: 1000 } });
641
670
  await flushSettlement();
642
- expect(settlePayment).toHaveBeenCalledExactlyOnceWith({ voucher: paymentVoucher, usage: { inputTokens: 3, outputTokens: 1000 } });
671
+ expect(capture).toHaveBeenCalledExactlyOnceWith({ voucher: paymentVoucher, usage: { inputTokens: 3, outputTokens: 1000 } });
643
672
  });
644
673
  test("refuses a voucher below the estimator's requirement without running inference", async () => {
645
674
  const exec = vi.spyOn(model.functions[0], "exec");
@@ -648,20 +677,20 @@ describe("inference functions", () => {
648
677
  expect(response.json()).toMatchObject({ requiredMaxAmount: MAX_AMOUNT });
649
678
  expect(exec).not.toHaveBeenCalled();
650
679
  await flushSettlement();
651
- expect(settlePayment).not.toHaveBeenCalled();
680
+ expect(capture).not.toHaveBeenCalled();
652
681
  });
653
682
  test.each([
654
- ["a different input rate", { inputCostMicroUsdcPerMillionTokens: 1 }],
655
- ["a different output rate", { outputCostMicroUsdcPerMillionTokens: 1 }],
683
+ ["a different input rate", { inputCostMicroUsdPerMillionTokens: 1 }],
684
+ ["a different output rate", { outputCostMicroUsdPerMillionTokens: 1 }],
656
685
  ["a maxTokens other than the call's", { maxTokens: 999 }],
657
- ["a different recipient", { recipientAddress: "11111111111111111111111111111111" }],
686
+ ["a different recipient", { recipientOrganizationId: "org_other" }],
658
687
  ])("rejects a voucher with %s", async (_, overrides) => {
659
688
  const response = await call("/v1/run/resource", { paymentVoucher: voucherFor("complete", overrides) });
660
689
  expect(response.statusCode).toBe(400);
661
690
  expect(response.json()).toEqual({ error: "Invalid payment voucher" });
662
691
  });
663
692
  test("rejects a fixed voucher for an inference function, and an inference voucher for a fixed function", async () => {
664
- const fixed = callerInvoker.createPaymentVoucher(RECIPIENT, MAX_AMOUNT, model.path, model.name, "complete", parameters);
693
+ const fixed = callerInvoker.createPaymentVoucher(ORGANIZATION, MAX_AMOUNT, model.path, model.name, "complete", parameters);
665
694
  expect((await call("/v1/run/resource", { paymentVoucher: fixed })).statusCode).toBe(400);
666
695
  const weatherParameters = [{ name: "city", value: "Oslo" }];
667
696
  const inference = callerInvoker.createInferenceVoucher(manifest, MAX_AMOUNT, 1000, weather.path, weather.name, "temperature", weatherParameters);
@@ -674,21 +703,25 @@ describe("inference functions", () => {
674
703
  const response = await call("/v1/run/resource", { paymentVoucher });
675
704
  expect(response.json().usage).toEqual({ inputTokens: 3, outputTokens: 1000 });
676
705
  await flushSettlement();
677
- expect(settlePayment).toHaveBeenCalledExactlyOnceWith({ voucher: paymentVoucher, usage: { inputTokens: 3, outputTokens: 1000 } });
706
+ expect(capture).toHaveBeenCalledExactlyOnceWith({ voucher: paymentVoucher, usage: { inputTokens: 3, outputTokens: 1000 } });
678
707
  });
679
- test("does not settle a call that charges nothing", async () => {
708
+ test("releases the hold of a call that charges nothing", async () => {
680
709
  vi.spyOn(model.functions[0], "exec").mockResolvedValue({ value: "", usage: { inputTokens: 0, outputTokens: 0 } });
681
- const response = await call("/v1/run/resource", { paymentVoucher: voucherFor() });
710
+ const paymentVoucher = voucherFor();
711
+ const response = await call("/v1/run/resource", { paymentVoucher });
682
712
  expect(response.statusCode).toBe(200);
683
713
  await flushSettlement();
684
- expect(settlePayment).not.toHaveBeenCalled();
714
+ expect(capture).not.toHaveBeenCalled();
715
+ expect(release).toHaveBeenCalledExactlyOnceWith(paymentVoucher);
685
716
  });
686
- test("does not settle when the function doesn't report usage", async () => {
717
+ test("releases the hold when the function doesn't report usage", async () => {
687
718
  vi.spyOn(model.functions[0], "exec").mockResolvedValue("no usage");
688
- const response = await call("/v1/run/resource", { paymentVoucher: voucherFor() });
719
+ const paymentVoucher = voucherFor();
720
+ const response = await call("/v1/run/resource", { paymentVoucher });
689
721
  expect(response.json().error.message).toContain("must return { value, usage");
690
722
  await flushSettlement();
691
- expect(settlePayment).not.toHaveBeenCalled();
723
+ expect(capture).not.toHaveBeenCalled();
724
+ expect(release).toHaveBeenCalledExactlyOnceWith(paymentVoucher);
692
725
  });
693
726
  });
694
727
  test("GET /v1/resources announces the kind and per-token pricing", async () => {
@@ -1,5 +1,5 @@
1
1
  import { afterEach, describe, expect, test, vi } from "vitest";
2
- import { DEFAULT_COST_LIMIT_MICRO_USDC, resolveConfig } from "../server.js";
2
+ import { DEFAULT_COST_LIMIT_MICRO_USD, resolveConfig } from "../server.js";
3
3
  import { modelResource, 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("COST_LIMIT_MICRO_USDC", "500");
19
- expect(resolveConfig({})).toMatchObject({ baseUrl: "http://env.example", publicKey: "env-public", privateKey: "env-private", costLimitMicroUsdc: 500 });
18
+ vi.stubEnv("COST_LIMIT_MICRO_USD", "500");
19
+ expect(resolveConfig({})).toMatchObject({ baseUrl: "http://env.example", publicKey: "env-public", privateKey: "env-private", costLimitMicroUsd: 500 });
20
20
  });
21
21
  test("defaults the cost limit", () => {
22
- vi.stubEnv("COST_LIMIT_MICRO_USDC", undefined);
23
- expect(resolveConfig(keys).costLimitMicroUsdc).toBe(DEFAULT_COST_LIMIT_MICRO_USDC);
22
+ vi.stubEnv("COST_LIMIT_MICRO_USD", undefined);
23
+ expect(resolveConfig(keys).costLimitMicroUsd).toBe(DEFAULT_COST_LIMIT_MICRO_USD);
24
24
  });
25
- test.each([-1, 1.5, Number.NaN])("rejects a cost limit of %s", (costLimitMicroUsdc) => {
26
- expect(() => resolveConfig({ ...keys, costLimitMicroUsdc })).toThrow("costLimitMicroUsdc");
25
+ test.each([-1, 1.5, Number.NaN])("rejects a cost limit of %s", (costLimitMicroUsd) => {
26
+ expect(() => resolveConfig({ ...keys, costLimitMicroUsd })).toThrow("costLimitMicroUsd");
27
27
  });
28
28
  test("requires the signing keys and base URL", () => {
29
29
  vi.stubEnv("SIGNING_PRIVATE_KEY", undefined);
@@ -35,12 +35,12 @@ describe("resolveConfig", () => {
35
35
  expect(() => resolveConfig(keys, [weatherResource()])).toThrow("OPERATOR_URL is required");
36
36
  });
37
37
  test("defaults the inference cost limit to the cost limit, and reads its own option or environment variable", () => {
38
- vi.stubEnv("INFERENCE_COST_LIMIT_MICRO_USDC", undefined);
39
- expect(resolveConfig({ ...keys, costLimitMicroUsdc: 700 }).inferenceCostLimitMicroUsdc).toBe(700);
40
- vi.stubEnv("INFERENCE_COST_LIMIT_MICRO_USDC", "900");
41
- expect(resolveConfig({ ...keys, costLimitMicroUsdc: 700 }).inferenceCostLimitMicroUsdc).toBe(900);
42
- expect(resolveConfig({ ...keys, inferenceCostLimitMicroUsdc: 1_000 }).inferenceCostLimitMicroUsdc).toBe(1_000);
43
- expect(() => resolveConfig({ ...keys, inferenceCostLimitMicroUsdc: -1 })).toThrow("inferenceCostLimitMicroUsdc");
38
+ vi.stubEnv("INFERENCE_COST_LIMIT_MICRO_USD", undefined);
39
+ expect(resolveConfig({ ...keys, costLimitMicroUsd: 700 }).inferenceCostLimitMicroUsd).toBe(700);
40
+ vi.stubEnv("INFERENCE_COST_LIMIT_MICRO_USD", "900");
41
+ expect(resolveConfig({ ...keys, costLimitMicroUsd: 700 }).inferenceCostLimitMicroUsd).toBe(900);
42
+ expect(resolveConfig({ ...keys, inferenceCostLimitMicroUsd: 1_000 }).inferenceCostLimitMicroUsd).toBe(1_000);
43
+ expect(() => resolveConfig({ ...keys, inferenceCostLimitMicroUsd: -1 })).toThrow("inferenceCostLimitMicroUsd");
44
44
  });
45
45
  test("accepts well-declared inference functions", () => {
46
46
  expect(() => resolveConfig({ ...keys, operatorUrl: "http://operator.example" }, [modelResource()])).not.toThrow();
@@ -49,8 +49,8 @@ describe("resolveConfig", () => {
49
49
  ["without a maxTokens parameter", { parameters: [{ name: "prompt", type: "string" }] }, "maxTokens: int32"],
50
50
  ["whose maxTokens isn't an int32", { parameters: [{ name: "maxTokens", type: "int64" }] }, "maxTokens: int32"],
51
51
  ["that is paid but has no estimator", { estimateInputTokens: undefined }, "estimateInputTokens"],
52
- ["priced with a flat cost", { paymentManifest: { costMicroUsdc: 5, recipientAddress: "r" } }, "per million tokens"],
53
- ["with a negative rate", { paymentManifest: { inputCostMicroUsdcPerMillionTokens: -1, outputCostMicroUsdcPerMillionTokens: 0, recipientAddress: "r" } }, "per million tokens"],
52
+ ["priced with a flat cost", { paymentManifest: { costMicroUsd: 5, recipientOrganizationId: "r" } }, "per million tokens"],
53
+ ["with a negative rate", { paymentManifest: { inputCostMicroUsdPerMillionTokens: -1, outputCostMicroUsdPerMillionTokens: 0, recipientOrganizationId: "r" } }, "per million tokens"],
54
54
  ])("rejects an inference function %s", (_, overrides, message) => {
55
55
  const model = modelResource();
56
56
  model.functions = [{ ...model.functions[0], ...overrides }];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stellarium-ts",
3
- "version": "0.16.0",
3
+ "version": "0.17.0",
4
4
  "description": "A Stellarium Node in TypeScript.",
5
5
  "homepage": "https://github.com/qualletio/stellarium-ts#readme",
6
6
  "bugs": {