@vcp-dev/site-edit-engine 0.10.1 → 0.10.3

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.
@@ -1 +1 @@
1
- import c from"node:fs";import u from"node:path";var P=/^page\.(?:tsx|ts|jsx|js|mjs|cjs)$/;function $(t){let r=W(t);return r?p(r).map(e=>({routeId:g(r,e),entryFile:d(u.relative(t,e))})).sort((e,n)=>e.routeId.localeCompare(n.routeId)):[]}function W(t){for(let r of["app","src/app"]){let e=u.join(t,r);if(c.existsSync(e)&&c.statSync(e).isDirectory()&&p(e).length>0)return e}return null}function p(t){let r=[];for(let e of c.readdirSync(t,{withFileTypes:!0})){let n=u.join(t,e.name);if(e.isDirectory()){if(e.name==="node_modules"||e.name.startsWith(".")||e.name.startsWith("_"))continue;r.push(...p(n));continue}e.isFile()&&P.test(e.name)&&r.push(n)}return r}function g(t,r){let e=d(u.relative(t,u.dirname(r))),n=e?e.split("/").map(S).filter(i=>!!i):[];return n.length===0?"/":`/${n.join("/")}`}function y(t){return t.startsWith("(")&&t.endsWith(")")}function S(t){return!t||t.startsWith("@")||t.startsWith("_")||y(t)?null:A(t)}function A(t){return t.replace(/^\((?:\.|\.\.|\.\.\.)\)/,"")}function d(t){return t.replace(/\\/g,"/")}var j=/^page\.(?:tsx|ts|jsx|js|mjs|cjs)$/,l=/^\[[^\]]+\]$/,h=/^\[\.\.\.[^\]]+\]$/,f=/^\[\[\.\.\.[^\]]+\]\]$/,m=new WeakMap;function k(t){let r=t.map(n=>T(n.path)),e=F(r);return e?r.filter(n=>B(e,n)).map(n=>({routeId:z(e,n),entryFile:n})).sort((n,i)=>n.routeId.localeCompare(i.routeId)):[]}function O(t,r,e=""){let n=x(t,e),i=v(r);return i.exactRouteIds.has(n)?n:i.dynamicMatchers.find(o=>o.matcher.test(n))?.routeId}function v(t){let r=t.map(o=>`${o.routeId}\0${o.entryFile}`).join("\0"),e=m.get(t);if(e?.signature===r)return e;let n=new Set(t.map(o=>o.routeId)),i=t.filter(o=>o.routeId!=="/"&&I(o.routeId)).sort((o,s)=>R(s.routeId)-R(o.routeId)||s.routeId.length-o.routeId.length||o.routeId.localeCompare(s.routeId)).map(o=>({routeId:o.routeId,matcher:D(o.routeId)})),a={signature:r,exactRouteIds:n,dynamicMatchers:i};return m.set(t,a),a}function I(t){return t.split("/").filter(Boolean).some(r=>l.test(r)||h.test(r)||f.test(r))}function Q(t){return I(x(t))}function x(t,r=""){let n=((t??"/").trim()||"/").split(/[?#]/,1)[0]||"/",i=n.startsWith("/")?n:`/${n}`,a=N(r),o=a&&(i===a||i.startsWith(`${a}/`))?i.slice(a.length)||"/":i,s=o.startsWith("/")?o:`/${o}`;return s==="/"?"/":s.replace(/\/+$/,"")}function F(t){return t.some(n=>n.startsWith("app/")&&!w(n))?"app":t.some(n=>n.startsWith("src/app/"))?"src/app":null}function w(t){return t.startsWith("app/_vcp/")||t.startsWith("src/app/_vcp/")}function B(t,r){if(!r.startsWith(`${t}/`))return!1;let e=r.slice(r.lastIndexOf("/")+1);return j.test(e)?r.slice(t.length+1,-e.length-1).split("/").filter(Boolean).every(n=>!n.startsWith("_")):!1}function z(t,r){let e=r.slice(t.length+1).split("/").slice(0,-1).map(_).filter(n=>!!n);return e.length===0?"/":`/${e.join("/")}`}function b(t){return t.startsWith("(")&&t.endsWith(")")}function _(t){return!t||t.startsWith("@")||t.startsWith("_")||b(t)?null:C(t)}function C(t){return t.replace(/^\((?:\.|\.\.|\.\.\.)\)/,"")}function D(t){if(t==="/")return/^\/$/;let r=t.split("/").filter(Boolean).map(e=>f.test(e)?"(?:/.*)?":h.test(e)?"/.+":l.test(e)?"/[^/]+":`/${M(e)}`).join("");return new RegExp(`^${r}$`)}function R(t){return t.split("/").filter(Boolean).reduce((r,e)=>f.test(e)?r+1:h.test(e)?r+2:l.test(e)?r+3:r+4,0)}function N(t){let r=t.trim();return!r||r==="/"?"":(r.startsWith("/")?r:`/${r}`).replace(/\/+$/,"")}function M(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function T(t){return t.replace(/\\/g,"/").replace(/^\.\//,"")}export{Q as isNextAppRouterDynamicRoute,x as normalizeNextRoutePath,O as resolveNextAppRouteId,$ as scanNextAppRouterRoutes,k as scanNextAppRouterRoutesFromFiles};
1
+ import c from"node:fs";import u from"node:path";var P=/^page\.(?:tsx|ts|jsx|js|mjs|cjs)$/;function $(t){let r=W(t);return r?l(r).map(e=>({routeId:g(r,e),entryFile:d(u.relative(t,e))})).sort((e,n)=>e.routeId.localeCompare(n.routeId)):[]}function W(t){for(let r of["app","src/app"]){let e=u.join(t,r);if(c.existsSync(e)&&c.statSync(e).isDirectory()&&l(e).length>0)return e}return null}function l(t){let r=[];for(let e of c.readdirSync(t,{withFileTypes:!0})){let n=u.join(t,e.name);if(e.isDirectory()){if(e.name==="node_modules"||e.name.startsWith(".")||e.name.startsWith("_"))continue;r.push(...l(n));continue}e.isFile()&&P.test(e.name)&&r.push(n)}return r}function g(t,r){let e=d(u.relative(t,u.dirname(r))),n=e?e.split("/").map(S).filter(i=>!!i):[];return n.length===0?"/":`/${n.join("/")}`}function y(t){return t.startsWith("(")&&t.endsWith(")")}function S(t){return!t||t.startsWith("@")||t.startsWith("_")||y(t)?null:A(t)}function A(t){return t.replace(/^\((?:\.|\.\.|\.\.\.)\)/,"")}function d(t){return t.replace(/\\/g,"/")}var j=/^page\.(?:tsx|ts|jsx|js|mjs|cjs)$/,p=/^\[[^\]]+\]$/,h=/^\[\.\.\.[^\]]+\]$/,f=/^\[\[\.\.\.[^\]]+\]\]$/,m=new WeakMap;function k(t){let r=t.map(n=>T(n.path)),e=F(r);return e?r.filter(n=>B(e,n)).map(n=>({routeId:z(e,n),entryFile:n})).sort((n,i)=>n.routeId.localeCompare(i.routeId)):[]}function O(t,r,e=""){let n=x(t,e),i=v(r);return i.exactRouteIds.has(n)?n:i.dynamicMatchers.find(o=>o.matcher.test(n))?.routeId}function v(t){let r=t.map(o=>`${o.routeId}\0${o.entryFile}`).join("\0"),e=m.get(t);if(e?.signature===r)return e;let n=new Set(t.map(o=>o.routeId)),i=t.filter(o=>o.routeId!=="/"&&I(o.routeId)).sort((o,s)=>R(s.routeId)-R(o.routeId)||s.routeId.length-o.routeId.length||o.routeId.localeCompare(s.routeId)).map(o=>({routeId:o.routeId,matcher:N(o.routeId)})),a={signature:r,exactRouteIds:n,dynamicMatchers:i};return m.set(t,a),a}function I(t){return t.split("/").filter(Boolean).some(r=>p.test(r)||h.test(r)||f.test(r))}function Q(t){return I(x(t))}function x(t,r=""){let n=((t??"/").trim()||"/").split(/[?#]/,1)[0]||"/",i=n.startsWith("/")?n:`/${n}`,a=_(r),o=a&&(i===a||i.startsWith(`${a}/`))?i.slice(a.length)||"/":i,s=o.startsWith("/")?o:`/${o}`;return s==="/"?"/":s.replace(/\/+$/,"")}function F(t){return t.some(n=>n.startsWith("app/")&&!w(n))?"app":t.some(n=>n.startsWith("src/app/"))?"src/app":null}function w(t){return/^(?:src\/)?app\/(?:_vcp|\.vcp)/.test(t)}function B(t,r){if(!r.startsWith(`${t}/`))return!1;let e=r.slice(r.lastIndexOf("/")+1);return j.test(e)?r.slice(t.length+1,-e.length-1).split("/").filter(Boolean).every(n=>!n.startsWith("_")&&!n.startsWith(".")):!1}function z(t,r){let e=r.slice(t.length+1).split("/").slice(0,-1).map(C).filter(n=>!!n);return e.length===0?"/":`/${e.join("/")}`}function b(t){return t.startsWith("(")&&t.endsWith(")")}function C(t){return!t||t.startsWith("@")||t.startsWith("_")||b(t)?null:D(t)}function D(t){return t.replace(/^\((?:\.|\.\.|\.\.\.)\)/,"")}function N(t){if(t==="/")return/^\/$/;let r=t.split("/").filter(Boolean).map(e=>f.test(e)?"(?:/.*)?":h.test(e)?"/.+":p.test(e)?"/[^/]+":`/${M(e)}`).join("");return new RegExp(`^${r}$`)}function R(t){return t.split("/").filter(Boolean).reduce((r,e)=>f.test(e)?r+1:h.test(e)?r+2:p.test(e)?r+3:r+4,0)}function _(t){let r=t.trim();return!r||r==="/"?"":(r.startsWith("/")?r:`/${r}`).replace(/\/+$/,"")}function M(t){return t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function T(t){return t.replace(/\\/g,"/").replace(/^\.\//,"")}export{Q as isNextAppRouterDynamicRoute,x as normalizeNextRoutePath,O as resolveNextAppRouteId,$ as scanNextAppRouterRoutes,k as scanNextAppRouterRoutesFromFiles};
@@ -1,14 +1,12 @@
1
- import { type SiteEditCompositionContext, type SiteEditCompositionSelector, type ManagedPageTemplateRouteManifestV1 } from "@vcp-dev/contracts";
1
+ import { type SiteEditCompositionContext, type SiteEditCompositionSelector } from "@vcp-dev/contracts";
2
2
  import type { SiteEditSnapshotFile } from "./types.js";
3
- export declare function isManagedPageTemplateManifestPath(path: string): boolean;
4
- /** A synchronous source view used by the pure managed-source helpers. */
3
+ export type PageTemplateAppRoot = "app" | "src/app";
5
4
  export type SiteEditFileSystem = ReadonlyMap<string, string>;
6
5
  export type SiteEditManagedSourceFiles = SiteEditFileSystem | readonly SiteEditSnapshotFile[];
7
6
  export interface ManagedPageTemplatePaths {
7
+ appRoot: PageTemplateAppRoot;
8
8
  routeRoot: string;
9
- manifestFile: string;
10
- runtimeFile: string;
11
- registryFile: string;
9
+ templateKey: string;
12
10
  templateEntryFile: string;
13
11
  }
14
12
  export type SiteEditEngineComposition = {
@@ -17,17 +15,15 @@ export type SiteEditEngineComposition = {
17
15
  };
18
16
  export type PageTemplateCompositionSelector = SiteEditCompositionSelector;
19
17
  export type ManagedPageTemplateCompositionResolution = SiteEditEngineComposition & {
20
- mode: "direct" | "delegated";
21
- /** The server-only source file selected for this resolution. */
18
+ mode: "direct" | "candidate";
22
19
  effectiveEntryFile: string;
23
20
  };
24
- export type PageTemplateManagedSourceErrorCode = "PAGE_TEMPLATE_MANAGED_SOURCE_INVALID" | "PAGE_TEMPLATE_ID_COLLISION" | "PAGE_TEMPLATE_ROUTE_AMBIGUOUS";
21
+ export type PageTemplateManagedSourceErrorCode = "PAGE_TEMPLATE_MANAGED_SOURCE_INVALID" | "PAGE_TEMPLATE_ROUTE_AMBIGUOUS";
25
22
  export interface PageTemplateManagedSourceErrorDetails {
26
23
  reason: string;
27
24
  routeId?: string;
28
25
  path?: string;
29
26
  templateId?: string;
30
- safeName?: string;
31
27
  candidates?: readonly string[];
32
28
  issues?: readonly string[];
33
29
  }
@@ -36,25 +32,25 @@ export declare class PageTemplateManagedSourceError extends Error {
36
32
  readonly details: PageTemplateManagedSourceErrorDetails;
37
33
  constructor(code: PageTemplateManagedSourceErrorCode, message: string, details: PageTemplateManagedSourceErrorDetails);
38
34
  }
39
- export declare function computePageTemplateRouteKey(routeId: string): string;
40
- export declare function computePageTemplateSafeName(rawTemplateId: string): string;
41
- export declare function computeManagedPageTemplatePaths(routeId: string, rawTemplateId: string): ManagedPageTemplatePaths;
42
- export declare function assertNoPageTemplateSafeNameCollision(input: readonly string[] | readonly {
43
- template_id: string;
44
- }[] | {
45
- rawTemplateIds: readonly string[];
46
- } | {
47
- templateIds: readonly string[];
48
- }): void;
49
- export declare function parseManagedPageTemplateManifest(input: {
35
+ export declare function encodePageTemplateId(templateId: string): string;
36
+ export declare function decodePageTemplateKey(key: string): string;
37
+ export declare function computeManagedPageTemplatePaths(routeId: string, rawTemplateId: string, appRoot?: PageTemplateAppRoot): ManagedPageTemplatePaths;
38
+ export declare function isManagedPageTemplateSourcePath(path: string): boolean;
39
+ export interface ManagedPageTemplateCandidate {
50
40
  routeId: string;
41
+ templateId: string;
42
+ entryFile: string;
43
+ canonicalEntryFile: string;
44
+ appRoot: PageTemplateAppRoot;
45
+ }
46
+ export declare function scanManagedPageTemplateCandidates(input: {
47
+ files: SiteEditManagedSourceFiles;
48
+ }): ManagedPageTemplateCandidate[];
49
+ export declare function scanSiteEditCompositionsFromFiles(input: {
51
50
  files: SiteEditManagedSourceFiles;
52
- }): ManagedPageTemplateRouteManifestV1 | null;
51
+ }): SiteEditEngineComposition[];
53
52
  export declare function resolveManagedPageTemplateComposition(input: {
54
53
  selector: PageTemplateCompositionSelector;
55
54
  files: SiteEditManagedSourceFiles;
56
55
  canonicalEntryFile: string;
57
56
  }): ManagedPageTemplateCompositionResolution;
58
- export declare function scanSiteEditCompositionsFromFiles(input: {
59
- files: SiteEditManagedSourceFiles;
60
- }): SiteEditEngineComposition[];
@@ -364,7 +364,7 @@ export declare class PreviewFileSystemSiteEditEngineRuntime implements PreviewSi
364
364
  refreshSourceForKey(key: string, composition: SiteEditCompositionSelector): Promise<void>;
365
365
  executeOperation(request: Parameters<PreviewSiteEditEngineRuntime["executeOperation"]>[0], mutationContext?: SiteEditMutationContext): Promise<SiteEditCommandSuccess<{
366
366
  requestId: string;
367
- kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
367
+ kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "replace-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
368
368
  composition: {
369
369
  routeId: string;
370
370
  effectiveTemplateId?: string | undefined;
@@ -419,7 +419,7 @@ export declare class PreviewFileSystemSiteEditEngineRuntime implements PreviewSi
419
419
  } | undefined;
420
420
  }> | import("@vcp-dev/contracts").SiteEditCommandFailure<"VERSION_STALE" | "RECOVERY_REQUIRED" | "NODE_NOT_FOUND" | "HOME_PAGE_LOCKED" | "ROUTE_NOT_FOUND" | "CAPABILITY_REJECTED" | "CONSTRAINT_VIOLATED" | "INVALID_PARAMS" | "PLAN_FAILED" | "TRANSACTION_PREFLIGHT_FAILED" | "ROUTE_REBUILD_FAILED" | "HISTORY_COMMIT_FAILED" | "MATERIALIZATION_CONFLICT" | "MATERIALIZATION_REJECTED" | "MUTATION_ASSERTION_REQUIRED" | "MUTATION_ASSERTION_INVALID" | "AST_PARSE_ERROR" | "UNSUPPORTED_OPERATION" | "LOCATOR_FAILED" | "INVALID_TARGET" | "WRITE_IO_ERROR" | "CONCURRENT_MODIFIED" | "ROLLBACK_FAILED" | "RECOVERY_PERSIST_FAILED" | "MUTATION_SESSION_REQUIRED" | "LEASE_ASSERTION_INVALID" | "LEASE_ASSERTION_EXPIRED" | "LEASE_ASSERTION_SCOPE_MISMATCH" | "CROSS_PAGE_MOVE_UNSUPPORTED" | "INTERNAL_ERROR", unknown, never, Partial<{
421
421
  requestId: string;
422
- kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
422
+ kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "replace-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
423
423
  composition: {
424
424
  routeId: string;
425
425
  effectiveTemplateId?: string | undefined;
@@ -485,7 +485,7 @@ export declare class PreviewFileSystemSiteEditEngineRuntime implements PreviewSi
485
485
  data: {
486
486
  affectedFiles?: string[] | undefined;
487
487
  requestId: string;
488
- kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
488
+ kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "replace-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
489
489
  composition: {
490
490
  routeId: string;
491
491
  effectiveTemplateId?: string | undefined;
@@ -530,7 +530,7 @@ export declare class PreviewFileSystemSiteEditEngineRuntime implements PreviewSi
530
530
  };
531
531
  data: {
532
532
  requestId: string;
533
- kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
533
+ kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "replace-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
534
534
  composition: {
535
535
  routeId: string;
536
536
  effectiveTemplateId?: string | undefined;
@@ -570,7 +570,7 @@ export declare class PreviewFileSystemSiteEditEngineRuntime implements PreviewSi
570
570
  };
571
571
  data: {
572
572
  requestId: string;
573
- kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
573
+ kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "replace-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
574
574
  composition: {
575
575
  routeId: string;
576
576
  effectiveTemplateId?: string | undefined;
@@ -638,7 +638,7 @@ export declare class PreviewFileSystemSiteEditEngineRuntime implements PreviewSi
638
638
  };
639
639
  data: {
640
640
  requestId: string;
641
- kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
641
+ kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "replace-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
642
642
  composition: {
643
643
  routeId: string;
644
644
  effectiveTemplateId?: string | undefined;
@@ -678,7 +678,7 @@ export declare class PreviewFileSystemSiteEditEngineRuntime implements PreviewSi
678
678
  };
679
679
  data: {
680
680
  requestId: string;
681
- kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
681
+ kind: "set-props" | "insert-child" | "update-text" | "update-array-item" | "remove-node" | "replace-node" | "move-node" | "set-class-name-source" | "apply-style-draft" | "source-edit" | "insert-page-resource" | "delete-page-source";
682
682
  composition: {
683
683
  routeId: string;
684
684
  effectiveTemplateId?: string | undefined;
@@ -1 +1 @@
1
- import u from"node:fs";import h from"node:path";var y=["app","src/app","components/site","src/components/site","lib/generated","src/lib/generated","public"],F=/\.(?:tsx|ts|jsx|js|mjs|cjs|css|scss|sass|mdx|json)$/,D=new Set([".git",".next",".turbo","build","coverage","dist","node_modules","output"]),_=512,M=5e3,w=8,T=1e3,b=50,v=500,x=class{constructor(t){this.options=t,this.watchers=[],this.registeredWatcherDirs=new Set,this.fileMtimes=new Map,this.queuedChangedFiles=new Set,this.hasReportedTruncatedBatch=!1,this.pollingTimer=null,this.changeFlushTimer=null,this.isPolling=!1,this.isStarted=!1,this.hasScanned=!1}start(){if(this.isStarted)return()=>this.stop();this.isStarted=!0;let t=!1,e=Date.now(),s=this.getBudget();for(let i of this.getWatchDirs()){if(g(e,s.maxStartupMs)){this.emitDiagnostic({code:"startup-budget-exceeded",message:"Source watcher startup budget was exceeded before all roots were registered.",details:{maxStartupMs:s.maxStartupMs}});break}let a=h.join(this.options.projectRoot,i);if(!u.existsSync(a))continue;if(this.registerWatcher(a,!0)){t=!0;continue}let o=P(this.options.projectRoot,a,{maxDirs:s.maxDirs,maxDepth:s.maxDepth,maxStartupMs:s.maxStartupMs,startedAt:e});o.truncated&&this.emitDiagnostic(o.truncated);for(let r of o.directories)t=this.registerWatcher(r,!1)||t}return this.scanFiles(),t||this.startPolling(),()=>this.stop()}stop(){if(this.isStarted){this.pollingTimer&&(clearInterval(this.pollingTimer),this.pollingTimer=null),this.changeFlushTimer&&(clearTimeout(this.changeFlushTimer),this.changeFlushTimer=null),this.queuedChangedFiles.clear(),this.hasReportedTruncatedBatch=!1;for(let t of this.watchers)t.close();this.watchers.length=0,this.registeredWatcherDirs.clear(),this.isStarted=!1}}getWatchDirs(){return C(this.options.projectRoot,this.options.watch_dirs?.length?this.options.watch_dirs:y)}getBudget(){return{maxDirs:Math.max(1,this.options.max_dirs??_),maxFiles:Math.max(1,this.options.max_files??M),maxDepth:Math.max(1,this.options.max_depth??w),maxStartupMs:Math.max(1,this.options.max_startup_ms??T),debounceMs:Math.max(0,this.options.debounce_ms??b),maxChangedFilesPerBatch:Math.max(1,this.options.max_changed_files_per_batch??v)}}registerWatcher(t,e){let s=f(this.options.projectRoot,t);if(this.registeredWatcherDirs.has(s))return!0;if(this.registeredWatcherDirs.size>=this.getBudget().maxDirs)return this.emitDiagnostic({code:"watcher-budget-exceeded",message:"Source watcher native watcher budget was exceeded.",details:{maxDirs:this.getBudget().maxDirs}}),!1;try{let i=u.watch(t,{recursive:e},(o,r)=>{let c=r?h.join(t,r.toString()):null;if(c&&u.existsSync(c))try{let d=u.lstatSync(c);if(d.isSymbolicLink())return;if(d.isDirectory()){let p=f(this.options.projectRoot,c);m(p)||(this.registerWatcher(c,!1),this.poll());return}if(!d.isFile())return}catch{}let l=A(this.options.projectRoot,t,r);if(l){this.queueChangedFile(l);return}this.poll()}),a=!1;return i.on("error",()=>{if(!this.isStarted||a)return;a=!0,i.close();let o=this.watchers.indexOf(i);o>=0&&this.watchers.splice(o,1),this.registeredWatcherDirs.delete(s),this.poll(),this.startPolling()}),i?.unref?.(),this.watchers.push(i),this.registeredWatcherDirs.add(s),!0}catch{return!1}}poll(){if(!this.isPolling){this.isPolling=!0;try{this.scanFiles()}finally{this.isPolling=!1}}}startPolling(){if(this.pollingTimer||!this.isStarted)return;let t=this.options.interval_ms??1e3;this.pollingTimer=setInterval(()=>this.poll(),t),this.pollingTimer?.unref?.()}scanFiles(){let t=new Set,e=!0,s=this.getBudget(),i=Date.now();for(let a of this.getWatchDirs()){let o=h.join(this.options.projectRoot,a);if(!u.existsSync(o))continue;let r=R(this.options.projectRoot,o,{maxFiles:s.maxFiles,maxDepth:s.maxDepth,maxStartupMs:s.maxStartupMs,startedAt:i});r.truncated&&this.emitDiagnostic(r.truncated),(!r.complete||r.truncated)&&(e=!1);for(let c of r.files)try{let l=u.statSync(c),d=f(this.options.projectRoot,c);t.add(d);let p=this.fileMtimes.get(d);if(this.hasScanned&&(p===void 0||p!==l.mtimeMs)){this.queueChangedFile(d);continue}this.fileMtimes.set(d,l.mtimeMs)}catch{e=!1}}if(this.hasScanned&&e)for(let a of this.fileMtimes.keys())t.has(a)||this.queueChangedFile(a);e&&(this.hasScanned=!0)}queueChangedFile(t){let e=this.getBudget();if(this.queuedChangedFiles.size>=e.maxChangedFilesPerBatch){!this.queuedChangedFiles.has(t)&&!this.hasReportedTruncatedBatch&&(this.hasReportedTruncatedBatch=!0,this.emitDiagnostic({code:"change-batch-truncated",message:"Source watcher change batch exceeded the configured file budget.",details:{maxChangedFiles:e.maxChangedFilesPerBatch}}));return}if(this.queuedChangedFiles.add(t),this.changeFlushTimer)return;let s=()=>this.flushQueuedChanges();if(e.debounceMs===0){s();return}this.changeFlushTimer=setTimeout(s,e.debounceMs),this.changeFlushTimer?.unref?.()}flushQueuedChanges(){if(this.changeFlushTimer&&(clearTimeout(this.changeFlushTimer),this.changeFlushTimer=null),this.queuedChangedFiles.size===0)return;let t=[...this.queuedChangedFiles].filter(e=>this.shouldReportQueuedFile(e)).sort();if(this.queuedChangedFiles.clear(),this.hasReportedTruncatedBatch=!1,t.length!==0){if(this.options.on_batch_change){this.options.on_batch_change(t);return}for(let e of t)this.options.on_change(e)}}shouldReportQueuedFile(t){let e=h.join(this.options.projectRoot,...t.split("/"));try{let s=u.lstatSync(e);if(!s.isFile()||s.isSymbolicLink())return!1;let i=this.fileMtimes.get(t);return this.fileMtimes.set(t,s.mtimeMs),i===void 0?this.hasScanned:i!==s.mtimeMs}catch(s){return W(s)?this.fileMtimes.delete(t):!1}}emitDiagnostic(t){this.options.on_diagnostic?.(t)}};function C(n,t){let e=h.resolve(n),s=new Set;for(let o of t){let r=j(e,o);!r||m(r)||s.add(r)}let i=[...s].sort((o,r)=>o.split("/").length-r.split("/").length||o.length-r.length||o.localeCompare(r)),a=[];for(let o of i)a.some(r=>o===r||o.startsWith(`${r}/`))||a.push(o);return a}function j(n,t){let e=t.trim();if(!e)return"";let s=h.isAbsolute(e)?h.resolve(e):h.resolve(n,e),i=h.relative(n,s);return!i||i.startsWith("..")?"":i.replace(/\\/g,"/").replace(/^\.\//,"")}function P(n,t,e){let s=[],i=[{directory:t,depth:0}];for(;i.length>0;){let a=i.shift();if(s.length>=e.maxDirs)return{directories:s,truncated:{code:"directory-budget-exceeded",message:"Source watcher fallback directory scan was truncated by max_dirs.",details:{maxDirs:e.maxDirs}}};if(g(e.startedAt,e.maxStartupMs))return{directories:s,truncated:{code:"startup-budget-exceeded",message:"Source watcher fallback directory scan exceeded max_startup_ms.",details:{maxStartupMs:e.maxStartupMs}}};if(s.push(a.directory),a.depth>=e.maxDepth)continue;let o;try{o=u.readdirSync(a.directory,{withFileTypes:!0})}catch{continue}for(let r of o){if(!r.isDirectory()||S(r.name))continue;let c=h.join(a.directory,r.name),l=f(n,c);m(l)||i.push({directory:c,depth:a.depth+1})}}return{directories:s}}function R(n,t,e){let s=[],i=[{directory:t,depth:0}];for(;i.length>0;){let a=i.shift();if(g(e.startedAt,e.maxStartupMs))return{files:s,complete:!1,truncated:{code:"startup-budget-exceeded",message:"Source watcher file scan exceeded max_startup_ms.",details:{maxStartupMs:e.maxStartupMs}}};let o;try{o=u.readdirSync(a.directory,{withFileTypes:!0})}catch{return{files:s,complete:!1}}for(let r of o){let c=h.join(a.directory,r.name);if(r.isDirectory()){!S(r.name)&&a.depth<e.maxDepth&&!m(f(n,c))&&i.push({directory:c,depth:a.depth+1});continue}let l=f(n,c);if(!m(l)&&F.test(l)){if(s.length>=e.maxFiles)return{files:s,complete:!1,truncated:{code:"file-budget-exceeded",message:"Source watcher file scan was truncated by max_files.",details:{maxFiles:e.maxFiles}}};s.push(c)}}}return{files:s,complete:!0}}function W(n){return n instanceof Error&&"code"in n&&(n.code==="ENOENT"||n.code==="ENOTDIR")}function A(n,t,e){if(!e)return null;let s=h.join(t,e.toString()),i=f(n,s);return!i||i.startsWith("..")||m(i)||!F.test(i)?null:i}function S(n){return n.startsWith(".")||D.has(n)}function m(n){return n.split("/").some(t=>D.has(t))}function g(n,t){return Date.now()-n>t}function f(n,t){return h.relative(n,t).replace(/\\/g,"/")}export{x as SiteEditSourceWatcher};
1
+ import u from"node:fs";import h from"node:path";var D=["app","src/app","components/site","src/components/site","lib/generated","src/lib/generated","public"],F=/\.(?:tsx|ts|jsx|js|mjs|cjs|css|scss|sass|mdx|json)$/,S=new Set([".git",".next",".turbo","build","coverage","dist","node_modules","output"]),y=512,_=5e3,M=8,w=1e3,T=50,b=500,x=class{constructor(t){this.options=t,this.watchers=[],this.registeredWatcherDirs=new Set,this.fileMtimes=new Map,this.queuedChangedFiles=new Set,this.hasReportedTruncatedBatch=!1,this.pollingTimer=null,this.changeFlushTimer=null,this.isPolling=!1,this.isStarted=!1,this.hasScanned=!1}start(){if(this.isStarted)return()=>this.stop();this.isStarted=!0;let t=!1,e=Date.now(),s=this.getBudget();for(let i of this.getWatchDirs()){if(g(e,s.maxStartupMs)){this.emitDiagnostic({code:"startup-budget-exceeded",message:"Source watcher startup budget was exceeded before all roots were registered.",details:{maxStartupMs:s.maxStartupMs}});break}let a=h.join(this.options.projectRoot,i);if(!u.existsSync(a))continue;if(this.registerWatcher(a,!0)){t=!0;continue}let n=j(this.options.projectRoot,a,{maxDirs:s.maxDirs,maxDepth:s.maxDepth,maxStartupMs:s.maxStartupMs,startedAt:e});n.truncated&&this.emitDiagnostic(n.truncated);for(let r of n.directories)t=this.registerWatcher(r,!1)||t}return this.scanFiles(),t||this.startPolling(),()=>this.stop()}stop(){if(this.isStarted){this.pollingTimer&&(clearInterval(this.pollingTimer),this.pollingTimer=null),this.changeFlushTimer&&(clearTimeout(this.changeFlushTimer),this.changeFlushTimer=null),this.queuedChangedFiles.clear(),this.hasReportedTruncatedBatch=!1;for(let t of this.watchers)t.close();this.watchers.length=0,this.registeredWatcherDirs.clear(),this.isStarted=!1}}getWatchDirs(){return v(this.options.projectRoot,this.options.watch_dirs?.length?this.options.watch_dirs:D)}getBudget(){return{maxDirs:Math.max(1,this.options.max_dirs??y),maxFiles:Math.max(1,this.options.max_files??_),maxDepth:Math.max(1,this.options.max_depth??M),maxStartupMs:Math.max(1,this.options.max_startup_ms??w),debounceMs:Math.max(0,this.options.debounce_ms??T),maxChangedFilesPerBatch:Math.max(1,this.options.max_changed_files_per_batch??b)}}registerWatcher(t,e){let s=f(this.options.projectRoot,t);if(this.registeredWatcherDirs.has(s))return!0;if(this.registeredWatcherDirs.size>=this.getBudget().maxDirs)return this.emitDiagnostic({code:"watcher-budget-exceeded",message:"Source watcher native watcher budget was exceeded.",details:{maxDirs:this.getBudget().maxDirs}}),!1;try{let i=u.watch(t,{recursive:e},(n,r)=>{let c=r?h.join(t,r.toString()):null;if(c&&u.existsSync(c))try{let d=u.lstatSync(c);if(d.isSymbolicLink())return;if(d.isDirectory()){let m=f(this.options.projectRoot,c);p(m)||(this.registerWatcher(c,!1),this.poll());return}if(!d.isFile())return}catch{}let l=W(this.options.projectRoot,t,r);if(l){this.queueChangedFile(l);return}this.poll()}),a=!1;return i.on("error",()=>{if(!this.isStarted||a)return;a=!0,i.close();let n=this.watchers.indexOf(i);n>=0&&this.watchers.splice(n,1),this.registeredWatcherDirs.delete(s),this.poll(),this.startPolling()}),i?.unref?.(),this.watchers.push(i),this.registeredWatcherDirs.add(s),!0}catch{return!1}}poll(){if(!this.isPolling){this.isPolling=!0;try{this.scanFiles()}finally{this.isPolling=!1}}}startPolling(){if(this.pollingTimer||!this.isStarted)return;let t=this.options.interval_ms??1e3;this.pollingTimer=setInterval(()=>this.poll(),t),this.pollingTimer?.unref?.()}scanFiles(){let t=new Set,e=!0,s=this.getBudget(),i=Date.now();for(let a of this.getWatchDirs()){let n=h.join(this.options.projectRoot,a);if(!u.existsSync(n))continue;let r=P(this.options.projectRoot,n,{maxFiles:s.maxFiles,maxDepth:s.maxDepth,maxStartupMs:s.maxStartupMs,startedAt:i});r.truncated&&this.emitDiagnostic(r.truncated),(!r.complete||r.truncated)&&(e=!1);for(let c of r.files)try{let l=u.statSync(c),d=f(this.options.projectRoot,c);t.add(d);let m=this.fileMtimes.get(d);if(this.hasScanned&&(m===void 0||m!==l.mtimeMs)){this.queueChangedFile(d);continue}this.fileMtimes.set(d,l.mtimeMs)}catch{e=!1}}if(this.hasScanned&&e)for(let a of this.fileMtimes.keys())t.has(a)||this.queueChangedFile(a);e&&(this.hasScanned=!0)}queueChangedFile(t){let e=this.getBudget();if(this.queuedChangedFiles.size>=e.maxChangedFilesPerBatch){!this.queuedChangedFiles.has(t)&&!this.hasReportedTruncatedBatch&&(this.hasReportedTruncatedBatch=!0,this.emitDiagnostic({code:"change-batch-truncated",message:"Source watcher change batch exceeded the configured file budget.",details:{maxChangedFiles:e.maxChangedFilesPerBatch}}));return}if(this.queuedChangedFiles.add(t),this.changeFlushTimer)return;let s=()=>this.flushQueuedChanges();if(e.debounceMs===0){s();return}this.changeFlushTimer=setTimeout(s,e.debounceMs),this.changeFlushTimer?.unref?.()}flushQueuedChanges(){if(this.changeFlushTimer&&(clearTimeout(this.changeFlushTimer),this.changeFlushTimer=null),this.queuedChangedFiles.size===0)return;let t=[...this.queuedChangedFiles].filter(e=>this.shouldReportQueuedFile(e)).sort();if(this.queuedChangedFiles.clear(),this.hasReportedTruncatedBatch=!1,t.length!==0){if(this.options.on_batch_change){this.options.on_batch_change(t);return}for(let e of t)this.options.on_change(e)}}shouldReportQueuedFile(t){let e=h.join(this.options.projectRoot,...t.split("/"));try{let s=u.lstatSync(e);if(!s.isFile()||s.isSymbolicLink())return!1;let i=this.fileMtimes.get(t);return this.fileMtimes.set(t,s.mtimeMs),i===void 0?this.hasScanned:i!==s.mtimeMs}catch(s){return R(s)?this.fileMtimes.delete(t):!1}}emitDiagnostic(t){this.options.on_diagnostic?.(t)}};function v(o,t){let e=h.resolve(o),s=new Set;for(let n of t){let r=C(e,n);!r||p(r)||s.add(r)}let i=[...s].sort((n,r)=>n.split("/").length-r.split("/").length||n.length-r.length||n.localeCompare(r)),a=[];for(let n of i)a.some(r=>n===r||n.startsWith(`${r}/`))||a.push(n);return a}function C(o,t){let e=t.trim();if(!e)return"";let s=h.isAbsolute(e)?h.resolve(e):h.resolve(o,e),i=h.relative(o,s);return!i||i.startsWith("..")?"":i.replace(/\\/g,"/").replace(/^\.\//,"")}function j(o,t,e){let s=[],i=[{directory:t,depth:0}];for(;i.length>0;){let a=i.shift();if(s.length>=e.maxDirs)return{directories:s,truncated:{code:"directory-budget-exceeded",message:"Source watcher fallback directory scan was truncated by max_dirs.",details:{maxDirs:e.maxDirs}}};if(g(e.startedAt,e.maxStartupMs))return{directories:s,truncated:{code:"startup-budget-exceeded",message:"Source watcher fallback directory scan exceeded max_startup_ms.",details:{maxStartupMs:e.maxStartupMs}}};if(s.push(a.directory),a.depth>=e.maxDepth)continue;let n;try{n=u.readdirSync(a.directory,{withFileTypes:!0})}catch{continue}for(let r of n){if(!r.isDirectory())continue;let c=h.join(a.directory,r.name),l=f(o,c);p(l)||i.push({directory:c,depth:a.depth+1})}}return{directories:s}}function P(o,t,e){let s=[],i=[{directory:t,depth:0}];for(;i.length>0;){let a=i.shift();if(g(e.startedAt,e.maxStartupMs))return{files:s,complete:!1,truncated:{code:"startup-budget-exceeded",message:"Source watcher file scan exceeded max_startup_ms.",details:{maxStartupMs:e.maxStartupMs}}};let n;try{n=u.readdirSync(a.directory,{withFileTypes:!0})}catch{return{files:s,complete:!1}}for(let r of n){let c=h.join(a.directory,r.name);if(r.isDirectory()){a.depth<e.maxDepth&&!p(f(o,c))&&i.push({directory:c,depth:a.depth+1});continue}let l=f(o,c);if(!p(l)&&F.test(l)){if(s.length>=e.maxFiles)return{files:s,complete:!1,truncated:{code:"file-budget-exceeded",message:"Source watcher file scan was truncated by max_files.",details:{maxFiles:e.maxFiles}}};s.push(c)}}}return{files:s,complete:!0}}function R(o){return o instanceof Error&&"code"in o&&(o.code==="ENOENT"||o.code==="ENOTDIR")}function W(o,t,e){if(!e)return null;let s=h.join(t,e.toString()),i=f(o,s);return!i||i.startsWith("..")||p(i)||!F.test(i)?null:i}function p(o){let t=o.split("/");return t.some((e,s)=>{if(S.has(e))return!0;if(!e.startsWith("."))return!1;if(e!==".vcp")return!0;if(s===0)return!1;let i=t.slice(0,s).join("/");return!((i==="app"||i==="src/app")&&(t[s+1]===void 0||t[s+1]==="page-templates"))})}function g(o,t){return Date.now()-o>t}function f(o,t){return h.relative(o,t).replace(/\\/g,"/")}export{x as SiteEditSourceWatcher};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vcp-dev/site-edit-engine",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "type": "module",
5
5
  "license": "UNLICENSED",
6
6
  "repository": {
@@ -60,7 +60,7 @@
60
60
  "@babel/parser": "^7.29.3",
61
61
  "@babel/traverse": "^7.29.0",
62
62
  "@babel/types": "^7.29.0",
63
- "@vcp-dev/contracts": "0.10.1",
63
+ "@vcp-dev/contracts": "0.10.3",
64
64
  "yaml": "^2.9.0"
65
65
  },
66
66
  "devDependencies": {