@tokenbuddy/tb-admin 1.0.36 → 1.0.38

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 (93) hide show
  1. package/dist/src/cli.js +98 -25
  2. package/dist/src/config.d.ts +8 -2
  3. package/dist/src/config.js +17 -5
  4. package/dist/src/display-format.js +6 -14
  5. package/dist/src/init-command.d.ts +50 -0
  6. package/dist/src/init-command.js +347 -0
  7. package/dist/src/providers/fly-io.d.ts +3 -0
  8. package/dist/src/providers/fly-io.js +137 -0
  9. package/dist/src/providers/provider-definition.d.ts +38 -0
  10. package/dist/src/providers/provider-definition.js +2 -0
  11. package/dist/src/seller.d.ts +2 -0
  12. package/dist/src/seller.js +30 -13
  13. package/dist/src/server-cmd.d.ts +1 -0
  14. package/dist/src/server-cmd.js +9 -2
  15. package/dist/src/ui-actions.d.ts +3 -0
  16. package/dist/src/ui-actions.js +199 -27
  17. package/dist/src/ui-command.js +3 -2
  18. package/dist/src/ui-state.d.ts +1 -3
  19. package/dist/src/ui-state.js +4 -8
  20. package/dist/src/ui-static.js +43 -15
  21. package/dist/src/workdir.d.ts +21 -0
  22. package/dist/src/workdir.js +50 -0
  23. package/package.json +9 -3
  24. package/templates/providers/fly.io/admin.toml.example +18 -0
  25. package/templates/providers/fly.io/deploy-secrets/bootstrap/README.md +18 -0
  26. package/templates/providers/fly.io/deploy-secrets/bootstrap/admin-web.example.env +3 -0
  27. package/templates/providers/fly.io/deploy-secrets/bootstrap/cloudflare-r2.example.env +6 -0
  28. package/templates/providers/fly.io/deploy-secrets/bootstrap/registry-signing-key.example.json +6 -0
  29. package/templates/providers/fly.io/deploy-secrets/bootstrap/registry.example.json +14 -0
  30. package/templates/providers/fly.io/deploy-secrets/bootstrap/tb-registry.example.yaml +14 -0
  31. package/templates/providers/fly.io/deploy-secrets/seller-configs/README.md +13 -0
  32. package/templates/providers/fly.io/deploy-secrets/seller-configs/seller.example.yaml +35 -0
  33. package/templates/providers/fly.io/env/deploy.env.example +12 -0
  34. package/templates/providers/fly.io/fly/fly.tb-registry.toml +31 -0
  35. package/templates/providers/fly.io/fly/fly.tb-seller.toml +25 -0
  36. package/templates/providers/fly.io/provider.toml.example +10 -0
  37. package/dist/src/bootstrap-registry.d.ts.map +0 -1
  38. package/dist/src/bootstrap-registry.js.map +0 -1
  39. package/dist/src/cli.d.ts.map +0 -1
  40. package/dist/src/cli.js.map +0 -1
  41. package/dist/src/client.d.ts.map +0 -1
  42. package/dist/src/client.js.map +0 -1
  43. package/dist/src/config.d.ts.map +0 -1
  44. package/dist/src/config.js.map +0 -1
  45. package/dist/src/display-format.d.ts.map +0 -1
  46. package/dist/src/display-format.js.map +0 -1
  47. package/dist/src/index.d.ts.map +0 -1
  48. package/dist/src/index.js.map +0 -1
  49. package/dist/src/provider.d.ts.map +0 -1
  50. package/dist/src/provider.js.map +0 -1
  51. package/dist/src/seller.d.ts.map +0 -1
  52. package/dist/src/seller.js.map +0 -1
  53. package/dist/src/server-cmd.d.ts.map +0 -1
  54. package/dist/src/server-cmd.js.map +0 -1
  55. package/dist/src/ui-actions.d.ts.map +0 -1
  56. package/dist/src/ui-actions.js.map +0 -1
  57. package/dist/src/ui-command.d.ts.map +0 -1
  58. package/dist/src/ui-command.js.map +0 -1
  59. package/dist/src/ui-server.d.ts.map +0 -1
  60. package/dist/src/ui-server.js.map +0 -1
  61. package/dist/src/ui-state.d.ts.map +0 -1
  62. package/dist/src/ui-state.js.map +0 -1
  63. package/dist/src/ui-static.d.ts.map +0 -1
  64. package/dist/src/ui-static.js.map +0 -1
  65. package/dist/src/upstream-balance-probe.d.ts.map +0 -1
  66. package/dist/src/upstream-balance-probe.js.map +0 -1
  67. package/dist/src/vendor-client.d.ts.map +0 -1
  68. package/dist/src/vendor-client.js.map +0 -1
  69. package/dist/src/vendor-commands.d.ts.map +0 -1
  70. package/dist/src/vendor-commands.js.map +0 -1
  71. package/src/bootstrap-registry.ts +0 -90
  72. package/src/cli.ts +0 -1614
  73. package/src/client.ts +0 -179
  74. package/src/config.ts +0 -194
  75. package/src/display-format.ts +0 -411
  76. package/src/index.ts +0 -11
  77. package/src/provider.ts +0 -150
  78. package/src/seller.ts +0 -538
  79. package/src/server-cmd.ts +0 -362
  80. package/src/ui-actions.ts +0 -1040
  81. package/src/ui-command.ts +0 -44
  82. package/src/ui-server.ts +0 -353
  83. package/src/ui-state.ts +0 -1318
  84. package/src/ui-static.ts +0 -673
  85. package/src/upstream-balance-probe.ts +0 -13
  86. package/src/vendor-client.ts +0 -23
  87. package/src/vendor-commands.ts +0 -65
  88. package/tests/admin.test.ts +0 -2162
  89. package/tests/seller.test.ts +0 -388
  90. package/tests/ui-state-fleet.test.ts +0 -526
  91. package/tests/ui-static-row.test.ts +0 -467
  92. package/tests/vendor-cli.test.ts +0 -241
  93. package/tsconfig.json +0 -8
