Update from source 46b1e857b
Some checks are pending
Deploy to GitHub Pages / build (push) Waiting to run
Deploy to GitHub Pages / deploy (push) Blocked by required conditions

This commit is contained in:
Doxa Maps 2026-09-28 00:36:45 +00:00
parent 079266367c
commit d9548e5959
37 changed files with 326 additions and 181 deletions

View file

@ -705,6 +705,8 @@ The studio is a plugin like any other: `plugin-designs/plugin-studio/plugin-stud
their browser within seconds, with no rebuild. Add OIDC settings and it puts a "Sign in with *your
provider*" page in front of everything, open only to the groups you allow. Recipe and settings:
[deployment/cloud/](./deployment/cloud/README.md).
Working from your own laptop alongside the team (following the shared branch, the team's PocketBase):
[documentation/HOWTO-join-the-table.md](./documentation/HOWTO-join-the-table.md).
---

View file

@ -28,6 +28,9 @@ async function proxy(req, url, prefix, port) {
Bun.serve({
hostname: '127.0.0.1',
port: 5175,
// No idle cut-off: PocketBase's realtime stream (/pb/api/realtime) sits quiet while someone signs in in the
// popup, and Bun's default (10 s) closed it before the sign-in result could arrive.
idleTimeout: 0,
async fetch(req) {
const url = new URL(req.url)
const p = url.pathname

View file

@ -113,12 +113,12 @@ So it cannot surprise you mid-thought. You can also check that any time at `/api
## The database, and the one thing that surprises people
There are three databases and you only ever touch one.
There are three databases. You work against one of the first two — never the third.
| Where | What is in it | Who touches it |
|---|---|---|
| Your laptop | your own sandbox data | you, freely |
| The shared dev server | the team's shared test data | the team |
| The team's shared one | the team's shared test data | the team — this is usually the default |
| Production | what the public sees | nobody directly |
**You never publish a database.** Not yours, not anyone's. What travels is the *shape* — the tables and
@ -132,12 +132,26 @@ This is deliberate. A database rule that opens something to the public arrives a
read** rather than as a setting somebody clicked at midnight. If you have ever inherited a system where the
live config did not match the repo, you already know why.
**You do not have to set up the database at all.** The first time you run `bun run dev` it downloads and
starts one for you, on your laptop, with its data in `.pb/`. You can open its admin screen from the dev
server at `/api/pb/_/`.
### Which one your laptop talks to
The only time you touch this is if the log says port 8090 is already in use — then set `DX_PB_PORT` to
something else in `.env.local`.
Most teams point every laptop at the **shared** one, so you are all working against the same test data.
Put this in `.env.local`:
```
DX_PB_URL=https://<your team's dev server>/pb
```
You sign in with the same team account you use for everything else — there is no separate password. Ask
whoever set up your team for the address if you do not have it.
**Leave it unset and you get a private one instead.** The first time you run `bun run dev` it downloads and
starts a database on your laptop, with its data in `.pb/`, and you can open its admin screen at
`/api/pb/_/`. That is the fallback, and it is a fine way to work while you are finding your feet.
The only other thing here is `DX_PB_PORT`, which you set only if the log says port 8090 is already in use.
> **New collections start locked.** Your plugin's data is not readable until a migration opens it —
> deliberately, so nothing is public by accident. That migration is a commit like any other.
---

View file

@ -0,0 +1,98 @@
/**
* _composed-tiers.mjs — the ONE place the composition tier is derived from `composes` edges.
*
* Shared on purpose. The generator WRITES this tier into the manifest and check-capability-derived
* CHECKS it, and for a while each held its own copy of the rule. A rule with three ref vocabularies
* and a self-exclusion will not stay identical in two files, and the drift has a specific shape: a
* gate that passes a manifest the generator would refuse to write. One implementation, two callers.
*
* What stays independent is the DATA, which is the half worth duplicating: the generator derives from
* the profiles it is about to emit, the gate rebuilds the same edges from the <profile>.meta.json files
* on disk and feeds them to this function against the PUBLISHED manifest. So a manifest that no longer
* matches its own sources still fails, while the rule itself cannot fork.
*
* Imports nothing — pure over the bundle rows, which is what makes it testable from either side.
*/
/**
* Derive the composition tier from the `composes` edges, and refuse to disagree with an author.
*
* ★ WHY DERIVE AT ALL (the agent, 2026-09-27). Tiers 3-5 were AUTHORED ONLY — discover.mjs infers just
* `single` and `parameterized`, so a composite with no meta.json shipped as capability 1. That is not
* hypothetical: research-dashboard did exactly that while nesting ten views, and the warning in
* detectProfileType exists because of it. A missing file is indistinguishable from a deliberate choice.
*
* THE RULE, measured against all 25 bundles before it was written: a profile that composes anything is
* cap-4 (nested-elements-mfe); if any of the things it composes is itself cap-4, it is cap-5
* (nested-mfe-spa). Keyed per PROFILE, and refs are accepted in BOTH published forms — 'bundle/profile'
* (doxa-maps-spa) and a bare 'bundle' (plugin-studio). Getting either of those wrong is not academic:
* keying on the bundle derived 11 false tiers, and resolving only the slashed form demoted plugin-studio
* from 5 to 4. With both handled: 10 composing profiles, 10 agree, 0 disagree.
*
* AN EXPLICIT type STAYS AUTHORITATIVE AND MUST AGREE. It is not overridden — it is CHECKED. A
* declaration that contradicts the structure is the interesting case: either the meta is stale or the
* composes list is, and both are worth a loud build failure rather than a silent pick between them.
*
* An UNRESOLVED ref is reported separately and never silently treated as "not cap-4", because a typo in
* composes and a genuinely non-composite child look identical from here.
*/
export function deriveComposedTiers(bundles) {
const TIER = { 'nested-mfe-spa': 5, 'nested-elements-mfe': 4, monolithic: 3, parameterized: 2, single: 1 }
const byKey = new Map(), byName = new Map(), byElement = new Map()
const reg = (m, k, bundle, type) => { if (!m.has(k)) m.set(k, []); m.get(k).push([bundle, type || null]) }
for (const b of bundles) {
for (const p of b.profiles || []) {
byKey.set(`${b.bundle}/${p.profile}`, p.type || null)
reg(byName, b.bundle, b.bundle, p.type)
reg(byName, p.profile, b.bundle, p.type)
if (p.element) reg(byElement, p.element, b.bundle, p.type)
}
for (const e of b.elements || []) reg(byElement, e, b.bundle, null)
}
// A name that covers SEVERAL profiles resolves to the HIGHEST tier among them, and both non-slashed
// vocabularies resolve the same way. They have to: a bare bundle name and that bundle's element tag
// both mean "this bundle", so taking the first profile for one and the highest for the other made
// the answer depend on discovery order. gospel-resources is the case that shows it — four `single`
// leaves and one cap-4 composite in one bundle, so "first" is a coin flip between 1 and 4, and
// losing the 4 silently demotes whoever composes it. Highest is also the truthful reading of a
// whole-bundle ref: nesting a bundle nests the most composed thing in it.
const best = (rows, selfBundle) => {
const others = rows.filter(([b, t]) => b !== selfBundle && t)
if (!others.length) return null
return others.sort((a, z) => (TIER[z[1]] || 0) - (TIER[a[1]] || 0))[0][1]
}
// ★ `composes` SPEAKS THREE VOCABULARIES, and only knowing two of them invents defects.
// Measured on the tree: 'bundle/profile' (doxa-maps-spa), a bare 'bundle' (plugin-studio's first four
// entries) and an ELEMENT TAG (its last three, plus big-picture and stack-demo). Resolving only the
// first two left FIVE refs "unresolved" and reported as possible typos — they were all element tags,
// written correctly by their authors. The data was right and the resolver was short.
//
// ★ AND A SELF-REFERENCE IS AN INTERNAL CHILD, NOT A NESTED PLUGIN. big-picture composes
// 'bp-research-header', which is its OWN element (src/components/BpResearchHeader.vue). Resolving that
// to the bundle registering it — itself, cap-4 — made big-picture look like it composes a cap-4 and
// promoted it to cap-5. Excluding self is what keeps "nests other plugins" from meaning "has parts".
const UNRESOLVED = Symbol('unresolved')
const resolve = (ref, selfBundle) => {
if (ref.includes('/')) {
if (!byKey.has(ref)) return UNRESOLVED
return ref.split('/')[0] === selfBundle ? null : byKey.get(ref)
}
if (byName.has(ref)) return best(byName.get(ref), selfBundle)
if (byElement.has(ref)) return best(byElement.get(ref), selfBundle)
return UNRESOLVED
}
const conflicts = [], unresolved = []
for (const b of bundles) for (const p of b.profiles || []) {
const own = p.composesOwn
if (!own || !own.length) continue
const kinds = own.map((ref) => {
const k = resolve(ref, b.bundle)
if (k === UNRESOLVED) unresolved.push(`${b.bundle}/${p.profile} -> ${ref}`)
return k
})
const derived = kinds.some((k) => k === 'nested-elements-mfe') ? 'nested-mfe-spa' : 'nested-elements-mfe'
if (!p.type) { p.type = derived; continue }
if (p.type !== derived) conflicts.push(`${b.bundle}/${p.profile}: declared tier "${p.type}" disagrees with the "${derived}" its composes edges derive`)
}
return { conflicts, unresolved }
}

