@assembly-js/app-foundation 0.0.55 → 0.0.56

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/CHANGELOG.md CHANGED
@@ -14,6 +14,9 @@ A foundation update reads the sections between an app's version and the target:
14
14
  from every bullet except `[guidance]`, agent work from the check scripts those `[action]`
15
15
  bullets ship. Write `[fix]`, `[behavior]` and `[action]` bullets for the app's owner.
16
16
 
17
+ ## 0.0.56
18
+ - [new] The client-call scan now marks each finding as gated only when every page or route that can load its file requires a staff user. Nothing in the app changes.
19
+
17
20
  ## 0.0.55
18
21
  - [new] Add a scan the platform can run on demand to find calls that use a signed-in viewer's access to the platform API from pages and routes clients can open. Nothing in the app changes and no file is added to it.
19
22
 
@@ -39,7 +39,7 @@ import {
39
39
  wrapperName,
40
40
  } from './scan-routes.mjs';
41
41
 
42
- export const SCANNER_VERSION = 1;
42
+ export const SCANNER_VERSION = 2;
43
43
 
44
44
  export const CLASS_BREAKS = 'BREAKS';
45
45
  export const CLASS_CLEAN = 'CLEAN';
@@ -878,15 +878,20 @@ export function createAnalysis(root) {
878
878
  return { root, files, ts, read, facts: factsFor, classifyEntries: () => classifyEntries(ts, root, files, read) };
879
879
  }
880
880
 
881
- // Maps every file an entry can load to the byte-smallest entry that loads it.
881
+ // Maps every file to the byte-smallest entry that loads it (`entry`) and to every entry that
882
+ // does (`entries`): a file shared with an ungated entry stays exposed however the others are gated.
882
883
  function reachFrom(analysis, entries) {
883
884
  const reach = new Map();
884
885
  for (const entry of entries) {
886
+ const visited = new Set();
885
887
  const queue = [entry];
886
888
  while (queue.length) {
887
889
  const file = queue.pop();
888
- if (reach.has(file)) continue;
889
- reach.set(file, entry);
890
+ if (visited.has(file)) continue;
891
+ visited.add(file);
892
+ const seen = reach.get(file);
893
+ if (seen) seen.entries.add(entry);
894
+ else reach.set(file, { entry, entries: new Set([entry]) });
890
895
  queue.push(...analysis.facts(file).imports);
891
896
  }
892
897
  }
@@ -904,14 +909,16 @@ export function projectClientReachable(analysis, allowlist = CLIENT_SAFE_SDK_MET
904
909
  const reach = reachFrom(analysis, entries);
905
910
  const findings = [];
906
911
  const unresolved = [];
907
- for (const [file, entry] of reach) {
912
+ const gatedSet = new Set(gatedEntries);
913
+ for (const [file, { entry, entries: reaching }] of reach) {
914
+ const gated = [...reaching].every((e) => gatedSet.has(e));
908
915
  const { calls, defeaters } = analysis.facts(file);
909
916
  for (const c of calls) {
910
917
  if (c.provenance === PROVENANCE_VIEWER && !allowed.has(c.method)) {
911
- findings.push({ file, line: c.line, method: c.method, provenance: c.provenance, entry });
918
+ findings.push({ file, line: c.line, method: c.method, provenance: c.provenance, entry, gated });
912
919
  }
913
920
  }
914
- for (const d of defeaters) unresolved.push({ file, line: d.line, reason: d.reason, entry });
921
+ for (const d of defeaters) unresolved.push({ file, line: d.line, reason: d.reason, entry, gated });
915
922
  }
916
923
  sortFindings(findings);
917
924
  sortFindings(unresolved);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@assembly-js/app-foundation",
3
- "version": "0.0.55",
3
+ "version": "0.0.56",
4
4
  "description": "Versioned foundation helpers and build context for Assembly generated apps",
5
5
  "type": "module",
6
6
  "files": [