@procedures/peer 0.2.2 → 0.3.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 (38) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/README.md +3 -3
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/connection/index.d.ts +3 -2
  5. package/dist/connection/index.d.ts.map +1 -1
  6. package/dist/connection/index.js +2 -1
  7. package/dist/connection/index.js.map +1 -1
  8. package/dist/discovery/index.d.ts +7 -5
  9. package/dist/discovery/index.d.ts.map +1 -1
  10. package/dist/discovery/index.js +30 -42
  11. package/dist/discovery/index.js.map +1 -1
  12. package/dist/peer/index.d.ts +16 -3
  13. package/dist/peer/index.d.ts.map +1 -1
  14. package/dist/peer/index.js +45 -6
  15. package/dist/peer/index.js.map +1 -1
  16. package/dist/procedures/manifest.generate.d.ts.map +1 -1
  17. package/dist/procedures/manifest.generate.js +11 -34
  18. package/dist/procedures/manifest.generate.js.map +1 -1
  19. package/dist/procedures/server.call.d.ts.map +1 -1
  20. package/dist/procedures/server.call.js +8 -3
  21. package/dist/procedures/server.call.js.map +1 -1
  22. package/dist/procedures/server.connect.d.ts.map +1 -1
  23. package/dist/procedures/server.connect.js +3 -1
  24. package/dist/procedures/server.connect.js.map +1 -1
  25. package/dist/procedures/server.create.d.ts.map +1 -1
  26. package/dist/procedures/server.create.js +6 -4
  27. package/dist/procedures/server.create.js.map +1 -1
  28. package/dist/types.d.ts +2 -0
  29. package/dist/types.d.ts.map +1 -1
  30. package/package.json +2 -2
  31. package/src/connection/index.ts +5 -4
  32. package/src/discovery/index.ts +38 -43
  33. package/src/peer/index.ts +70 -7
  34. package/src/procedures/manifest.generate.ts +11 -34
  35. package/src/procedures/server.call.ts +8 -3
  36. package/src/procedures/server.connect.ts +3 -1
  37. package/src/procedures/server.create.ts +7 -4
  38. package/src/types.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"server.create.d.ts","sourceRoot":"","sources":["../../src/procedures/server.create.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAmB,KAAK,OAAO,EAAE,KAAK,SAAS,EAAsB,MAAM,oBAAoB,CAAC;AAIvG,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AASzD,eAAO,MAAM,qBAAqB,EAAE,SAAS,CAC3C,iBAAiB,EACjB,kBAAkB,EAClB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAiDjC,CAAC;AAEX;;GAEG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAE1D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC"}
1
+ {"version":3,"file":"server.create.d.ts","sourceRoot":"","sources":["../../src/procedures/server.create.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAmB,KAAK,OAAO,EAAE,KAAK,SAAS,EAAgE,MAAM,oBAAoB,CAAC;AAIjJ,OAAO,KAAK,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACzE,OAAO,EAAc,KAAK,IAAI,EAAE,MAAM,kBAAkB,CAAC;AASzD,eAAO,MAAM,qBAAqB,EAAE,SAAS,CAC3C,iBAAiB,EACjB,kBAAkB,EAClB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAoDjC,CAAC;AAEX;;GAEG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAE1D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,CAAC"}
@@ -2,7 +2,7 @@
2
2
  * Procedure: server.create
3
3
  * Creates a transport-agnostic peer that exposes procedures
4
4
  */
5
- import { createProcedure, PROCEDURE_REGISTRY } from "@procedures/client";
5
+ import { createProcedure, PROCEDURE_REGISTRY, ProcedureRegistry } from "@procedures/client";
6
6
  import { wrapSchema } from "../schema.js";
7
7
  import { ServerCreateOutputSchema } from "../output-schemas.js";
8
8
  import { serverCreateInputSchema } from "../input-schemas.js";
@@ -21,7 +21,9 @@ export const serverCreateProcedure = createProcedure()
21
21
  // Each call starts a new peer that listens on its transports. It replaces nothing.
22
22
  effects: { reads: ["registry"], writes: ["network", "server"], destructive: false },
23
23
  })
