@stacksjs/path 0.70.362 → 0.70.363

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/index.d.ts CHANGED
@@ -719,6 +719,22 @@ export declare function storagePath(path?: string): string;
719
719
  * @returns The absolute path to the specified file or directory within the public directory.
720
720
  */
721
721
  export declare function publicPath(path?: string): string;
722
+ /** Where `buddy upgrade` reads the managed scaffold from. */
723
+ export declare function defaultsPackagePath(projectRoot?: string): string;
724
+ /** Version of the installed `@stacksjs/defaults`, or null when absent. */
725
+ export declare function installedDefaultsVersion(projectRoot?: string): string | null;
726
+ /**
727
+ * Compare the vendored framework defaults against the installed package.
728
+ *
729
+ * `storage/framework/defaults` is the copy that executes, and `buddy upgrade`
730
+ * is the only thing that writes it. Bump `stacks` in package.json and run
731
+ * `bun install`, which is how anyone moves a dependency, and the package
732
+ * advances while the vendored tree stays put.
733
+ *
734
+ * Cheap by construction: two manifest reads and one marker read, so callers on
735
+ * a boot path can consult it freely.
736
+ */
737
+ export declare function inspectDefaultsProvenance(projectRoot?: string): DefaultsSkew;
722
738
  /**
723
739
  * Returns the path to the `push` directory within the `notifications` directory.
724
740
  *
@@ -1055,7 +1071,23 @@ export declare function socialsPath(path?: string): string;
1055
1071
  * @returns The absolute path to the specified file or directory within the home directory.
1056
1072
  */
1057
1073
  export declare function homeDir(path?: string): string;
1074
+ /**
1075
+ * Provenance stamp written next to the synced tree. `buddy upgrade` is the only
1076
+ * thing that writes `storage/framework/defaults`, so this is the only record of
1077
+ * which release the tree came from.
1078
+ */
1079
+ export declare const DEFAULTS_SYNC_MARKER: '.stacks-sync.json';
1058
1080
  export declare const path: Path;
1081
+ export declare interface DefaultsSyncMarker {
1082
+ version: string
1083
+ syncedAt: string
1084
+ }
1085
+ export declare interface DefaultsSkew {
1086
+ status: DefaultsProvenance
1087
+ installed: string | null
1088
+ vendored: string | null
1089
+ syncedAt: string | null
1090
+ }
1059
1091
  /**
1060
1092
  * The outcome of relocating one runtime directory.
1061
1093
  *
@@ -1154,6 +1186,9 @@ export declare interface Path {
1154
1186
  findProjectPath: (project: string) => Promise<string>
1155
1187
  coreStoragePath: (path?: string) => string
1156
1188
  publicPath: (path?: string) => string
1189
+ defaultsPackagePath: (projectRoot?: string) => string
1190
+ installedDefaultsVersion: (projectRoot?: string) => string | null
1191
+ inspectDefaultsProvenance: (projectRoot?: string) => DefaultsSkew
1157
1192
  pushPath: (path?: string) => string
1158
1193
  queryBuilderPath: (path?: string) => string
1159
1194
  queuePath: (path?: string) => string
@@ -1220,4 +1255,12 @@ export declare interface Path {
1220
1255
  * @returns The absolute path to the specified library entry file.
1221
1256
  */
1222
1257
  export type LibraryType = 'web-components' | 'functions';
1258
+ /**
1259
+ * - `not-applicable` — nothing to compare: no vendored tree, no installed
1260
+ * package, or a framework checkout where the tree is the source rather than a
1261
+ * copy of it.
1262
+ * - `unstamped` — the tree predates provenance stamping, so only a file
1263
+ * comparison can say whether it is current.
1264
+ */
1265
+ export type DefaultsProvenance = 'not-applicable' | 'current' | 'stale' | 'unstamped';
1223
1266
  export { basename, delimiter, dirname, extname, isAbsolute, join, normalize, relative, resolve, sep, toNamespacedPath };
