@query-farm/vgi 0.37.1 → 0.38.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 (46) hide show
  1. package/README.md +74 -0
  2. package/dist/catalog/composite.d.ts +23 -1
  3. package/dist/catalog/contents-digest.d.ts +25 -0
  4. package/dist/catalog/interface.d.ts +107 -2
  5. package/dist/catalog/read-only.d.ts +45 -1
  6. package/dist/client/client.d.ts +19 -1
  7. package/dist/client-entry.js +141 -4
  8. package/dist/client-entry.js.map +9 -8
  9. package/dist/codec/asd.d.ts +8 -0
  10. package/dist/generated/vgi-client.d.ts +19 -0
  11. package/dist/generated/vgi-protocol-schemas.d.ts +3 -0
  12. package/dist/generated/vgi-protocol-types.d.ts +26 -0
  13. package/dist/http/fetch.d.ts +2 -1
  14. package/dist/index.core.d.ts +5 -2
  15. package/dist/index.js +574 -36
  16. package/dist/index.js.map +20 -16
  17. package/dist/protocol/handlers/catalog/contents.d.ts +27 -0
  18. package/dist/rpc-server.d.ts +97 -0
  19. package/dist/serve-entry.d.ts +2 -1
  20. package/dist/serve-entry.js +405 -25
  21. package/dist/serve-entry.js.map +18 -14
  22. package/dist/worker-cf-entry.d.ts +3 -0
  23. package/dist/worker-cf-entry.js +528 -31
  24. package/dist/worker-cf-entry.js.map +20 -16
  25. package/dist/worker.d.ts +9 -1
  26. package/package.json +3 -3
  27. package/src/catalog/composite.ts +81 -0
  28. package/src/catalog/contents-digest.ts +78 -0
  29. package/src/catalog/interface.ts +167 -5
  30. package/src/catalog/read-only.ts +68 -6
  31. package/src/client/client.ts +53 -0
  32. package/src/codec/asd.ts +96 -1
  33. package/src/generated/vgi-client.ts +22 -1
  34. package/src/generated/vgi-protocol-schemas.ts +30 -1
  35. package/src/generated/vgi-protocol-types.ts +126 -0
  36. package/src/http/fetch.ts +10 -2
  37. package/src/index.core.ts +21 -2
  38. package/src/protocol/dispatch.ts +1 -1
  39. package/src/protocol/handlers/catalog/admin.ts +35 -26
  40. package/src/protocol/handlers/catalog/contents.ts +162 -0
  41. package/src/protocol/handlers/catalog/macro.ts +2 -1
  42. package/src/protocol/handlers/catalog/shared.ts +12 -1
  43. package/src/rpc-server.ts +273 -0
  44. package/src/serve-entry.ts +7 -1
  45. package/src/worker-cf-entry.ts +8 -0
  46. package/src/worker.ts +24 -6
