@procedures/client 0.3.0 → 0.4.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 (120) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +16 -6
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/adapters/http/server/transport.d.ts.map +1 -1
  5. package/dist/adapters/http/server/transport.js +2 -3
  6. package/dist/adapters/http/server/transport.js.map +1 -1
  7. package/dist/adapters/local/client/transport.d.ts.map +1 -1
  8. package/dist/adapters/local/client/transport.js +4 -2
  9. package/dist/adapters/local/client/transport.js.map +1 -1
  10. package/dist/adapters/websocket/client/node.d.ts +30 -0
  11. package/dist/adapters/websocket/client/node.d.ts.map +1 -0
  12. package/dist/adapters/websocket/client/node.js +32 -0
  13. package/dist/adapters/websocket/client/node.js.map +1 -0
  14. package/dist/adapters/websocket/client/transport.d.ts.map +1 -1
  15. package/dist/adapters/websocket/client/transport.js +17 -9
  16. package/dist/adapters/websocket/client/transport.js.map +1 -1
  17. package/dist/adapters/websocket/client/types.d.ts +3 -2
  18. package/dist/adapters/websocket/client/types.d.ts.map +1 -1
  19. package/dist/adapters/websocket/client/types.js.map +1 -1
  20. package/dist/client/errors/http-errors.d.ts.map +1 -1
  21. package/dist/client/errors/http-errors.js +6 -0
  22. package/dist/client/errors/http-errors.js.map +1 -1
  23. package/dist/client/errors/index.d.ts +1 -1
  24. package/dist/client/errors/index.js +1 -1
  25. package/dist/client/errors/registry.d.ts +2 -1
  26. package/dist/client/errors/registry.d.ts.map +1 -1
  27. package/dist/client/errors/registry.js +72 -22
  28. package/dist/client/errors/registry.js.map +1 -1
  29. package/dist/client/middleware/rate-limit.d.ts.map +1 -1
  30. package/dist/client/middleware/rate-limit.js +0 -1
  31. package/dist/client/middleware/rate-limit.js.map +1 -1
  32. package/dist/client/middleware/timeout.d.ts.map +1 -1
  33. package/dist/client/middleware/timeout.js +2 -9
  34. package/dist/client/middleware/timeout.js.map +1 -1
  35. package/dist/index.d.ts +4 -0
  36. package/dist/index.d.ts.map +1 -1
  37. package/dist/index.js +4 -0
  38. package/dist/index.js.map +1 -1
  39. package/dist/node.d.ts +11 -0
  40. package/dist/node.d.ts.map +1 -0
  41. package/dist/node.js +10 -0
  42. package/dist/node.js.map +1 -0
  43. package/dist/procedures/core/array.d.ts +1 -1
  44. package/dist/procedures/core/array.d.ts.map +1 -1
  45. package/dist/procedures/core/array.js +56 -15
  46. package/dist/procedures/core/array.js.map +1 -1
  47. package/dist/procedures/core/index.d.ts.map +1 -1
  48. package/dist/procedures/core/index.js +9 -2
  49. package/dist/procedures/core/index.js.map +1 -1
  50. package/dist/procedures/core/logic.js +1 -1
  51. package/dist/procedures/core/logic.js.map +1 -1
  52. package/dist/procedures/core/math.d.ts.map +1 -1
  53. package/dist/procedures/core/math.js +5 -1
  54. package/dist/procedures/core/math.js.map +1 -1
  55. package/dist/procedures/core/meta.d.ts.map +1 -1
  56. package/dist/procedures/core/meta.js +41 -7
  57. package/dist/procedures/core/meta.js.map +1 -1
  58. package/dist/procedures/core/type.d.ts.map +1 -1
  59. package/dist/procedures/core/type.js +4 -2
  60. package/dist/procedures/core/type.js.map +1 -1
  61. package/dist/procedures/discovery.d.ts +4 -6
  62. package/dist/procedures/discovery.d.ts.map +1 -1
  63. package/dist/procedures/discovery.js +4 -6
  64. package/dist/procedures/discovery.js.map +1 -1
  65. package/dist/procedures/ref.d.ts +4 -2
  66. package/dist/procedures/ref.d.ts.map +1 -1
  67. package/dist/procedures/ref.js +2 -1
  68. package/dist/procedures/ref.js.map +1 -1
  69. package/dist/protocol.d.ts +9 -2
  70. package/dist/protocol.d.ts.map +1 -1
  71. package/dist/protocol.js +12 -2
  72. package/dist/protocol.js.map +1 -1
  73. package/dist/server/procedure-server.d.ts +2 -1
  74. package/dist/server/procedure-server.d.ts.map +1 -1
  75. package/dist/server/procedure-server.js +4 -2
  76. package/dist/server/procedure-server.js.map +1 -1
  77. package/package.json +5 -4
  78. package/src/adapters/http/server/transport.ts +2 -3
  79. package/src/adapters/local/client/transport.ts +4 -2
  80. package/src/adapters/websocket/client/node.ts +34 -0
  81. package/src/adapters/websocket/client/transport.ts +20 -9
  82. package/src/adapters/websocket/client/types.ts +3 -2
  83. package/src/client/errors/README.md +2 -0
  84. package/src/client/errors/http-errors.ts +5 -0
  85. package/src/client/errors/index.ts +1 -1
  86. package/src/client/errors/registry.ts +79 -22
  87. package/src/client/middleware/rate-limit.ts +0 -2
  88. package/src/client/middleware/timeout.ts +2 -9
  89. package/src/index.ts +4 -0
  90. package/src/node.ts +11 -0
  91. package/src/procedures/core/array.ts +53 -16
  92. package/src/procedures/core/index.ts +9 -2
  93. package/src/procedures/core/logic.ts +1 -1
  94. package/src/procedures/core/math.ts +5 -1
  95. package/src/procedures/core/meta.ts +43 -7
  96. package/src/procedures/core/type.ts +4 -2
  97. package/src/procedures/discovery.ts +4 -6
  98. package/src/procedures/ref.ts +4 -2
  99. package/src/protocol.ts +13 -2
  100. package/src/server/procedure-server.ts +4 -2
  101. package/dist/procedures/cli/announce.d.ts +0 -67
  102. package/dist/procedures/cli/announce.d.ts.map +0 -1
  103. package/dist/procedures/cli/announce.js +0 -392
  104. package/dist/procedures/cli/announce.js.map +0 -1
  105. package/dist/procedures/cli/discover.d.ts +0 -66
  106. package/dist/procedures/cli/discover.d.ts.map +0 -1
  107. package/dist/procedures/cli/discover.js +0 -310
  108. package/dist/procedures/cli/discover.js.map +0 -1
  109. package/dist/procedures/cli/index.d.ts +0 -13
  110. package/dist/procedures/cli/index.d.ts.map +0 -1
  111. package/dist/procedures/cli/index.js +0 -203
  112. package/dist/procedures/cli/index.js.map +0 -1
  113. package/dist/procedures/cli/init.d.ts +0 -17
  114. package/dist/procedures/cli/init.d.ts.map +0 -1
  115. package/dist/procedures/cli/init.js +0 -336
  116. package/dist/procedures/cli/init.js.map +0 -1
  117. package/src/procedures/cli/announce.ts +0 -470
  118. package/src/procedures/cli/discover.ts +0 -390
  119. package/src/procedures/cli/index.ts +0 -231
  120. package/src/procedures/cli/init.ts +0 -370
