@launchfile/macos-dev 0.11.0 → 0.12.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.
@@ -171,6 +171,19 @@ export declare function refusedResourceUses(launch: NormalizedLaunch): Map<strin
171
171
  * removal IS the refusal.
172
172
  */
173
173
  export declare function applyResourceUseRefusals(launch: NormalizedLaunch): "ok" | "none-left";
174
+ /**
175
+ * The mandatory report for every `provides` entry that declares `at:` (D-68
176
+ * rule 5), one line per declaring entry. This provider starts each process on
177
+ * a local port with nothing in front that routes by host name, so every
178
+ * request reaches the listener with its `Host` intact and only name resolution
179
+ * is left to the operator. It launches and reports — never a silent launch,
180
+ * and never a refusal.
181
+ *
182
+ * `ports` maps a component to the local port its process listens on; an
183
+ * absent entry means the port is not known yet. Under a supplied publication
184
+ * URL (D-58) the names are whoever routes that URL's to send here (rule 7).
185
+ */
186
+ export declare function atReports(launch: NormalizedLaunch, ports?: Record<string, number>, suppliedAppUrl?: string): string[];
174
187
  export declare function launchUp(opts?: LaunchUpOpts): Promise<void>;
175
188
  export declare function launchDown(opts?: {
176
189
  destroy?: boolean;
package/dist/provider.js CHANGED
@@ -7,7 +7,7 @@
7
7
  import { accessSync, constants as fsConstants } from "node:fs";
8
8
  import { readFile } from "node:fs/promises";
9
9
  import { join, resolve as resolvePath } from "node:path";
10
- import { CERTIFICATE, certificateBindings, indexOperatorStoragePaths, MissingOperatorStoragePathError, normalizeAppUrl, readLaunch, resolveSourcePrepareCommand, resolveSourceRunCommand, selectionClosure, UnboundOperatorStorageError, unsuppliedRequiredEnv, appEndpointReferences, useKeys, } from "@launchfile/sdk";
10
+ import { AT_APP_HOST, atDeclarations, atEntryLabel, CERTIFICATE, certificateBindings, indexOperatorStoragePaths, MissingOperatorStoragePathError, normalizeAppUrl, readLaunch, resolveSourcePrepareCommand, resolveSourceRunCommand, selectionClosure, UnboundOperatorStorageError, unsuppliedRequiredEnv, appEndpointReferences, useKeys, } from "@launchfile/sdk";
11
11
  import { checkPrereqs } from "./prereqs.js";
12
12
  import { HTTPS_ORIGIN, httpsOriginSatisfied, httpsOriginShortfall, } from "./https-origin.js";
13
13
  import { loadState, initState, saveState, ensureDirs, withRecordedDbIndexes } from "./state.js";
@@ -306,6 +306,43 @@ export function applyResourceUseRefusals(launch) {
306
306
  launch.components = Object.fromEntries(Object.entries(launch.components).filter(([n]) => !refused.has(n)));
307
307
  return Object.keys(launch.components).length === 0 ? "none-left" : "ok";
308
308
  }
309
+ /**
310
+ * The mandatory report for every `provides` entry that declares `at:` (D-68
311
+ * rule 5), one line per declaring entry. This provider starts each process on
312
+ * a local port with nothing in front that routes by host name, so every
313
+ * request reaches the listener with its `Host` intact and only name resolution
314
+ * is left to the operator. It launches and reports — never a silent launch,
315
+ * and never a refusal.
316
+ *
317
+ * `ports` maps a component to the local port its process listens on; an
318
+ * absent entry means the port is not known yet. Under a supplied publication
319
+ * URL (D-58) the names are whoever routes that URL's to send here (rule 7).
320
+ */
321
+ export function atReports(launch, ports = {}, suppliedAppUrl) {
322
+ const host = suppliedAppUrl === undefined ? "localhost" : new URL(suppliedAppUrl).hostname;
323
+ return atDeclarations(launch).map((declaration) => {
324
+ const names = declaration.values
325
+ .map((value) => (value === AT_APP_HOST ? host : `${value}.${host}`))
326
+ .join(", ");
327
+ const head = `${atEntryLabel(declaration)} answers at ${names} (\`at:\`, D-68)`;
328
+ if (suppliedAppUrl !== undefined) {
329
+ return (`${head} — this provider sets up no host names, and the supplied publication URL ` +
330
+ `(${suppliedAppUrl}) says nothing about them; whatever routes that URL must send each ` +
331
+ "name to this endpoint with the requested `Host` intact");
332
+ }
333
+ const port = ports[declaration.component];
334
+ const target = port === undefined ? "the component's local port" : `localhost:${port}`;
335
+ return (`${head} — this provider starts the process on a local port and sets up no host names. ` +
336
+ `Every request that reaches ${target} reaches the listener with its \`Host\` intact, so ` +
337
+ "map each name that does not resolve to this machine (hosts file or DNS), or use a " +
338
+ "provider that routes host names");
339
+ });
340
+ }
341
+ /** Print {@link atReports} the way this provider prints every warning. */
342
+ function printAtReports(reports) {
343
+ for (const report of reports)
344
+ console.warn(` Warning: ${report}`);
345
+ }
309
346
  export async function launchUp(opts = {}) {
310
347
  const projectDir = opts.projectDir ?? process.cwd();
311
348
  // Publication context (D-58): validated and normalized before anything is
@@ -415,6 +452,11 @@ export async function launchUp(opts = {}) {
415
452
  console.error("Every selected component requires a use of a resource this provider cannot cover.");
416
453
  process.exit(1);
417
454
  }
455
+ // 2a-sexies. A `provides` entry declaring `at:` is reported, not refused
456
+ // (D-68 rule 5). The report belongs at the end of provisioning, after the
457
+ // summary; a dry run never gets there, so it prints here.
458
+ if (opts.dryRun)
459
+ printAtReports(atReports(launch, {}, suppliedAppUrl));
418
460
  // An optional capability is not refused — the component runs, degraded.
419
461
  for (const [name, c] of Object.entries(launch.components)) {
420
462
  for (const sup of c.supports ?? []) {
@@ -832,6 +874,7 @@ export async function launchUp(opts = {}) {
832
874
  state.processes = pm2.getRecordedProcesses();
833
875
  // 17. Print summary
834
876
  printSummary(launch, componentPorts, resourceMap);
877
+ printAtReports(atReports(launch, componentPorts, suppliedAppUrl));
835
878
  // Save final state (now including recorded pids)
836
879
  await saveState(projectDir, state);
837
880
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@launchfile/macos-dev",
3
- "version": "0.11.0",
3
+ "version": "0.12.0",
4
4
  "description": "macOS dev provider for Launchfile — run apps locally via brew services and native runtimes",
5
5
  "os": [
6
6
  "darwin"
@@ -36,7 +36,7 @@
36
36
  "directory": "providers/macos-dev"
37
37
  },
38
38
  "dependencies": {
39
- "@launchfile/sdk": "^0.11.0",
39
+ "@launchfile/sdk": "^0.12.0",
40
40
  "semver": "^7.7.4"
41
41
  },
42
42
  "devDependencies": {