@@ -1,241 +0,0 @@
1
- import request from "supertest";
2
- import * as fs from "fs";
3
- import * as path from "path";
4
- import { buildAdminCli } from "../src/cli.js";
5
- import { ConfigManager } from "../src/config.js";
6
- import { execSync } from "child_process";
7
-
8
- // Use the workspace-linked package. ts-jest will resolve the
9
- // `.js` to the compiled `.ts` via the root moduleNameMapper.
10
- import { buildApp } from "@tokenbuddy/wallet-bootstrap";
11
- import type { BootstrapConfig } from "@tokenbuddy/wallet-bootstrap";
12
- import { RegistryAdminClient } from "../src/client.js";
13
-
14
- const WALLET_TEST_DIR = path.resolve(__dirname, "../../data-vendor-cli-test");
15
- const TEMP_REGISTRY_PATH = path.join(WALLET_TEST_DIR, "sellers.json");
16
- const TEMP_REGISTRY_DB_PATH = path.join(WALLET_TEST_DIR, "bootstrap.sqlite");
17
- const TEMP_CONFIG_PATH = path.join(WALLET_TEST_DIR, "tb-registry.yaml");
18
- const TEMP_ADMIN_CONF_PATH = path.join(WALLET_TEST_DIR, "admin-config.json");
19
- const SUPER_ADMIN_KEY = "platform-super-admin-key-please-rotate-me-1234567890";
20
- const SESSION_SECRET = "session-secret-32-chars-min-please";
21
-
22
- const baseRegistry = {
23
- version: 1,
24
- defaultSeller: "platform-seed",
25
- sellers: [
26
- {
27
- id: "platform-seed",
28
- name: "Platform Seed",
29
- url: "https://platform-seed.example.com",
30
- status: "active",
31
- models: ["seed-model"],
32
- supportedProtocols: ["chat_completions"],
33
- paymentMethods: ["clawtip"]
34
- }
35
- ]
36
- };
37
-
38
- const baseConfig: BootstrapConfig = {
39
- configPath: TEMP_CONFIG_PATH,
40
- payTo: "pay-to-x",
41
- sm4KeyBase64: "MDEyMzQ1Njc4OUFCQ0RFRg==",
42
- skillSlug: "tb-registry",
43
- skillId: "si-tb-registry",
44
- description: "Activate",
45
- resourceUrl: "https://example.com",
46
- activationFeeFen: 1,
47
- microsPerFen: 1000000,
48
- sellerRegistryPath: TEMP_REGISTRY_PATH,
49
- operatorSecret: "op-secret",
50
- superAdminKey: SUPER_ADMIN_KEY,
51
- superAdminLabel: "ops",
52
- sessionSecret: SESSION_SECRET
53
- };
54
-
55
- function buildServer() {
56
- fs.mkdirSync(WALLET_TEST_DIR, { recursive: true });
57
- fs.writeFileSync(TEMP_REGISTRY_PATH, JSON.stringify(baseRegistry), "utf8");
58
- for (const f of [TEMP_REGISTRY_DB_PATH, `${TEMP_REGISTRY_DB_PATH}-wal`, `${TEMP_REGISTRY_DB_PATH}-shm`]) {
59
- try { fs.rmSync(f, { force: true }); } catch { /* ignore */ }
60
- }
61
- return buildApp(baseConfig);
62
- }
63
-
64
- async function createVendorToken(app: ReturnType<typeof buildServer>, name: string): Promise<string> {
65
- const response = await request(app)
66
- .post("/platform/vendors")
67
- .set("X-Registry-Admin-Key", SUPER_ADMIN_KEY)
68
- .send({ name });
69
- expect(response.status).toBe(200);
70
- return response.body.token;
71
- }
72
-
73
- async function runCli(args: string[], env: NodeJS.ProcessEnv): Promise<{ stdout: string; stderr: string; status: number }> {
74
- // We invoke the CLI as a child process so the `program` state does
75
- // not leak between tests. The package's `dist/` may not exist in
76
- // worktrees, so we run from TypeScript source via `tsx` if
77
- // available; fall back to requiring the source.
78
- const cliEntry = path.resolve(__dirname, "../src/cli.ts");
79
- // Try `npx tsx` first, then `node --import tsx`, then fallback
80
- // to `node -r ts-node/register`.
81
- let cmd: string;
82
- let finalArgs: string[];
83
- try {
84
- execSync("which tsx", { stdio: "ignore" });
85
- cmd = "npx";
86
- finalArgs = ["tsx", cliEntry, ...args];
87
- } catch {
88
- cmd = "node";
89
- finalArgs = ["--import", "tsx", cliEntry, ...args];
90
- }
91
- try {
92
- const stdout = execSync(`${cmd} ${finalArgs.map((a) => JSON.stringify(a)).join(" ")}`, {
93
- env: { ...process.env, ...env },
94
- stdio: ["ignore", "pipe", "pipe"],
95
- encoding: "utf8"
96
- });
97
- return { stdout, stderr: "", status: 0 };
98
- } catch (err: any) {
99
- return {
100
- stdout: err.stdout?.toString() || "",
101
- stderr: err.stderr?.toString() || err.message,
102
- status: err.status || 1
103
- };
104
- }
105
- }
106
-
107
- describe("Vendor CLI integration (Step 5)", () => {
108
- beforeEach(() => {
109
- fs.mkdirSync(WALLET_TEST_DIR, { recursive: true });
110
- for (const f of [TEMP_REGISTRY_PATH, TEMP_REGISTRY_DB_PATH, `${TEMP_REGISTRY_DB_PATH}-wal`, `${TEMP_REGISTRY_DB_PATH}-shm`, TEMP_CONFIG_PATH, TEMP_ADMIN_CONF_PATH]) {
111
- try { fs.rmSync(f, { force: true }); } catch { /* ignore */ }
112
- }
113
- });
114
-
115
- afterAll(() => {
116
- fs.rmSync(WALLET_TEST_DIR, { recursive: true, force: true });
117
- });
118
-
119
- test("buildAdminCli still constructs without errors after the registry redesign", () => {
120
- const config = new ConfigManager(TEMP_ADMIN_CONF_PATH);
121
- const cli = buildAdminCli(config);
122
- expect(cli.commands.find((c: any) => c.name() === "vendor-bootstrap")).toBeDefined();
123
- // The legacy `bootstrap` command is still there for backward compat.
124
- expect(cli.commands.find((c: any) => c.name() === "bootstrap")).toBeDefined();
125
- });
126
-
127
- test("RegistryVendorClient can authenticate against a live wallet-bootstrap app and stage a seller", async () => {
128
- const app = buildServer();
129
- const token = await createVendorToken(app, "Acme");
130
- // Direct HTTP call to the vendor API as the CLI would do.
131
- const stage = await request(app)
132
- .post("/platform/sellers/stage")
133
- .set("Authorization", `Bearer ${token}`)
134
- .send({ seller: {
135
- id: "acme-seller-1",
136
- name: "Acme Seller 1",
137
- url: "https://acme.example.com",
138
- status: "active",
139
- models: ["m1"],
140
- supportedProtocols: ["chat_completions"],
141
- paymentMethods: ["clawtip"]
142
- } });
143
- expect(stage.status).toBe(200);
144
- expect(stage.body.pendingSeller.id).toBe("acme-seller-1");
145
- expect(stage.body.pendingSeller.status).toBe("staged");
146
- });
147
-
148
- test("RegistryVendorClient listPendingSellers only returns this vendor's rows", async () => {
149
- const app = buildServer();
150
- const tokenA = await createVendorToken(app, "VendorA");
151
- const tokenB = await createVendorToken(app, "VendorB");
152
- await request(app)
153
- .post("/platform/sellers/stage")
154
- .set("Authorization", `Bearer ${tokenA}`)
155
- .send({ seller: {
156
- id: "va-1", name: "VA1", url: "https://va1.example.com", status: "active",
157
- models: ["m1"], supportedProtocols: ["chat_completions"], paymentMethods: ["clawtip"]
158
- } });
159
- await request(app)
160
- .post("/platform/sellers/stage")
161
- .set("Authorization", `Bearer ${tokenB}`)
162
- .send({ seller: {
163
- id: "vb-1", name: "VB1", url: "https://vb1.example.com", status: "active",
164
- models: ["m1"], supportedProtocols: ["chat_completions"], paymentMethods: ["clawtip"]
165
- } });
166
- const aList = await request(app)
167
- .get("/platform/sellers/pending?status=staged")
168
- .set("Authorization", `Bearer ${tokenA}`);
169
- const bList = await request(app)
170
- .get("/platform/sellers/pending?status=staged")
171
- .set("Authorization", `Bearer ${tokenB}`);
172
- expect(aList.body.pendingSellers).toHaveLength(1);
173
- expect(aList.body.pendingSellers[0].id).toBe("va-1");
174
- expect(bList.body.pendingSellers).toHaveLength(1);
175
- expect(bList.body.pendingSellers[0].id).toBe("vb-1");
176
- });
177
-
178
- test("RegistryVendorClient submitRelease -> listReleaseRequests round-trips", async () => {
179
- const app = buildServer();
180
- const token = await createVendorToken(app, "VendorC");
181
- await request(app)
182
- .post("/platform/sellers/stage")
183
- .set("Authorization", `Bearer ${token}`)
184
- .send({ seller: {
185
- id: "vc-1", name: "VC1", url: "https://vc1.example.com", status: "active",
186
- models: ["m1"], supportedProtocols: ["chat_completions"], paymentMethods: ["clawtip"]
187
- } });
188
- const submit = await request(app)
189
- .post("/platform/release-requests")
190
- .set("Authorization", `Bearer ${token}`)
191
- .send({ stagedSellerIds: ["vc-1"], note: "test" });
192
- expect(submit.status).toBe(200);
193
- const list = await request(app)
194
- .get("/platform/release-requests?limit=10")
195
- .set("Authorization", `Bearer ${token}`);
196
- expect(list.body.releaseRequests).toHaveLength(1);
197
- expect(list.body.releaseRequests[0].id).toBe(submit.body.releaseRequest.id);
198
- });
199
-
200
- test("RegistryAdminClient uses canonical admin API routes", async () => {
201
- const app = buildServer();
202
- const server = app.listen(0);
203
- const address = server.address();
204
- if (!address || typeof address !== "object") {
205
- throw new Error("test server did not bind a TCP port");
206
- }
207
- const client = new RegistryAdminClient(`http://127.0.0.1:${address.port}`, SUPER_ADMIN_KEY);
208
- try {
209
- const vendor = await client.createVendor("AdminClientVendor");
210
- expect(vendor.token).toBeTruthy();
211
-
212
- const vendors = await client.listVendors();
213
- expect(vendors.vendors.length).toBeGreaterThan(0);
214
-
215
- const versions = await client.listVersions();
216
- expect(versions.versions.length).toBeGreaterThan(0);
217
-
218
- const token = vendor.token;
219
- await request(app)
220
- .post("/platform/sellers/stage")
221
- .set("Authorization", `Bearer ${token}`)
222
- .send({ seller: {
223
- id: "admin-client-force-1",
224
- name: "Admin Client Force",
225
- url: "https://admin-client-force.example.com",
226
- status: "active",
227
- models: ["m1"],
228
- supportedProtocols: ["chat_completions"],
229
- paymentMethods: ["clawtip"]
230
- } });
231
- const submit = await request(app)
232
- .post("/platform/release-requests")
233
- .set("Authorization", `Bearer ${token}`)
234
- .send({ stagedSellerIds: ["admin-client-force-1"] });
235
- const forced = await client.forcePublish(submit.body.releaseRequest.id);
236
- expect(forced.releaseRequest).toMatchObject({ status: "published" });
237
- } finally {
238
- await new Promise<void>((resolve) => server.close(() => resolve()));
239
- }
240
- });
241
- });
package/tsconfig.json DELETED
@@ -1,8 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "./dist",
5
- "rootDir": "./"
6
- },
7
- "include": ["src/**/*"]
8
- }