@@ -0,0 +1,27 @@
1
+ import { type CatalogContentsResponse } from "../../../generated/vgi-protocol-types.js";
2
+ import type { AttachOpaqueData, CatalogInterface } from "../../../catalog/interface.js";
3
+ type Wire = {
4
+ result: Uint8Array;
5
+ };
6
+ /**
7
+ * Ask the catalog for its contents and shape the typed wire response.
8
+ *
9
+ * Enforces the revalidation rules: `not_modified` needs an etag equal to
10
+ * `ifNoneMatch` and no schemas; a catalog with no etag never yields
11
+ * `not_modified` (and so ignores `ifNoneMatch`). Validates the schema paths
12
+ * (unique, parent present) and orders them parent-first. Every item is
13
+ * encoded with the SAME encoder its per-schema RPC uses, so items are
14
+ * byte-identical to catalog_schemas / catalog_schema_contents_* items.
15
+ */
16
+ export declare function buildCatalogContents(cat: CatalogInterface, owner: CatalogInterface, attach: AttachOpaqueData, version: number, ifNoneMatch: string | null): Promise<CatalogContentsResponse>;
17
+ /**
18
+ * Serve one catalog_contents call (the attach value is already opened).
19
+ *
20
+ * Caching: a catalog whose `catalogContentsCacheable()` is true (by default:
21
+ * version frozen and contents attach-independent; ReadOnlyCatalogInterface) is
22
+ * built once per (catalog instance, version); every later call reuses the same
23
+ * serialized response bytes. A conditional call matching the cached etag is
24
+ * answered `not_modified` without touching the snapshot.
25
+ */
26
+ export declare function serveCatalogContents(cat: CatalogInterface, attach: AttachOpaqueData, ifNoneMatch: string | null): Promise<Wire>;
27
+ export {};
@@ -0,0 +1,97 @@
1
+ import { type GrantMinter, type Protocol, type TokenResolver, VgiRpcServer } from "@query-farm/vgi-rpc";
2
+ /** The transport a server is being built for. Only `"http"` changes what is
3
+ * hosted (identity); the rest are recorded so the decision lives here rather
4
+ * than at each call site. `"iroh"` is the raw TCP upstream of a
5
+ * `vgi-iroh-bridge`; `"stream"` a caller-provided byte-stream pair. */
6
+ export type ServerTransport = "pipe" | "unix" | "tcp" | "iroh" | "stream" | "http";
7
+ /** Environment variable naming the principals allowed to call `introspect_token`. */
8
+ export declare const INTROSPECT_PRINCIPALS_ENV = "VGI_INTROSPECT_PRINCIPALS";
9
+ /**
10
+ * What a worker hosts beyond `vgi.v2`, and whether it opts into identity.
11
+ *
12
+ * Accepted by `new Worker({...})`, `serveVgiWorker`, `createVgiWorkerFetch`
13
+ * and `createVgiFetch` (Cloudflare Workers) alike, so one worker definition
14
+ * hosts the same set on every transport.
15
+ */
16
+ export interface HostingOptions {
17
+ /**
18
+ * Additional vgi-rpc protocols to host beside `vgi.v2`, on the **same**
19
+ * listener, whatever the transport.
20
+ *
21
+ * A vgi-rpc `Protocol` carries its handlers, so each entry is a whole
22
+ * `(protocol, implementation)` pair. Called **once**, when the server is
23
+ * built; it may consult configuration or the environment, but the answer is
24
+ * fixed for the life of the process, so reflection output and protocol
25
+ * hashes stay stable. Hosted after `vgi.v2`, in the order returned.
26
+ *
27
+ * The protocol is the unit of optionality: there is no way to host a subset
28
+ * of a protocol's methods. A capability that is optional is its own
29
+ * protocol, returned here or not.
30
+ *
31
+ * Each needs a distinct wire name, which may not be `vgi.v2` and may not
32
+ * use the reserved `vgi_rpc.` prefix: reflection is hosted automatically and
33
+ * `vgi_rpc.Identity.v1` is enabled through {@link resolveToken} /
34
+ * {@link mintGrant}. Violations are a startup error naming this hook.
35
+ */
36
+ hostedProtocols?: () => Iterable<Protocol>;
37
+ /**
38
+ * Resolve an opaque bearer credential to the identity it authenticates as.
39
+ * Supplying it hosts `vgi_rpc.Identity.v1`'s `introspect_token` -- on HTTP,
40
+ * the transport that authenticates callers. Absent, the method is absent
41
+ * (not hosted-and-refusing), which keeps a dependency upgrade from growing a
42
+ * credential-to-identity oracle on every existing worker.
43
+ *
44
+ * Return `null` for "the store answered and this credential is unknown".
45
+ * For "I could not find out" (a store or sidecar outage, a timeout, a 5xx)
46
+ * throw `AuthUnavailableError` from `@query-farm/vgi-rpc` -- the same error
47
+ * an `authenticate` callback throws for an outage. The framework translates
48
+ * it to `identity_unavailable` with that error's retry hint
49
+ * (`vgi_rpc.RetryInfo`), so callers know to retry rather than cache a
50
+ * refusal. `IdentityUnavailableError` works too. Never throw a plain
51
+ * `Error` for an outage: a caller cannot tell it from a definitive answer.
52
+ *
53
+ * Requires {@link introspectPrincipals} (or `VGI_INTROSPECT_PRINCIPALS`);
54
+ * there is no permissive default, and a worker without one refuses to start.
55
+ */
56
+ resolveToken?: TokenResolver;
57
+ /**
58
+ * Mint a standing delegation credential for the *calling* user. Supplying
59
+ * it hosts `issue_grant` (HTTP only). Throw `GrantRefusedError` to decline,
60
+ * and `AuthUnavailableError` for a transient failure (translated as for
61
+ * {@link resolveToken}). Needs no allowlist: it is not an oracle about
62
+ * anybody else.
63
+ */
64
+ mintGrant?: GrantMinter;
65
+ /**
66
+ * Principals permitted to call `introspect_token`. When omitted,
67
+ * `VGI_INTROSPECT_PRINCIPALS` (comma-separated) is read. Only consulted when
68
+ * {@link resolveToken} is supplied.
69
+ */
70
+ introspectPrincipals?: Iterable<string>;
71
+ /** Maximum age of the caller's authentication for `issue_grant`, in
72
+ * seconds. vgi-rpc's default when omitted. */
73
+ maxAuthAge?: number;
74
+ }
75
+ /** Server-level options passed through to `VgiRpcServer`. */
76
+ export interface BuildRpcServerOptions {
77
+ /** Which transport this server will serve. */
78
+ transport: ServerTransport;
79
+ /** Server identifier, surfaced through reflection. */
80
+ serverId?: string;
81
+ /** Environment to read `VGI_INTROSPECT_PRINCIPALS` from. Default
82
+ * `process.env` where it exists (not on Cloudflare Workers). */
83
+ env?: Record<string, string | undefined>;
84
+ }
85
+ /**
86
+ * Build the vgi-rpc server for a worker's `vgi.v2` protocol on `transport`.
87
+ *
88
+ * Calls `hosting.hostedProtocols()` exactly once and hosts the result beside
89
+ * `primary`; see the module comment for the full hosted set.
90
+ *
91
+ * @throws TypeError `hostedProtocols()` returned something other than an
92
+ * iterable of vgi-rpc `Protocol`s.
93
+ * @throws Error A hosted protocol's name is invalid, reserved, `vgi.v2`'s, or
94
+ * repeated; the transport is unknown; or the worker supplies `resolveToken`
95
+ * on HTTP with no introspector allowlist.
96
+ */
97
+ export declare function buildRpcServer(primary: Protocol, hosting: HostingOptions, options: BuildRpcServerOptions): VgiRpcServer;
@@ -1,6 +1,7 @@
1
1
  import type { CatalogInterface } from "./catalog/interface.js";
2
2
  import type { FunctionRegistry } from "./functions/registry.js";
3
3
  import { type AuthenticateFn, type PeerResolutionOptions } from "@query-farm/vgi-rpc";
4
+ import type { HostingOptions } from "./rpc-server.js";
4
5
  /** Environment variables `serveVgiWorker` reads. Injectable for testing. */
5
6
  export interface ServeEnv {
6
7
  PORT?: string;
@@ -26,7 +27,7 @@ export interface IrohHttpBridgeOptions {
26
27
  */
27
28
  peerResolutionContext?: (request: Request) => PeerResolutionOptions | Promise<PeerResolutionOptions>;
28
29
  }
29
- export interface ServeVgiWorkerOptions {
30
+ export interface ServeVgiWorkerOptions extends HostingOptions {
30
31
  /** Short worker name shown on the landing page, e.g. "ishares". */
31
32
  name: string;
32
33
  /** One-line description of what the worker serves. */