Sync generated provider output

This commit is contained in:
github-actions[bot]
2026-07-29 23:47:41 +00:00
parent 9b2659f9c7
commit 48e665edf2
30 changed files with 435 additions and 330 deletions
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]
@@ -1,6 +1,11 @@
import crypto from 'node:crypto';
import { readFileSync } from 'node:fs';
import { CONCEPT_STATUSES, normalizeConceptForm } from './concept-catalog.mjs';
// Defined in roll-selection.mjs for the same reason WELL_TIERS is: this file
// reads the filesystem, and the roll API imports the taxonomy to validate its
// area parameter. Re-exported so existing importers keep working.
import { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS } from './roll-selection.mjs';
export { areasForSurface, COMPOSITION_AREAS, ALL_COMPOSITION_AREAS };
// Catalog B: compositions rather than styles. A composition organizes attention,
// sequence, or manipulation on a surface and must survive being dressed in
@@ -19,28 +24,6 @@ export const COMPOSITION_GRAMMAR_PREFIXES = [
// composition are different species, and read/experience surfaces get their own.
export const COMPOSITION_SURFACES = new Set(['persuade', 'operate', 'read', 'experience']);
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
export function compositionContentHash(composition) {
const payload = [
@@ -21,6 +21,30 @@
export const WELL_TIERS = ['graphic', 'interaction', 'atmosphere'];
// Areas of concern, one level below surface. Surface alone is too coarse to deal
// against: "operate" spans onboarding, settings, dashboards and editors, so a
// build designing an onboarding flow could legitimately draw a settings
// composition and the input would read as noise. Areas name the problem the
// composition is about, not how it is built, which is what familyId already does.
//
// `area` is optional. An entry without one is eligible for any request in its
// surface, so nothing has to be backfilled before this ships, and a request for
// an area with a thin pool tops up from the rest of the surface rather than
// dealing fewer.
export const COMPOSITION_AREAS = {
persuade: ['landing-hero', 'feature-argument', 'pricing-and-plans', 'proof-and-testimony', 'campaign-and-launch'],
operate: ['onboarding-and-setup', 'dashboard-and-overview', 'records-and-tables', 'editor-and-canvas', 'settings-and-account', 'empty-and-failure'],
read: ['long-form-article', 'reference-and-docs', 'index-and-archive', 'search-and-results'],
experience: ['gallery-and-collection', 'player-and-timeline', 'space-and-map', 'play-and-toy'],
};
export const ALL_COMPOSITION_AREAS = new Set(Object.values(COMPOSITION_AREAS).flat());
export function areasForSurface(surface) {
return COMPOSITION_AREAS[surface] ?? [];
}
/**
* Drives a selection generator with a synchronous hash.
* @param {Generator} generator yields string[] to hash, resumes with hex string[]