@ory/argus 0.1.1 → 0.1.2

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.
package/dist/dev.js CHANGED
@@ -127,8 +127,19 @@ function npmEnv() {
127
127
  // the local registry through an isolated pacote cache, with the user's
128
128
  // supply-chain freshness gate disabled (otherwise just-published tarballs
129
129
  // get filtered out as `ENOVERSIONS — No versions available`).
130
+ //
131
+ // `npm_config_userconfig` swaps the userconfig file from `~/.npmrc` to a
132
+ // launcher-managed npmrc that pins `@ory:registry` to the local Verdaccio.
133
+ // Without this, a developer-level `@ory:registry=…` line in their own
134
+ // `~/.npmrc` (left over from `npm login --scope=@ory` or similar) wins
135
+ // against `--registry` for scoped packages and routes the launcher's
136
+ // `npm install @ory/<harness>` — and the harness's own runtime `npx`
137
+ // calls — back to npmjs.org. The symptoms are ENOVERSIONS or tarball
138
+ // sha512 corruption depending on which side of the manifest/tarball
139
+ // split each subprocess hits.
130
140
  return {
131
141
  ...process.env,
142
+ npm_config_userconfig: (0, manager_js_1.ensureLauncherNpmrc)(),
132
143
  npm_config_registry: config_js_1.REGISTRY_URL,
133
144
  npm_config_cache: (0, manager_js_1.getLocalRegistryNpmCacheDir)(),
134
145
  npm_config_min_release_age: "0",
@@ -21,3 +21,20 @@ export declare const REGISTRY_CONTAINER_STORAGE = "/verdaccio/storage";
21
21
  export declare const REGISTRY_CONTAINER_CONFIG = "/verdaccio/conf/config.yaml";
22
22
  export declare function verdaccioConfigYaml(): string;
23
23
  export declare function npmrcContent(): string;
24
+ /**
25
+ * Userconfig file used by the dev launcher's npm/npx subprocesses.
26
+ *
27
+ * The scope-specific `@ory:registry=…` line is the critical bit. If a
28
+ * developer has ever run `npm login --scope=@ory` (or otherwise pinned
29
+ * `@ory:registry` in their `~/.npmrc`) to publish or fetch from npmjs.org,
30
+ * that pin takes precedence over `--registry` / `npm_config_registry` for
31
+ * scoped packages — so the launcher's `npm install @ory/<harness>` and the
32
+ * harness's own runtime `npx -y -p @ory/<harness>` calls silently hit
33
+ * npmjs.org instead of localhost, producing either `ENOVERSIONS` (because
34
+ * npmjs's manifest doesn't list the just-bumped local version) or a tarball
35
+ * sha512 mismatch (when the local manifest is consulted but npmjs serves
36
+ * the bytes). We expose this file as `npm_config_userconfig` so it
37
+ * displaces `~/.npmrc` entirely for subprocesses the launcher spawns,
38
+ * without modifying any global config or polluting the sandbox.
39
+ */
40
+ export declare function launcherNpmrcContent(): string;
@@ -13,6 +13,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.REGISTRY_CONTAINER_CONFIG = exports.REGISTRY_CONTAINER_STORAGE = exports.REGISTRY_CONTAINER = exports.REGISTRY_IMAGE = exports.REGISTRY_DIR_NAME = exports.REGISTRY_URL = exports.REGISTRY_PORT = void 0;
14
14
  exports.verdaccioConfigYaml = verdaccioConfigYaml;
15
15
  exports.npmrcContent = npmrcContent;
16
+ exports.launcherNpmrcContent = launcherNpmrcContent;
16
17
  exports.REGISTRY_PORT = 4873;
17
18
  exports.REGISTRY_URL = `http://localhost:${exports.REGISTRY_PORT}`;
18
19
  exports.REGISTRY_DIR_NAME = ".ory-dev/registry";
@@ -44,15 +45,22 @@ uplinks:
44
45
  cache: false
45
46
 
46
47
  packages:
48
+ # @ory/client is a transitive Ory SDK dep that lives on npmjs.org — proxy
49
+ # it so installs can resolve it from upstream.
50
+ "@ory/client":
51
+ access: $all
52
+ publish: $all
53
+ proxy: npmjs
54
+
55
+ # All other @ory/* packages are workspace packages we publish locally.
56
+ # No proxy: if upstream were consulted, Verdaccio would merge npmjs.org's
57
+ # already-published versions into the manifest and reject every republish
58
+ # at the same version with "cannot publish over previously published
59
+ # versions: X.Y.Z".
47
60
  "@ory/*":
48
61
  access: $all
49
62
  publish: $all
50
63
  unpublish: $all
51
- # Locally-published workspace packages (e.g. @ory/argus) are served from
52
- # storage; everything else under @ory/* (notably @ory/client, a transitive
53
- # dep) falls through to npmjs. Without this, transitive @ory/client
54
- # resolution fails with E404 against the local registry.
55
- proxy: npmjs
56
64
 
57
65
  "**":
58
66
  access: $all
@@ -78,3 +86,26 @@ function npmrcContent() {
78
86
  //localhost:${exports.REGISTRY_PORT}/:_authToken=local-dev-token
79
87
  `;
80
88
  }
89
+ /**
90
+ * Userconfig file used by the dev launcher's npm/npx subprocesses.
91
+ *
92
+ * The scope-specific `@ory:registry=…` line is the critical bit. If a
93
+ * developer has ever run `npm login --scope=@ory` (or otherwise pinned
94
+ * `@ory:registry` in their `~/.npmrc`) to publish or fetch from npmjs.org,
95
+ * that pin takes precedence over `--registry` / `npm_config_registry` for
96
+ * scoped packages — so the launcher's `npm install @ory/<harness>` and the
97
+ * harness's own runtime `npx -y -p @ory/<harness>` calls silently hit
98
+ * npmjs.org instead of localhost, producing either `ENOVERSIONS` (because
99
+ * npmjs's manifest doesn't list the just-bumped local version) or a tarball
100
+ * sha512 mismatch (when the local manifest is consulted but npmjs serves
101
+ * the bytes). We expose this file as `npm_config_userconfig` so it
102
+ * displaces `~/.npmrc` entirely for subprocesses the launcher spawns,
103
+ * without modifying any global config or polluting the sandbox.
104
+ */
105
+ function launcherNpmrcContent() {
106
+ return `registry=${exports.REGISTRY_URL}/
107
+ @ory:registry=${exports.REGISTRY_URL}/
108
+ //localhost:${exports.REGISTRY_PORT}/:_authToken=local-dev-token
109
+ min-release-age=0
110
+ `;
111
+ }
@@ -19,6 +19,17 @@
19
19
  * pnpm publish/npm install even after we drop the version from Verdaccio.
20
20
  */
21
21
  export declare function getLocalRegistryNpmCacheDir(): string;
22
+ /**
23
+ * Path to the userconfig npmrc the dev launcher hands to its subprocesses.
24
+ * See `launcherNpmrcContent` in `./config.ts` for why this exists.
25
+ */
26
+ export declare function getLauncherNpmrcPath(): string;
27
+ /**
28
+ * Materialize the launcher userconfig npmrc on disk and return its path.
29
+ * Idempotent: rewrites the file every call so any drift in the rendered
30
+ * content (e.g. registry URL change) lands without a clean-and-restart.
31
+ */
32
+ export declare function ensureLauncherNpmrc(): string;
22
33
  /**
23
34
  * Start the local registry if it isn't already running.
24
35
  */
@@ -46,6 +46,8 @@ var __importStar = (this && this.__importStar) || (function () {
46
46
  })();
47
47
  Object.defineProperty(exports, "__esModule", { value: true });
48
48
  exports.getLocalRegistryNpmCacheDir = getLocalRegistryNpmCacheDir;
49
+ exports.getLauncherNpmrcPath = getLauncherNpmrcPath;
50
+ exports.ensureLauncherNpmrc = ensureLauncherNpmrc;
49
51
  exports.ensureRegistryRunning = ensureRegistryRunning;
50
52
  exports.publishHarnessToLocal = publishHarnessToLocal;
51
53
  exports.registryStart = registryStart;
@@ -84,6 +86,24 @@ function getRegistryDir() {
84
86
  function getLocalRegistryNpmCacheDir() {
85
87
  return path.join(getRegistryDir(), "npm-cache");
86
88
  }
89
+ /**
90
+ * Path to the userconfig npmrc the dev launcher hands to its subprocesses.
91
+ * See `launcherNpmrcContent` in `./config.ts` for why this exists.
92
+ */
93
+ function getLauncherNpmrcPath() {
94
+ return path.join(getRegistryDir(), "launcher.npmrc");
95
+ }
96
+ /**
97
+ * Materialize the launcher userconfig npmrc on disk and return its path.
98
+ * Idempotent: rewrites the file every call so any drift in the rendered
99
+ * content (e.g. registry URL change) lands without a clean-and-restart.
100
+ */
101
+ function ensureLauncherNpmrc() {
102
+ const npmrcPath = getLauncherNpmrcPath();
103
+ ensureDir(path.dirname(npmrcPath));
104
+ fs.writeFileSync(npmrcPath, (0, config_js_1.launcherNpmrcContent)());
105
+ return npmrcPath;
106
+ }
87
107
  function ensureDir(dir) {
88
108
  if (!fs.existsSync(dir)) {
89
109
  fs.mkdirSync(dir, { recursive: true });
@@ -176,15 +196,28 @@ async function withLocalPublishConfig(workspaceRoot, fn) {
176
196
  async function cleanScopeStorage() {
177
197
  // Verdaccio caches package metadata in memory; deleting on-disk storage
178
198
  // alone leaves stale manifests served and causes publish to report
179
- // "already exists". Issue an HTTP DELETE for every known scoped package
180
- // first (Verdaccio drops both memory + disk state), then remove any
181
- // residual scope dir for completeness.
199
+ // "already exists". Issue an authenticated HTTP DELETE for every known
200
+ // scoped package first (Verdaccio drops both memory + disk state), then
201
+ // remove any residual scope dir for completeness.
202
+ //
203
+ // The Authorization header is required: Verdaccio silently rejects
204
+ // unauthenticated DELETEs, leaves its in-memory manifest intact, and then
205
+ // rewrites the on-disk `package.json` from that cache on the next publish
206
+ // — so the second publish sees the stale versions and fails with
207
+ // "cannot publish over previously published versions".
182
208
  const root = findProjectRoot(process.cwd());
183
209
  const names = listWorkspaceScopedPackages(root);
210
+ const token = readToken(getRegistryDir());
211
+ const headers = token
212
+ ? { Authorization: `Bearer ${token}` }
213
+ : {};
184
214
  await Promise.all(names.map(async (name) => {
185
215
  const encoded = name.replace("/", "%2f");
186
216
  try {
187
- await fetch(`${config_js_1.REGISTRY_URL}/${encoded}/-rev/0`, { method: "DELETE" });
217
+ await fetch(`${config_js_1.REGISTRY_URL}/${encoded}/-rev/0`, {
218
+ method: "DELETE",
219
+ headers,
220
+ });
188
221
  }
189
222
  catch {
190
223
  // Best-effort.
@@ -292,6 +325,48 @@ async function registerDevUser(registryDir) {
292
325
  fs.writeFileSync(getTokenFile(registryDir), token);
293
326
  return token;
294
327
  }
328
+ /**
329
+ * Restart the registry container if the rendered Verdaccio config has
330
+ * drifted from what's on disk. Verdaccio 6 does not hot-reload `config.yaml`,
331
+ * so a config change in the codebase has no effect on a running container
332
+ * until it restarts — and a stale config can silently keep mis-routing
333
+ * publishes through the upstream proxy. Called from `publishAllOryToLocal`
334
+ * so any code-bundled policy fix lands without an explicit `registry:clean`.
335
+ */
336
+ async function ensureConfigInSync(quiet) {
337
+ const registryDir = getRegistryDir();
338
+ // If the registry dir doesn't exist here, the running container was
339
+ // started from a different cwd (e.g. main repo while we're in a worktree,
340
+ // or vice versa). We don't own the on-disk state and writing a config
341
+ // file at this path wouldn't reach the container's bind mount anyway.
342
+ // Skip silently — the downstream auth-token check will surface a clear
343
+ // error if the caller actually needs local registry state.
344
+ if (!fs.existsSync(registryDir))
345
+ return;
346
+ const configPath = path.join(registryDir, "config.yaml");
347
+ const expected = (0, config_js_1.verdaccioConfigYaml)();
348
+ const current = fs.existsSync(configPath)
349
+ ? fs.readFileSync(configPath, "utf-8")
350
+ : "";
351
+ if (current === expected)
352
+ return;
353
+ if (!quiet) {
354
+ console.log("Verdaccio config out of date — restarting registry...");
355
+ }
356
+ fs.writeFileSync(configPath, expected);
357
+ const restart = (0, node_child_process_1.spawnSync)("docker", ["restart", config_js_1.REGISTRY_CONTAINER], {
358
+ stdio: ["ignore", "ignore", "pipe"],
359
+ encoding: "utf-8",
360
+ });
361
+ if (restart.status !== 0) {
362
+ const stderr = (restart.stderr ?? "").toString().trim();
363
+ throw new Error(`Failed to restart registry container after config change (exit ${restart.status}): ${stderr}`);
364
+ }
365
+ const ready = await waitForRegistry();
366
+ if (!ready) {
367
+ throw new Error("Registry did not come back online after config restart within 30 seconds.");
368
+ }
369
+ }
295
370
  // ─── Public lifecycle ──────────────────────────────────────────────
296
371
  /**
297
372
  * Start the local registry if it isn't already running.
@@ -362,6 +437,7 @@ async function publishAllOryToLocal(opts = {}) {
362
437
  if (!isRegistryRunning()) {
363
438
  throw new Error("Local registry is not running. Call ensureRegistryRunning() first.");
364
439
  }
440
+ await ensureConfigInSync(opts.quiet);
365
441
  const registryDir = getRegistryDir();
366
442
  const token = readToken(registryDir);
367
443
  if (!token) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ory/argus",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "Ory Argus: the core API for building authentication, authorization, and audit into AI agent harness plugins, extensions, and custom integrations",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://ory.com",