package/dist/index.js CHANGED
@@ -4,8 +4,10 @@ import {
4
4
  existsSync,
5
5
  lstatSync,
6
6
  mkdirSync,
7
+ readFileSync,
7
8
  readdirSync,
8
9
  readlinkSync,
10
+ realpathSync,
9
11
  renameSync,
10
12
  rmSync,
11
13
  unlinkSync
@@ -353,6 +355,59 @@ function storagePath(path) {
353
355
  function publicPath(path) {
354
356
  return projectPath(`public/${path || ""}`);
355
357
  }
358
+ var DEFAULTS_SYNC_MARKER = ".stacks-sync.json";
359
+ function notApplicable() {
360
+ return { status: "not-applicable", installed: null, vendored: null, syncedAt: null };
361
+ }
362
+ function defaultsPackagePath(projectRoot = projectPath()) {
363
+ return join(projectRoot, "node_modules/@stacksjs/defaults");
364
+ }
365
+ function manifestVersion(packageRoot) {
366
+ try {
367
+ const version = JSON.parse(readFileSync(join(packageRoot, "package.json"), "utf8"))?.version;
368
+ return typeof version === "string" ? version : null;
369
+ } catch {
370
+ return null;
371
+ }
372
+ }
373
+ function installedDefaultsVersion(projectRoot = projectPath()) {
374
+ return manifestVersion(defaultsPackagePath(projectRoot));
375
+ }
376
+ function isInside(child, parent) {
377
+ const resolved = realpathSync(child);
378
+ return resolved === parent || resolved.startsWith(`${parent}${sep}`);
379
+ }
380
+ function inspectDefaultsProvenance(projectRoot = projectPath()) {
381
+ const targetDefaults = join(projectRoot, "storage/framework/defaults");
382
+ const packageRoot = defaultsPackagePath(projectRoot);
383
+ if (!existsSync(targetDefaults) || !existsSync(join(packageRoot, "package.json")))
384
+ return notApplicable();
385
+ if (existsSync(join(projectRoot, "storage/framework/core/buddy/package.json")))
386
+ return notApplicable();
387
+ try {
388
+ if (!isInside(packageRoot, join(realpathSync(projectRoot), "node_modules")))
389
+ return notApplicable();
390
+ } catch {
391
+ return notApplicable();
392
+ }
393
+ const installed = manifestVersion(packageRoot);
394
+ if (!installed)
395
+ return notApplicable();
396
+ let marker = null;
397
+ try {
398
+ const raw = JSON.parse(readFileSync(join(targetDefaults, DEFAULTS_SYNC_MARKER), "utf8"));
399
+ if (typeof raw?.version === "string")
400
+ marker = { version: raw.version, syncedAt: typeof raw.syncedAt === "string" ? raw.syncedAt : "" };
401
+ } catch {}
402
+ if (!marker)
403
+ return { status: "unstamped", installed, vendored: null, syncedAt: null };
404
+ return {
405
+ status: marker.version === installed ? "current" : "stale",
406
+ installed,
407
+ vendored: marker.version,
408
+ syncedAt: marker.syncedAt || null
409
+ };
410
+ }
356
411
  function pushPath(path) {
357
412
  return notificationsPath(`push/${path || ""}`);
358
413
  }
@@ -629,6 +684,9 @@ var path = {
629
684
  findProjectPath,
630
685
  coreStoragePath,
631
686
  publicPath,
687
+ defaultsPackagePath,
688
+ installedDefaultsVersion,
689
+ inspectDefaultsProvenance,
632
690
  pushPath,
633
691
  queryBuilderPath,
634
692
  queuePath,
@@ -777,6 +835,8 @@ export {
777
835
  join,
778
836
  jobsPath,
779
837
  isAbsolute,
838
+ installedDefaultsVersion,
839
+ inspectDefaultsProvenance,
780
840
  homeDir,
781
841
  healthPath,
782
842
  gitPath,
@@ -802,6 +862,7 @@ export {
802
862
  desktopPath,
803
863
  delimiter,
804
864
  defaultsResourcesPath,
865
+ defaultsPackagePath,
805
866
  defaultsAppPath,
806
867
  datetimePath,
807
868
  databasePath,
@@ -834,5 +895,6 @@ export {
834
895
  analyticsPath,
835
896
  aliasPath,
836
897
  aiPath,
837
- actionsPath
898
+ actionsPath,
899
+ DEFAULTS_SYNC_MARKER
838
900
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/path",
3
3
  "type": "module",
4
- "version": "0.70.362",
4
+ "version": "0.70.363",
5
5
  "description": "The Stacks path.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [