@heroiclands/package-build 17.2.0 → 18.0.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.
Files changed (152) hide show
  1. package/CHANGELOG.md +1711 -0
  2. package/CONTENT.md +288 -72
  3. package/README.md +1 -1
  4. package/bin/content-build.mjs +218 -137
  5. package/bin/package-build.mjs +43 -0
  6. package/content-config.mjs +62 -67
  7. package/docs/content-format.md +768 -58
  8. package/engine/actor-compiler.mjs +586 -0
  9. package/engine/address-charset.mjs +11 -8
  10. package/engine/address-diff.mjs +266 -22
  11. package/engine/anchored-sections.mjs +83 -0
  12. package/engine/anchors.mjs +83 -0
  13. package/engine/base-compiler.mjs +148 -18
  14. package/engine/bundle-notes.mjs +276 -0
  15. package/engine/bundles.mjs +307 -0
  16. package/engine/code-fences.mjs +103 -0
  17. package/engine/compile-corpus.mjs +89 -0
  18. package/engine/content-address.mjs +267 -5
  19. package/engine/content-format-check.mjs +54 -11
  20. package/engine/content-format.mjs +37 -5
  21. package/engine/content-index.mjs +225 -127
  22. package/engine/content-links.mjs +185 -77
  23. package/engine/content-lint.mjs +232 -14
  24. package/engine/content-package.mjs +2 -1
  25. package/engine/content-tables.mjs +99 -3
  26. package/engine/document-subtypes.mjs +49 -6
  27. package/engine/field-reference.mjs +1 -1
  28. package/engine/field-spec.mjs +56 -6
  29. package/engine/folder-notes.mjs +470 -0
  30. package/engine/foreign-catalog.mjs +195 -4
  31. package/engine/{manifest-emit.mjs → foundry-entries.mjs} +55 -83
  32. package/engine/frontmatter-lint.mjs +245 -19
  33. package/engine/frontmatter.mjs +88 -8
  34. package/engine/generate.mjs +304 -13
  35. package/engine/helpers.mjs +293 -64
  36. package/engine/ids.mjs +137 -2
  37. package/engine/index-records.mjs +126 -0
  38. package/engine/index.mjs +23 -5
  39. package/engine/item-compiler.mjs +349 -0
  40. package/engine/item-docs.mjs +7 -1
  41. package/engine/item-registry.mjs +6 -0
  42. package/engine/journals.mjs +93 -27
  43. package/engine/macros.mjs +4 -2
  44. package/engine/metadata-index.mjs +495 -0
  45. package/engine/note-claims.mjs +146 -25
  46. package/engine/note-ids.mjs +112 -0
  47. package/engine/note-renames.mjs +134 -0
  48. package/engine/note-schemas.mjs +25 -0
  49. package/engine/note-vocabulary.mjs +110 -27
  50. package/engine/pack-config.mjs +4 -0
  51. package/engine/pack-router.mjs +23 -0
  52. package/engine/retired-fields.mjs +137 -3
  53. package/engine/scenes.mjs +66 -34
  54. package/engine/schema-check.mjs +58 -17
  55. package/engine/site-build.mjs +71 -12
  56. package/engine/site-index.mjs +20 -7
  57. package/engine/sql-tables.mjs +485 -0
  58. package/engine/subtype-registry.mjs +102 -0
  59. package/engine/system-block.mjs +96 -12
  60. package/engine/systems.mjs +201 -0
  61. package/engine/web-wikilinks.mjs +50 -20
  62. package/engine/wikilink-syntax.mjs +17 -8
  63. package/engine/wikilinks.mjs +124 -51
  64. package/engine/yaml-lint.mjs +282 -0
  65. package/hm3/actors.mjs +352 -0
  66. package/hm3/default-item-art.mjs +75 -0
  67. package/hm3/document-subtypes.mjs +134 -0
  68. package/hm3/index.mjs +56 -0
  69. package/hm3/item-builders.mjs +84 -0
  70. package/hm3/item-fields.mjs +180 -0
  71. package/hm3/items.mjs +96 -0
  72. package/hm3/template-priority.mjs +85 -0
  73. package/manifest.mjs +43 -2
  74. package/package.json +18 -4
  75. package/release.mjs +62 -7
  76. package/sohl/actors.mjs +33 -487
  77. package/sohl/being-info.mjs +16 -7
  78. package/sohl/default-item-art.mjs +14 -3
  79. package/sohl/document-subtypes.mjs +16 -10
  80. package/sohl/item-builders.mjs +14 -5
  81. package/sohl/item-fields.mjs +68 -7
  82. package/sohl/items.mjs +44 -258
  83. package/sohl/note-schemas.mjs +2 -2
  84. package/types/content-config.d.mts +21 -42
  85. package/types/engine/actor-compiler.d.mts +204 -0
  86. package/types/engine/address-charset.d.mts +11 -8
  87. package/types/engine/address-diff.d.mts +53 -5
  88. package/types/engine/anchored-sections.d.mts +21 -0
  89. package/types/engine/anchors.d.mts +20 -0
  90. package/types/engine/base-compiler.d.mts +17 -17
  91. package/types/engine/bundle-notes.d.mts +173 -0
  92. package/types/engine/bundles.d.mts +60 -0
  93. package/types/engine/code-fences.d.mts +43 -0
  94. package/types/engine/compile-corpus.d.mts +32 -0
  95. package/types/engine/content-address.d.mts +205 -5
  96. package/types/engine/content-format-check.d.mts +6 -2
  97. package/types/engine/content-format.d.mts +57 -1
  98. package/types/engine/content-index.d.mts +54 -49
  99. package/types/engine/content-links.d.mts +52 -7
  100. package/types/engine/content-lint.d.mts +10 -1
  101. package/types/engine/content-package.d.mts +2 -1
  102. package/types/engine/content-tables.d.mts +21 -39
  103. package/types/engine/document-subtypes.d.mts +37 -3
  104. package/types/engine/field-spec.d.mts +76 -5
  105. package/types/engine/folder-notes.d.mts +159 -0
  106. package/types/engine/foreign-catalog.d.mts +53 -0
  107. package/types/engine/{manifest-emit.d.mts → foundry-entries.d.mts} +2 -43
  108. package/types/engine/frontmatter-lint.d.mts +10 -2
  109. package/types/engine/frontmatter.d.mts +64 -0
  110. package/types/engine/generate.d.mts +38 -0
  111. package/types/engine/helpers.d.mts +94 -30
  112. package/types/engine/ids.d.mts +96 -0
  113. package/types/engine/index-records.d.mts +68 -0
  114. package/types/engine/index.d.mts +9 -3
  115. package/types/engine/item-compiler.d.mts +131 -0
  116. package/types/engine/journals.d.mts +47 -9
  117. package/types/engine/metadata-index.d.mts +226 -0
  118. package/types/engine/note-claims.d.mts +57 -11
  119. package/types/engine/note-ids.d.mts +38 -0
  120. package/types/engine/note-renames.d.mts +102 -0
  121. package/types/engine/note-vocabulary.d.mts +44 -8
  122. package/types/engine/retired-fields.d.mts +75 -0
  123. package/types/engine/scenes.d.mts +3 -2
  124. package/types/engine/schema-check.d.mts +25 -4
  125. package/types/engine/site-build.d.mts +4 -4
  126. package/types/engine/site-index.d.mts +1 -1
  127. package/types/engine/sql-tables.d.mts +185 -0
  128. package/types/engine/subtype-registry.d.mts +49 -0
  129. package/types/engine/system-block.d.mts +40 -1
  130. package/types/engine/systems.d.mts +106 -0
  131. package/types/engine/web-wikilinks.d.mts +4 -2
  132. package/types/engine/wikilink-syntax.d.mts +10 -3
  133. package/types/engine/wikilinks.d.mts +41 -13
  134. package/types/engine/yaml-lint.d.mts +107 -0
  135. package/types/hm3/actors.d.mts +48 -0
  136. package/types/hm3/default-item-art.d.mts +42 -0
  137. package/types/hm3/document-subtypes.d.mts +24 -0
  138. package/types/hm3/index.d.mts +7 -0
  139. package/types/hm3/item-builders.d.mts +11 -0
  140. package/types/hm3/item-fields.d.mts +12 -0
  141. package/types/hm3/items.d.mts +23 -0
  142. package/types/hm3/template-priority.d.mts +21 -0
  143. package/types/manifest.d.mts +22 -1
  144. package/types/release.d.mts +9 -4
  145. package/types/sohl/actors.d.mts +7 -74
  146. package/types/sohl/being-info.d.mts +8 -27
  147. package/types/sohl/default-item-art.d.mts +5 -3
  148. package/types/sohl/items.d.mts +17 -32
  149. package/engine/foreign-manifests.mjs +0 -126
  150. package/engine/kb-manifest.mjs +0 -490
  151. package/types/engine/foreign-manifests.d.mts +0 -43
  152. package/types/engine/kb-manifest.d.mts +0 -241
package/release.mjs CHANGED
@@ -16,10 +16,12 @@
16
16
  * carries.
17
17
  *
18
18
  * Foundry installs a package by fetching the `download` URL its manifest
19
- * advertises, so a release publishes exactly two assets: `<artifact>.zip`, the
20
- * whole staged tree, and `<artifact>.json` beside it, which is what an already
21
- * installed package re-fetches to notice a new version. Both names are fixed by
22
- * what the manifest says, not chosen here see `manifest.mjs`.
19
+ * advertises, so a release publishes `<artifact>.zip`, the whole staged tree,
20
+ * and `<artifact>.json` beside it, which is what an already installed package
21
+ * re-fetches to notice a new version. A package that ships content publishes a
22
+ * third: the content index other packages resolve its addresses through (#239),
23
+ * named by the `flags.metadataUrl` the manifest advertises. Every name is fixed
24
+ * by what the manifest says, not chosen here — see `manifest.mjs`.
23
25
  *
24
26
  * Kept apart from `stage.mjs` because this is the only part of assembling a
25
27
  * package that needs a dependency. A repository that never cuts a release from
@@ -53,9 +55,12 @@ import { ZipArchive } from "archiver";
53
55
  * @param {string} [opts.outDir] - Where the release assets are written.
54
56
  * @param {"system"|"module"} [opts.artifact] - Which artifact is shipped.
55
57
  * Determines both asset names.
56
- * @returns {Promise<{zip: string, manifest: string, bytes: number,
57
- * version: string}>} The two paths written, the archive's size, and the
58
- * version the manifest declares.
58
+ * @param {string} [opts.metadataDir] - Where the build writes its content
59
+ * index, consulted when the advertised file was not staged.
60
+ * @returns {Promise<{zip: string, manifest: string, metadata?: string,
61
+ * bytes: number, version: string}>} The paths written, the archive's size,
62
+ * and the version the manifest declares. `metadata` is absent when the
63
+ * manifest advertises no content index.
59
64
  * @throws {Error} When the stage has no manifest — there is nothing to release,
60
65
  * and an archive without one installs as nothing.
61
66
  */
@@ -63,6 +68,7 @@ export async function packRelease({
63
68
  stageDir = "build/stage",
64
69
  outDir = "build/dist",
65
70
  artifact = "system",
71
+ metadataDir = "build/content-index",
66
72
  } = {}) {
67
73
  const stage = path.resolve(stageDir);
68
74
  const out = path.resolve(outDir);
@@ -104,10 +110,59 @@ export async function packRelease({
104
110
 
105
111
  await fsp.copyFile(stagedManifest, path.join(out, manifestName));
106
112
 
113
+ const metadata = await publishMetadataIndex({ manifest, stage, out, metadataDir });
114
+
107
115
  return {
108
116
  zip: zipPath,
109
117
  manifest: path.join(out, manifestName),
118
+ ...(metadata ? { metadata } : {}),
110
119
  bytes: archive.pointer(),
111
120
  version: manifest.version,
112
121
  };
113
122
  }
123
+
124
+ /**
125
+ * Place the content index the manifest advertises beside the archive (#239).
126
+ *
127
+ * **The asset's name comes from the manifest, not from here.** `flags.metadataUrl`
128
+ * is the URL every consumer fetches, so its basename is by definition the name
129
+ * the file has to be published under — deriving it a second time would let the
130
+ * two disagree, and a release whose asset is named differently from its
131
+ * advertised URL fails at the consumer, not here.
132
+ *
133
+ * A manifest that advertises no index publishes none: a package with no content
134
+ * tree has nothing to index, and is perfectly releasable. But a manifest that
135
+ * *does* advertise one and cannot produce it is a build error. The alternative
136
+ * is a release that promises an index it does not carry, whose symptom is a
137
+ * dead cross-package link in somebody else's build weeks later — the silent
138
+ * failure the vendored manifest was replaced to end.
139
+ *
140
+ * @param {object} opts
141
+ * @param {object} opts.manifest - The parsed staged manifest.
142
+ * @param {string} opts.stage - The staged tree.
143
+ * @param {string} opts.out - Where release assets are written.
144
+ * @param {string} opts.metadataDir - Where the build writes its index, tried
145
+ * when the file was not staged.
146
+ * @returns {Promise<string|undefined>} The published path, or nothing when the
147
+ * manifest advertises no index.
148
+ * @throws {Error} When one is advertised and no file backs it.
149
+ */
150
+ async function publishMetadataIndex({ manifest, stage, out, metadataDir }) {
151
+ const url = manifest.flags?.metadataUrl;
152
+ if (!url) return undefined;
153
+
154
+ const name = path.basename(new URL(url, "https://example.invalid").pathname);
155
+ const candidates = [path.join(stage, name), path.resolve(metadataDir, name)];
156
+ const found = candidates.find((c) => fs.existsSync(c));
157
+ if (!found) {
158
+ throw new Error(
159
+ `the manifest advertises ${name} as \`flags.metadataUrl\` but no such ` +
160
+ `file exists — looked in ${candidates.join(" and ")}. Build the ` +
161
+ `content index before packing the release.`,
162
+ );
163
+ }
164
+
165
+ const dest = path.join(out, name);
166
+ await fsp.copyFile(found, dest);
167
+ return dest;
168
+ }