@opendatalabs/personal-server-ts-server 0.0.1-canary.0d0705b

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 (73) hide show
  1. package/dist/api.d.ts +2 -0
  2. package/dist/api.d.ts.map +1 -0
  3. package/dist/api.js +2 -0
  4. package/dist/api.js.map +1 -0
  5. package/dist/app.d.ts +31 -0
  6. package/dist/app.d.ts.map +1 -0
  7. package/dist/app.js +94 -0
  8. package/dist/app.js.map +1 -0
  9. package/dist/bootstrap.d.ts +29 -0
  10. package/dist/bootstrap.d.ts.map +1 -0
  11. package/dist/bootstrap.js +159 -0
  12. package/dist/bootstrap.js.map +1 -0
  13. package/dist/dev-token.d.ts +6 -0
  14. package/dist/dev-token.d.ts.map +1 -0
  15. package/dist/dev-token.js +9 -0
  16. package/dist/dev-token.js.map +1 -0
  17. package/dist/index.d.ts +2 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +34 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/middleware/access-log.d.ts +8 -0
  22. package/dist/middleware/access-log.d.ts.map +1 -0
  23. package/dist/middleware/access-log.js +38 -0
  24. package/dist/middleware/access-log.js.map +1 -0
  25. package/dist/middleware/body-limit.d.ts +10 -0
  26. package/dist/middleware/body-limit.d.ts.map +1 -0
  27. package/dist/middleware/body-limit.js +20 -0
  28. package/dist/middleware/body-limit.js.map +1 -0
  29. package/dist/middleware/builder-check.d.ts +8 -0
  30. package/dist/middleware/builder-check.d.ts.map +1 -0
  31. package/dist/middleware/builder-check.js +29 -0
  32. package/dist/middleware/builder-check.js.map +1 -0
  33. package/dist/middleware/grant-check.d.ts +12 -0
  34. package/dist/middleware/grant-check.d.ts.map +1 -0
  35. package/dist/middleware/grant-check.js +90 -0
  36. package/dist/middleware/grant-check.js.map +1 -0
  37. package/dist/middleware/owner-check.d.ts +9 -0
  38. package/dist/middleware/owner-check.d.ts.map +1 -0
  39. package/dist/middleware/owner-check.js +37 -0
  40. package/dist/middleware/owner-check.js.map +1 -0
  41. package/dist/middleware/web3-auth.d.ts +16 -0
  42. package/dist/middleware/web3-auth.d.ts.map +1 -0
  43. package/dist/middleware/web3-auth.js +56 -0
  44. package/dist/middleware/web3-auth.js.map +1 -0
  45. package/dist/routes/access-logs.d.ts +16 -0
  46. package/dist/routes/access-logs.d.ts.map +1 -0
  47. package/dist/routes/access-logs.js +30 -0
  48. package/dist/routes/access-logs.js.map +1 -0
  49. package/dist/routes/data.d.ts +20 -0
  50. package/dist/routes/data.d.ts.map +1 -0
  51. package/dist/routes/data.js +213 -0
  52. package/dist/routes/data.js.map +1 -0
  53. package/dist/routes/grants.d.ts +16 -0
  54. package/dist/routes/grants.d.ts.map +1 -0
  55. package/dist/routes/grants.js +122 -0
  56. package/dist/routes/grants.js.map +1 -0
  57. package/dist/routes/health.d.ts +14 -0
  58. package/dist/routes/health.d.ts.map +1 -0
  59. package/dist/routes/health.js +35 -0
  60. package/dist/routes/health.js.map +1 -0
  61. package/dist/routes/sync.d.ts +16 -0
  62. package/dist/routes/sync.d.ts.map +1 -0
  63. package/dist/routes/sync.js +52 -0
  64. package/dist/routes/sync.js.map +1 -0
  65. package/dist/routes/ui-config.d.ts +7 -0
  66. package/dist/routes/ui-config.d.ts.map +1 -0
  67. package/dist/routes/ui-config.js +89 -0
  68. package/dist/routes/ui-config.js.map +1 -0
  69. package/dist/routes/ui.d.ts +6 -0
  70. package/dist/routes/ui.d.ts.map +1 -0
  71. package/dist/routes/ui.js +36 -0
  72. package/dist/routes/ui.js.map +1 -0
  73. package/package.json +45 -0
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Grants routes — POST /verify (public endpoint).
3
+ * Verifies EIP-712 grant signatures locally without network calls.
4
+ */
5
+ import { Hono } from "hono";
6
+ import { verifyTypedData } from "viem";
7
+ import { GRANT_DOMAIN, GRANT_TYPES, } from "@opendatalabs/personal-server-ts-core/grants";
8
+ import { createWeb3AuthMiddleware } from "../middleware/web3-auth.js";
9
+ import { createOwnerCheckMiddleware } from "../middleware/owner-check.js";
10
+ function isValidVerifyBody(body) {
11
+ if (body === null || typeof body !== "object" || Array.isArray(body))
12
+ return false;
13
+ const b = body;
14
+ if (typeof b.grantId !== "string" || b.grantId.length === 0)
15
+ return false;
16
+ if (typeof b.signature !== "string" || !b.signature.startsWith("0x"))
17
+ return false;
18
+ if (b.payload === null ||
19
+ typeof b.payload !== "object" ||
20
+ Array.isArray(b.payload))
21
+ return false;
22
+ const p = b.payload;
23
+ if (typeof p.user !== "string" || !p.user.startsWith("0x"))
24
+ return false;
25
+ if (typeof p.builder !== "string" || !p.builder.startsWith("0x"))
26
+ return false;
27
+ if (!Array.isArray(p.scopes) || p.scopes.length === 0)
28
+ return false;
29
+ if (!p.scopes.every((s) => typeof s === "string"))
30
+ return false;
31
+ if (typeof p.expiresAt !== "number")
32
+ return false;
33
+ if (typeof p.nonce !== "number")
34
+ return false;
35
+ return true;
36
+ }
37
+ export function grantsRoutes(deps) {
38
+ const app = new Hono();
39
+ const web3Auth = createWeb3AuthMiddleware({
40
+ serverOrigin: deps.serverOrigin,
41
+ devToken: deps.devToken,
42
+ serverOwner: deps.serverOwner,
43
+ });
44
+ const ownerCheck = createOwnerCheckMiddleware(deps.serverOwner);
45
+ // GET / — list all grants for the server owner (owner auth required)
46
+ app.get("/", web3Auth, ownerCheck, async (c) => {
47
+ if (!deps.serverOwner) {
48
+ return c.json({
49
+ error: {
50
+ code: 500,
51
+ errorCode: "SERVER_NOT_CONFIGURED",
52
+ message: "Server owner address not configured. Set VANA_MASTER_KEY_SIGNATURE environment variable.",
53
+ },
54
+ }, 500);
55
+ }
56
+ const grants = await deps.gateway.listGrantsByUser(deps.serverOwner);
57
+ return c.json({ grants });
58
+ });
59
+ // POST /verify — public endpoint, no auth required
60
+ app.post("/verify", async (c) => {
61
+ let body;
62
+ try {
63
+ body = await c.req.json();
64
+ }
65
+ catch {
66
+ return c.json({ error: "INVALID_BODY", message: "Invalid JSON body" }, 400);
67
+ }
68
+ if (!isValidVerifyBody(body)) {
69
+ return c.json({
70
+ error: "INVALID_BODY",
71
+ message: "Body must include grantId (string), payload (object with user, builder, scopes, expiresAt, nonce), and signature (0x string)",
72
+ }, 400);
73
+ }
74
+ const { payload, signature } = body;
75
+ // Verify EIP-712 signature — recover signer and check === payload.user
76
+ let valid;
77
+ try {
78
+ valid = await verifyTypedData({
79
+ address: payload.user,
80
+ domain: GRANT_DOMAIN,
81
+ types: GRANT_TYPES,
82
+ primaryType: "Grant",
83
+ message: {
84
+ user: payload.user,
85
+ builder: payload.builder,
86
+ scopes: payload.scopes,
87
+ expiresAt: BigInt(payload.expiresAt),
88
+ nonce: BigInt(payload.nonce),
89
+ },
90
+ signature: signature,
91
+ });
92
+ }
93
+ catch {
94
+ return c.json({
95
+ valid: false,
96
+ error: "EIP-712 signature verification failed",
97
+ });
98
+ }
99
+ if (!valid) {
100
+ return c.json({
101
+ valid: false,
102
+ error: "Grant signature does not match user",
103
+ });
104
+ }
105
+ // Check expiry: expiresAt > 0 means there IS an expiry
106
+ if (payload.expiresAt > 0) {
107
+ const nowSeconds = Math.floor(Date.now() / 1000);
108
+ if (payload.expiresAt < nowSeconds) {
109
+ return c.json({ valid: false, error: "Grant has expired" });
110
+ }
111
+ }
112
+ return c.json({
113
+ valid: true,
114
+ user: payload.user,
115
+ builder: payload.builder,
116
+ scopes: payload.scopes,
117
+ expiresAt: payload.expiresAt,
118
+ });
119
+ });
120
+ return app;
121
+ }
122
+ //# sourceMappingURL=grants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grants.js","sourceRoot":"","sources":["../../src/routes/grants.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { Hono } from "hono";
2
+ import type { GatewayClient } from "@opendatalabs/personal-server-ts-core/gateway";
3
+ import type { Logger } from "pino";
4
+ import type { IdentityInfo } from "../app.js";
5
+ export interface HealthDeps {
6
+ version: string;
7
+ startedAt: Date;
8
+ serverOwner?: `0x${string}`;
9
+ identity?: IdentityInfo;
10
+ gateway?: GatewayClient;
11
+ logger?: Logger;
12
+ }
13
+ export declare function healthRoute(deps: HealthDeps): Hono;
14
+ //# sourceMappingURL=health.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+CAA+C,CAAC;AACnF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAEnC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;IAChB,WAAW,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,YAAY,CAAC;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,CAuClD"}
@@ -0,0 +1,35 @@
1
+ import { Hono } from "hono";
2
+ export function healthRoute(deps) {
3
+ const app = new Hono();
4
+ app.get("/health", async (c) => {
5
+ const uptimeMs = Date.now() - deps.startedAt.getTime();
6
+ let serverId = deps.identity?.serverId ?? null;
7
+ if (deps.identity && deps.gateway) {
8
+ try {
9
+ const server = await deps.gateway.getServer(deps.identity.address);
10
+ serverId = server?.id ?? null;
11
+ }
12
+ catch (err) {
13
+ // Keep health endpoint available even if gateway is unreachable.
14
+ serverId = null;
15
+ deps.logger?.debug({ err, serverAddress: deps.identity.address }, "Gateway lookup failed during health check");
16
+ }
17
+ }
18
+ const identity = deps.identity
19
+ ? {
20
+ address: deps.identity.address,
21
+ publicKey: deps.identity.publicKey,
22
+ serverId,
23
+ }
24
+ : null;
25
+ return c.json({
26
+ status: "healthy",
27
+ version: deps.version,
28
+ uptime: Math.floor(uptimeMs / 1000),
29
+ owner: deps.serverOwner ?? null,
30
+ identity,
31
+ });
32
+ });
33
+ return app;
34
+ }
35
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../src/routes/health.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAe5B,MAAM,UAAU,WAAW,CAAC,IAAgB;IAC1C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvD,IAAI,QAAQ,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,IAAI,IAAI,CAAC;QAE/C,IAAI,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YAClC,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;gBACnE,QAAQ,GAAG,MAAM,EAAE,EAAE,IAAI,IAAI,CAAC;YAChC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,iEAAiE;gBACjE,QAAQ,GAAG,IAAI,CAAC;gBAChB,IAAI,CAAC,MAAM,EAAE,KAAK,CAChB,EAAE,GAAG,EAAE,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAC7C,2CAA2C,CAC5C,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,QAAQ;YAC5B,CAAC,CAAC;gBACE,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO;gBAC9B,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS;gBAClC,QAAQ;aACT;YACH,CAAC,CAAC,IAAI,CAAC;QAET,OAAO,CAAC,CAAC,IAAI,CAAC;YACZ,MAAM,EAAE,SAAS;YACjB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;YACnC,KAAK,EAAE,IAAI,CAAC,WAAW,IAAI,IAAI;YAC/B,QAAQ;SACT,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Sync routes — endpoints for triggering and monitoring the sync engine.
3
+ * All endpoints require owner authentication.
4
+ */
5
+ import { Hono } from "hono";
6
+ import type { Logger } from "pino";
7
+ import type { SyncManager } from "@opendatalabs/personal-server-ts-core/sync";
8
+ export interface SyncRouteDeps {
9
+ logger: Logger;
10
+ serverOrigin: string;
11
+ serverOwner?: `0x${string}`;
12
+ devToken?: string;
13
+ syncManager: SyncManager | null;
14
+ }
15
+ export declare function syncRoutes(deps: SyncRouteDeps): Hono;
16
+ //# sourceMappingURL=sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,4CAA4C,CAAC;AAI9E,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,CAAC,EAAE,KAAK,MAAM,EAAE,CAAC;IAC5B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,WAAW,GAAG,IAAI,CAAC;CACjC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,CAsDpD"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Sync routes — endpoints for triggering and monitoring the sync engine.
3
+ * All endpoints require owner authentication.
4
+ */
5
+ import { Hono } from "hono";
6
+ import { createWeb3AuthMiddleware } from "../middleware/web3-auth.js";
7
+ import { createOwnerCheckMiddleware } from "../middleware/owner-check.js";
8
+ export function syncRoutes(deps) {
9
+ const app = new Hono();
10
+ const web3Auth = createWeb3AuthMiddleware({
11
+ serverOrigin: deps.serverOrigin,
12
+ devToken: deps.devToken,
13
+ serverOwner: deps.serverOwner,
14
+ });
15
+ const ownerCheck = createOwnerCheckMiddleware(deps.serverOwner);
16
+ // POST /trigger — request a full sync (owner auth required)
17
+ app.post("/trigger", web3Auth, ownerCheck, async (c) => {
18
+ if (!deps.syncManager) {
19
+ return c.json({ status: "disabled", message: "Sync is not enabled" }, 200);
20
+ }
21
+ await deps.syncManager.trigger();
22
+ return c.json({ status: "started", message: "Sync triggered" }, 202);
23
+ });
24
+ // GET /status — current sync status (owner auth required)
25
+ app.get("/status", web3Auth, ownerCheck, async (c) => {
26
+ if (!deps.syncManager) {
27
+ return c.json({
28
+ enabled: false,
29
+ running: false,
30
+ lastSync: null,
31
+ lastProcessedTimestamp: null,
32
+ pendingFiles: 0,
33
+ errors: [],
34
+ });
35
+ }
36
+ return c.json(deps.syncManager.getStatus());
37
+ });
38
+ // POST /file/:fileId — request sync for a specific file (owner auth required)
39
+ app.post("/file/:fileId", web3Auth, ownerCheck, async (c) => {
40
+ const fileId = c.req.param("fileId");
41
+ if (!deps.syncManager) {
42
+ return c.json({ fileId, status: "disabled", message: "Sync is not enabled" }, 200);
43
+ }
44
+ // Trigger a full sync (individual file sync is handled by the download worker
45
+ // when it encounters the fileId from Gateway)
46
+ deps.logger.info({ fileId }, "File sync requested, triggering full sync");
47
+ await deps.syncManager.trigger();
48
+ return c.json({ fileId, status: "started" }, 202);
49
+ });
50
+ return app;
51
+ }
52
+ //# sourceMappingURL=sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/routes/sync.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AAU1E,MAAM,UAAU,UAAU,CAAC,IAAmB;IAC5C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,MAAM,QAAQ,GAAG,wBAAwB,CAAC;QACxC,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC;IACH,MAAM,UAAU,GAAG,0BAA0B,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IAEhE,4DAA4D;IAC5D,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACrD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB,EAAE,EACtD,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACjC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,0DAA0D;IAC1D,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QACnD,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,CAAC,CAAC,IAAI,CAAC;gBACZ,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,IAAI;gBACd,sBAAsB,EAAE,IAAI;gBAC5B,YAAY,EAAE,CAAC;gBACf,MAAM,EAAE,EAAE;aACX,CAAC,CAAC;QACL,CAAC;QACD,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,8EAA8E;IAC9E,GAAG,CAAC,IAAI,CAAC,eAAe,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE;QAC1D,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,OAAO,CAAC,CAAC,IAAI,CACX,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,qBAAqB,EAAE,EAC9D,GAAG,CACJ,CAAC;QACJ,CAAC;QACD,8EAA8E;QAC9E,8CAA8C;QAC9C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,2CAA2C,CAAC,CAAC;QAC1E,MAAM,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,CAAC;QACjC,OAAO,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,GAAG,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { Hono } from "hono";
2
+ export interface UiConfigRouteDeps {
3
+ devToken: string;
4
+ configPath: string;
5
+ }
6
+ export declare function uiConfigRoutes(deps: UiConfigRouteDeps): Hono;
7
+ //# sourceMappingURL=ui-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-config.d.ts","sourceRoot":"","sources":["../../src/routes/ui-config.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAI5B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,cAAc,CAAC,IAAI,EAAE,iBAAiB,GAAG,IAAI,CA8G5D"}
@@ -0,0 +1,89 @@
1
+ import { readFile, writeFile } from "node:fs/promises";
2
+ import { Hono } from "hono";
3
+ import { ServerConfigSchema } from "@opendatalabs/personal-server-ts-core/schemas";
4
+ export function uiConfigRoutes(deps) {
5
+ const app = new Hono();
6
+ const requireDevToken = async (c, next) => {
7
+ const authHeader = c.req.header("authorization");
8
+ if (authHeader !== `Bearer ${deps.devToken}`) {
9
+ return c.json({
10
+ error: {
11
+ code: 401,
12
+ errorCode: "UNAUTHORIZED",
13
+ message: "Invalid dev token",
14
+ },
15
+ }, 401);
16
+ }
17
+ await next();
18
+ };
19
+ // GET /ui/api/config — read config from disk
20
+ app.get("/config", requireDevToken, async (c) => {
21
+ try {
22
+ const contents = await readFile(deps.configPath, "utf-8");
23
+ const config = JSON.parse(contents);
24
+ return c.json(config);
25
+ }
26
+ catch (err) {
27
+ if (err instanceof Error &&
28
+ "code" in err &&
29
+ err.code === "ENOENT") {
30
+ return c.json({
31
+ error: {
32
+ code: 404,
33
+ errorCode: "NOT_FOUND",
34
+ message: "Config file not found",
35
+ },
36
+ }, 404);
37
+ }
38
+ return c.json({
39
+ error: {
40
+ code: 500,
41
+ errorCode: "READ_ERROR",
42
+ message: "Failed to read config",
43
+ },
44
+ }, 500);
45
+ }
46
+ });
47
+ // PUT /ui/api/config — validate and write config to disk
48
+ app.put("/config", requireDevToken, async (c) => {
49
+ let body;
50
+ try {
51
+ body = await c.req.json();
52
+ }
53
+ catch {
54
+ return c.json({
55
+ error: {
56
+ code: 400,
57
+ errorCode: "INVALID_BODY",
58
+ message: "Invalid JSON body",
59
+ },
60
+ }, 400);
61
+ }
62
+ const result = ServerConfigSchema.safeParse(body);
63
+ if (!result.success) {
64
+ return c.json({
65
+ error: {
66
+ code: 400,
67
+ errorCode: "VALIDATION_ERROR",
68
+ message: "Invalid config",
69
+ issues: result.error.issues,
70
+ },
71
+ }, 400);
72
+ }
73
+ try {
74
+ await writeFile(deps.configPath, JSON.stringify(result.data, null, 2) + "\n");
75
+ return c.json({ status: "saved", config: result.data });
76
+ }
77
+ catch {
78
+ return c.json({
79
+ error: {
80
+ code: 500,
81
+ errorCode: "WRITE_ERROR",
82
+ message: "Failed to write config",
83
+ },
84
+ }, 500);
85
+ }
86
+ });
87
+ return app;
88
+ }
89
+ //# sourceMappingURL=ui-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-config.js","sourceRoot":"","sources":["../../src/routes/ui-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { Hono } from "hono";
2
+ export interface UiRouteDeps {
3
+ devToken: string;
4
+ }
5
+ export declare function uiRoute(deps: UiRouteDeps): Hono;
6
+ //# sourceMappingURL=ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.d.ts","sourceRoot":"","sources":["../../src/routes/ui.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAiBD,wBAAgB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,CAsB/C"}
@@ -0,0 +1,36 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import { Hono } from "hono";
5
+ // Read the HTML file once at module load time
6
+ let cachedHtml = null;
7
+ function getHtmlPath() {
8
+ const currentDir = dirname(fileURLToPath(import.meta.url));
9
+ return join(currentDir, "..", "ui", "index.html");
10
+ }
11
+ function loadHtml(devToken) {
12
+ if (!cachedHtml) {
13
+ cachedHtml = readFileSync(getHtmlPath(), "utf-8");
14
+ }
15
+ return cachedHtml.replace("__DEV_TOKEN__", devToken);
16
+ }
17
+ export function uiRoute(deps) {
18
+ const app = new Hono();
19
+ app.get("/", (c) => {
20
+ try {
21
+ const html = loadHtml(deps.devToken);
22
+ return c.html(html);
23
+ }
24
+ catch {
25
+ return c.json({
26
+ error: {
27
+ code: 500,
28
+ errorCode: "UI_ERROR",
29
+ message: "Failed to load UI",
30
+ },
31
+ }, 500);
32
+ }
33
+ });
34
+ return app;
35
+ }
36
+ //# sourceMappingURL=ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/routes/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,8CAA8C;AAC9C,IAAI,UAAU,GAAkB,IAAI,CAAC;AAErC,SAAS,WAAW;IAClB,MAAM,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC;AACpD,CAAC;AAED,SAAS,QAAQ,CAAC,QAAgB;IAChC,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,UAAU,GAAG,YAAY,CAAC,WAAW,EAAE,EAAE,OAAO,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,UAAU,CAAC,OAAO,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAiB;IACvC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;IAEvB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE;QACjB,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YACrC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,CAAC,IAAI,CACX;gBACE,KAAK,EAAE;oBACL,IAAI,EAAE,GAAG;oBACT,SAAS,EAAE,UAAU;oBACrB,OAAO,EAAE,mBAAmB;iBAC7B;aACF,EACD,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,OAAO,GAAG,CAAC;AACb,CAAC"}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@opendatalabs/personal-server-ts-server",
3
+ "version": "0.0.1-canary.0d0705b",
4
+ "description": "Hono HTTP server for the Vana Personal Server — routes, middleware, composition root",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/vana-com/personal-server-ts.git",
9
+ "directory": "packages/server"
10
+ },
11
+ "homepage": "https://github.com/vana-com/personal-server-ts#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/vana-com/personal-server-ts/issues"
14
+ },
15
+ "type": "module",
16
+ "main": "./dist/api.js",
17
+ "types": "./dist/api.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/api.d.ts",
21
+ "import": "./dist/api.js"
22
+ },
23
+ "./runtime": {
24
+ "types": "./dist/index.d.ts",
25
+ "import": "./dist/index.js"
26
+ }
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "files": [
32
+ "dist"
33
+ ],
34
+ "scripts": {
35
+ "copy-ui": "mkdir -p dist/ui && cp src/ui/index.html dist/ui/index.html",
36
+ "build": "tsc --build && npm run copy-ui",
37
+ "start": "node dist/index.js",
38
+ "dev": "node --watch dist/index.js"
39
+ },
40
+ "dependencies": {
41
+ "@opendatalabs/personal-server-ts-core": "0.0.1-canary.0d0705b",
42
+ "hono": "^4.7.0",
43
+ "@hono/node-server": "^1.14.0"
44
+ }
45
+ }