@@ -10,6 +10,7 @@ import { anyOutput, booleanOutput, stringOutput } from "./outputs.js";
10
10
  import { defineProcedure, namespace } from "../define.js";
11
11
  import type { AnyProcedure, Procedure } from "../types.js";
12
12
  import { PURE_EFFECTS, withEffects } from "../effects.js";
13
+ import { isPlainObject } from "../ref.js";
13
14
 
14
15
  // =============================================================================
15
16
  // Typeof Procedure
@@ -168,11 +169,12 @@ const isObjectProcedure: IsObjectProcedure = defineProcedure({
168
169
  input: IsObjectInputSchema,
169
170
  output: booleanOutput("True for a plain object"),
170
171
  metadata: {
171
- description: "Check if value is a plain object (not array, not null)",
172
+ description: "Check if value is a plain object (not array, not null, not a Date or another class instance)",
172
173
  tags: ["core", "type"],
173
174
  },
174
175
  handler: async (input: IsObjectInput): Promise<boolean> => {
175
- return typeof input.value === "object" && input.value !== null && !Array.isArray(input.value);
176
+ // Before, a Date or a Map gave true (catalog test, roadmap R29)
177
+ return isPlainObject(input.value);
176
178
  },
177
179
  });
178
180
 
@@ -1,13 +1,11 @@
1
1
  /**
2
2
  * Procedure Registration Helpers
3
3
  *
4
- * Manual registration helpers for procedures. For compile-time auto-discovery,
5
- * use the CLI: `npx client-registry discover`
4
+ * These helpers add procedures to the global registry.
6
5
  *
7
- * Libraries that depend on client should:
8
- * 1. Add `"client": { "procedures": "./dist/register.js" }` to package.json
9
- * 2. Create a register.ts that uses createAndRegister()
10
- * 3. Consumers run `npx client-registry discover` to generate imports
6
+ * A package with procedures declares `"client": { "procedures": "./dist/register.js" }` in its
7
+ * `package.json`. Its `src/register.ts` registers its module. `mark` finds the packages by the
8
+ * `client.procedures` field, and an app imports the `/register` entry of each package that it uses.
11
9
  */
