@heroiclands/package-build 23.2.2 → 23.3.1
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 +29 -0
- package/bin/content-commands.mjs +293 -2
- package/ci/content-format-reference.mjs +28 -5
- package/docs/api.md +37 -23
- package/docs/authoring/frontmatter.md +2 -0
- package/docs/commands.md +183 -0
- package/docs/content-format.md +6 -0
- package/docs/guides/e2e.md +8 -1
- package/docs/reference/format-details.md +471 -46
- package/docs/reference/note-types.md +124 -107
- package/e2e.mjs +37 -10
- package/engine/appearance-profile.mjs +330 -0
- package/engine/content-format.yaml +8 -0
- package/engine/data-keys.mjs +26 -6
- package/engine/index.mjs +3 -0
- package/engine/infobox.mjs +1 -1
- package/engine/language-names.mjs +634 -0
- package/engine/literature-notes.mjs +62 -27
- package/engine/note-vocabulary.mjs +370 -19
- package/engine/npc-generate.mjs +633 -0
- package/engine/settlement-tables.mjs +777 -0
- package/package.json +1 -1
- package/types/e2e.d.mts +5 -1
- package/types/engine/appearance-profile.d.mts +94 -0
- package/types/engine/data-keys.d.mts +2 -2
- package/types/engine/index.d.mts +1 -0
- package/types/engine/infobox.d.mts +1 -1
- package/types/engine/language-names.d.mts +140 -0
- package/types/engine/literature-notes.d.mts +14 -3
- package/types/engine/note-vocabulary.d.mts +31 -0
- package/types/engine/npc-generate.d.mts +124 -0
- package/types/engine/settlement-tables.d.mts +164 -0
|
@@ -53,33 +53,33 @@ These fields are accepted by every note type. A field's value can still be irrel
|
|
|
53
53
|
|
|
54
54
|
**Subtypes:** `npc`, `character`, `creature`.
|
|
55
55
|
|
|
56
|
-
| Field | Shape | Meaning
|
|
57
|
-
| -------------------------------- | ------------------------------- |
|
|
58
|
-
| `data.icon` | an Address | The document's profile art — an `icon` address, resolved into `img`.
|
|
59
|
-
| `data.tokenIcon` | an Address | What a token on the canvas wears — an `icon` address; unset, it follows `icon`.
|
|
60
|
-
| `data.templatePriority` | number | Template priority; unset means the note is not a template.
|
|
61
|
-
| `data.archetypes` | list of strings | Archetypal behaviours the being fits.
|
|
62
|
-
| `data.occupation` | string | What the being does for a living.
|
|
63
|
-
| `data.lore` | list of Addresses | Lore concerning this being — the law it lives under, the customs it is subject to, the traditions it was raised in.
|
|
64
|
-
| `data.culture` | an Address | The being's primary culture, as a culture lore note.
|
|
65
|
-
| `data.homes` | list of Addresses | Places the being calls home.
|
|
66
|
-
| `data.affiliations` | a standing map keyed by Address | Bodies the being belongs to, keyed by Address, each entry holding the standing it holds there — `rank`, required, a level on that body's own ladder, and `office`, optional, a post that body names.
|
|
67
|
-
| `data.socialTies` | a map keyed by Address | Defining ties directed from this being to others: `patron` (Supports the subject from greater power, wealth, or status.); `friend` (Supports the subject out of goodwill.); `dependent` (Relies on the subject's support or protection.); `acquaintance` (Knows the subject without a strong disposition.); `rival` (Opposes the subject without implacable hostility.); `nemesis` (Opposes the subject personally and implacably.)
|
|
68
|
-
| `data.gender` | string | One of `
|
|
69
|
-
| `data.species` | an Address | The being's species, as a lore note.
|
|
70
|
-
| `data.born` | string | When the being was born — a date, or `unknown` where the birth is unrecorded. Absent, the being was never born.
|
|
71
|
-
| `data.calendar` | an Address | Calendar that displays this being's dates.
|
|
72
|
-
| `data.died` | string | When the being died — a date, or `unknown` where the death is unrecorded. Absent, the being is alive.
|
|
73
|
-
| `data.age` | string | Age in years, stated only to override what `born` says — `34`, or `~34` for an estimate. Unstated beside a dated `born` it is computed; unstated beside an unknown or absent `born` the age is unknown.
|
|
74
|
-
| `data.ageYears` | number | Written by the compiler beside an `age` estimate — the `~` stripped, the magnitude alone. A note never authors this.
|
|
75
|
-
| `data.height` | metres or feet and inches | Height in metres or feet and inches.
|
|
76
|
-
| `data.weight` | kilograms or pounds | Body weight in kilograms or pounds.
|
|
77
|
-
| `data.frame` | string | Relative frame — one of `scant`, `light`, `medium`, `heavy` or `massive`.
|
|
78
|
-
| `data.appearance.eye_color` | string | Eye colour.
|
|
79
|
-
| `data.appearance.hair_color` | string | Hair colour.
|
|
80
|
-
| `data.appearance.skin_color` | string | Skin colour.
|
|
81
|
-
| `data.appearance.complexion` | string or list | The skin's condition
|
|
82
|
-
| `data.appearance.extra_features` | list of strings | Anything else a stranger would notice.
|
|
56
|
+
| Field | Shape | Meaning |
|
|
57
|
+
| -------------------------------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
58
|
+
| `data.icon` | an Address | The document's profile art — an `icon` address, resolved into `img`. |
|
|
59
|
+
| `data.tokenIcon` | an Address | What a token on the canvas wears — an `icon` address; unset, it follows `icon`. |
|
|
60
|
+
| `data.templatePriority` | number | Template priority; unset means the note is not a template. |
|
|
61
|
+
| `data.archetypes` | list of strings | Archetypal behaviours the being fits. |
|
|
62
|
+
| `data.occupation` | string | What the being does for a living. |
|
|
63
|
+
| `data.lore` | list of Addresses | Lore concerning this being — the law it lives under, the customs it is subject to, the traditions it was raised in. |
|
|
64
|
+
| `data.culture` | an Address | The being's primary culture, as a culture lore note. |
|
|
65
|
+
| `data.homes` | list of Addresses | Places the being calls home. |
|
|
66
|
+
| `data.affiliations` | a standing map keyed by Address | Bodies the being belongs to, keyed by Address, each entry holding the standing it holds there — `rank`, required, a level on that body's own ladder, and `office`, optional, a post that body names. |
|
|
67
|
+
| `data.socialTies` | a map keyed by Address | Defining ties directed from this being to others: `patron` (Supports the subject from greater power, wealth, or status.); `friend` (Supports the subject out of goodwill.); `dependent` (Relies on the subject's support or protection.); `acquaintance` (Knows the subject without a strong disposition.); `rival` (Opposes the subject without implacable hostility.); `nemesis` (Opposes the subject personally and implacably.) |
|
|
68
|
+
| `data.gender` | string | One of `female`, `male`, `nonbinary`, `none` or `other`. `none` says the being has no gender; an absent field says its gender is unrecorded. See [a being's look](format-details.md#a-beings-look) for what each word means. |
|
|
69
|
+
| `data.species` | an Address | The being's species, as a lore note. |
|
|
70
|
+
| `data.born` | string | When the being was born — a date, or `unknown` where the birth is unrecorded. Absent, the being was never born. |
|
|
71
|
+
| `data.calendar` | an Address | Calendar that displays this being's dates. |
|
|
72
|
+
| `data.died` | string | When the being died — a date, or `unknown` where the death is unrecorded. Absent, the being is alive. |
|
|
73
|
+
| `data.age` | string | Age in years, stated only to override what `born` says — `34`, or `~34` for an estimate. Unstated beside a dated `born` it is computed; unstated beside an unknown or absent `born` the age is unknown. |
|
|
74
|
+
| `data.ageYears` | number | Written by the compiler beside an `age` estimate — the `~` stripped, the magnitude alone. A note never authors this. |
|
|
75
|
+
| `data.height` | metres or feet and inches | Height in metres or feet and inches. |
|
|
76
|
+
| `data.weight` | kilograms or pounds | Body weight in kilograms or pounds. |
|
|
77
|
+
| `data.frame` | string | Relative frame — one of `scant`, `light`, `medium`, `heavy` or `massive`. See [a being's look](format-details.md#a-beings-look) for what each word means. |
|
|
78
|
+
| `data.appearance.eye_color` | string | Eye colour: one of `amber`, `black`, `blue`, `brown`, `dark_brown`, `grey`, `green`, `hazel` or `violet`. See [a being's look](format-details.md#a-beings-look) for what each word means. |
|
|
79
|
+
| `data.appearance.hair_color` | string | Hair colour: one of `auburn`, `black`, `blonde`, `brown`, `chestnut`, `dark_blonde`, `dark_brown`, `grey`, `greying_black`, `greying_brown`, `red`, `silver`, `strawberry_blond` or `white`. See [a being's look](format-details.md#a-beings-look) for what each word means. |
|
|
80
|
+
| `data.appearance.skin_color` | string | Skin colour: one of `pale`, `fair`, `light`, `medium`, `olive`, `tawny`, `golden`, `tanned`, `swarthy`, `brown`, `dark`, `dark_brown` or `ebony`. See [a being's look](format-details.md#a-beings-look) for what each word means. |
|
|
81
|
+
| `data.appearance.complexion` | string or list | The skin's condition: `ashen`, `blotchy`, `chapped`, `clear`, `freckled`, `jaundiced`, `leathery`, `oily`, `pasty`, `pimpled`, `pockmarked`, `rough`, `ruddy`, `sallow`, `scabrous`, `scarred`, `smooth`, `sun_kissed`, `sunburnt`, `translucent`, `vitiligo`, `wan`, `weathered` or `wrinkled`, one word or a list of several, because a face carries more than one at once. A single word means a list of one. See [a being's look](format-details.md#a-beings-look) for what each word means. |
|
|
82
|
+
| `data.appearance.extra_features` | list of strings | Anything else a stranger would notice, in free text. |
|
|
83
83
|
|
|
84
84
|
**Inner keys** — a key a field's value does not declare is an error at its own line and column.
|
|
85
85
|
|
|
@@ -443,12 +443,20 @@ These fields are accepted by every note type. A field's value can still be irrel
|
|
|
443
443
|
|
|
444
444
|
**Subtypes:** `social`, `nature`, `craft`, `lore`, `language`, `script`, `mystical`, `physical`, `combat`, `combattechnique`.
|
|
445
445
|
|
|
446
|
-
| Field | Shape
|
|
447
|
-
| ----------------------- |
|
|
448
|
-
| `data.icon` | an Address
|
|
449
|
-
| `data.templatePriority` | number
|
|
450
|
-
| `data.masteryLevel` | number
|
|
451
|
-
| `data.parentSkill` | an Address
|
|
446
|
+
| Field | Shape | Meaning |
|
|
447
|
+
| ----------------------- | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
448
|
+
| `data.icon` | an Address | The document's profile art — an `icon` address, resolved into `img`. |
|
|
449
|
+
| `data.templatePriority` | number | Template priority; unset means the note is not a template. |
|
|
450
|
+
| `data.masteryLevel` | number | Mastery before any modifier. |
|
|
451
|
+
| `data.parentSkill` | an Address | The skill this one specialises. |
|
|
452
|
+
| `data.names` | a language's name lists | How this language's speakers are named, for `package-build npc new`: `pattern` builds a name from placeholders such as "{given} {clan}" and literal text, `given` maps a gender to a list of given names, `female` and `male` required, and every other key is a list of names a placeholder of the same name draws from. A language skill note only. See [name lists](format-details.md#name-lists). |
|
|
453
|
+
|
|
454
|
+
**Inner keys** — a key a field's value does not declare is an error at its own line and column.
|
|
455
|
+
|
|
456
|
+
| Key | Shape | Required | Meaning |
|
|
457
|
+
| -------------------- | --------------------------------------------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
458
|
+
| `data.names.pattern` | a pattern such as "{given} {clan}", a list of them, or a map of genders to either | yes | How a name is built: each `{list}` placeholder is filled from the list of that name, `{given.<gender>}` from that gender's given names, and the text around them is written as it stands. A list states every form a name may take; a map keyed by gender states each gender's forms, and a gender with none takes every pattern stated. |
|
|
459
|
+
| `data.names.given` | a map of genders to lists of names | yes | Given names by gender word. A gender with no list draws from every given list together. |
|
|
452
460
|
|
|
453
461
|
**System mappings**
|
|
454
462
|
|
|
@@ -516,83 +524,92 @@ These fields are accepted by every note type. A field's value can still be irrel
|
|
|
516
524
|
|
|
517
525
|
Lore records in-world knowledge. A `culture` describes a people; a `custom` describes how they practice a rite, observance, or usage. A `material` describes a physical constituent and its qualities, which may vary by region. See the [lore subtype definitions](format-details.md#type-lore) for the complete vocabulary.
|
|
518
526
|
|
|
519
|
-
| Field
|
|
520
|
-
|
|
|
521
|
-
| `data.epoch`
|
|
522
|
-
| `data.months`
|
|
523
|
-
| `data.weekdays`
|
|
524
|
-
| `data.seasons`
|
|
525
|
-
| `data.namedDays`
|
|
526
|
-
| `data.eras`
|
|
527
|
-
| `data.formats`
|
|
528
|
-
| `data.culture`
|
|
529
|
-
| `data.form`
|
|
530
|
-
| `data.subjects`
|
|
531
|
-
| `data.language`
|
|
532
|
-
| `data.events`
|
|
527
|
+
| Field | Shape | Meaning |
|
|
528
|
+
| ------------------------ | ----------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
529
|
+
| `data.epoch` | a canonical `<year>.<day>` | Canonical day when calendar year 1, day 1 begins — `1.1`. |
|
|
530
|
+
| `data.months` | list of `{ name, abbreviation?, days }` | The months this calendar keeps, in order — position in the list is position in the year, and the day counts sum to the world's year. |
|
|
531
|
+
| `data.weekdays` | list of `{ name, abbreviation? }` | The days of the week this calendar names, in order. A calendar with no week writes none. |
|
|
532
|
+
| `data.seasons` | list of `{ name, abbreviation?, start }` | The seasons this calendar marks, starting on numbered days of the year. |
|
|
533
|
+
| `data.namedDays` | list of `{ name, abbreviation?, day }` | Names assigned to particular days of the year. |
|
|
534
|
+
| `data.eras` | list of `{ shortcode, name, marker?, abbreviation?, proclaimedBy?, start, label? }` | The year-counts kept in this calendar. A marker names one era and uses these months. |
|
|
535
|
+
| `data.formats` | map of named Calendaria format strings | Named patterns for reading and writing this calendar's dates. |
|
|
536
|
+
| `data.culture` | an Address | The people this lore belongs to — for a work of literature, the people whose work it is — as a culture lore note. A culture note is its own culture, and states the field only as itself. |
|
|
537
|
+
| `data.form` | string | The kind of work in its people's own terms — an epic, a saga, a praise-song, an elegy. Free text. |
|
|
538
|
+
| `data.subjects` | list of Addresses | The beings, places, gods and other notes the work concerns, and each event it concerns, named as `place-ironfells#sack`. |
|
|
539
|
+
| `data.language` | an Address | The tongue the work is composed in, or on a culture note the tongue its people speak, as a language skill note. `package-build npc new` draws a culture's names from its language's `data.names`. A `literature` or `culture` note only. |
|
|
540
|
+
| `data.events` | list of event entries | What happened to or at this subject — each entry one dated, attributed event: a founding, a war, a fall, or an occasion that recurs. |
|
|
541
|
+
| `data.appearanceProfile` | an appearance profile | What this culture's people look like, for `package-build npc new`: `frame`, `eye_color`, `hair_color`, `skin_color` and `complexion` each map words of that field's vocabulary to positive weights, and `height` maps a gender to a `{min, max}` range, `female` and `male` required. A culture note only. See [appearance profiles](format-details.md#appearance-profiles). |
|
|
533
542
|
|
|
534
543
|
**Inner keys** — a key a field's value does not declare is an error at its own line and column.
|
|
535
544
|
|
|
536
|
-
| Key | Shape | Required | Meaning
|
|
537
|
-
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -------- |
|
|
538
|
-
| `data.months[].name` | a string | yes | What it is called.
|
|
539
|
-
| `data.months[].abbreviation` | a string | no | Its short form, for a compact date.
|
|
540
|
-
| `data.months[].days` | a whole number of days | yes | How many days the month holds.
|
|
541
|
-
| `data.weekdays[].name` | a string | yes | What it is called.
|
|
542
|
-
| `data.weekdays[].abbreviation` | a string | no | Its short form, for a compact date.
|
|
543
|
-
| `data.seasons[].name` | a string | yes | What it is called.
|
|
544
|
-
| `data.seasons[].abbreviation` | a string | no | Its short form, for a compact date.
|
|
545
|
-
| `data.seasons[].start` | a one-based day of the year, as a whole number | yes | The day of the year the season begins.
|
|
546
|
-
| `data.namedDays[].name` | a string | yes | What it is called.
|
|
547
|
-
| `data.namedDays[].abbreviation` | a string | no | Its short form, for a compact date.
|
|
548
|
-
| `data.namedDays[].day` | a one-based day of the year, as a whole number | yes | The day of the year it names.
|
|
549
|
-
| `data.eras[].shortcode` | the era's own shortcode, unique within the calendar — an era is addressed `<calendar shortcode>.<era shortcode>` | yes | The era's own segment of `<calendar>.<era>`.
|
|
550
|
-
| `data.eras[].name` | a string | yes | What it is called.
|
|
551
|
-
| `data.eras[].marker` | uppercase letters and digits, beginning with a letter | no | The marker an authored date names the era by, unique across the corpus.
|
|
552
|
-
| `data.eras[].abbreviation` | a string | no | Its short form, for a compact date.
|
|
553
|
-
| `data.eras[].proclaimedBy` | an Address | no | The body that began the reckoning.
|
|
554
|
-
| `data.eras[].start` | `null`, or the calendar year the era begins, as a whole number | yes | The calendar year the era begins; `null` for the era before year 1.
|
|
555
|
-
| `data.eras[].label` | a string, or an `{ after, before }` map | no | How a date in the era reads, around one `{date}` slot.
|
|
556
|
-
| `data.eras[].label.after` | a string with one `{date}` slot | no | How a date in the era reads.
|
|
557
|
-
| `data.eras[].label.before` | a string with one `{date}` slot | no | How a date before the era's start reads.
|
|
558
|
-
| `data.events[].id` | an address segment | no | The event's name within its note — lowercase letters and digits.
|
|
559
|
-
| `data.events[].kind` | one `eventKind` value | no | What sort of thing happened.
|
|
560
|
-
| `data.events[].depth` | one `depth` value | no | How far the event's history reaches.
|
|
561
|
-
| `data.events[].when` | a date, or `"0.<day>"` | yes | When it happened, or the anchor and first instance of an event that recurs.
|
|
562
|
-
| `data.events[].until` | a date | no | When a continuous event ended, or where a recurring series stopped.
|
|
563
|
-
| `data.events[].recurs` | `{ every }` or `{ on }` | no | How further occurrences are found; absent for an event that happened once.
|
|
564
|
-
| `data.events[].recurs.every` | a whole number of years, 1 or more | no | A period counted on the canonical axis from `when`.
|
|
565
|
-
| `data.events[].recurs.on` | a list of dates, strictly increasing, each later than `when` | no | Recorded occurrences beyond the first, in place of a period.
|
|
566
|
-
| `data.events[].summary` | a string | yes | What happened, stated plainly.
|
|
567
|
-
| `data.events[].standing` | one `standing` value | no | What the world's evidence supports.
|
|
568
|
-
| `data.events[].names` | `{ name, by, gloss? }[]` | no | The event's names in the world, each with who uses it.
|
|
569
|
-
| `data.events[].names[].name` | a string | yes | One name the event goes by in the world.
|
|
570
|
-
| `data.events[].names[].by` | an Address naming an `affiliation`, `lore`, `place`, `being` or `skill` note | yes | Who uses that name — a people, a polity, a faith, a place, a tongue.
|
|
571
|
-
| `data.events[].names[].gloss` | a string | no | What the name means, or how it is used.
|
|
572
|
-
| `data.events[].where` | `{ locus?, reach? }` | no | Where it happened, and where it was felt.
|
|
573
|
-
| `data.events[].where.locus` | a list of Addresses, each defaulting to `place` | no | Where the event physically happened; each resolves to a place.
|
|
574
|
-
| `data.events[].where.reach` | `{ place, how, knowledge, attributedTo? }[]` | no | Where the event was felt, and whether each place knows why.
|
|
575
|
-
| `data.events[].where.reach[].place` | an Address, defaulting to `place` | yes | A place where the event was felt.
|
|
576
|
-
| `data.events[].where.reach[].how` | a string | yes | One clause: a consequence someone in that place could notice.
|
|
577
|
-
| `data.events[].where.reach[].knowledge` | one `knowledge` value | yes | Whether that place connects what it felt to this event.
|
|
578
|
-
| `data.events[].where.reach[].attributedTo` | an Address, defaulting to `lore`, naming an event or a `lore` note | no | Only beside `knowledge: misattributed` — the cause that place names instead.
|
|
579
|
-
| `data.events[].who` | `{ ref, role }[]` | no | Who took part, and as what.
|
|
580
|
-
| `data.events[].who[].ref` | an Address naming a `being`, `affiliation` or `lore` note | yes | A participant — a being, a people, an affiliation.
|
|
581
|
-
| `data.events[].who[].role` | one `role` value | yes | What the participant was to the event.
|
|
582
|
-
| `data.events[].follows` | `{ event, how, note? }[]` | no | The earlier events this one follows from.
|
|
583
|
-
| `data.events[].follows[].event` | an Address, defaulting to `lore`, anchored to an `event` where its note holds several | yes | The earlier event; it resolves to exactly one event.
|
|
584
|
-
| `data.events[].follows[].how` | one `followsHow` value | yes | How this event follows from it.
|
|
585
|
-
| `data.events[].follows[].note` | a string | no | One clause saying what connects the two.
|
|
586
|
-
| `data.events[].accounts` | `{ by, says, agrees, withholds? }[]` | no | What each people, polity, faith or place says about it.
|
|
587
|
-
| `data.events[].accounts[].by` | an Address naming an `affiliation`, `lore`, `place` or `being` note | yes | Who holds the account.
|
|
588
|
-
| `data.events[].accounts[].says` | a string | yes | What they say happened, in their terms.
|
|
589
|
-
| `data.events[].accounts[].agrees` | one `agrees` value | yes | How far their account agrees with `summary`.
|
|
590
|
-
| `data.events[].accounts[].withholds` | a string | no | What they decline to say.
|
|
591
|
-
| `data.events[].unresolved` | a list of strings | no | What the world itself has not settled.
|
|
592
|
-
| `data.events[].sources` | a list of Addresses | no | The notes that state or support the event; each resolves.
|
|
593
|
-
| `data.events[].stated` | `{ calendar, text }` | no | The date as one tradition writes it in its own reckoning.
|
|
594
|
-
| `data.events[].stated.calendar` | an Address, or a lore shortcode | yes | The calendar that tradition reckons in — a `lore` note with `subType: calendar`.
|
|
595
|
-
| `data.events[].stated.text` | a string | yes | The date as that tradition writes it.
|
|
545
|
+
| Key | Shape | Required | Meaning |
|
|
546
|
+
| ------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------ |
|
|
547
|
+
| `data.months[].name` | a string | yes | What it is called. |
|
|
548
|
+
| `data.months[].abbreviation` | a string | no | Its short form, for a compact date. |
|
|
549
|
+
| `data.months[].days` | a whole number of days | yes | How many days the month holds. |
|
|
550
|
+
| `data.weekdays[].name` | a string | yes | What it is called. |
|
|
551
|
+
| `data.weekdays[].abbreviation` | a string | no | Its short form, for a compact date. |
|
|
552
|
+
| `data.seasons[].name` | a string | yes | What it is called. |
|
|
553
|
+
| `data.seasons[].abbreviation` | a string | no | Its short form, for a compact date. |
|
|
554
|
+
| `data.seasons[].start` | a one-based day of the year, as a whole number | yes | The day of the year the season begins. |
|
|
555
|
+
| `data.namedDays[].name` | a string | yes | What it is called. |
|
|
556
|
+
| `data.namedDays[].abbreviation` | a string | no | Its short form, for a compact date. |
|
|
557
|
+
| `data.namedDays[].day` | a one-based day of the year, as a whole number | yes | The day of the year it names. |
|
|
558
|
+
| `data.eras[].shortcode` | the era's own shortcode, unique within the calendar — an era is addressed `<calendar shortcode>.<era shortcode>` | yes | The era's own segment of `<calendar>.<era>`. |
|
|
559
|
+
| `data.eras[].name` | a string | yes | What it is called. |
|
|
560
|
+
| `data.eras[].marker` | uppercase letters and digits, beginning with a letter | no | The marker an authored date names the era by, unique across the corpus. |
|
|
561
|
+
| `data.eras[].abbreviation` | a string | no | Its short form, for a compact date. |
|
|
562
|
+
| `data.eras[].proclaimedBy` | an Address | no | The body that began the reckoning. |
|
|
563
|
+
| `data.eras[].start` | `null`, or the calendar year the era begins, as a whole number | yes | The calendar year the era begins; `null` for the era before year 1. |
|
|
564
|
+
| `data.eras[].label` | a string, or an `{ after, before }` map | no | How a date in the era reads, around one `{date}` slot. |
|
|
565
|
+
| `data.eras[].label.after` | a string with one `{date}` slot | no | How a date in the era reads. |
|
|
566
|
+
| `data.eras[].label.before` | a string with one `{date}` slot | no | How a date before the era's start reads. |
|
|
567
|
+
| `data.events[].id` | an address segment | no | The event's name within its note — lowercase letters and digits. |
|
|
568
|
+
| `data.events[].kind` | one `eventKind` value | no | What sort of thing happened. |
|
|
569
|
+
| `data.events[].depth` | one `depth` value | no | How far the event's history reaches. |
|
|
570
|
+
| `data.events[].when` | a date, or `"0.<day>"` | yes | When it happened, or the anchor and first instance of an event that recurs. |
|
|
571
|
+
| `data.events[].until` | a date | no | When a continuous event ended, or where a recurring series stopped. |
|
|
572
|
+
| `data.events[].recurs` | `{ every }` or `{ on }` | no | How further occurrences are found; absent for an event that happened once. |
|
|
573
|
+
| `data.events[].recurs.every` | a whole number of years, 1 or more | no | A period counted on the canonical axis from `when`. |
|
|
574
|
+
| `data.events[].recurs.on` | a list of dates, strictly increasing, each later than `when` | no | Recorded occurrences beyond the first, in place of a period. |
|
|
575
|
+
| `data.events[].summary` | a string | yes | What happened, stated plainly. |
|
|
576
|
+
| `data.events[].standing` | one `standing` value | no | What the world's evidence supports. |
|
|
577
|
+
| `data.events[].names` | `{ name, by, gloss? }[]` | no | The event's names in the world, each with who uses it. |
|
|
578
|
+
| `data.events[].names[].name` | a string | yes | One name the event goes by in the world. |
|
|
579
|
+
| `data.events[].names[].by` | an Address naming an `affiliation`, `lore`, `place`, `being` or `skill` note | yes | Who uses that name — a people, a polity, a faith, a place, a tongue. |
|
|
580
|
+
| `data.events[].names[].gloss` | a string | no | What the name means, or how it is used. |
|
|
581
|
+
| `data.events[].where` | `{ locus?, reach? }` | no | Where it happened, and where it was felt. |
|
|
582
|
+
| `data.events[].where.locus` | a list of Addresses, each defaulting to `place` | no | Where the event physically happened; each resolves to a place. |
|
|
583
|
+
| `data.events[].where.reach` | `{ place, how, knowledge, attributedTo? }[]` | no | Where the event was felt, and whether each place knows why. |
|
|
584
|
+
| `data.events[].where.reach[].place` | an Address, defaulting to `place` | yes | A place where the event was felt. |
|
|
585
|
+
| `data.events[].where.reach[].how` | a string | yes | One clause: a consequence someone in that place could notice. |
|
|
586
|
+
| `data.events[].where.reach[].knowledge` | one `knowledge` value | yes | Whether that place connects what it felt to this event. |
|
|
587
|
+
| `data.events[].where.reach[].attributedTo` | an Address, defaulting to `lore`, naming an event or a `lore` note | no | Only beside `knowledge: misattributed` — the cause that place names instead. |
|
|
588
|
+
| `data.events[].who` | `{ ref, role }[]` | no | Who took part, and as what. |
|
|
589
|
+
| `data.events[].who[].ref` | an Address naming a `being`, `affiliation` or `lore` note | yes | A participant — a being, a people, an affiliation. |
|
|
590
|
+
| `data.events[].who[].role` | one `role` value | yes | What the participant was to the event. |
|
|
591
|
+
| `data.events[].follows` | `{ event, how, note? }[]` | no | The earlier events this one follows from. |
|
|
592
|
+
| `data.events[].follows[].event` | an Address, defaulting to `lore`, anchored to an `event` where its note holds several | yes | The earlier event; it resolves to exactly one event. |
|
|
593
|
+
| `data.events[].follows[].how` | one `followsHow` value | yes | How this event follows from it. |
|
|
594
|
+
| `data.events[].follows[].note` | a string | no | One clause saying what connects the two. |
|
|
595
|
+
| `data.events[].accounts` | `{ by, says, agrees, withholds? }[]` | no | What each people, polity, faith or place says about it. |
|
|
596
|
+
| `data.events[].accounts[].by` | an Address naming an `affiliation`, `lore`, `place` or `being` note | yes | Who holds the account. |
|
|
597
|
+
| `data.events[].accounts[].says` | a string | yes | What they say happened, in their terms. |
|
|
598
|
+
| `data.events[].accounts[].agrees` | one `agrees` value | yes | How far their account agrees with `summary`. |
|
|
599
|
+
| `data.events[].accounts[].withholds` | a string | no | What they decline to say. |
|
|
600
|
+
| `data.events[].unresolved` | a list of strings | no | What the world itself has not settled. |
|
|
601
|
+
| `data.events[].sources` | a list of Addresses | no | The notes that state or support the event; each resolves. |
|
|
602
|
+
| `data.events[].stated` | `{ calendar, text }` | no | The date as one tradition writes it in its own reckoning. |
|
|
603
|
+
| `data.events[].stated.calendar` | an Address, or a lore shortcode | yes | The calendar that tradition reckons in — a `lore` note with `subType: calendar`. |
|
|
604
|
+
| `data.events[].stated.text` | a string | yes | The date as that tradition writes it. |
|
|
605
|
+
| `data.appearanceProfile.frame` | a map of words to weights | yes | Weighted `frame` words; a word left out is never drawn. |
|
|
606
|
+
| `data.appearanceProfile.eye_color` | a map of words to weights | yes | Weighted `eye_color` words; a word left out is never drawn. |
|
|
607
|
+
| `data.appearanceProfile.hair_color` | a map of words to weights | yes | Weighted `hair_color` words; a word left out is never drawn. |
|
|
608
|
+
| `data.appearanceProfile.skin_color` | a map of words to weights | yes | Weighted `skin_color` words; a word left out is never drawn. |
|
|
609
|
+
| `data.appearanceProfile.complexion` | a map of words to weights | yes | Weighted `complexion` words; a word left out is never drawn. |
|
|
610
|
+
| `data.appearanceProfile.height` | a map of genders to height ranges | yes | Height ranges keyed by gender; a gender with no range draws from the span of every range stated. |
|
|
611
|
+
| `data.appearanceProfile.height.<name>.min` | a height in metres or feet and inches | yes | The shortest height drawn. |
|
|
612
|
+
| `data.appearanceProfile.height.<name>.max` | a height in metres or feet and inches | yes | The tallest height drawn. |
|
|
596
613
|
|
|
597
614
|
### map
|
|
598
615
|
|
package/e2e.mjs
CHANGED
|
@@ -636,26 +636,48 @@ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
|
636
636
|
* @param {string} opts.url - The container's base URL.
|
|
637
637
|
* @param {string} opts.container - The container name, for its log.
|
|
638
638
|
* @param {string} opts.stage - The stage, named in a licence failure.
|
|
639
|
+
* @param {string} [opts.dataRoot] - The stage's data root, named when its licence is unsigned.
|
|
640
|
+
* @param {(container: string) => string} [opts.readLog] - Reads the container's log since it started.
|
|
639
641
|
* @param {number} [opts.timeoutMs] - How long to wait.
|
|
640
642
|
* @param {(message: string) => void} [opts.log] - Progress reporting.
|
|
641
643
|
* @returns {Promise<void>} Resolves once the world is active.
|
|
642
644
|
* @throws {Error} On a licence failure or a timeout.
|
|
643
645
|
*/
|
|
644
|
-
export async function waitForWorld({
|
|
646
|
+
export async function waitForWorld({
|
|
647
|
+
url,
|
|
648
|
+
container,
|
|
649
|
+
stage,
|
|
650
|
+
dataRoot,
|
|
651
|
+
readLog = captureContainerLog,
|
|
652
|
+
timeoutMs = 180_000,
|
|
653
|
+
log = () => {},
|
|
654
|
+
}) {
|
|
645
655
|
const join = `${url}/join`;
|
|
646
656
|
const deadline = Date.now() + timeoutMs;
|
|
647
657
|
log(`Waiting for the world at ${join} …`);
|
|
648
658
|
while (Date.now() < deadline) {
|
|
649
|
-
const logs =
|
|
659
|
+
const logs = readLog(container);
|
|
660
|
+
if (/software license requires signature/i.test(logs)) {
|
|
661
|
+
throw new Error(
|
|
662
|
+
"The Foundry licence is not signed, so Foundry serves its licence " +
|
|
663
|
+
"page and no world activates. Each installation fetches its own " +
|
|
664
|
+
"signature with the owner's Foundry account, once per data root: " +
|
|
665
|
+
`run \`package-build container ${stage} start\` with no world ` +
|
|
666
|
+
`(FOUNDRYVTT_${stage.toUpperCase()}_WORLD unset), open the stage in a ` +
|
|
667
|
+
"browser and accept the licence agreement. The signature then " +
|
|
668
|
+
`persists in Config/license.json${dataRoot ? ` under ${dataRoot}` : " in the data root"}. ` +
|
|
669
|
+
"The image applies the key but never signs it.",
|
|
670
|
+
);
|
|
671
|
+
}
|
|
650
672
|
if (/license verification failed/i.test(logs)) {
|
|
651
673
|
throw new Error(
|
|
652
674
|
"Foundry licence verification failed. The end-to-end container " +
|
|
653
|
-
"needs its own
|
|
654
|
-
`FOUNDRYVTT_${stage.toUpperCase()}_LICENSE_KEY ` +
|
|
655
|
-
"
|
|
656
|
-
"
|
|
657
|
-
"
|
|
658
|
-
"
|
|
675
|
+
"needs its own signed licence, set with " +
|
|
676
|
+
`FOUNDRYVTT_${stage.toUpperCase()}_LICENSE_KEY and signed by ` +
|
|
677
|
+
"accepting the licence agreement in Foundry's own page once " +
|
|
678
|
+
"per data root. Another installation's license.json does not " +
|
|
679
|
+
"verify, and a licence shared with a running container is " +
|
|
680
|
+
"single-seat and will fail too.",
|
|
659
681
|
);
|
|
660
682
|
}
|
|
661
683
|
try {
|
|
@@ -677,12 +699,15 @@ export async function waitForWorld({ url, container, stage, timeoutMs = 180_000,
|
|
|
677
699
|
|
|
678
700
|
/**
|
|
679
701
|
* @param {string} container - Container name.
|
|
680
|
-
* @returns {string}
|
|
702
|
+
* @returns {string} Its log since it last started, or `""`.
|
|
681
703
|
*/
|
|
682
704
|
function captureContainerLog(container) {
|
|
683
|
-
const
|
|
705
|
+
const started = spawnSync("docker", ["inspect", "-f", "{{.State.StartedAt}}", container], {
|
|
684
706
|
encoding: "utf8",
|
|
685
707
|
});
|
|
708
|
+
const since = (started.stdout ?? "").trim();
|
|
709
|
+
const args = since ? ["logs", "--since", since, container] : ["logs", container];
|
|
710
|
+
const result = spawnSync("docker", args, { encoding: "utf8" });
|
|
686
711
|
return `${result.stdout ?? ""}${result.stderr ?? ""}`;
|
|
687
712
|
}
|
|
688
713
|
|
|
@@ -1098,6 +1123,7 @@ export async function e2eRun({
|
|
|
1098
1123
|
url: container.url,
|
|
1099
1124
|
container: container.name,
|
|
1100
1125
|
stage,
|
|
1126
|
+
dataRoot: resolveDataRoot(stage, { env }),
|
|
1101
1127
|
log,
|
|
1102
1128
|
});
|
|
1103
1129
|
return runSuite({
|
|
@@ -1175,6 +1201,7 @@ export async function e2eFast({ config, argv = [], env = process.env, log = () =
|
|
|
1175
1201
|
url: container.url,
|
|
1176
1202
|
container: container.name,
|
|
1177
1203
|
stage,
|
|
1204
|
+
dataRoot: resolveDataRoot(stage, { env }),
|
|
1178
1205
|
log,
|
|
1179
1206
|
});
|
|
1180
1207
|
|