View file

@ -21,12 +21,15 @@
* - `composes` is PER-PROFILE at source and HOISTED TO THE BUNDLE in the manifest. Deriving from
* the bundle row applies a composite's edges to its plain sibling leaves: gospel-resources has one
* composite and four single leaves, and all four derived as cap-4. 11 false failures.
* - refs appear in TWO FORMS in the same field: 'bundle/profile' and a bare 'bundle'. Resolving
* only the first demoted plugin-studio from 5 to 4.
* - refs appear in THREE FORMS in the same field: 'bundle/profile', a bare 'bundle', and an ELEMENT
* TAG. Resolving only the first demoted plugin-studio from 5 to 4; not knowing the third left five
* refs "unresolved" and reported as possible typos when all five were correct.
* With both handled: 10 composing profiles, 10 agree, 0 disagree, on the tree as it stands.
*
* An UNRESOLVED ref is REPORTED, never counted as "not cap-4": a typo and a genuine non-composite
* child look identical from here, and quietly treating one as the other is how a tier silently drops.
* An UNRESOLVED ref now FAILS. It was only ever REPORTED because five were outstanding and they turned
* out to be correct data this gate could not read — failing then would have blamed five authors for a
* gap here. At zero, the reasoning inverts: a typo and a genuine non-composite child still look
* identical from here, so the one thing that must not happen is quietly reading one as the other.
*
* Headless, no browser. Exit 0 pass · 1 fail.
*/
@ -34,6 +37,7 @@ import { readFileSync, existsSync } from 'node:fs'
import { resolve, dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
import { TREE_NAME } from './_tree-name.mjs'
import { deriveComposedTiers } from './_composed-tiers.mjs'
const TAG = 'CAPABILITY-DERIVED'
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..')
@ -54,36 +58,31 @@ for (const b of bundles) for (const p of b.profiles || []) {
}
// ── 2. a declared tier must agree with the edges it declares ────────────────────────────────────
// Uses the SHARED resolver (internal/_composed-tiers.mjs) rather than a second copy. Two implementations of a rule this
// fiddly — three ref vocabularies and a self-exclusion — would drift, and the drift would show up as a
// gate that passes a manifest the generator would refuse to write. What stays independent is the DATA:
// the gate rebuilds composesOwn from the <profile>.meta.json files on disk and checks the PUBLISHED
// manifest against them, so a manifest that no longer matches its own sources still fails.
const readMeta = (bundle, profile) => {
const f = join(ROOT, 'plugin-designs', bundle, `${profile}.meta.json`)
try { return existsSync(f) ? JSON.parse(readFileSync(f, 'utf8')) : null } catch { return null }
}
const byKey = new Map(), byName = new Map()
for (const b of bundles) for (const p of b.profiles || []) {
byKey.set(`${b.bundle}/${p.profile}`, p.type || null)
if (!byName.has(b.bundle)) byName.set(b.bundle, p.type || null)
if (!byName.has(p.profile)) byName.set(p.profile, p.type || null)
}
const resolveRef = (ref) => (ref.includes('/') ? byKey.get(ref) : byName.get(ref))
const unresolved = []
let composing = 0
for (const b of bundles) for (const p of b.profiles || []) {
const meta = readMeta(b.bundle, p.profile)
const own = Array.isArray(meta?.composes) ? meta.composes.map(String).filter(Boolean) : []
if (!own.length) continue
composing++
const kinds = own.map((ref) => { const k = resolveRef(ref); if (k === undefined) unresolved.push(`${b.bundle}/${p.profile} -> ${ref}`); return k })
const derived = kinds.some((k) => k === 'nested-elements-mfe') ? 'nested-mfe-spa' : 'nested-elements-mfe'
if (p.type !== derived) {
fails.push(`${b.bundle}/${p.profile}: declares "${p.type}" but its own composes edges derive "${derived}" — one of the two is stale.`)
}
}
const probe = bundles.map((b) => ({
...b,
profiles: (b.profiles || []).map((p) => {
const meta = readMeta(b.bundle, p.profile)
const own = Array.isArray(meta?.composes) ? meta.composes.map(String).filter(Boolean) : []
if (own.length) composing++
return { ...p, composesOwn: own.length ? own : null }
}),
}))
const { conflicts, unresolved } = deriveComposedTiers(probe)
for (const c of conflicts) fails.push(`${c} — the meta.json or the composes list is stale.`)
for (const u of unresolved) fails.push(`${u}: composes ref resolves to nothing. A ref may be "<bundle>/<profile>", a bare "<bundle>", or a registered element tag.`)
console.log(` · ${checked} profile(s) across ${bundles.length} bundle(s); ${composing} declare composes edges`)
if (unresolved.length) {
console.log(` · ${unresolved.length} composes ref(s) resolve to no known bundle/profile. Reported, NOT treated as "not a composite" — a typo and a plain child look the same from here:`)
for (const u of unresolved) console.log(` ${u}`)
}
if (fails.length) {
console.error(`\n${TAG}: FAIL`)
for (const f of fails) console.error(` ✗ ${f}`)

View file

@ -0,0 +1,32 @@
#!/usr/bin/env node
/**
* check-no-repo-pb-hooks.mjs — no PocketBase hooks (pb_hooks, *.pb.js) may live in the repo.
*
* WHY: the cloud container pulls this repo every few seconds. A PocketBase hook is server-side JS; one pushed
* by any plugin writer would run on the team backend within seconds, which is the rogue-writer hole the
* roundtable test closed. The container never points PocketBase at the repo (--hooksDir is outside the
* pulled tree; the one team sign-in hook is baked into the image and pinned, deployment/cloud/Dockerfile).
* This gate keeps anyone from adding a hooks folder that LOOKS like it would run, or that a later recipe
* change could start running.
*
* HOW: every tracked path; a self-test on every run (a poisoned list must fail), so the gate cannot go blind.
*/
import { execFileSync } from 'node:child_process'
import { join, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
const ROOT = process.env.DOXA_REPO || join(dirname(fileURLToPath(import.meta.url)), '..')
export const offending = (paths) => paths.filter((p) => /(^|\/)pb_hooks(\/|$)/.test(p) || /\.pb\.(js|ts)$/.test(p))
if (offending(['README.md', 'backend/pocketbase/pb_hooks/x.pb.js', 'a/b.pb.ts']).length !== 2) {
console.error('✗ check:no-repo-pb-hooks self-test failed: the matcher went blind'); process.exit(1)
}
const tracked = execFileSync('git', ['ls-files', '-z'], { cwd: ROOT }).toString().split('\0').filter(Boolean)
const bad = offending(tracked)
if (bad.length) {
console.error(`✗ PocketBase hooks in the repo (server-side JS must never ride the live pull):\n${bad.map((p) => ' ' + p).join('\n')}`)
console.error(' The team sign-in hook is baked into the image (deployment/cloud/Dockerfile); anything else needs a design review.')
process.exit(1)
}
console.log(`✓ no PocketBase hooks among ${tracked.length} tracked files`)

View file

@ -57,6 +57,16 @@ const BUNDLES = [
'upg-neighbor', 'wall-of-people-groups', 'key-cities', 'gospel-internet',
]
const ALLOW = {
'*:LOC-ENUS:library/utils/formatCount.js':
'HELD DECISION, and this file IS the decision: formatCount() is the one place the count locale is '
+ 'chosen, so COUNT_LOCALE = \'en-US\' is the policy written down rather than a bundle ignoring the '
+ 'reader. NUMERALS ARE HELD -- counts do not follow the locale -- and folding every dashboard onto '
+ 'this constant is what makes that auditable in one line instead of scattered across eight call '
+ 'sites. Bundle-wildcarded ON PURPOSE: the alternative is one entry per importer, so the LOCALE '
+ 'column warns every time a bundle adopts the shared helper -- punishing the fix and teaching '
+ 'people to stop reading the column. Restricted to library/ (see the lookup): no per-bundle source '
+ 'can be wildcarded, and a new toLocaleString(\'en-US\') inside research-dashboard or '
+ 'people-groups-grid still warns. Revisit only if the agent unholds numerals.',
'prayer-walk-planner:ENG-PIN': 'keyless by design: always MapLibre, needs no token (index.js header)',
'regions-dashboard:LOC-ENUS:plugin-designs/regions-dashboard/src/RegionCountryMap.vue':
'HELD DECISION, not an oversight: the map popup formats population as fixed en-US on purpose. '
@ -175,6 +185,15 @@ if (locWrong.length) {
+ locWrong.map(([f, l]) => `${f ? 'missed' : 'false-flagged'}: ${l.slice(0, 56)}`).join(' | '))
process.exit(3)
}
// The bundle-wildcard is honoured ONLY under library/. Pinned because the failure is silent: widen it
// to any path and one entry could clear the column for a bundle's own source.
const wildcardKeys = Object.keys(ALLOW).filter((k) => k.startsWith('*:'))
const badWildcard = wildcardKeys.filter((k) => !k.split(':').slice(2).join(':').startsWith('library/'))
if (badWildcard.length) {
console.error('UNIVERSAL-PROPS: SELF-TEST FAILED — a `*:RULE:file` ALLOW entry outside library/ would '
+ 'never be honoured by the lookup, so it silently exempts nothing: ' + badWildcard.join(', '))
process.exit(3)
}
if (missed.length || falsePos.length) {
console.error(`UNIVERSAL-PROPS: SELF-TEST FAILED — ${missed.length ? 'rules blind to a planted bypass: ' + missed.join(', ') : ''}${falsePos.length ? ' false positives on clean code: ' + falsePos.join(', ') : ''}`)
process.exit(3)
@ -251,7 +270,16 @@ for (const b of BUNDLES.filter((x) => !ONLY || ONLY.includes(x))) {
// silenced any FUTURE operative en-US anywhere in that bundle -- clearing a column by going
// blind. A `bundle:RULE:file` key exempts the one file that earned it and leaves the rest of the
// bundle answerable.
const allowed = ALLOW[`${b}:${r.id}:${relative(ROOT, f)}`] || ALLOW[`${b}:${r.id}`]
// ★ AND A SHARED LIBRARY FILE CAN BE ALLOWED FOR EVERY BUNDLE THAT IMPORTS IT. A `*:RULE:file`
// key is honoured only for a path under library/, because that is the one case where the site is
// not the bundle's: library/utils/formatCount.js holds the HELD numerals decision for eight call
// sites, and it is attributed to every bundle that compiles it. Per-importer entries would mean
// the LOCALE column warns each time a bundle adopts the shared helper -- the column punishing the
// fold that made the policy auditable. The library/ restriction is the whole guard: a bundle's own
// source can never be wildcarded, so this cannot be used to clear a column broadly.
const rel = relative(ROOT, f).replace(/\\/g, '/')
const allowed = ALLOW[`${b}:${r.id}:${rel}`] || ALLOW[`${b}:${r.id}`]
|| (rel.startsWith('library/') ? ALLOW[`*:${r.id}:${rel}`] : undefined)
if (allowed) { if (matrix[b][r.prop] === 'ok') matrix[b][r.prop] = 'allowed'; continue }
findings.push({ b, rule: r.id, prop: r.prop, warn: !!r.warn, where: `${relative(ROOT, f)}:${lineOf(src, idx)}`, text: src.slice(idx, idx + 70).replace(/\s+/g, ' ').trim() })
matrix[b][r.prop] = r.warn ? (matrix[b][r.prop] === 'BYPASS' ? 'BYPASS' : 'warn') : 'BYPASS'

View file

@ -46,6 +46,7 @@ import { createHash } from 'node:crypto'
import { detectProfileType } from './plugin-gallery/discover.mjs'
import { profileMetaFields, bundleStage } from './profile-meta.mjs'
import { TREE_NAME as CONFIGURED_TREE_NAME } from './_tree-name.mjs'
import { deriveComposedTiers } from './_composed-tiers.mjs'
import { syncAppShells } from './sync-app-shells.mjs'
const __dirname = dirname(fileURLToPath(import.meta.url))
@ -396,48 +397,6 @@ function composesAMapLeaf(dir, profileName, file) {
* composesAMapLeaf reads (see its point 1) but returns the author's data itself rather than
* a map-ness boolean derived from it — the manifest needs the edges, not just the verdict.
*/
/**
* Derive the composition tier from the `composes` edges, and refuse to disagree with an author.
*
* ★ WHY DERIVE AT ALL (the agent, 2026-09-27). Tiers 3-5 were AUTHORED ONLY — discover.mjs infers just
* `single` and `parameterized`, so a composite with no meta.json shipped as capability 1. That is not
* hypothetical: research-dashboard did exactly that while nesting ten views, and the warning in
* detectProfileType exists because of it. A missing file is indistinguishable from a deliberate choice.
*
* THE RULE, measured against all 25 bundles before it was written: a profile that composes anything is
* cap-4 (nested-elements-mfe); if any of the things it composes is itself cap-4, it is cap-5
* (nested-mfe-spa). Keyed per PROFILE, and refs are accepted in BOTH published forms — 'bundle/profile'
* (doxa-maps-spa) and a bare 'bundle' (plugin-studio). Getting either of those wrong is not academic:
* keying on the bundle derived 11 false tiers, and resolving only the slashed form demoted plugin-studio
* from 5 to 4. With both handled: 10 composing profiles, 10 agree, 0 disagree.
*
* AN EXPLICIT type STAYS AUTHORITATIVE AND MUST AGREE. It is not overridden — it is CHECKED. A
* declaration that contradicts the structure is the interesting case: either the meta is stale or the
* composes list is, and both are worth a loud build failure rather than a silent pick between them.
*
* An UNRESOLVED ref is reported separately and never silently treated as "not cap-4", because a typo in
* composes and a genuinely non-composite child look identical from here.
*/
export function deriveComposedTiers(bundles) {
const byKey = new Map(), byBundle = new Map()
for (const b of bundles) for (const p of b.profiles || []) {
byKey.set(`${b.bundle}/${p.profile}`, p.type || null)
if (!byBundle.has(b.bundle)) byBundle.set(b.bundle, p.type || null)
if (!byBundle.has(p.profile)) byBundle.set(p.profile, p.type || null)
}
const resolve = (ref) => (ref.includes('/') ? byKey.get(ref) : byBundle.get(ref))
const conflicts = [], unresolved = []
for (const b of bundles) for (const p of b.profiles || []) {
const own = p.composesOwn
if (!own || !own.length) continue
const kinds = own.map((ref) => { const k = resolve(ref); if (k === undefined) unresolved.push(`${b.bundle}/${p.profile} -> ${ref}`); return k })
const derived = kinds.some((k) => k === 'nested-elements-mfe') ? 'nested-mfe-spa' : 'nested-elements-mfe'
if (!p.type) { p.type = derived; continue }
if (p.type !== derived) conflicts.push(`${b.bundle}/${p.profile}: meta.json declares "${p.type}" but its composes edges derive "${derived}"`)
}
return { conflicts, unresolved }
}
function readComposes(dir, profileName) {
try {
const metaPath = join(dir, `${profileName}.meta.json`)
@ -1415,9 +1374,15 @@ function writeManifestAndHtml(root, bundles, tokenUrlExpr, bakedToken) {
// author forgot a meta.json, and a stale meta can no longer disagree with the structure in silence.
{
const { conflicts, unresolved } = deriveComposedTiers(bundles)
// FAILS rather than warns, now that the resolver understands all three vocabularies and the tree has
// ZERO unresolved refs. While five were outstanding a warning was right — they turned out to be
// correct data my resolver could not read, and failing would have blamed five authors for my gap.
// With the count at 0, a new unresolved ref is a genuinely broken edge and silently weakens a tier.
if (unresolved.length) {
console.warn(`[tree] ${unresolved.length} composes ref(s) resolve to no known bundle/profile — a typo here silently weakens a tier:`)
for (const u of unresolved) console.warn(` ${u}`)
console.error(`[tree] ${unresolved.length} composes ref(s) resolve to nothing — a broken edge silently weakens a tier:`)
for (const u of unresolved) console.error(` ${u}`)
console.error(' A ref may be "<bundle>/<profile>", a bare "<bundle>", or a registered element tag.')
process.exit(1)
}
if (conflicts.length) {
console.error('[tree] composition tier CONFLICT — a profile\'s meta.json disagrees with its own composes edges:')

View file

@ -352,14 +352,14 @@ const VTL_SHADOW_CSS = `
.vtl-chev svg { width:15px; height:15px; }
.vtl-chev.open { transform:rotate(90deg); }
.vtl-rows { display:flex; flex-direction:column; gap:1px; }
/* MATERIAL NAV-ROW METRICS (2026-09-21). the agent: "people are used to the YouTube layout, Google
layout is just way better. We do not need to create custom styles people are not used to."
/* MATERIAL NAV-ROW METRICS (2026-09-21). Product decision: follow the familiar
Material/YouTube list layout rather than custom styling readers are not used to.
Measured before this change: 44px rows with an 8px radius.
min-height:48px the Material list-item height. min-height, not height, so a wrapping
label still grows instead of clipping.
border-radius var(--vtl-radius,8px) — SUPERSEDED THE FULL PILL (2026-09-23).
The 999px stadium above was a real instruction ("imitate the YouTube
active row") and it shipped. The agent then measured it against the
active row") and it shipped. It was then measured against the
rest of the product and reversed it: "the roundedness of the tabs is a
little bit too round because there is nowhere else in the app that has
that same roundedness. Even the collapse button is not that round...
@ -841,14 +841,14 @@ export default defineComponent({
.vtl-chev svg { width:15px; height:15px; }
.vtl-chev.open { transform:rotate(90deg); }
.vtl-rows { display:flex; flex-direction:column; gap:1px; }
/* MATERIAL NAV-ROW METRICS (2026-09-21). the agent: "people are used to the YouTube layout, Google
layout is just way better. We do not need to create custom styles people are not used to."
/* MATERIAL NAV-ROW METRICS (2026-09-21). Product decision: follow the familiar
Material/YouTube list layout rather than custom styling readers are not used to.
Measured before this change: 44px rows with an 8px radius.
min-height:48px the Material list-item height. min-height, not height, so a wrapping
label still grows instead of clipping.
border-radius var(--vtl-radius,8px) — SUPERSEDED THE FULL PILL (2026-09-23).
The 999px stadium above was a real instruction ("imitate the YouTube
active row") and it shipped. The agent then measured it against the
active row") and it shipped. It was then measured against the
rest of the product and reversed it: "the roundedness of the tabs is a
little bit too round because there is nowhere else in the app that has
that same roundedness. Even the collapse button is not that round...

View file

@ -137,7 +137,7 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null })
.pg-h1{margin:2px 0 0;font:700 40px Georgia,serif;color:#1b1a17}
.pg-lede{margin:0 0 22px;max-width:1180px;font:400 19px/1.5 Georgia,serif;color:#413d35}
/* ⚠ THE CELLS ARE RECTANGLES, NOT SQUARES, and that is forced by the sheet rather than chosen.
52 columns is fixed by the data (weeks in a year) and 100 rows by the agent's "100 year life",
52 columns is fixed by the data (weeks in a year) and 100 rows by the product's "100 year life" framing,
so both dimensions are given and only the SHAPE is free. Squares would need
(1380/52)=26.5px per side x 100 rows = 2,654px of grid in 1,521px of printable height — it
overflows the page by 1.7x. Caught by computing the height before rendering rather than by
@ -169,7 +169,7 @@ export function createPacketRenderer({ strings, lang = 'en', fontData = null })
justify-content:center;font:italic 13px Georgia,serif;color:#a89f8c;text-align:center;padding:6px}
.nm{font:700 25px Georgia,serif;color:#1b1a17;line-height:1.1}
.mt{font:400 17px Georgia,serif;color:#6d766e}
/* FINE PRINT — the agent: "attribution minimal, fine print small". */
/* FINE PRINT — product decision: attribution minimal, fine print small. */
.fine{position:absolute;left:0;right:0;bottom:22px;text-align:center;
font:400 13px Georgia,serif;color:#a89f8c}
/* PRINT. The sheet is authored at ${W}px wide while @page is physical, so without

View file

@ -2,7 +2,7 @@
"_meta": {
"purpose": "EVERY human-readable string in the UPG-100 prayer packet, in one file, so a new language is a new block here and NOT a code change. packet.mjs reads LANG (default 'en') and falls back to 'en' key-by-key, so a partial translation renders the translated keys and leaves the rest in English rather than blanking.",
"how_to_translate": "Copy the \"en\" block, change the key to the ISO code, translate the values. Keep {placeholders} exactly as they are — they are substituted at render time. Do not translate scripture REFERENCES (book names are resolved by the reader's own Bible); DO translate the prayer text.",
"note_on_scripture": "point4_passage is the ONLY full scripture text in the packet (Mark 5:1-20, printed in full at the agent's instruction). A translation MUST supply its own rendering in a public-domain or properly-licensed version FOR THAT LANGUAGE. ⚠ Do NOT translate it yourself and do NOT leave a machine rendering in place: this is printed scripture in a prayer packet. A language block that omits point4_passage falls back to the English WEB text per-key, which is honest — an untrusted translation of Mark 5 is not.",
"note_on_scripture": "point4_passage is the ONLY full scripture text in the packet (Mark 5:1-20, printed in full by product decision). A translation MUST supply its own rendering in a public-domain or properly-licensed version FOR THAT LANGUAGE. ⚠ Do NOT translate it yourself and do NOT leave a machine rendering in place: this is printed scripture in a prayer packet. A language block that omits point4_passage falls back to the English WEB text per-key, which is honest — an untrusted translation of Mark 5 is not.",
"note_on_references": "Scripture REFERENCES (Matthew 27:27, Mark 5:1-20) are deliberately left in English in every language block, so a reader can look them up in their own Bible regardless of the packet's language. ⚠ MEASURED TRADEOFF, not an oversight: on a rendered French page the English book names are visibly foreign next to fully-translated prayer text. If a language wants localised book names, add a `books` map to that block and teach the renderer to use it — do NOT translate the refs inline, because the same strings identify the passage for any future lookup.",
"note_on_scripts": "ALL 11 app locales now ship. Script coverage MEASURED by rendering at 48px and READING THE PIXELS: Latin, Cyrillic (ru), Arabic (ar) and CJK (zh) shape correctly with the system Georgia/Palatino/serif stack. DEVANAGARI (hi) does NOT — it renders as tofu boxes — so Noto Serif Devanagari is vendored (OFL) and base64-INLINED into hi packets by the renderer's SCRIPT_FONT map. Inlined, not linked, because a packet is a standalone file that must print offline; ~165KB on a 3.5MB packet, and only for that language. mr and ne map to the same face.\n⚠ TWO MEASUREMENTS LIED ABOUT THIS, so do not automate it cheaply: (1) comparing shaped width against a missing font reported ar and zh BROKEN and hi FINE — exactly backwards, because Devanagari tofu boxes match real glyph advance; (2) an ink-column-profile heuristic scored CORRECTLY-RENDERED Devanagari the same as tofu (3 vs 2 distinct heights), because its baseline bar gives a uniform profile. check:packet-render therefore asserts only that a DECLARED @font-face LOADED — the mechanical half — and leaves glyph correctness to a human reading a screenshot. A detector that blocks working packets is worse than none.",
"note_on_rtl": "ar is right-to-left. The renderer emits dir on <html> from an RTL set (packet-render.js), and scripture REFERENCES are wrapped in dir=ltr + unicode-bidi:isolate. Without that isolation the bidi algorithm reorders a reference that STARTS WITH A DIGIT: '1 Peter 5:6-11' rendered as 'Peter 5:6-11 1'. Note the reference LIST then reads right-to-left on an RTL page (first item rightmost) — that is correct for an RTL reader, not a defect."

View file

@ -168,6 +168,7 @@
"check:one-palette:self-test": "node internal/check-one-palette.mjs --self-test",
"check:optional-t-equivalence": "node internal/check-optional-t-equivalence.mjs",
"check:package-json-unique-keys": "node internal/check-package-json-unique-keys.mjs",
"check:no-repo-pb-hooks": "node internal/check-no-repo-pb-hooks.mjs",
"check:packet-browser": "node internal/check-packet-browser.mjs",
"check:packet-fixture": "node internal/generate-packet-fixture.mjs --check",
"check:packet-render": "node internal/check-packet-render.mjs",
@ -247,7 +248,7 @@
"fix:sri": "node internal/fix-sri.mjs",
"gallery": "node internal/generate-gallery.mjs",
"gates:post": "node internal/run-parallel.mjs --label=post -- check:capability-derived check:drop check:parse verify check:sri check:public-hygiene check:label-joins check:facet-cascade check:facet-one-field check:heartbeat check:kpi-unit check:composite-reg check:descriptions check:no-abs-paths check:no-codename check:dep-names check:composite-srcs check:embed-targets check:nested-token check:i18n-parity check:tabs-localized check:packets-all check:packet-strings-parity check:zone-census check:zoning-declared check:share-policy check:library-index check:csv-shape check:capability-citations check:catalog-identity check:no-orphan-gates check:quoted-scripts check:done-evidence check:script-flags check:backlog-status check:capability-exemplars check:packet-fixture check:packet-browser check:provider-switch check:locale-reachable check:url-resolver check:manifest-covers check:one-palette check:pin-dim-slider check:legend-source check:backlog-refs check:clustering-modes check:composite-embed-knobs check:composite-locale-leaks check:linked-vocabulary check:wp-embed check:dashboard-geocoder-provider check:leaf-engine-per-provider check:map-props-unit check:composites-mount check:composite-interop check:no-free-identifiers check:map-fly-reduced-motion check:mst-clustering check:list-prop-unit check:profiles-mount check:cdn-pins check:no-eval check:popup-escaping check:i18n-treeshake check:pinned-umd check:one-palette:self-test check:no-cross-plugin-imports check:no-cross-plugin-imports:self-test check:map-attribution check:studio-rail check:approx-pin-note check:embedder-keys check:provider-for check:legend-logical-insets check:legend-logical-insets:self-test check:optional-t-equivalence check:text-highlight check:religion-label-not-value check:i18n-stopped-scope check:no-silent-engine check:regions-uses-library check:shadow-css-parses check:square-map-controls",
"gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:doc-scripts check:setup-order check:package-json-unique-keys check:no-credentials-omit check:no-credentials-omit:self-test check:shadow-reduced-motion",
"gates:pre": "node internal/run-parallel.mjs --label=pre -- check:template-literal check:mjs-parse check:sfc-parse check:tab-radius check:synced-css check:doc-scripts check:setup-order check:package-json-unique-keys check:no-repo-pb-hooks check:no-credentials-omit check:no-credentials-omit:self-test check:shadow-reduced-motion",
"gen:iso3-to-alpha2": "node library/scripts/generate-iso3-to-alpha2.mjs",
"internet:adm1": "node plugin-designs/cities-internet/scripts/build-adm1-internet.mjs",
"library-index": "node internal/generate-library-index.mjs",
@ -395,6 +396,7 @@
"check:no-silent-engine": "A profile must NEVER fall back to a different map engine than its provider asked for. `engineGlobal(provider) || window.mapboxgl` looks defensive and is not: engineGlobal already returns the right global for the requested provider (useMapInstance.js:115 falls back to mapbox's NAME only for an UNKNOWN provider, never a missing engine), so the || fires in exactly one case — the page asked for maplibre and maplibre failed to load — and hands back the TOKEN-GATED engine to a page that asked for the KEYLESS one. Worse, accessToken is gated on !isMaplibre, so the substitute arrives WITHOUT a token: 401s on every tile instead of a legible failure. Found by regions' C3 read 2026-09-26; 2 offenders remained (cities-internet, gospel-resources) after my-upg-100-list was fixed. NOT a duplicate of check:leaf-engine-per-provider / check:provider-switch / check:auto-engine — all three assert the HAPPY path (what loads) and this bug only appears when something does NOT load, so all three were green while it existed. A SOURCE check on purpose: reproducing it live means serving a leaf with MapLibre deliberately blocked, spending a browser slot on what a grep decides. Exits 75 when no file calls engineGlobal — 'found nothing' is not 'found nothing wrong'. Run :self-test to prove the pattern still matches.",
"check:optional-t-equivalence": "C4's shared guarded translator (library/composables/useOptionalT.js) must behave like the twenty hand-written try{useI18n()}catch blocks it replaces: all three host states, and the per-site register asserts each migrated file still passes ITS OWN fallback rather than inheriting the catalogue, because routing them through tStatic would change what seven bare-host bundles render. EVERY LATER C4 WAVE APPENDS A ROW. Extract-and-executes the module source, since useOptionalT imports vue-i18n and an i18n index that calls import.meta.glob.",
"check:package-json-unique-keys": "no object in package.json may carry the same key twice: JSON.parse keeps the last silently, so a duplicate kills the first entry while every gate that reads the PARSED object passes (a //scripts note sat twice after a merge). A small scanner tracks keys per object; its self-test runs every time.",
"check:no-repo-pb-hooks": "no PocketBase hooks (pb_hooks/, *.pb.js) in the repo: the cloud container pulls it live, so a pushed hook would be server-side JS from any writer; the one team sign-in hook is baked into the image",
"check:packet-browser": "the packet the READER gets — the legend's Export > Prayer packet path, proving the shared renderer runs in a BROWSER. Asserts the same 12 points / 12 wheel labels / page-1 geography / print layer as check:packet-render, which it did not until 2026-09-24. CONDITIONAL: SKIPs without a server over the repo root (python3 -m http.server 4898) and a reachable records API.",
"check:packet-fixture": "the committed fixture must still match clusters.json and must never carry image_url (CI would fetch 43 photos from someone else's CDN).",
"check:packet-render:expect-funnel": "check:packet-render with the page-2 FUNNEL declared REQUIRED. Exists because of a real near-miss: a merge resolved with `git checkout --ours` deleted the printPacket call site that supplies the funnel data (60 lines) and EVERY GATE STAYED GREEN — it had to, because the funnel page is OPTIONAL by design (buildPacket omits it when the arg is null), so a packet without page 2 is not malformed, just smaller. Always requiring it would be the wrong fix: the 11 pre-funnel laos packets and any host with no funnel data would go red, and a false red costs as much as a false green. So the CALLER, which knows whether this packet was built with funnel data, declares it — an absence is then either declared (no flag) or a failure (flag passed, page missing), never a silent nothing. Pass it for any packet from a profile that wires packetFunnel(). Browser gate.",

View file

@ -1,6 +1,7 @@
<script setup>
import { dataUrl, glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
import { usePplrT } from '../composables/usePplrT.js'
import { formatCount } from '@map/utils/formatCount.js' // counts stay fixed en-US: numerals are held for the agent
import { tStatic } from '@map/i18n/index.js'
/**
* pplr-coverage.vue — Country choropleth: avg # of locales filled per PG in that country.
@ -126,7 +127,7 @@ onMounted(async () => {
new (glFor(map.value)).Popup({ maxWidth: '320px' })
.setLngLat(f.geometry.coordinates).setHTML(popupForPG(f.properties)).addTo(map.value)
})
status.value = t('pplr.status.readyCoverage', { countries: countryStats.size, rows: [...countryStats.values()].reduce((n, c) => n + c.pgCount, 0).toLocaleString('en-US') })
status.value = t('pplr.status.readyCoverage', { countries: countryStats.size, rows: formatCount([...countryStats.values()].reduce((n, c) => n + c.pgCount, 0)) })
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
await whenGeojsonDrawn(map.value)
dataReady.value = true

View file

@ -7,6 +7,7 @@
import { inject, onMounted, onBeforeUnmount, ref } from 'vue'
import { glFor, exposeMap, whenGeojsonDrawn } from '../utils/pplrData.js'
import { usePplrT } from '../composables/usePplrT.js'
import { formatCount } from '@map/utils/formatCount.js' // counts stay fixed en-US: numerals are held for the agent
import { tStatic } from '@map/i18n/index.js'
import { useMapInstance } from '@map/composables/useMapInstance.js'
import { addCountryPolygons, addPGPoints, popupForPG, POPUP_CSS } from '../utils/pplrMap.js'
@ -58,7 +59,7 @@ onMounted(async () => {
.setHTML(popupForPG(f.properties))
.addTo(map.value)
})
status.value = t('pplr.status.readyPins', { pins: fc.features.length.toLocaleString('en-US') })
status.value = t('pplr.status.readyPins', { pins: formatCount(fc.features.length) })
// keep the LoadingGlobe up until the pins are actually drawn, not merely added
await whenGeojsonDrawn(map.value)
dataReady.value = true

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -32,7 +32,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -47,7 +47,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <country-posters-map> custom element. -->
<script src="../country-posters.js" integrity="sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML" crossorigin="anonymous"></script>
<script src="../country-posters.js" integrity="sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -98,14 +98,14 @@
.vtl-chev svg { width:15px; height:15px; }
.vtl-chev.open { transform:rotate(90deg); }
.vtl-rows { display:flex; flex-direction:column; gap:1px; }
/* MATERIAL NAV-ROW METRICS (2026-09-21). the agent: "people are used to the YouTube layout, Google
layout is just way better. We do not need to create custom styles people are not used to."
/* MATERIAL NAV-ROW METRICS (2026-09-21). Product decision: follow the familiar
Material/YouTube list layout rather than custom styling readers are not used to.
Measured before this change: 44px rows with an 8px radius.
min-height:48px the Material list-item height. min-height, not height, so a wrapping
label still grows instead of clipping.
border-radius var(--vtl-radius,8px) — SUPERSEDED THE FULL PILL (2026-09-23).
The 999px stadium above was a real instruction ("imitate the YouTube
active row") and it shipped. The agent then measured it against the
active row") and it shipped. It was then measured against the
rest of the product and reversed it: "the roundedness of the tabs is a
little bit too round because there is nowhere else in the app that has
that same roundedness. Even the collapse button is not that round...

View file

@ -32,7 +32,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
<script src="../../doxa-maps-spa.js" integrity="sha384-PNd2QYytXnHHGBEvXVjgoA93Owlm7Nnji5tJeBP81rq2merTNg2pSfFwt19x1AMJ" crossorigin="anonymous"></script>
<script src="../../doxa-maps-spa.js" integrity="sha384-rLTDkqumxtv1rDoCpF7Gubflil8YbosAnEN741ue/oml2btEkGBJrHoLcERx3Iiw" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -32,7 +32,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <doxa-maps-spa> custom element. -->
<script src="../doxa-maps-spa.js" integrity="sha384-PNd2QYytXnHHGBEvXVjgoA93Owlm7Nnji5tJeBP81rq2merTNg2pSfFwt19x1AMJ" crossorigin="anonymous"></script>
<script src="../doxa-maps-spa.js" integrity="sha384-rLTDkqumxtv1rDoCpF7Gubflil8YbosAnEN741ue/oml2btEkGBJrHoLcERx3Iiw" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -165,7 +165,7 @@
"bundle": "country-posters",
"scriptUrl": "./country-posters/country-posters.js",
"output": "dx-maps/country-posters/country-posters.js",
"integrity": "sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML",
"integrity": "sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ",
"elements": [
"country-posters-map"
],
@ -187,7 +187,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/countries-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -202,7 +202,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -217,7 +217,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-posters-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
}
]
@ -317,7 +317,7 @@
"bundle": "doxa-maps-spa",
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"output": "dx-maps/doxa-maps-spa/doxa-maps-spa.js",
"integrity": "sha384-PNd2QYytXnHHGBEvXVjgoA93Owlm7Nnji5tJeBP81rq2merTNg2pSfFwt19x1AMJ",
"integrity": "sha384-rLTDkqumxtv1rDoCpF7Gubflil8YbosAnEN741ue/oml2btEkGBJrHoLcERx3Iiw",
"elements": [
"doxa-maps-spa"
],
@ -344,7 +344,7 @@
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"embed": {
"iframe": "<iframe src=\"./doxa-maps-spa/doxa-maps-spa/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-PNd2QYytXnHHGBEvXVjgoA93Owlm7Nnji5tJeBP81rq2merTNg2pSfFwt19x1AMJ\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-rLTDkqumxtv1rDoCpF7Gubflil8YbosAnEN741ue/oml2btEkGBJrHoLcERx3Iiw\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
},
"instances": [
{
@ -814,7 +814,7 @@
"bundle": "my-upg-100-list",
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"output": "dx-maps/my-upg-100-list/my-upg-100-list.js",
"integrity": "sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i",
"integrity": "sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l",
"elements": [
"my-upg-100-list-map"
],
@ -836,7 +836,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -851,7 +851,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -866,7 +866,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
}
]
@ -938,7 +938,7 @@
"bundle": "plugin-studio",
"scriptUrl": "./plugin-studio/plugin-studio.js",
"output": "dx-maps/plugin-studio/plugin-studio.js",
"integrity": "sha384-8qq9TrPab9dfj4aHBbSMKj2dwCzyuH2gA2xGq4YhK4GNEy38/uVVmeEhJIXiEr1e",
"integrity": "sha384-TIIWS9puN8S1tAFHIeIOLIWlWADIW9lxmKLv2M+BKWGp7yjd/dVcpjU41RfH77WD",
"elements": [
"plugin-studio"
],
@ -968,7 +968,7 @@
"scriptUrl": "./plugin-studio/plugin-studio.js",
"embed": {
"iframe": "<iframe src=\"./plugin-studio/plugin-studio/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-8qq9TrPab9dfj4aHBbSMKj2dwCzyuH2gA2xGq4YhK4GNEy38/uVVmeEhJIXiEr1e\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-TIIWS9puN8S1tAFHIeIOLIWlWADIW9lxmKLv2M+BKWGp7yjd/dVcpjU41RfH77WD\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
},
"instances": [
{
@ -995,7 +995,7 @@
"bundle": "pplr-data-maps",
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
"output": "dx-maps/pplr-data-maps/pplr-data-maps.js",
"integrity": "sha384-HyV8R97czSk4eeg7lOFsB9NePlf3dJ7N0q6wlX0fKY1Zf0ner2lZ+QRwsHjRELVv",
"integrity": "sha384-01tSl+RnPCA0oGugtwlOJb+TBg01zGbmgF/Dpf5qHu/Ok/eFNzFG027mEM4crbT7",
"elements": [
"pplr-data-maps"
],
@ -1013,7 +1013,7 @@
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
"embed": {
"iframe": "<iframe src=\"./pplr-data-maps/pplr-data-maps/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-HyV8R97czSk4eeg7lOFsB9NePlf3dJ7N0q6wlX0fKY1Zf0ner2lZ+QRwsHjRELVv\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-01tSl+RnPCA0oGugtwlOJb+TBg01zGbmgF/Dpf5qHu/Ok/eFNzFG027mEM4crbT7\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
},
"bundle": "pplr-data-maps"
}
@ -1050,7 +1050,7 @@
"bundle": "regions-dashboard",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"output": "dx-maps/regions-dashboard/regions-dashboard.js",
"integrity": "sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z",
"integrity": "sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X",
"elements": [
"regions-dashboard"
],
@ -1072,7 +1072,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/region-dashboards/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1087,7 +1087,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1102,7 +1102,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
}
]

View file

@ -19,6 +19,6 @@
</head>
<body>
<plugin-studio tree-base="."></plugin-studio>
<script src="./plugin-studio/plugin-studio.js" integrity="sha384-8qq9TrPab9dfj4aHBbSMKj2dwCzyuH2gA2xGq4YhK4GNEy38/uVVmeEhJIXiEr1e" crossorigin="anonymous"></script>
<script src="./plugin-studio/plugin-studio.js" integrity="sha384-TIIWS9puN8S1tAFHIeIOLIWlWADIW9lxmKLv2M+BKWGp7yjd/dVcpjU41RfH77WD" crossorigin="anonymous"></script>
</body>
</html>

View file

@ -165,7 +165,7 @@
"bundle": "country-posters",
"scriptUrl": "./country-posters/country-posters.js",
"output": "dx-maps/country-posters/country-posters.js",
"integrity": "sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML",
"integrity": "sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ",
"elements": [
"country-posters-map"
],
@ -187,7 +187,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/countries-map/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"countries-map\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -202,7 +202,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
},
{
@ -217,7 +217,7 @@
"scriptUrl": "./country-posters/country-posters.js",
"embed": {
"iframe": "<iframe src=\"./country-posters/country-posters-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-qvahseKUBbt8fF4+sve6YfLB3ylz2zosiN772O5HbXVxvaDvM6K/SwWnMNKJ9lML\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./country-posters/country-posters.js\" integrity=\"sha384-LIBXLNfvnjdauLi7aG74iDswH2Tzd29d/hp342/mDbmQYFz89Sw3RvjkkTCoW+CQ\" crossorigin=\"anonymous\"></script>\n<country-posters-map profile-config='{\"profile\":\"country-posters-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></country-posters-map>"
}
}
]
@ -317,7 +317,7 @@
"bundle": "doxa-maps-spa",
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"output": "dx-maps/doxa-maps-spa/doxa-maps-spa.js",
"integrity": "sha384-PNd2QYytXnHHGBEvXVjgoA93Owlm7Nnji5tJeBP81rq2merTNg2pSfFwt19x1AMJ",
"integrity": "sha384-rLTDkqumxtv1rDoCpF7Gubflil8YbosAnEN741ue/oml2btEkGBJrHoLcERx3Iiw",
"elements": [
"doxa-maps-spa"
],
@ -344,7 +344,7 @@
"scriptUrl": "./doxa-maps-spa/doxa-maps-spa.js",
"embed": {
"iframe": "<iframe src=\"./doxa-maps-spa/doxa-maps-spa/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-PNd2QYytXnHHGBEvXVjgoA93Owlm7Nnji5tJeBP81rq2merTNg2pSfFwt19x1AMJ\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./doxa-maps-spa/doxa-maps-spa.js\" integrity=\"sha384-rLTDkqumxtv1rDoCpF7Gubflil8YbosAnEN741ue/oml2btEkGBJrHoLcERx3Iiw\" crossorigin=\"anonymous\"></script>\n<doxa-maps-spa profile-config='{\"profile\":\"doxa-maps-spa\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></doxa-maps-spa>"
},
"instances": [
{
@ -814,7 +814,7 @@
"bundle": "my-upg-100-list",
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"output": "dx-maps/my-upg-100-list/my-upg-100-list.js",
"integrity": "sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i",
"integrity": "sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l",
"elements": [
"my-upg-100-list-map"
],
@ -836,7 +836,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/poster-wall/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"poster-wall\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -851,7 +851,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
},
{
@ -866,7 +866,7 @@
"scriptUrl": "./my-upg-100-list/my-upg-100-list.js",
"embed": {
"iframe": "<iframe src=\"./my-upg-100-list/upg-100-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./my-upg-100-list/my-upg-100-list.js\" integrity=\"sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l\" crossorigin=\"anonymous\"></script>\n<my-upg-100-list-map profile-config='{\"profile\":\"upg-100-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></my-upg-100-list-map>"
}
}
]
@ -938,7 +938,7 @@
"bundle": "plugin-studio",
"scriptUrl": "./plugin-studio/plugin-studio.js",
"output": "dx-maps/plugin-studio/plugin-studio.js",
"integrity": "sha384-8qq9TrPab9dfj4aHBbSMKj2dwCzyuH2gA2xGq4YhK4GNEy38/uVVmeEhJIXiEr1e",
"integrity": "sha384-TIIWS9puN8S1tAFHIeIOLIWlWADIW9lxmKLv2M+BKWGp7yjd/dVcpjU41RfH77WD",
"elements": [
"plugin-studio"
],
@ -968,7 +968,7 @@
"scriptUrl": "./plugin-studio/plugin-studio.js",
"embed": {
"iframe": "<iframe src=\"./plugin-studio/plugin-studio/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-8qq9TrPab9dfj4aHBbSMKj2dwCzyuH2gA2xGq4YhK4GNEy38/uVVmeEhJIXiEr1e\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./plugin-studio/plugin-studio.js\" integrity=\"sha384-TIIWS9puN8S1tAFHIeIOLIWlWADIW9lxmKLv2M+BKWGp7yjd/dVcpjU41RfH77WD\" crossorigin=\"anonymous\"></script>\n<plugin-studio profile-config='{\"profile\":\"plugin-studio\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></plugin-studio>"
},
"instances": [
{
@ -995,7 +995,7 @@
"bundle": "pplr-data-maps",
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
"output": "dx-maps/pplr-data-maps/pplr-data-maps.js",
"integrity": "sha384-HyV8R97czSk4eeg7lOFsB9NePlf3dJ7N0q6wlX0fKY1Zf0ner2lZ+QRwsHjRELVv",
"integrity": "sha384-01tSl+RnPCA0oGugtwlOJb+TBg01zGbmgF/Dpf5qHu/Ok/eFNzFG027mEM4crbT7",
"elements": [
"pplr-data-maps"
],
@ -1013,7 +1013,7 @@
"scriptUrl": "./pplr-data-maps/pplr-data-maps.js",
"embed": {
"iframe": "<iframe src=\"./pplr-data-maps/pplr-data-maps/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-HyV8R97czSk4eeg7lOFsB9NePlf3dJ7N0q6wlX0fKY1Zf0ner2lZ+QRwsHjRELVv\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./pplr-data-maps/pplr-data-maps.js\" integrity=\"sha384-01tSl+RnPCA0oGugtwlOJb+TBg01zGbmgF/Dpf5qHu/Ok/eFNzFG027mEM4crbT7\" crossorigin=\"anonymous\"></script>\n<pplr-data-maps profile-config='{\"profile\":\"pplr-data-maps\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></pplr-data-maps>"
},
"bundle": "pplr-data-maps"
}
@ -1050,7 +1050,7 @@
"bundle": "regions-dashboard",
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"output": "dx-maps/regions-dashboard/regions-dashboard.js",
"integrity": "sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z",
"integrity": "sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X",
"elements": [
"regions-dashboard"
],
@ -1072,7 +1072,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/region-dashboards/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"region-dashboards\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1087,7 +1087,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-list/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-list\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
},
{
@ -1102,7 +1102,7 @@
"scriptUrl": "./regions-dashboard/regions-dashboard.js",
"embed": {
"iframe": "<iframe src=\"./regions-dashboard/regions-mfe/index.html?utm_source=YOUR_SOURCE\" width=\"100%\" height=\"600\" style=\"border:none;border-radius:12px;\" allowfullscreen></iframe>",
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
"script": "<!-- Mapbox engine, fetched early. Keep it only with a real Mapbox token in \"tk\": without one (or with \"provider\":\"maplibre\") the map draws with MapLibre and this line must go -->\n<link rel=\"preload\" as=\"script\" href=\"https://api.mapbox.com/mapbox-gl-js/v3.24.0/mapbox-gl.js\" integrity=\"sha384-tO0clamXONKwbiz7O6xJpUeyJbTSPugC+xM9clvfFvKTH3i8SmCawHGdf5quMWmZ\" crossorigin=\"anonymous\">\n<script>window.MAP_APP_API_URL=\"https://pray.doxa.life\";</script>\n<script src=\"./regions-dashboard/regions-dashboard.js\" integrity=\"sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X\" crossorigin=\"anonymous\"></script>\n<regions-dashboard profile-config='{\"profile\":\"regions-mfe\",\"tk\":\"YOUR_MAPBOX_TOKEN\",\"utmSource\":\"YOUR_SOURCE\",\"assetsBase\":\"YOUR_TREE_URL/assets\"}'></regions-dashboard>"
}
}
]

File diff suppressed because one or more lines are too long

View file

@ -32,7 +32,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
<script src="../my-upg-100-list.js" integrity="sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
<script src="../my-upg-100-list.js" integrity="sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -47,7 +47,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <my-upg-100-list-map> custom element. -->
<script src="../my-upg-100-list.js" integrity="sha384-hAswKX2m8kfhk4SAPBie72rFlYYtXYgLXr6HLz6cMU8MD5V8T4cMcgfSwsK4vI5i" crossorigin="anonymous"></script>
<script src="../my-upg-100-list.js" integrity="sha384-W485SqOh5YedO5tXj85tPYyRqjSeQlBnxahf5YgX7q9118qZk3uDCpfqJUSCRD4l" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -99,14 +99,14 @@
.vtl-chev svg { width:15px; height:15px; }
.vtl-chev.open { transform:rotate(90deg); }
.vtl-rows { display:flex; flex-direction:column; gap:1px; }
/* MATERIAL NAV-ROW METRICS (2026-09-21). the agent: "people are used to the YouTube layout, Google
layout is just way better. We do not need to create custom styles people are not used to."
/* MATERIAL NAV-ROW METRICS (2026-09-21). Product decision: follow the familiar
Material/YouTube list layout rather than custom styling readers are not used to.
Measured before this change: 44px rows with an 8px radius.
min-height:48px the Material list-item height. min-height, not height, so a wrapping
label still grows instead of clipping.
border-radius var(--vtl-radius,8px) — SUPERSEDED THE FULL PILL (2026-09-23).
The 999px stadium above was a real instruction ("imitate the YouTube
active row") and it shipped. The agent then measured it against the
active row") and it shipped. It was then measured against the
rest of the product and reversed it: "the roundedness of the tabs is a
little bit too round because there is nowhere else in the app that has
that same roundedness. Even the collapse button is not that round...

View file

@ -32,7 +32,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <plugin-studio> custom element. -->
<script src="../plugin-studio.js" integrity="sha384-8qq9TrPab9dfj4aHBbSMKj2dwCzyuH2gA2xGq4YhK4GNEy38/uVVmeEhJIXiEr1e" crossorigin="anonymous"></script>
<script src="../plugin-studio.js" integrity="sha384-TIIWS9puN8S1tAFHIeIOLIWlWADIW9lxmKLv2M+BKWGp7yjd/dVcpjU41RfH77WD" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -32,7 +32,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <plugin-studio> custom element. -->
<script src="../../plugin-studio.js" integrity="sha384-8qq9TrPab9dfj4aHBbSMKj2dwCzyuH2gA2xGq4YhK4GNEy38/uVVmeEhJIXiEr1e" crossorigin="anonymous"></script>
<script src="../../plugin-studio.js" integrity="sha384-TIIWS9puN8S1tAFHIeIOLIWlWADIW9lxmKLv2M+BKWGp7yjd/dVcpjU41RfH77WD" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <pplr-data-maps> custom element. -->
<script src="../pplr-data-maps.js" integrity="sha384-HyV8R97czSk4eeg7lOFsB9NePlf3dJ7N0q6wlX0fKY1Zf0ner2lZ+QRwsHjRELVv" crossorigin="anonymous"></script>
<script src="../pplr-data-maps.js" integrity="sha384-01tSl+RnPCA0oGugtwlOJb+TBg01zGbmgF/Dpf5qHu/Ok/eFNzFG027mEM4crbT7" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -36,7 +36,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

File diff suppressed because one or more lines are too long

View file

@ -32,7 +32,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order:

View file

@ -47,7 +47,7 @@
<script>window.MAP_APP_API_URL = "https://pray.doxa.life";</script>
<!-- Bundle IIFE — registers the <regions-dashboard> custom element. -->
<script src="../regions-dashboard.js" integrity="sha384-cIs9LG3sHsQf+LV4UsaqNOYrDMoMfhku9CDHAd1V+BSmE2R9Xvjrz/vYadIINH9Z" crossorigin="anonymous"></script>
<script src="../regions-dashboard.js" integrity="sha384-3aB5szRuMvvvZRSWB9CcCWnJW8d/fVTHZClloQyv1pjS4E+30OV2rzK6sRXPyX+X" crossorigin="anonymous"></script>
<script>
// Mapbox token resolution — the A3 ladder, in precedence order: