@heroiclands/package-build 23.4.1 → 23.5.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 (48) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +29 -25
  3. package/assets/images/provenance.yaml +1 -0
  4. package/bin/package-build.mjs +259 -28
  5. package/ci/prettier.mjs +73 -0
  6. package/config.mjs +10 -0
  7. package/container.mjs +232 -1
  8. package/content-config.mjs +5 -1
  9. package/docs/api.md +100 -52
  10. package/docs/authoring/assets.md +16 -1
  11. package/docs/commands.md +154 -7
  12. package/docs/configuration.md +39 -2
  13. package/docs/content-format.md +30 -6
  14. package/docs/guides/e2e.md +38 -0
  15. package/docs/guides/icons.md +5 -0
  16. package/docs/guides/release-and-deploy.md +36 -1
  17. package/docs/reference/format-details.md +180 -34
  18. package/docs/reference/note-types.md +69 -69
  19. package/engine/asset-index.mjs +63 -22
  20. package/engine/asset-references.mjs +355 -0
  21. package/engine/asset-shipping.mjs +363 -0
  22. package/engine/asset-types.mjs +70 -0
  23. package/engine/base-compiler.mjs +24 -1
  24. package/engine/cdn-publish.mjs +618 -0
  25. package/engine/index.mjs +6 -0
  26. package/engine/note-vocabulary.mjs +4 -1
  27. package/engine/pathnames.mjs +21 -10
  28. package/engine/rank-ladder.mjs +40 -16
  29. package/engine/scenes.mjs +1 -1
  30. package/engine/standing-terms.mjs +3 -1
  31. package/package.json +4 -3
  32. package/packagebuild-metadata.jsonl +13 -13
  33. package/release.mjs +69 -7
  34. package/sohl/actors.mjs +12 -4
  35. package/sohl/default-item-art.mjs +23 -19
  36. package/types/config.d.mts +7 -0
  37. package/types/container.d.mts +137 -1
  38. package/types/engine/asset-index.d.mts +3 -2
  39. package/types/engine/asset-references.d.mts +136 -0
  40. package/types/engine/asset-shipping.d.mts +240 -0
  41. package/types/engine/asset-types.d.mts +36 -0
  42. package/types/engine/base-compiler.d.mts +7 -1
  43. package/types/engine/cdn-publish.d.mts +311 -0
  44. package/types/engine/index.d.mts +2 -0
  45. package/types/engine/pathnames.d.mts +2 -1
  46. package/types/engine/rank-ladder.d.mts +25 -6
  47. package/types/release.d.mts +5 -3
  48. package/types/sohl/default-item-art.d.mts +2 -1
@@ -195,6 +195,91 @@ export function needsFoundryAccount({ cacheDir, dataRoot, version, licenseKey, f
195
195
  licenseKey?: string | null | undefined;
196
196
  fileExists?: ((file: string) => boolean) | undefined;
197
197
  }): boolean;
198
+ /**
199
+ * Whether the S3 server is asked for: `FOUNDRYVTT_CONTAINER_S3` set to `1` or
200
+ * `true`. Anything else, including unset, leaves the container as it is.
201
+ *
202
+ * @param {NodeJS.ProcessEnv} [env] - Environment to read.
203
+ * @returns {boolean} Whether to run the S3 server.
204
+ */
205
+ export function s3Requested(env?: NodeJS.ProcessEnv): boolean;
206
+ /**
207
+ * Everything the S3 opt-in does, as data.
208
+ *
209
+ * @typedef {object} S3Plan
210
+ * @property {string} network - The user-defined network the Foundry container
211
+ * and the S3 server share.
212
+ * @property {string} server - The S3 server's container name.
213
+ * @property {string} identities - Absolute path of the identities file.
214
+ * @property {string} awsConfig - Absolute path of the Foundry `awsConfig`.
215
+ * @property {string} awsConfigName - The file's name under the data root's
216
+ * `Config/`, and the value of `FOUNDRY_AWS_CONFIG`.
217
+ */
218
+ /**
219
+ * The S3 plan for a container, or `null` when the opt-in is off.
220
+ *
221
+ * @param {object} opts
222
+ * @param {string} opts.name - The Foundry container's name.
223
+ * @param {string} opts.rootDir - The consumer repository root, which holds the
224
+ * identities and the `awsConfig`.
225
+ * @param {NodeJS.ProcessEnv} [opts.env] - Environment to read.
226
+ * @returns {S3Plan|null} The plan.
227
+ */
228
+ export function resolveS3({ name, rootDir, env }: {
229
+ name: string;
230
+ rootDir: string;
231
+ env?: NodeJS.ProcessEnv | undefined;
232
+ }): S3Plan | null;
233
+ /**
234
+ * The `docker run` argument vector for the S3 server.
235
+ *
236
+ * @param {S3Plan} plan - The S3 plan.
237
+ * @returns {string[]} Arguments after `docker`.
238
+ */
239
+ export function s3RunArgs(plan: S3Plan): string[];
240
+ /**
241
+ * The `docker exec` argument vector that runs one `weed shell` command in the
242
+ * S3 server.
243
+ *
244
+ * @param {S3Plan} plan - The S3 plan.
245
+ * @param {string} command - The shell command, such as `s3.bucket.list`.
246
+ * @returns {string[]} Arguments after `docker`.
247
+ */
248
+ export function s3ShellArgs(plan: S3Plan, command: string): string[];
249
+ /**
250
+ * Start the S3 server on its network and create the bucket, unless it is
251
+ * already running, and copy the `awsConfig` into the data root.
252
+ *
253
+ * @param {object} opts
254
+ * @param {S3Plan} opts.plan - The S3 plan.
255
+ * @param {string} opts.dataRoot - The Foundry user-data root.
256
+ * @param {(message: string) => void} [opts.log] - Progress reporting.
257
+ * @param {(args: string[]) => number} [opts.run] - Runs docker, returning the
258
+ * exit status.
259
+ * @param {(args: string[]) => string} [opts.capture] - Runs docker, returning
260
+ * its stdout, or `""` on failure.
261
+ * @param {(ms: number) => void} [opts.sleep] - Waits.
262
+ * @param {number} [opts.attempts] - How often to ask the server whether it is
263
+ * ready.
264
+ * @throws {Error} When an input file is missing or the server never answers.
265
+ */
266
+ export function ensureS3({ plan, dataRoot, log, run, capture, sleep, attempts, }: {
267
+ plan: S3Plan;
268
+ dataRoot: string;
269
+ log?: ((message: string) => void) | undefined;
270
+ run?: ((args: string[]) => number) | undefined;
271
+ capture?: ((args: string[]) => string) | undefined;
272
+ sleep?: ((ms: number) => void) | undefined;
273
+ attempts?: number | undefined;
274
+ }): void;
275
+ /**
276
+ * Remove the S3 server and its network, tolerating either being absent.
277
+ *
278
+ * @param {S3Plan} plan - The S3 plan.
279
+ * @param {(args: string[]) => number} [run] - Runs docker.
280
+ * @param {(args: string[]) => string} [capture] - Runs docker for its stdout.
281
+ */
282
+ export function removeS3(plan: S3Plan, run?: (args: string[]) => number, capture?: (args: string[]) => string): void;
198
283
  /**
199
284
  * The full `docker run` argument vector for a stage's container.
200
285
  *
@@ -214,6 +299,11 @@ export function needsFoundryAccount({ cacheDir, dataRoot, version, licenseKey, f
214
299
  * @param {string|null} [opts.licenseKey] - Dedicated licence key.
215
300
  * @param {boolean} [opts.account] - Whether to pass `FOUNDRY_USERNAME` and
216
301
  * `FOUNDRY_PASSWORD` through; see {@link needsFoundryAccount}.
302
+ * @param {string|null} [opts.network] - A user-defined network to attach the
303
+ * container to as it is created, so it can reach the S3 server before Foundry
304
+ * starts.
305
+ * @param {string|null} [opts.awsConfig] - Name of the `awsConfig` file under the
306
+ * data root's `Config/`, passed as `FOUNDRY_AWS_CONFIG`.
217
307
  * @param {string|null} [opts.user] - `--user` value to run the container as.
218
308
  * `felddy/foundryvtt` runs Foundry as user 1000 and ignores `FOUNDRY_UID` and
219
309
  * `FOUNDRY_GID`; under rootless Docker, container root is the host user, so
@@ -221,7 +311,7 @@ export function needsFoundryAccount({ cacheDir, dataRoot, version, licenseKey, f
221
311
  * the image's own user.
222
312
  * @returns {string[]} Arguments after `docker`.
223
313
  */
224
- export function dockerRunArgs({ name, image, port, dataRoot, env, cacheDir, version, world, licenseKey, account, user, }: {
314
+ export function dockerRunArgs({ name, image, port, dataRoot, env, cacheDir, version, world, licenseKey, account, network, awsConfig, user, }: {
225
315
  name: string;
226
316
  image: string;
227
317
  port: number;
@@ -232,6 +322,8 @@ export function dockerRunArgs({ name, image, port, dataRoot, env, cacheDir, vers
232
322
  world?: string | null | undefined;
233
323
  licenseKey?: string | null | undefined;
234
324
  account?: boolean | undefined;
325
+ network?: string | null | undefined;
326
+ awsConfig?: string | null | undefined;
235
327
  user?: string | null | undefined;
236
328
  }): string[];
237
329
  /**
@@ -362,6 +454,7 @@ export function clearStaleLock(dataRoot: string, log?: (message: string) => void
362
454
  * @property {string|null} licenseKey
363
455
  * @property {string|null} cacheDir
364
456
  * @property {string|null} user - From `FOUNDRYVTT_CONTAINER_USER`.
457
+ * @property {S3Plan|null} s3 - Set by `FOUNDRYVTT_CONTAINER_S3`.
365
458
  */
366
459
  /**
367
460
  * Resolve a stage's container settings.
@@ -443,6 +536,18 @@ export const CONTAINER_PORT: 30000;
443
536
  export const CACHE_MOUNT: "/container_cache";
444
537
  /** What `package-build container` can be asked to do. */
445
538
  export const CONTAINER_ACTIONS: readonly string[];
539
+ /** The S3 image: MinIO images cannot be pulled everywhere, SeaweedFS can. */
540
+ export const S3_IMAGE: "chrislusf/seaweedfs:3.80";
541
+ /** The name the S3 server answers to on the shared network, and in `awsConfig`. */
542
+ export const S3_ALIAS: "s3.localhost";
543
+ /** The port the S3 server listens on and publishes. */
544
+ export const S3_PORT: 8333;
545
+ /** The bucket the S3 server is created with. */
546
+ export const S3_BUCKET: "sohl-e2e";
547
+ /** The consumer's S3 identities, relative to the repository root. */
548
+ export const S3_IDENTITIES_FILE: "cypress/s3/s3-identities.json";
549
+ /** The consumer's Foundry `awsConfig`, relative to the repository root. */
550
+ export const S3_AWS_CONFIG_FILE: "cypress/s3/aws-e2e.json";
446
551
  /**
447
552
  * A stage declared in `packageBuild.container.stages`.
448
553
  */
@@ -460,6 +565,33 @@ export type ContainerStage = {
460
565
  */
461
566
  version: string | null;
462
567
  };
568
+ /**
569
+ * Everything the S3 opt-in does, as data.
570
+ */
571
+ export type S3Plan = {
572
+ /**
573
+ * - The user-defined network the Foundry container
574
+ * and the S3 server share.
575
+ */
576
+ network: string;
577
+ /**
578
+ * - The S3 server's container name.
579
+ */
580
+ server: string;
581
+ /**
582
+ * - Absolute path of the identities file.
583
+ */
584
+ identities: string;
585
+ /**
586
+ * - Absolute path of the Foundry `awsConfig`.
587
+ */
588
+ awsConfig: string;
589
+ /**
590
+ * - The file's name under the data root's
591
+ * `Config/`, and the value of `FOUNDRY_AWS_CONFIG`.
592
+ */
593
+ awsConfigName: string;
594
+ };
463
595
  /**
464
596
  * Everything a container action needs, resolved from configuration and the
465
597
  * environment once.
@@ -478,4 +610,8 @@ export type ResolvedContainer = {
478
610
  * - From `FOUNDRYVTT_CONTAINER_USER`.
479
611
  */
480
612
  user: string | null;
613
+ /**
614
+ * - Set by `FOUNDRYVTT_CONTAINER_S3`.
615
+ */
616
+ s3: S3Plan | null;
481
617
  };
@@ -12,8 +12,9 @@
12
12
  * asserts that the address does not exist.
13
13
  * @returns {Array<Record<string, any>>} One record per addressable file, in walk
14
14
  * order; the caller imposes the index's total order.
15
- * @throws {Error} When a file cannot be addressed and no `problems` array was
16
- * supplied. `file` rides on the error.
15
+ * @throws {Error} When any finding is made and no `problems` array was
16
+ * supplied. Its message is every finding as a located diagnostic line, one
17
+ * per line; `file` and `position` name the first.
17
18
  */
18
19
  export function collectAssetRecords(assetsBase: string, { contentPackage, problems }: {
19
20
  contentPackage: string;
@@ -0,0 +1,136 @@
1
+ /**
2
+ * One asset a compiled path can name.
3
+ *
4
+ * @typedef {object} AssetReferenceEntry
5
+ * @property {string} address - The canonical address.
6
+ * @property {string} package - The content package shipping it.
7
+ * @property {string} type - `icon` or `image`.
8
+ * @property {string} foundry - Its path in a Foundry install.
9
+ * @property {boolean} shipped - Whether its package ships it.
10
+ */
11
+ /**
12
+ * Every picture a compiled document can name, by Foundry path and by address.
13
+ *
14
+ * Built from this package's asset records and every fetched dependency's, so a
15
+ * reference to another package's picture states its address too.
16
+ *
17
+ * @param {{assets?: Map<string, object>, foreign?: Map<string, object>}} linkIndex -
18
+ * The compile's link index.
19
+ * @param {object} config - The resolved build configuration.
20
+ * @returns {{byPath: Map<string, AssetReferenceEntry>, byAddress: Map<string, AssetReferenceEntry>}}
21
+ */
22
+ export function assetReferenceLookup(linkIndex: {
23
+ assets?: Map<string, object>;
24
+ foreign?: Map<string, object>;
25
+ }, config: object): {
26
+ byPath: Map<string, AssetReferenceEntry>;
27
+ byAddress: Map<string, AssetReferenceEntry>;
28
+ };
29
+ /**
30
+ * Mark every `<img>` in one HTML string with its asset's address.
31
+ *
32
+ * @param {string} html
33
+ * @param {Parameters<typeof resolveReference>[1]} lookup
34
+ * @param {(message: string) => void} report
35
+ * @returns {string} The HTML, every asset `<img>` carrying `data-asset`.
36
+ */
37
+ export function annotateHtml(html: string, lookup: Parameters<typeof resolveReference>[1], report: (message: string) => void): string;
38
+ /**
39
+ * State the address of every asset one compiled document references, and draw
40
+ * a stand-in for each the package does not ship. Changes `doc` in place.
41
+ *
42
+ * @param {Record<string, any>} doc - The compiled document.
43
+ * @param {string} documentType - Its Foundry document type.
44
+ * @param {object} opts - Options.
45
+ * @param {Parameters<typeof resolveReference>[1]} opts.lookup - From
46
+ * {@link assetReferenceLookup}.
47
+ * @param {string|null|undefined} opts.system - The flag scope; no flag is
48
+ * written without one.
49
+ * @param {(message: string) => void} opts.report - Receives each finding.
50
+ * @returns {Record<string, any>} `doc`.
51
+ */
52
+ export function annotateAssetReferences(doc: Record<string, any>, documentType: string, { lookup, system, report }: {
53
+ lookup: Parameters<typeof resolveReference>[1];
54
+ system: string | null | undefined;
55
+ report: (message: string) => void;
56
+ }): Record<string, any>;
57
+ /**
58
+ * One path field: the object whose `flags` record it, and the field's path
59
+ * inside that object.
60
+ *
61
+ * @typedef {object} AssetPathField
62
+ * @property {readonly string[]} holder - From the document to the object
63
+ * carrying the flag; empty for the document itself.
64
+ * @property {readonly string[]} field - From that object to the value.
65
+ * @property {(doc: object) => boolean} [when] - Whether the field is a picture
66
+ * on this document.
67
+ */
68
+ /**
69
+ * The path fields naming an asset, by document type.
70
+ *
71
+ * @type {Readonly<Record<string, readonly AssetPathField[]>>}
72
+ */
73
+ export const ASSET_PATH_FIELDS: Readonly<Record<string, readonly AssetPathField[]>>;
74
+ /**
75
+ * One asset a compiled path can name.
76
+ */
77
+ export type AssetReferenceEntry = {
78
+ /**
79
+ * - The canonical address.
80
+ */
81
+ address: string;
82
+ /**
83
+ * - The content package shipping it.
84
+ */
85
+ package: string;
86
+ /**
87
+ * - `icon` or `image`.
88
+ */
89
+ type: string;
90
+ /**
91
+ * - Its path in a Foundry install.
92
+ */
93
+ foundry: string;
94
+ /**
95
+ * - Whether its package ships it.
96
+ */
97
+ shipped: boolean;
98
+ };
99
+ /**
100
+ * One path field: the object whose `flags` record it, and the field's path
101
+ * inside that object.
102
+ */
103
+ export type AssetPathField = {
104
+ /**
105
+ * - From the document to the object
106
+ * carrying the flag; empty for the document itself.
107
+ */
108
+ holder: readonly string[];
109
+ /**
110
+ * - From that object to the value.
111
+ */
112
+ field: readonly string[];
113
+ /**
114
+ * - Whether the field is a picture
115
+ * on this document.
116
+ */
117
+ when?: ((doc: object) => boolean) | undefined;
118
+ };
119
+ /**
120
+ * What one compiled path becomes: the path to write and the address to state.
121
+ *
122
+ * @param {string} value - A compiled path.
123
+ * @param {{byPath: Map<string, AssetReferenceEntry>, byAddress: Map<string, AssetReferenceEntry>}} lookup
124
+ * @param {(message: string) => void} report - Called once per excluded asset
125
+ * with no stand-in.
126
+ * @returns {{src: string, address: string}|null} `null` for a path naming no
127
+ * asset.
128
+ */
129
+ declare function resolveReference(value: string, lookup: {
130
+ byPath: Map<string, AssetReferenceEntry>;
131
+ byAddress: Map<string, AssetReferenceEntry>;
132
+ }, report: (message: string) => void): {
133
+ src: string;
134
+ address: string;
135
+ } | null;
136
+ export {};
@@ -0,0 +1,240 @@
1
+ /**
2
+ * The deployed path of one asset record, or `undefined` for a record of a type
3
+ * that does not deploy flat.
4
+ *
5
+ * @param {{type?: string, asset?: {path?: string}}} record - An asset record.
6
+ * @returns {string|undefined} `<icons|images>/<basename>`.
7
+ */
8
+ export function deployedAssetPath(record: {
9
+ type?: string;
10
+ asset?: {
11
+ path?: string;
12
+ };
13
+ }): string | undefined;
14
+ /**
15
+ * Why one asset record does not ship, or `""` when it does.
16
+ *
17
+ * @param {{asset?: {ai?: unknown, license?: unknown}}} record - An asset record.
18
+ * @param {readonly string[]} [additions] - Licences the package adds to
19
+ * {@link SHIPPING_LICENSES}, from `packageBuild.shippingLicenses`.
20
+ * @returns {string} The reason, as a clause, or `""`.
21
+ */
22
+ export function exclusionReason(record: {
23
+ asset?: {
24
+ ai?: unknown;
25
+ license?: unknown;
26
+ };
27
+ }, additions?: readonly string[]): string;
28
+ /**
29
+ * Whether one asset record ships in the Foundry package.
30
+ *
31
+ * @param {object} record - An asset record.
32
+ * @param {readonly string[]} [additions] - The package's added licences.
33
+ * @returns {boolean} True for a deployed type with `ai: false` and a licence on
34
+ * {@link SHIPPING_LICENSES} or in `additions`.
35
+ */
36
+ export function shipsAsset(record: object, additions?: readonly string[]): boolean;
37
+ /**
38
+ * The canonical address of a package's stand-in for one asset type.
39
+ *
40
+ * @param {string} pkg - The content package.
41
+ * @param {string} type - `icon` or `image`.
42
+ * @returns {string} `<package>-none-<type>-missing`.
43
+ */
44
+ export function standInAddress(pkg: string, type: string): string;
45
+ /**
46
+ * Split a package's picture records into those the stage ships and those it
47
+ * leaves out.
48
+ *
49
+ * Audio and every other record are in neither list.
50
+ *
51
+ * @param {readonly object[]} records - Asset records, in any order.
52
+ * @param {readonly string[]} [additions] - The package's added licences.
53
+ * @returns {{staged: object[], excluded: {record: object, reason: string}[]}}
54
+ * Both in address order.
55
+ */
56
+ export function selectStagedAssets(records: readonly object[], additions?: readonly string[]): {
57
+ staged: object[];
58
+ excluded: {
59
+ record: object;
60
+ reason: string;
61
+ }[];
62
+ };
63
+ /**
64
+ * One asset-set entry.
65
+ *
66
+ * @typedef {object} AssetsManifestEntry
67
+ * @property {string} address - The canonical address.
68
+ * @property {string} source - Where the file is fetched from, resolved against
69
+ * the URL of the set file holding it.
70
+ * @property {string} target - Its path relative to the location's root, in the
71
+ * deployed layout.
72
+ * @property {number} size - Its size in bytes.
73
+ */
74
+ /**
75
+ * An asset set: a display name, the package its addresses belong to, and one
76
+ * entry per file.
77
+ *
78
+ * @typedef {object} AssetSet
79
+ * @property {string} name - The set's display name.
80
+ * @property {string} package - The content package.
81
+ * @property {AssetsManifestEntry[]} assets - The files, in target order.
82
+ */
83
+ /**
84
+ * The display name of a staged package's own asset set.
85
+ *
86
+ * @param {string} title - The package's manifest title.
87
+ * @returns {string} `<title> — shipped art`.
88
+ */
89
+ export function shippedSetName(title: string): string;
90
+ /**
91
+ * The asset-set entries for a set of staged files, as the staged package's own
92
+ * set lists them.
93
+ *
94
+ * The set sits in `asset-sets/` under the package root, so each `source` is
95
+ * `../<target>`.
96
+ *
97
+ * @param {readonly object[]} staged - The records staged.
98
+ * @param {string} stageDir - The staged package root, where each file's size
99
+ * is measured — after any transform, since that is the file a location holds.
100
+ * @returns {AssetsManifestEntry[]} In target order.
101
+ */
102
+ export function assetsManifest(staged: readonly object[], stageDir: string): AssetsManifestEntry[];
103
+ /**
104
+ * Stage a package's shipped pictures flat at the package root, and write the
105
+ * package's own asset set, `asset-sets/default.json`.
106
+ *
107
+ * The records are read by {@link module:engine/asset-index.collectAssetRecords},
108
+ * so provenance resolves exactly as the content index resolves it — per file,
109
+ * a sidecar replacing an inherited record. Any finding that walk makes stops the
110
+ * stage before a file is copied: a package whose provenance cannot be read is
111
+ * not one whose shipping can be decided.
112
+ *
113
+ * @param {object} opts - Options.
114
+ * @param {string} opts.assetsBase - The package's asset directory, the roots'
115
+ * parent.
116
+ * @param {string} opts.contentPackage - The package the trees belong to.
117
+ * @param {string} opts.stageDir - The staged package root.
118
+ * @param {string} opts.title - The package's manifest title, which names the
119
+ * set.
120
+ * @param {(sourcePath: string) => string|null|undefined} [opts.transform] -
121
+ * The repository's per-file transform.
122
+ * @param {readonly string[]} [opts.shippingLicenses] - Licences the package
123
+ * adds to {@link SHIPPING_LICENSES}.
124
+ * @returns {{staged: object[], excluded: {record: object, reason: string}[],
125
+ * findings: object[], manifest: AssetSet|null}}
126
+ * What was staged and left out, and the findings that stopped the stage —
127
+ * nothing is staged when `findings` is non-empty. A package with neither
128
+ * picture root stages nothing and writes no asset set.
129
+ */
130
+ export function stagePackageAssets({ assetsBase, contentPackage, stageDir, title, transform, shippingLicenses, }: {
131
+ assetsBase: string;
132
+ contentPackage: string;
133
+ stageDir: string;
134
+ title: string;
135
+ transform?: ((sourcePath: string) => string | null | undefined) | undefined;
136
+ shippingLicenses?: readonly string[] | undefined;
137
+ }): {
138
+ staged: object[];
139
+ excluded: {
140
+ record: object;
141
+ reason: string;
142
+ }[];
143
+ findings: object[];
144
+ manifest: AssetSet | null;
145
+ };
146
+ /**
147
+ * The `packageBuild.assets` rows that would stage a picture root themselves.
148
+ *
149
+ * The stage copies `icons/` and `images/` itself, filtered; a row copying
150
+ * either root, a directory inside one, or a directory holding one would put
151
+ * every file back unfiltered, so each is refused.
152
+ *
153
+ * @param {readonly {from: string, to: string}[]} rows - The configured rows.
154
+ * @param {object} opts - Options.
155
+ * @param {string} opts.rootDir - The repository root rows resolve against.
156
+ * @param {string} opts.assetsBase - The package's asset directory.
157
+ * @returns {{index: number, from: string, root: string}[]} One per offending
158
+ * row, naming the root it reaches.
159
+ */
160
+ export function rowsStagingPictureRoots(rows: readonly {
161
+ from: string;
162
+ to: string;
163
+ }[], { rootDir, assetsBase }: {
164
+ rootDir: string;
165
+ assetsBase: string;
166
+ }): {
167
+ index: number;
168
+ from: string;
169
+ root: string;
170
+ }[];
171
+ /**
172
+ * The licences a shipped picture may carry, as its provenance `license` spells
173
+ * them.
174
+ *
175
+ * A package adds to this list with `packageBuild.shippingLicenses`; the list a
176
+ * package ships under is this one together with its additions.
177
+ *
178
+ * `LicenseRef-PublicDomain` is the spelling for a work in the public domain,
179
+ * which SPDX gives no identifier of its own. `CC0` is accepted beside
180
+ * `CC0-1.0` because both spellings name the one dedication. Nothing is
181
+ * normalised: a value off this list is excluded, however close it reads.
182
+ *
183
+ * @type {readonly string[]}
184
+ */
185
+ export const SHIPPING_LICENSES: readonly string[];
186
+ /**
187
+ * The staged package's own asset set, relative to the package root — the set
188
+ * listing the pictures it ships.
189
+ *
190
+ * @type {string}
191
+ */
192
+ export const SHIPPED_SET_FILE: string;
193
+ /**
194
+ * The shortcode a package's stand-in picture carries under each deployed root.
195
+ *
196
+ * @type {string}
197
+ */
198
+ export const STAND_IN_SHORTCODE: string;
199
+ /**
200
+ * One asset-set entry.
201
+ */
202
+ export type AssetsManifestEntry = {
203
+ /**
204
+ * - The canonical address.
205
+ */
206
+ address: string;
207
+ /**
208
+ * - Where the file is fetched from, resolved against
209
+ * the URL of the set file holding it.
210
+ */
211
+ source: string;
212
+ /**
213
+ * - Its path relative to the location's root, in the
214
+ * deployed layout.
215
+ */
216
+ target: string;
217
+ /**
218
+ * - Its size in bytes.
219
+ */
220
+ size: number;
221
+ };
222
+ /**
223
+ * An asset set: a display name, the package its addresses belong to, and one
224
+ * entry per file.
225
+ */
226
+ export type AssetSet = {
227
+ /**
228
+ * - The set's display name.
229
+ */
230
+ name: string;
231
+ /**
232
+ * - The content package.
233
+ */
234
+ package: string;
235
+ /**
236
+ * - The files, in target order.
237
+ */
238
+ assets: AssetsManifestEntry[];
239
+ };
240
+ export { DEPLOYED_ASSET_TYPES, deployedSuffix } from "./asset-types.mjs";
@@ -1,3 +1,33 @@
1
+ /**
2
+ * Whether a source suffix sits under a picture root, and so deploys flat.
3
+ *
4
+ * @param {string} suffix - A path inside a package's `assets/` directory.
5
+ * @returns {boolean} True for `icons/…` and `images/…`.
6
+ */
7
+ export function isDeployedSuffix(suffix: string): boolean;
8
+ /**
9
+ * A source suffix rewritten into the deployed layout.
10
+ *
11
+ * `images/beings/characters/thorn.webp` becomes `images/thorn.webp`. A suffix
12
+ * under no deployed root — `audio/…`, `ui/…`, `generated/…` — is returned
13
+ * unchanged, because only the picture roots deploy flat.
14
+ *
15
+ * @param {string} suffix - A path inside a package's `assets/` directory,
16
+ * `/`-separated.
17
+ * @returns {string} The path the file has in a deployed location.
18
+ */
19
+ export function deployedSuffix(suffix: string): string;
20
+ /**
21
+ * What is wrong with a package's `packageBuild.shippingLicenses`, or `""` when
22
+ * nothing is.
23
+ *
24
+ * The key lists licences a package adds to the default shipping list, spelled
25
+ * as provenance spells them: a list of non-empty strings with no duplicates.
26
+ *
27
+ * @param {unknown} value - The declared value; `undefined` is absent and fine.
28
+ * @returns {string} The problem as a clause, or `""`.
29
+ */
30
+ export function shippingLicensesProblem(value: unknown): string;
1
31
  /**
2
32
  * Whether a type name addresses a file rather than a note.
3
33
  *
@@ -98,6 +128,12 @@ export const AUDIO_EXTENSIONS: readonly string[];
98
128
  * @type {readonly AssetType[]}
99
129
  */
100
130
  export const ASSET_TYPES: readonly AssetType[];
131
+ /**
132
+ * The asset types that deploy flat — `icon` and `image`, never `audio`.
133
+ *
134
+ * @type {readonly import("./asset-types.mjs").AssetType[]}
135
+ */
136
+ export const DEPLOYED_ASSET_TYPES: readonly import("./asset-types.mjs").AssetType[];
101
137
  /**
102
138
  * Every asset type name.
103
139
  *
@@ -563,10 +563,16 @@ export class BasePackCompiler {
563
563
  /**
564
564
  * Write one document into a directory, named for its name and id.
565
565
  *
566
+ * Every asset the document references states its address on the way out,
567
+ * and an asset its package does not ship is drawn by that package's
568
+ * stand-in — see {@link module:engine/asset-references}.
569
+ *
566
570
  * @param {string} dir - The destination directory.
567
571
  * @param {object} doc - The document.
572
+ * @param {string} [documentType] - Its Foundry document type; this pass's
573
+ * own by default.
568
574
  */
569
- writeTo(dir: string, doc: object): void;
575
+ writeTo(dir: string, doc: object, documentType?: string): void;
570
576
  /**
571
577
  * Write one document into this pass's own pack.
572
578
  *