24
- .handler(async (input) => {
24
+ .handler(async (input, ctx) => {
25
+ // The registry of the caller: a host with its own registry serves its own procedures
26
+ const registry = ctx?.registry instanceof ProcedureRegistry ? ctx.registry : PROCEDURE_REGISTRY;
25
27
  // Generate unique server ID
26
28
  const serverId = `peer-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
27
29
  // Default transports if not specified
@@ -35,7 +37,7 @@ export const serverCreateProcedure = createProcedure()
35
37
  id: serverId,
36
38
  transports,
37
39
  autoRegister,
38
- registry: PROCEDURE_REGISTRY,
40
+ registry,
39
41
  ...(input.expose ? { expose: exposeRule(input.expose) } : {}),
40
42
  });
41
43
  // Start the peer
@@ -44,7 +46,7 @@ export const serverCreateProcedure = createProcedure()
44
46
  activePeers.set(serverId, peer);
45
47
  // Get procedure count
46
48
  const procedureCount = input.autoRegister
47
- ? PROCEDURE_REGISTRY.getAll().filter((p) => p.handler).length
49
+ ? registry.getAll().filter((p) => p.handler).length
48
50
  : 0;
49
51
  return {
50
52
  serverId,
@@ -1 +1 @@
1
- {"version":3,"file":"server.create.js","sourceRoot":"","sources":["../../src/procedures/server.create.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.create.js","sourceRoot":"","sources":["../../src/procedures/server.create.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -15,6 +15,8 @@ export interface HttpTransportConfig {
15
15
  urlStrategy?: "rest" | "rpc" | undefined;
16
16
  /** A secret that every request must send as `Authorization: Bearer <token>` */
17
17
  token?: string | undefined;
18
+ /** The largest request body in bytes. The default is 1 MiB. */
19
+ bodyLimit?: number | undefined;
18
20
  }
19
21
  export interface WebSocketTransportConfig {
20
22
  type: "websocket";
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,WAAW,GAAG,OAAO,CAAC;AAE3D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,8GAA8G;IAC9G,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,uEAAuE;IACvE,WAAW,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACnC,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAAC;IACzC,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,iEAAiE;IACjE,OAAO,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/B,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,OAAO,CAAC;CACf;AAED,MAAM,MAAM,eAAe,GAAG,mBAAmB,GAAG,wBAAwB,GAAG,oBAAoB,CAAC;AAMpG,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,UAAU,CAAC,EAAE,eAAe,EAAE,GAAG,SAAS,CAAC;IAC3C,iDAAiD;IACjD,YAAY,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,yGAAyG;IACzG,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,yGAAyG;IACzG,MAAM,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,iCAAiC;IACjC,SAAS,EAAE,KAAK,CAAC;QACf,IAAI,EAAE,aAAa,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,sCAAsC;IACtC,cAAc,EAAE,MAAM,CAAC;CACxB;AAMD,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACtC,+BAA+B;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,qBAAqB;IACrB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,kCAAkC;IAClC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAClD,mCAAmC;IACnC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CACpD;AAED,MAAM,WAAW,mBAAmB;IAClC,oBAAoB;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,qBAAqB;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,qCAAqC;IACrC,gBAAgB,EAAE,aAAa,EAAE,CAAC;CACnC;AAMD,MAAM,WAAW,qBAAqB;IACpC,kCAAkC;IAClC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,sBAAsB;IACrC,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;CAClB;AAMD,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,YAAY,CAAC;AAEnD,MAAM,WAAW,qBAAqB;IACpC,iCAAiC;IACjC,OAAO,CAAC,EAAE,cAAc,EAAE,GAAG,SAAS,CAAC;IACvC,iEAAiE;IACjE,SAAS,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IACjC,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,8BAA8B;IAC9B,IAAI,CAAC,EACD;QACE,UAAU,EAAE,aAAa,EAAE,CAAC;QAC5B,WAAW,EAAE,MAAM,CAAC;QACpB,OAAO,EAAE,MAAM,CAAC;KACjB,GACD,SAAS,CAAC;IACd,uCAAuC;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,0CAA0C;IAC1C,YAAY,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CACrC;AAMD,MAAM,WAAW,cAAc;IAC7B,2BAA2B;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,0BAA0B;IAC1B,SAAS,EAAE,aAAa,CAAC;IACzB,uBAAuB;IACvB,KAAK,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,GAAG,OAAO,CAAC;IAC7D,wBAAwB;IACxB,gBAAgB,EAAE,aAAa,EAAE,CAAC;IAClC,sCAAsC;IACtC,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB;AAMD,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,oBAAoB,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,aAAa,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAMD,MAAM,WAAW,gBAAgB;IAC/B,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,SAAS,CAAC;CACvD;AAED,MAAM,WAAW,iBAAiB;IAChC,8BAA8B;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,2BAA2B;IAC3B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,gCAAgC;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,MAAM,WAAW,eAAe;IAC9B,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,iDAAiD;IACjD,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,6BAA6B;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAMD,MAAM,WAAW,iBAAiB;IAChC,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3B;AAED,MAAM,WAAW,kBAAkB;IACjC,gCAAgC;IAChC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB;IACjB,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB,WAAW;IACX,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,qBAAqB;IACrB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,uCAAuC;IACvC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,4BAA4B;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,oBAAoB;IACpB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@procedures/peer",
4
- "version": "0.2.2",
4
+ "version": "0.3.0",
5
5
  "description": "Serve procedures: HTTP and WebSocket peers with token authentication, browser checks, an expose list, server.create, status and stop, and manifests.",
6
6
  "keywords": [
7
7
  "server",
@@ -77,7 +77,7 @@
77
77
  "procedures": "./dist/register.js"
78
78
  },
79
79
  "dependencies": {
80
- "@procedures/client": "0.2.2",
80
+ "@procedures/client": "0.3.0",
81
81
  "zod": "^4.6.5"
82
82
  },
83
83
  "optionalDependencies": {
@@ -19,6 +19,7 @@ import type {
19
19
  ProcedureInfo,
20
20
  ProcedureAnnounceMessage,
21
21
  } from "../types.js";
22
+ import { ms, type Duration } from "@procedures/client";
22
23
 
23
24
  // =============================================================================
24
25
  // Types
@@ -29,8 +30,8 @@ export interface ConnectOptions {
29
30
  address: string;
30
31
  /** Transport type (auto-detected from URL if not specified) */
31
32
  transport?: TransportType;
32
- /** Connection timeout in ms */
33
- timeout?: number;
33
+ /** The time limit of the connection, for example `seconds(10)` */
34
+ timeout?: Duration;
34
35
  /** Local peer ID to identify ourselves */
35
36
  localPeerId?: string;
36
37
  }
@@ -143,7 +144,7 @@ function detectTransport(address: string): TransportType {
143
144
  function createClient(
144
145
  address: string,
145
146
  transport: TransportType,
146
- timeout?: number
147
+ timeout?: Duration
147
148
  ): Client {
148
149
  switch (transport) {
149
150
  case "http": {
@@ -164,7 +165,7 @@ function createClient(
164
165
  return new Client({
165
166
  transport: new WebSocketTransport({
166
167
  url: address,
167
- connectionTimeout: timeout ?? 10000,
168
+ connectionTimeout: timeout ?? ms(10000),
168
169
  reconnect: {
169
170
  enabled: true,
170
171
  maxAttempts: 3,
@@ -9,8 +9,15 @@ import {
9
9
  createProcedure,
10
10
  type Effects,
11
11
  type Procedure,
12
+ type ProcedureContext,
13
+ type ProcedureRegistry,
14
+ type ProcedureRegistryLike,
12
15
  PROCEDURE_REGISTRY,
13
16
  REGISTRY_READ_EFFECTS,
17
+ describeRegistry,
18
+ type AnyProcedure,
19
+ type ProcedureEntry,
20
+ type ProcedurePath,
14
21
  } from "@procedures/client";
15
22
  import { schema } from "../schema.js";
16
23
  import type {
@@ -51,28 +58,15 @@ export const discoveryAnnounceProcedure: Procedure<
51
58
  internal: true,
52
59
  effects: REGISTRY_READ_EFFECTS,
53
60
  })
54
- .handler(async (_input: DiscoveryAnnounceInput) => {
55
- // Get all registered procedures
56
- const procedures = PROCEDURE_REGISTRY.getAll();
57
-
58
- // Convert to ProcedureInfo format
59
- const procedureInfos: ProcedureInfo[] = procedures
60
- .filter((proc) => {
61
- // Skip internal procedures in discovery
62
- const meta = proc.metadata as { internal?: boolean } | undefined;
63
- return !meta?.internal;
64
- })
65
- .map((proc) => {
66
- const meta = proc.metadata as { description?: string } | undefined;
67
- const info: ProcedureInfo = {
68
- path: proc.path,
69
- };
70
- if (meta?.description !== undefined) {
71
- info.description = meta.description;
72
- }
73
- // TODO: Generate JSON schema from input/output schemas
74
- return info;
75
- });
61
+ .handler(async (_input: DiscoveryAnnounceInput, ctx?: ProcedureContext) => {
62
+ // The one manifest of the core (roadmap R17): the procedures of the registry that serves this
63
+ // call and that the host exposes, with their JSON Schemas, without the internal ones.
64
+ // Before, the announce gave no schemas and listed the procedures that the host hides.
65
+ const manifest = describeRegistry(ctx?.registry ?? PROCEDURE_REGISTRY, {
66
+ ...(ctx?.expose ? { expose: ctx.expose } : {}),
67
+ include: (proc: AnyProcedure) => !(proc.metadata as { internal?: boolean } | undefined)?.internal,
68
+ });
69
+ const procedureInfos: ProcedureInfo[] = manifest.procedures.map(infoOf);
76
70
 
77
71
  // Generate a peer ID based on process (could be configured)
78
72
  const peerId = `peer-${process.pid}-${Date.now().toString(36)}`;
@@ -90,30 +84,31 @@ export const discoveryAnnounceProcedure: Procedure<
90
84
  // =============================================================================
91
85
 
92
86
  /**
93
- * Get procedure info for all registered procedures
87
+ * Get procedure info for all registered procedures of a registry (default: the global registry)
94
88
  */
95
- export function getProcedureInfos(): ProcedureInfo[] {
96
- const procedures = PROCEDURE_REGISTRY.getAll();
89
+ export function getProcedureInfos(
90
+ registry: ProcedureRegistryLike = PROCEDURE_REGISTRY,
91
+ expose?: (path: ProcedurePath) => boolean
92
+ ): ProcedureInfo[] {
93
+ // The one manifest of the core (roadmap R17), without the schemas
94
+ return describeRegistry(registry, { schemas: false, ...(expose ? { expose } : {}) }).procedures.map(infoOf);
95
+ }
97
96
 
98
- return procedures
99
- .filter((proc) => proc.handler !== undefined)
100
- .map((proc) => {
101
- const meta = proc.metadata as { description?: string } | undefined;
102
- const info: ProcedureInfo = {
103
- path: proc.path,
104
- };
105
- if (meta?.description !== undefined) {
106
- info.description = meta.description;
107
- }
108
- return info;
109
- });
97
+ /** The ProcedureInfo of a manifest entry: the form that the peers exchange. */
98
+ export function infoOf(entry: ProcedureEntry): ProcedureInfo {
99
+ const info: ProcedureInfo = { path: [...entry.path] };
100
+ if (entry.description !== undefined) info.description = entry.description;
101
+ if (entry.input) info.inputSchema = entry.input;
102
+ if (entry.output) info.outputSchema = entry.output;
103
+ return info;
110
104
  }
111
105
 
112
106
  /**
113
- * Watch for procedure changes
107
+ * Watch for procedure changes in a registry (default: the global registry)
114
108
  */
115
109
  export function watchProcedures(
116
- callback: (event: "register" | "unregister", info: ProcedureInfo) => void
110
+ callback: (event: "register" | "unregister", info: ProcedureInfo) => void,
111
+ registry: ProcedureRegistry = PROCEDURE_REGISTRY
117
112
  ): () => void {
118
113
  const createHandler = (eventType: "register" | "unregister") => {
119
114
  return (proc: { path: string[]; metadata?: { description?: string } }) => {
@@ -130,11 +125,11 @@ export function watchProcedures(
130
125
  const registerHandler = createHandler("register");
131
126
  const unregisterHandler = createHandler("unregister");
132
127
 
133
- PROCEDURE_REGISTRY.on("register", registerHandler);
134
- PROCEDURE_REGISTRY.on("unregister", unregisterHandler);
128
+ registry.on("register", registerHandler);
129
+ registry.on("unregister", unregisterHandler);
135
130
 
136
131
  return () => {
137
- PROCEDURE_REGISTRY.off("register", registerHandler);
138
- PROCEDURE_REGISTRY.off("unregister", unregisterHandler);
132
+ registry.off("register", registerHandler);
133
+ registry.off("unregister", unregisterHandler);
139
134
  };
140
135
  }
package/src/peer/index.ts CHANGED
@@ -14,12 +14,15 @@ import {
14
14
  defaultServerUrlStrategy,
15
15
  defaultUrlPattern,
16
16
  procedureServerOptions,
17
+ hostProcedures,
18
+ metricsInterceptor,
19
+ Client,
17
20
  type BrowserGuardOptions,
18
21
  type HostPolicy,
19
22
  type Method,
20
23
  } from "@procedures/client";
21
24
  import type { Request } from "express";
22
- import type { ProcedurePath } from "@procedures/client";
25
+ import type { ProcedurePath, StopOptions } from "@procedures/client";
23
26
  import type { HttpTransportConfig, TransportConfig, TransportType, WebSocketTransportConfig } from "../types.js";
24
27
  import { bearerToken, hostAllowed, originAllowed, tokenMatches } from "./security.js";
25
28
 
@@ -57,6 +60,11 @@ export interface PeerOptions {
57
60
  registry?: ProcedureRegistry;
58
61
  /** The procedures that the peer serves (see `exposeRule`). Without it, the peer serves every procedure. */
59
62
  expose?: ((path: ProcedurePath) => boolean) | undefined;
63
+ /**
64
+ * The peer counts the calls of each procedure, and `host.metrics` gives the counts (roadmap
65
+ * R19). The default is true.
66
+ */
67
+ metrics?: boolean | undefined;
60
68
  /**
61
69
  * The policy of the host (`hostPolicy()` of the core, roadmap 2.3): the expose rule, the call
62
70
  * rule, the interceptors (a time limit), the token of each network transport that has none of
@@ -76,11 +84,19 @@ export interface Peer {
76
84
  /** Start all transports */
77
85
  start(): Promise<void>;
78
86
  /** Stop all transports */
79
- stop(): Promise<void>;
87
+ /** Stop the peer. With `grace`, the calls in flight have that time to end (roadmap R14). */
88
+ stop(options?: StopOptions): Promise<void>;
80
89
  /** Get active endpoints */
81
90
  getEndpoints(): PeerEndpoint[];
82
91
  /** Get underlying server */
83
92
  getServer(): ProcedureServer;
93
+ /** The ids of the WebSocket connections of the clients (roadmap R24). */
94
+ connections(): string[];
95
+ /**
96
+ * A client of one connected client (roadmap R24): its calls go to the procedures that the client
97
+ * serves (the `serve` option of its WebSocketTransport), over the same WebSocket.
98
+ */
99
+ clientFor(connectionId: string): Client;
84
100
  }
85
101
 
86
102
  // =============================================================================
@@ -93,6 +109,10 @@ class PeerImpl implements Peer {
93
109
  private transports: TransportConfig[];
94
110
  private endpoints: PeerEndpoint[] = [];
95
111
  private started = false;
112
+ /** The WebSocket transports of the peer: the calls to its clients go over them (R24) */
113
+ private wsTransports: WebSocketServerTransport[] = [];
114
+ /** The HTTP servers that the peer made for its WebSocket transports: `stop()` closes them */
115
+ private ownedServers: Array<import("node:http").Server> = [];
96
116
  private registry: ProcedureRegistry;
97
117
  private startTime: number = Date.now();
98
118
 
@@ -111,13 +131,27 @@ class PeerImpl implements Peer {
111
131
  this.registry = options.registry ?? PROCEDURE_REGISTRY;
112
132
  this.browser = policy?.browser ?? {};
113
133
 
114
- // Create procedure server
134
+ // Create procedure server. The metrics interceptor counts each call for host.metrics (R19).
135
+ const metrics = options.metrics === false ? undefined : metricsInterceptor();
136
+ const serverOptions = policy ? procedureServerOptions(policy, this.registry) : {};
137
+ const interceptors = [...(serverOptions.interceptors ?? []), ...(metrics ? [metrics.interceptor] : [])];
115
138
  this.server = new ProcedureServer({
116
- ...(policy ? procedureServerOptions(policy, this.registry) : {}),
139
+ ...serverOptions,
140
+ ...(interceptors.length > 0 ? { interceptors } : {}),
117
141
  autoRegister: options.autoRegister ?? true,
118
142
  registry: this.registry,
119
143
  ...(options.expose ? { expose: options.expose } : {}),
120
144
  });
145
+ // host.health, host.info and host.metrics: pinned on the server, not in the registry (R19)
146
+ this.server.registerProcedures(
147
+ hostProcedures({
148
+ id: this.id,
149
+ startedAt: this.startTime,
150
+ server: this.server,
151
+ endpoints: () => this.getEndpoints(),
152
+ ...(metrics ? { metrics } : {}),
153
+ })
154
+ );
121
155
  }
122
156
 
123
157
  async start(): Promise<void> {
@@ -160,7 +194,9 @@ class PeerImpl implements Peer {
160
194
  const express = (await import("express")).default;
161
195
 
162
196
  const app = express();
163
- app.use(express.json());
197
+ // No body parser here: the transport reads the body itself, with bodyLimit, and accepts each
198
+ // JSON value (roadmap R5). Before, the strict parser of express refused a bare value (a
199
+ // number, a string, null) with 400, and its limit of 100 kB replaced bodyLimit.
164
200
 
165
201
  const port = config.port ?? 3000;
166
202
  // Loopback by default so the full procedure registry (incl. shell.run / fs.write) is not
@@ -227,6 +263,7 @@ class PeerImpl implements Peer {
227
263
  allowedOrigins: this.browser.allowedOrigins ?? ((origin) => originAllowed(origin, config.corsOrigins)),
228
264
  ...(this.browser.allowedHosts ? { allowedHosts: this.browser.allowedHosts } : {}),
229
265
  allowGet: this.browser.allowGet ?? config.urlStrategy === "rest",
266
+ ...(config.bodyLimit !== undefined ? { bodyLimit: config.bodyLimit } : {}),
230
267
  });
231
268
 
232
269
  this.server.addTransport(httpTransport);
@@ -290,6 +327,8 @@ class PeerImpl implements Peer {
290
327
  httpServer.close();
291
328
  throw error;
292
329
  }
330
+ this.ownedServers.push(httpServer);
331
+ this.wsTransports.push(wsTransport);
293
332
 
294
333
  this.endpoints.push({
295
334
  type: "websocket",
@@ -297,11 +336,25 @@ class PeerImpl implements Peer {
297
336
  });
298
337
  }
299
338
 
300
- async stop(): Promise<void> {
339
+ async stop(options: StopOptions = {}): Promise<void> {
301
340
  if (!this.started) return;
302
- await this.server.stop();
341
+ await this.server.stop(options);
342
+ // The HTTP servers of the WebSocket transports: before, they stayed open, so the port stayed
343
+ // bound after stop() (roadmap R5)
344
+ const owned = this.ownedServers;
345
+ this.ownedServers = [];
346
+ await Promise.all(
347
+ owned.map(
348
+ (httpServer) =>
349
+ new Promise<void>((resolve) => {
350
+ httpServer.close(() => resolve());
351
+ httpServer.closeAllConnections();
352
+ }),
353
+ ),
354
+ );
303
355
  this.started = false;
304
356
  this.endpoints = [];
357
+ this.wsTransports = [];
305
358
  }
306
359
 
307
360
  getEndpoints(): PeerEndpoint[] {
@@ -311,6 +364,16 @@ class PeerImpl implements Peer {
311
364
  getServer(): ProcedureServer {
312
365
  return this.server;
313
366
  }
367
+
368
+ connections(): string[] {
369
+ return this.wsTransports.flatMap((transport) => transport.getTrackedConnections().map((connection) => connection.id));
370
+ }
371
+
372
+ clientFor(connectionId: string): Client {
373
+ const transport = this.wsTransports.find((ws) => ws.getTrackedConnection(connectionId) !== undefined);
374
+ if (!transport) throw new Error(`Connection not found: ${connectionId}`);
375
+ return new Client({ transport: transport.transportFor(connectionId), throwOnError: true });
376
+ }
314
377
  }
315
378
 
316
379
  // =============================================================================
@@ -3,7 +3,8 @@
3
3
  * Generates procedure manifests in various formats
4
4
  */
5
5
 
6
- import { createProcedure, jsonSchemaOf, type Effects, type Procedure, PROCEDURE_REGISTRY } from "@procedures/client";
6
+ import { createProcedure, describeRegistry, type AnyProcedure, type Effects, type Procedure, type ProcedureContext, PROCEDURE_REGISTRY } from "@procedures/client";
7
+ import { infoOf } from "../discovery/index.js";
7
8
  import { wrapSchema } from "../schema.js";
8
9
  import { ManifestGenerateOutputSchema } from "../output-schemas.js";
9
10
  import { manifestGenerateInputSchema } from "../input-schemas.js";
@@ -29,40 +30,16 @@ export const manifestGenerateProcedure: Procedure<
29
30
  // With `outputDir`, it overwrites procedures.json and procedures.d.ts there
30
31
  effects: { reads: ["registry"], writes: ["fs"], idempotent: true },
31
32
  })
32
- .handler(async (input: ManifestGenerateInput) => {
33
- // Get all registered procedures
34
- const allProcedures = PROCEDURE_REGISTRY.getAll();
35
-
36
- // Filter by namespace if specified
37
- let procedures = allProcedures;
38
- if (input.namespace && input.namespace.length > 0) {
39
- procedures = allProcedures.filter((proc) => {
40
- // Check if procedure path starts with namespace
41
- for (let i = 0; i < input.namespace!.length; i++) {
42
- if (proc.path[i] !== input.namespace![i]) {
43
- return false;
44
- }
45
- }
46
- return true;
47
- });
48
- }
49
-
50
- // Convert to ProcedureInfo format
51
- const procedureInfos: ProcedureInfo[] = procedures.map((proc) => {
52
- const meta = proc.metadata as { description?: string; internal?: boolean } | undefined;
53
- const info: ProcedureInfo = {
54
- path: proc.path,
55
- };
56
- if (meta?.description !== undefined) {
57
- info.description = meta.description;
58
- }
59
- // The JSON Schemas of the input and the output, when the schemas can describe themselves
60
- const inputSchema = jsonSchemaOf(proc.input, { io: "input" });
61
- const outputSchema = jsonSchemaOf(proc.output, { io: "output" });
62
- if (inputSchema) info.inputSchema = inputSchema;
63
- if (outputSchema) info.outputSchema = outputSchema;
64
- return info;
33
+ .handler(async (input: ManifestGenerateInput, ctx?: ProcedureContext) => {
34
+ // The one manifest of the core (roadmap R17): the procedures that the host exposes, with
35
+ // their JSON Schemas, under the namespace when the input gives one
36
+ const namespace = input.namespace ?? [];
37
+ const manifest = describeRegistry(ctx?.registry ?? PROCEDURE_REGISTRY, {
38
+ ...(ctx?.expose ? { expose: ctx.expose } : {}),
39
+ withoutHandler: true,
40
+ include: (proc: AnyProcedure) => namespace.every((segment, index) => proc.path[index] === segment),
65
41
  });
42
+ const procedureInfos: ProcedureInfo[] = manifest.procedures.map(infoOf);
66
43
 
67
44
  // Determine formats to generate
68
45
  const formats = input.formats ?? ["json"];
@@ -3,7 +3,7 @@
3
3
  * Call a procedure on a remote peer through an outbound connection
4
4
  */
5
5
 
6
- import { createProcedure, pathToMethod, type Effects, type Procedure } from "@procedures/client";
6
+ import { TIMEOUT_METADATA_KEY, createProcedure, pathToMethod, type Effects, type Procedure, type ProcedureContext } from "@procedures/client";
7
7
  import { wrapSchema } from "../schema.js";
8
8
  import { ServerCallOutputSchema } from "../output-schemas.js";
9
9
  import { serverCallInputSchema } from "../input-schemas.js";
@@ -55,7 +55,7 @@ export const serverCallProcedure: Procedure<
55
55
  shorts: { connectionId: "c", address: "a" },
56
56
  output: "json",
57
57
  })
58
- .handler(async (input: ServerCallInput): Promise<ServerCallOutput> => {
58
+ .handler(async (input: ServerCallInput, ctx?: ProcedureContext): Promise<ServerCallOutput> => {
59
59
  // Normalize path: accept dot-separated string or array
60
60
  const pathArray = typeof input.path === "string"
61
61
  ? input.path.split(".")
@@ -87,7 +87,12 @@ export const serverCallProcedure: Procedure<
87
87
  // (deep dive architecture review 3.3)
88
88
  const method = pathToMethod(pathArray);
89
89
 
90
- const result = await client.call(method, input.input ?? {});
90
+ // The signal and the remaining time of this call go with the relayed call (roadmap R14)
91
+ const deadline = ctx?.capability?.deadline;
92
+ const result = await client.call(method, input.input ?? {}, {
93
+ ...(ctx?.signal ? { signal: ctx.signal } : {}),
94
+ ...(deadline !== undefined ? { context: { [TIMEOUT_METADATA_KEY]: Math.max(0, deadline - Date.now()) } } : {}),
95
+ });
91
96
 
92
97
  return {
93
98
  result,
@@ -9,6 +9,7 @@ import { ServerConnectOutputSchema } from "../output-schemas.js";
9
9
  import { serverConnectInputSchema } from "../input-schemas.js";
10
10
  import type { ServerConnectInput, ServerConnectOutput } from "../types.js";
11
11
  import { connect } from "../connection/index.js";
12
+ import { ms } from "@procedures/client";
12
13
 
13
14
  // Use pass-through schemas
14
15
  const serverConnectOutputSchema = wrapSchema<ServerConnectOutput>(ServerConnectOutputSchema);
@@ -35,7 +36,8 @@ export const serverConnectProcedure: Procedure<
35
36
  connectOptions.transport = input.transport;
36
37
  }
37
38
  if (input.timeout !== undefined) {
38
- connectOptions.timeout = input.timeout;
39
+ // The input is data: a number of milliseconds
40
+ connectOptions.timeout = ms(input.timeout);
39
41
  }
40
42
  const connection = await connect(connectOptions);
41
43
 
@@ -3,7 +3,7 @@
3
3
  * Creates a transport-agnostic peer that exposes procedures
4
4
  */
5
5
 
6
- import { createProcedure, type Effects, type Procedure, PROCEDURE_REGISTRY } from "@procedures/client";
6
+ import { createProcedure, type Effects, type Procedure, type ProcedureContext, PROCEDURE_REGISTRY, ProcedureRegistry } from "@procedures/client";
7
7
  import { wrapSchema } from "../schema.js";
8
8
  import { ServerCreateOutputSchema } from "../output-schemas.js";
9
9
  import { serverCreateInputSchema } from "../input-schemas.js";
@@ -30,7 +30,10 @@ export const serverCreateProcedure: Procedure<
30
30
  // Each call starts a new peer that listens on its transports. It replaces nothing.
31
31
  effects: { reads: ["registry"], writes: ["network", "server"], destructive: false },
32
32
  })
33
- .handler(async (input: ServerCreateInput) => {
33
+ .handler(async (input: ServerCreateInput, ctx?: ProcedureContext) => {
34
+ // The registry of the caller: a host with its own registry serves its own procedures
35
+ const registry = ctx?.registry instanceof ProcedureRegistry ? ctx.registry : PROCEDURE_REGISTRY;
36
+
34
37
  // Generate unique server ID
35
38
  const serverId = `peer-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
36
39
 
@@ -48,7 +51,7 @@ export const serverCreateProcedure: Procedure<
48
51
  id: serverId,
49
52
  transports,
50
53
  autoRegister,
51
- registry: PROCEDURE_REGISTRY,
54
+ registry,
52
55
  ...(input.expose ? { expose: exposeRule(input.expose) } : {}),
53
56
  });
54
57
 
@@ -60,7 +63,7 @@ export const serverCreateProcedure: Procedure<
60
63
 
61
64
  // Get procedure count
62
65
  const procedureCount = input.autoRegister
63
- ? PROCEDURE_REGISTRY.getAll().filter((p) => p.handler).length
66
+ ? registry.getAll().filter((p) => p.handler).length
64
67
  : 0;
65
68
 
66
69
  return {
package/src/types.ts CHANGED
@@ -21,6 +21,8 @@ export interface HttpTransportConfig {
21
21
  urlStrategy?: "rest" | "rpc" | undefined;
22
22
  /** A secret that every request must send as `Authorization: Bearer <token>` */
23
23
  token?: string | undefined;
24
+ /** The largest request body in bytes. The default is 1 MiB. */
25
+ bodyLimit?: number | undefined;
24
26
  }
25
27
 
26
28
  export interface WebSocketTransportConfig {