12
10
 
13
11
  import { PROCEDURE_REGISTRY } from "./registry.js";
@@ -22,7 +22,8 @@
22
22
  * - `"$never"`: Never execute during hydration, pass as pure data (with its whole subtree)
23
23
  * - `"$parent"`: Defer to parent procedure (pass as data)
24
24
  * - `"someName"`: Defer to the runner that gives this name in its `contextStack`
25
- * (`dag.traverse` gives "dag.traverse", `core.catch` gives "catch")
25
+ * (`dag.traverse` gives "dag.traverse". `client.tryCatch` gives no name: it is control flow,
26
+ * and it runs its `try` and `catch` operands itself.)
26
27
  *
27
28
  * A deferred ref is data at every depth: hydration of the input that holds it does not run it.
28
29
  * The procedure that receives it runs it later (deep dive CORE-11).
@@ -681,7 +682,8 @@ export interface HydrateOptions {
681
682
 
682
683
  /**
683
684
  * The context names of the runner. A ref with `$when: "<name>"` runs only when this list has
684
- * the name. A runner such as `core.catch` gives its own name here when it hydrates its operand.
685
+ * the name. A runner such as `dag.traverse` gives its own name here when it hydrates its operand.
686
+ * (Control flow such as `client.tryCatch` runs its operands itself and gives no name.)
685
687
  */
686
688
  contextStack?: string[] | undefined;
687
689
 
package/src/protocol.ts CHANGED
@@ -50,8 +50,9 @@ export type ProtocolErrorCode =
50
50
 
51
51
  /**
52
52
  * The error codes of the protocol, on each face (HTTP, WebSocket, MCP, local). An error that a
53
- * handler throws with its own `code` keeps it. Such a code is not in this list, and HTTP gives it
54
- * the status 500.
53
+ * handler throws with its own `code` keeps it, for a value and for a stream (`errorCodeOf`). The
54
+ * HTTP status follows the code: the status of this list, the status of `ERROR_REGISTRY` for
55
+ * another known code, or 500.
55
56
  */
56
57
  export const ERROR_CODES: Readonly<Record<ProtocolErrorCode, ErrorCodeInfo>> = {
57
58
  NOT_FOUND: { http: 404, retryable: false, meaning: "No procedure has the path, or the host does not expose it" },
@@ -82,6 +83,16 @@ export function isProtocolErrorCode(code: unknown): code is ProtocolErrorCode {
82
83
  return typeof code === "string" && Object.prototype.hasOwnProperty.call(ERROR_CODES, code);
83
84
  }
84
85
 
86
+ /**
87
+ * The code of an error that a handler or an invocation throws, on each face: its own code when
88
+ * it is a string, or `HANDLER_ERROR`. An invocation error has a code of this list. Before, a
89
+ * value lost the own code of a handler error, and a stream kept it (roadmap R30).
90
+ */
91
+ export function errorCodeOf(error: unknown): string {
92
+ const code = (error as { code?: unknown } | null | undefined)?.code;
93
+ return typeof code === "string" ? code : "HANDLER_ERROR";
94
+ }
95
+
85
96
  /** The HTTP status of an error code, or undefined for a code that is not in the list. */
86
97
  export function httpStatusOf(code: unknown): number | undefined {
87
98
  return isProtocolErrorCode(code) ? ERROR_CODES[code].http : undefined;
@@ -24,6 +24,7 @@ import { IdempotencyCache, idempotencyKeyOf, isRepeatable, type IdempotencyOptio
24
24
  import { optionalMs, type Duration } from "../duration.js";
25
25
  import type { CollectionStorage } from "../procedures/collection/storage.js";
26
26
  import { TIMER_DEFAULTS } from "../timers.js";
27
+ import { errorCodeOf } from "../protocol.js";
27
28
 
28
29
  // =============================================================================
29
30
  // Types
@@ -198,7 +199,8 @@ function withRequestTimeout(
198
199
 
199
200
  /**
200
201
  * The error response of a failed invocation. An invocation error keeps its code
201
- * (VALIDATION_ERROR, NOT_EXPOSED, ABORTED and so on). An error of the handler is HANDLER_ERROR.
202
+ * (VALIDATION_ERROR, NOT_EXPOSED, ABORTED and so on). An error of the handler keeps its own code
203
+ * when it is a string, as for a stream (`WIRE-PROTOCOL.md`). Without a code, it is HANDLER_ERROR.
202
204
  */
203
205
  export function errorResponse(id: string, error: unknown): ServerResponse<unknown> {
204
206
  // An error that says it is retryable stays retryable: before, every error lost the flag
@@ -214,7 +216,7 @@ export function errorResponse(id: string, error: unknown): ServerResponse<unknow
214
216
  id,
215
217
  status: {
216
218
  type: "error",
217
- code: error instanceof InvocationError ? error.code : "HANDLER_ERROR",
219
+ code: errorCodeOf(error),
218
220
  message: error instanceof Error ? error.message : String(error),
219
221
  retryable: typeof retryable === "boolean" ? retryable : false,
220
222
  },
@@ -1,67 +0,0 @@
1
- /**
2
- * Procedure Announcement (Self-Registration)
3
- *
4
- * When a package with procedures is installed, it "announces" itself
5
- * by writing to a registry file at the root of the project.
6
- *
7
- * This enables true bottom-up propagation:
8
- * - Each package with procedures has `"postinstall": "client-registry announce"`
9
- * - On install, it walks up to find the root and registers itself
10
- * - `client-registry discover` reads this registry instead of scanning
11
- *
12
- * The registry file (.client-registry.json) accumulates entries from
13
- * all packages as they're installed, making discovery instant.
14
- */
15
- export interface AnnounceOptions {
16
- /** Be verbose about what's happening */
17
- verbose: boolean;
18
- /** The folder to start from (default: the current folder) */
19
- cwd?: string | undefined;
20
- /**
21
- * Add `client-registry announce` to the postinstall script of the package that depends on this one.
22
- * This edits a package.json that belongs to the consumer, so it happens only when asked
23
- * (`client-registry announce --propagate`). Default: false.
24
- */
25
- propagate?: boolean | undefined;
26
- }
27
- interface RegistryEntry {
28
- /** Path to procedures file relative to package */
29
- proceduresPath: string;
30
- /** When this entry was added */
31
- registeredAt: string;
32
- /** Package version */
33
- version?: string;
34
- }
35
- interface Registry {
36
- /** Schema version for future compatibility */
37
- schemaVersion: 1;
38
- /** Map of package name to registry entry */
39
- packages: Record<string, RegistryEntry>;
40
- }
41
- declare const REGISTRY_FILENAME = ".client-registry.json";
42
- /**
43
- * Announce this package's procedures to the project registry.
44
- *
45
- * Called from a package's postinstall script to register its procedures.
46
- *
47
- * With `propagate: true` (`client-registry announce --propagate`), it also adds the postinstall script
48
- * to the package that depends on this one, for transitive discovery:
49
- * - When client is installed in package D, client's postinstall adds postinstall to D
50
- * - When D is installed in C, D's postinstall adds postinstall to C
51
- * - When C is installed in B, C's postinstall adds postinstall to B
52
- *
53
- * The propagation edits the package.json of the consumer, so it happens only when asked.
54
- * Without it, each package that has its own postinstall script still registers itself.
55
- */
56
- export declare function announce(options: AnnounceOptions): Promise<void>;
57
- /**
58
- * Remove this package from the registry (for uninstall).
59
- */
60
- export declare function unannounce(options: AnnounceOptions): Promise<void>;
61
- /**
62
- * Get the registry for use by discover command.
63
- */
64
- export declare function getRegistry(rootDir: string): Promise<Registry>;
65
- export { REGISTRY_FILENAME };
66
- export type { Registry, RegistryEntry };
67
- //# sourceMappingURL=announce.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"announce.d.ts","sourceRoot":"","sources":["../../../src/procedures/cli/announce.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,MAAM,WAAW,eAAe;IAC9B,wCAAwC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,6DAA6D;IAC7D,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACjC;AAED,UAAU,aAAa;IACrB,kDAAkD;IAClD,cAAc,EAAE,MAAM,CAAC;IACvB,gCAAgC;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,sBAAsB;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,QAAQ;IAChB,8CAA8C;IAC9C,aAAa,EAAE,CAAC,CAAC;IACjB,4CAA4C;IAC5C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;CACzC;AAkFD,QAAA,MAAM,iBAAiB,0BAA0B,CAAC;AA0GlD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0BtE;AAiKD;;GAEG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBxE;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,CAEpE;AAED,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAC7B,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC"}
@@ -1,392 +0,0 @@
1
- /**
2
- * Procedure Announcement (Self-Registration)
3
- *
4
- * When a package with procedures is installed, it "announces" itself
5
- * by writing to a registry file at the root of the project.
6
- *
7
- * This enables true bottom-up propagation:
8
- * - Each package with procedures has `"postinstall": "client-registry announce"`
9
- * - On install, it walks up to find the root and registers itself
10
- * - `client-registry discover` reads this registry instead of scanning
11
- *
12
- * The registry file (.client-registry.json) accumulates entries from
13
- * all packages as they're installed, making discovery instant.
14
- */
15
- import * as fs from "node:fs/promises";
16
- import * as path from "node:path";
17
- // =============================================================================
18
- // Path Utilities
19
- // =============================================================================
20
- /**
21
- * Find the root of the project (topmost directory with package.json that isn't in node_modules).
22
- */
23
- async function findProjectRoot(startDir) {
24
- let current = path.resolve(startDir);
25
- let lastValidRoot = null;
26
- while (true) {
27
- const pkgPath = path.join(current, "package.json");
28
- try {
29
- await fs.access(pkgPath);
30
- // Check if we're inside node_modules
31
- const isInNodeModules = current.includes("node_modules");
32
- if (!isInNodeModules) {
33
- // This is a valid root candidate
34
- lastValidRoot = current;
35
- }
36
- }
37
- catch {
38
- // No package.json here
39
- }
40
- const parent = path.dirname(current);
41
- if (parent === current) {
42
- // Reached filesystem root
43
- break;
44
- }
45
- current = parent;
46
- }
47
- return lastValidRoot;
48
- }
49
- /**
50
- * Find the package that contains the current directory.
51
- * This is the package that depends on client and is being installed.
52
- */
53
- async function findContainingPackage(startDir) {
54
- let current = path.resolve(startDir);
55
- while (true) {
56
- const pkgPath = path.join(current, "package.json");
57
- try {
58
- const content = await fs.readFile(pkgPath, "utf-8");
59
- const pkg = JSON.parse(content);
60
- return { dir: current, pkg };
61
- }
62
- catch {
63
- // No package.json here, go up
64
- }
65
- const parent = path.dirname(current);
66
- if (parent === current) {
67
- // Reached filesystem root
68
- break;
69
- }
70
- current = parent;
71
- }
72
- return null;
73
- }
74
- // =============================================================================
75
- // Registry Operations
76
- // =============================================================================
77
- const REGISTRY_FILENAME = ".client-registry.json";
78
- /**
79
- * Read the registry file, or return an empty registry if the file does not exist.
80
- *
81
- * Any other failure is an error. Before, every failure gave an empty registry, so a read that
82
- * failed (a corrupt file, a file that Windows held for a moment) made the next write remove
83
- * every entry.
84
- */
85
- async function readRegistry(rootDir) {
86
- const registryPath = path.join(rootDir, REGISTRY_FILENAME);
87
- let content;
88
- try {
89
- content = await retryOnWindowsContention(() => fs.readFile(registryPath, "utf-8"));
90
- }
91
- catch (error) {
92
- if (error.code === "ENOENT") {
93
- return { schemaVersion: 1, packages: {} };
94
- }
95
- throw error;
96
- }
97
- return JSON.parse(content);
98
- }
99
- /**
100
- * Run a file operation again when Windows reports that another process holds the file for a
101
- * moment (EPERM, EACCES, EBUSY): a rename over a file that a reader has open fails that way.
102
- */
103
- async function retryOnWindowsContention(operation) {
104
- for (let attempt = 1;; attempt++) {
105
- try {
106
- return await operation();
107
- }
108
- catch (error) {
109
- if (attempt >= 20 || !isLockContention(error) || error.code === "EEXIST")
110
- throw error;
111
- await new Promise((resolve) => setTimeout(resolve, 10 * attempt));
112
- }
113
- }
114
- }
115
- /**
116
- * Write the registry file: to a temporary file, then a rename, so a reader never sees a part.
117
- */
118
- async function writeRegistry(rootDir, registry) {
119
- const registryPath = path.join(rootDir, REGISTRY_FILENAME);
120
- const content = JSON.stringify(registry, null, 2) + "\n";
121
- const temporary = `${registryPath}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
122
- try {
123
- await fs.writeFile(temporary, content, "utf-8");
124
- await retryOnWindowsContention(() => fs.rename(temporary, registryPath));
125
- }
126
- catch (error) {
127
- await fs.rm(temporary, { force: true });
128
- throw error;
129
- }
130
- }
131
- /** A lock older than this belongs to a process that stopped: it is removed. */
132
- const STALE_LOCK_MS = 10_000;
133
- /**
134
- * True when another writer holds the lock. On Windows, a lock file that its owner is deleting
135
- * cannot be opened until the delete completes: `open` fails with EPERM (or EACCES, EBUSY), not
136
- * EEXIST.
137
- */
138
- function isLockContention(error) {
139
- const code = error.code;
140
- if (code === "EEXIST")
141
- return true;
142
- return process.platform === "win32" && (code === "EPERM" || code === "EACCES" || code === "EBUSY");
143
- }
144
- /**
145
- * Read, change and write the registry under a lock file. Package managers run postinstall
146
- * scripts in parallel: without the lock, two announcements read the same registry, and the
147
- * second write loses the first entry (deep dive CORE-17).
148
- */
149
- async function updateRegistry(rootDir, change) {
150
- const lockPath = path.join(rootDir, `${REGISTRY_FILENAME}.lock`);
151
- const deadline = Date.now() + 30_000;
152
- for (;;) {
153
- try {
154
- const handle = await fs.open(lockPath, "wx");
155
- await handle.close();
156
- break;
157
- }
158
- catch (error) {
159
- if (!isLockContention(error) || Date.now() > deadline)
160
- throw error;
161
- try {
162
- const { mtimeMs } = await fs.stat(lockPath);
163
- if (Date.now() - mtimeMs > STALE_LOCK_MS)
164
- await fs.rm(lockPath, { force: true });
165
- }
166
- catch {
167
- // The lock went away: try again
168
- }
169
- await new Promise((resolve) => setTimeout(resolve, 10 + Math.random() * 20));
170
- }
171
- }
172
- try {
173
- const registry = await readRegistry(rootDir);
174
- if (change(registry)) {
175
- await writeRegistry(rootDir, registry);
176
- }
177
- }
178
- finally {
179
- await fs.rm(lockPath, { force: true });
180
- }
181
- }
182
- // =============================================================================
183
- // Main
184
- // =============================================================================
185
- /**
186
- * Announce this package's procedures to the project registry.
187
- *
188
- * Called from a package's postinstall script to register its procedures.
189
- *
190
- * With `propagate: true` (`client-registry announce --propagate`), it also adds the postinstall script
191
- * to the package that depends on this one, for transitive discovery:
192
- * - When client is installed in package D, client's postinstall adds postinstall to D
193
- * - When D is installed in C, D's postinstall adds postinstall to C
194
- * - When C is installed in B, C's postinstall adds postinstall to B
195
- *
196
- * The propagation edits the package.json of the consumer, so it happens only when asked.
197
- * Without it, each package that has its own postinstall script still registers itself.
198
- */
199
- export async function announce(options) {
200
- const { verbose } = options;
201
- // Find the package we're in (the one whose postinstall is running)
202
- const containing = await findContainingPackage(options.cwd ?? process.cwd());
203
- if (!containing) {
204
- if (verbose) {
205
- console.log("[client] No package.json found, skipping announcement");
206
- }
207
- return;
208
- }
209
- const { dir: packageDir, pkg } = containing;
210
- // Propagate the postinstall script to the parent package only when asked: it edits the
211
- // consumer's package.json (deep dive CORE-17)
212
- if (options.propagate) {
213
- await propagatePostinstallToParent(packageDir, pkg, verbose);
214
- }
215
- // If this package has procedures, register them
216
- if (pkg.client?.procedures) {
217
- await registerProcedures(packageDir, pkg, verbose);
218
- }
219
- else if (verbose) {
220
- console.log(`[client] ${pkg.name} does not declare procedures`);
221
- }
222
- }
223
- /**
224
- * Register this package's procedures at the project root.
225
- */
226
- async function registerProcedures(packageDir, pkg, verbose) {
227
- // Find the project root
228
- const projectRoot = await findProjectRoot(packageDir);
229
- if (!projectRoot) {
230
- if (verbose) {
231
- console.log("[client] Could not find project root, skipping registration");
232
- }
233
- return;
234
- }
235
- // Don't register if we ARE the project root (we're the app, not a dependency)
236
- if (path.resolve(packageDir) === path.resolve(projectRoot)) {
237
- if (verbose) {
238
- console.log(`[client] ${pkg.name} is the project root, skipping self-registration`);
239
- }
240
- return;
241
- }
242
- // Add/update our entry, under the lock
243
- const entry = {
244
- proceduresPath: pkg.client.procedures,
245
- registeredAt: new Date().toISOString(),
246
- };
247
- if (pkg.version) {
248
- entry.version = pkg.version;
249
- }
250
- await updateRegistry(projectRoot, (registry) => {
251
- registry.packages[pkg.name] = entry;
252
- return true;
253
- });
254
- if (verbose) {
255
- console.log(`[client] Registered ${pkg.name} -> ${pkg.client.procedures}`);
256
- }
257
- }
258
- /**
259
- * Propagate postinstall to the parent package.
260
- * This ensures the chain continues when this package is installed elsewhere.
261
- */
262
- async function propagatePostinstallToParent(packageDir, pkg, verbose) {
263
- // Find parent package (the one that depends on this package)
264
- const parent = await findParentPackage(packageDir);
265
- if (!parent) {
266
- if (verbose) {
267
- console.log(`[client] No parent package found for ${pkg.name}`);
268
- }
269
- return;
270
- }
271
- const { dir: parentDir, pkg: parentPkg } = parent;
272
- // Don't modify packages inside node_modules of other packages
273
- // We only want to modify the immediate dependent
274
- if (isNestedNodeModules(parentDir)) {
275
- if (verbose) {
276
- console.log(`[client] Parent ${parentPkg.name} is nested in node_modules, skipping`);
277
- }
278
- return;
279
- }
280
- await ensurePostinstall(parentDir, parentPkg, verbose);
281
- }
282
- /**
283
- * Find the parent package (the one that depends on the current package).
284
- * Walks up from node_modules to find the containing project.
285
- */
286
- async function findParentPackage(packageDir) {
287
- let current = path.dirname(packageDir);
288
- while (true) {
289
- // Skip node_modules directories
290
- const basename = path.basename(current);
291
- if (basename === "node_modules") {
292
- current = path.dirname(current);
293
- continue;
294
- }
295
- const pkgPath = path.join(current, "package.json");
296
- try {
297
- const content = await fs.readFile(pkgPath, "utf-8");
298
- const pkg = JSON.parse(content);
299
- return { dir: current, pkg };
300
- }
301
- catch {
302
- // No package.json here
303
- }
304
- const parent = path.dirname(current);
305
- if (parent === current) {
306
- break;
307
- }
308
- current = parent;
309
- }
310
- return null;
311
- }
312
- /**
313
- * Check if a path is inside nested node_modules (e.g., node_modules/a/node_modules/b).
314
- */
315
- function isNestedNodeModules(dir) {
316
- const normalized = dir.replace(/\\/g, "/");
317
- const parts = normalized.split("/node_modules/");
318
- return parts.length > 2;
319
- }
320
- /**
321
- * Ensure a package has the postinstall script for propagation.
322
- */
323
- async function ensurePostinstall(packageDir, pkg, verbose) {
324
- const pkgPath = path.join(packageDir, "package.json");
325
- let fullPkg;
326
- try {
327
- fullPkg = JSON.parse(await fs.readFile(pkgPath, "utf-8"));
328
- }
329
- catch {
330
- if (verbose) {
331
- console.log(`[client] Could not read ${pkgPath}`);
332
- }
333
- return;
334
- }
335
- const scripts = (fullPkg["scripts"] ?? {});
336
- const postinstall = scripts["postinstall"] ?? "";
337
- // Check if postinstall already includes client-registry announce
338
- if (postinstall.includes("client-registry announce")) {
339
- if (verbose) {
340
- console.log(`[client] ${pkg.name} already has client-registry announce in postinstall`);
341
- }
342
- return;
343
- }
344
- // Add client-registry announce to postinstall (cross-platform, no shell-specific syntax)
345
- // The CLI handles errors internally and always exits 0
346
- const newPostinstall = postinstall
347
- ? `${postinstall} && client-registry announce`
348
- : "client-registry announce";
349
- scripts["postinstall"] = newPostinstall;
350
- fullPkg["scripts"] = scripts;
351
- try {
352
- await fs.writeFile(pkgPath, JSON.stringify(fullPkg, null, 2) + "\n", "utf-8");
353
- if (verbose) {
354
- console.log(`[client] Added postinstall to ${pkg.name}`);
355
- }
356
- }
357
- catch (error) {
358
- if (verbose) {
359
- console.log(`[client] Could not write to ${pkgPath}: ${error}`);
360
- }
361
- }
362
- }
363
- /**
364
- * Remove this package from the registry (for uninstall).
365
- */
366
- export async function unannounce(options) {
367
- const { verbose } = options;
368
- const containing = await findContainingPackage(options.cwd ?? process.cwd());
369
- if (!containing)
370
- return;
371
- const { dir: packageDir, pkg } = containing;
372
- const projectRoot = await findProjectRoot(packageDir);
373
- if (!projectRoot)
374
- return;
375
- await updateRegistry(projectRoot, (registry) => {
376
- if (!registry.packages[pkg.name])
377
- return false;
378
- delete registry.packages[pkg.name];
379
- if (verbose) {
380
- console.log(`[client] Unregistered ${pkg.name}`);
381
- }
382
- return true;
383
- });
384
- }
385
- /**
386
- * Get the registry for use by discover command.
387
- */
388
- export async function getRegistry(rootDir) {
389
- return readRegistry(rootDir);
390
- }
391
- export { REGISTRY_FILENAME };
392
- //# sourceMappingURL=announce.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"announce.js","sourceRoot":"","sources":["../../../src/procedures/cli/announce.ts"],"names":[],"mappings":"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"}
@@ -1,66 +0,0 @@
1
- /**
2
- * Procedure Discovery
3
- *
4
- * Generates a TypeScript file with static imports for all discovered procedures.
5
- *
6
- * Fast path: Reads from .client-registry.json (populated by `client-registry announce`)
7
- * Fallback: Scans node_modules for packages with `client.procedures`
8
- *
9
- * This is compile-time discovery - the generated file contains static imports
10
- * that get compiled/bundled with your application.
11
- */
12
- export interface DiscoverOptions {
13
- /** Output file path */
14
- output: string;
15
- /** Root directory to scan from */
16
- root: string;
17
- /** Watch mode for development */
18
- watch: boolean;
19
- /** Check if generated file is up-to-date (CI mode) */
20
- check: boolean;
21
- /** Verbose logging */
22
- verbose: boolean;
23
- }
24
- /** A package that declares procedures. */
25
- export interface DiscoveredPackage {
26
- name: string;
27
- proceduresPath: string;
28
- /** The module specifier that the generated file imports */
29
- importPath: string;
30
- }
31
- /**
32
- * The specifier that imports the procedures file of a package. With an `exports` map, a bare
33
- * `pkg/dist/register.js` import fails unless the map exports that path: the function looks for
34
- * the subpath (also a `./*` pattern) whose target is the file: for the packages of this
35
- * repository, `./register`. When the map has none, it imports the package root. (Before, the
36
- * generated import ignored the map, and failed: deep dive CORE-17.)
37
- *
38
- * @param name - Package name
39
- * @param manifest - The package.json of the package
40
- * @param proceduresPath - The `client.procedures` field
41
- * @returns The module specifier for the generated import
42
- */
43
- export declare function procedureImportPath(name: string, manifest: {
44
- exports?: unknown;
45
- }, proceduresPath: string): string;
46
- /**
47
- * Discover packages with procedure declarations: the dependencies of the root package and
48
- * their dependencies, in `node_modules`.
49
- *
50
- * @param rootDir - The folder of the root package.json
51
- * @param verbose - Log each package
52
- * @returns The packages that declare procedures, sorted by name
53
- */
54
- export declare function discoverPackages(rootDir: string, verbose: boolean): Promise<DiscoveredPackage[]>;
55
- /**
56
- * Generate the TypeScript file content.
57
- *
58
- * @param packages - The discovered packages
59
- * @returns The file content: one side-effect import for each package
60
- */
61
- export declare function generateCode(packages: DiscoveredPackage[]): string;
62
- /**
63
- * Run procedure discovery.
64
- */
65
- export declare function discover(options: DiscoverOptions): Promise<void>;
66
- //# sourceMappingURL=discover.d.ts.map