@nextcommerce/campaigns-os 1.48.0 → 1.52.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +539 -0
- package/agents/claude/CLAUDE.md +6 -5
- package/agents/codex/AGENTS.md +6 -5
- package/agents/copilot/copilot-instructions.md +3 -3
- package/agents/cursor/campaigns-os.mdc +3 -3
- package/campaign-spec/dist/rules/campaign-metadata.d.ts +5 -1
- package/campaign-spec/dist/rules/campaign-metadata.js +9 -2
- package/campaign-spec/dist/rules/design-source-shape.js +13 -3
- package/campaign-spec/dist/rules/sdk-version.js +2 -1
- package/compatibility.json +1 -1
- package/contracts/commerce-surface-catalog.json +26 -46
- package/contracts/effects.v1.json +254 -2
- package/contracts/release-ledger.json +1239 -0
- package/contracts/supported-surface.json +4 -4
- package/contracts/template-brand-contract.shared-commerce.v0.json +2 -2
- package/contracts/template-slot-manifest.shared-content-core.v0.json +24 -0
- package/docs/brand-theme-bridge.md +12 -6
- package/docs/build-packet.md +101 -12
- package/docs/campaign-build-brief.md +25 -1
- package/docs/effects.md +6 -0
- package/docs/local-setup.md +1 -1
- package/docs/orientation-contract-reference.md +1 -1
- package/docs/polish-evidence.md +10 -0
- package/docs/qa-and-test-orders.md +66 -11
- package/docs/runtime-readiness.md +1 -1
- package/docs/sdk-storage-compatibility.md +1 -1
- package/docs/skills-revision.md +10 -10
- package/package.json +1 -1
- package/schemas/campaign-runtime-build-packet.v0.schema.json +4 -0
- package/schemas/campaigns-os-qa-verdict.v0.schema.json +8 -3
- package/skills/campaign-lifecycle-orientation/SKILL.md +3 -3
- package/skills/campaign-readback-classification/SKILL.md +3 -3
- package/skills/campaign-run-evidence/SKILL.md +3 -3
- package/skills/contribution-intake/SKILL.md +3 -3
- package/skills/next-campaigns-build/SKILL.md +4 -4
- package/skills/next-campaigns-os/SKILL.md +4 -4
- package/skills/next-campaigns-os/references/session-intake.md +7 -3
- package/skills/next-campaigns-os-setup/SKILL.md +3 -3
- package/skills/next-campaigns-polish/SKILL.md +5 -4
- package/skills/next-campaigns-qa/SKILL.md +6 -5
- package/skills.json +10 -10
- package/src/adapter-decision-contract.mjs +1 -1
- package/src/brand-theme.mjs +25 -2
- package/src/build-brief.mjs +68 -21
- package/src/built-site-scope.mjs +39 -6
- package/src/built-smoke-qc.mjs +1117 -0
- package/src/campaign-identity.mjs +36 -2
- package/src/cart-placeholders.mjs +730 -0
- package/src/cli.mjs +320 -42
- package/src/commercial-journey.mjs +65 -4
- package/src/commercial-parity.mjs +6 -1
- package/src/doctor/checks.mjs +291 -24
- package/src/doctor/inspect.mjs +53 -2
- package/src/doctor/next-step.mjs +1 -1
- package/src/install-mode.mjs +0 -8
- package/src/invocation.mjs +5 -2
- package/src/local-preview-policy.mjs +1 -1
- package/src/local-proof.mjs +4 -1
- package/src/polish-browser.mjs +218 -1
- package/src/polish-capture.mjs +1 -1
- package/src/polish-media-weight.mjs +492 -0
- package/src/polish-node.mjs +96 -4
- package/src/progress-node.mjs +5 -1
- package/src/qa-binding-evidence.mjs +21 -0
- package/src/qa-browser.mjs +338 -97
- package/src/qa-content-params.mjs +889 -0
- package/src/qa-node.mjs +114 -14
- package/src/qa-order-bump.mjs +22 -1
- package/src/qa-policy-links.mjs +1019 -0
- package/src/qa-tracking-params.mjs +1389 -0
- package/src/qa-url-privacy.mjs +168 -0
- package/src/qc-accept.mjs +446 -0
- package/src/qc-check-registry.mjs +83 -0
- package/src/qc-results.mjs +1049 -0
- package/src/sdk-attribute-index.mjs +71 -0
- package/src/sdk-markup.mjs +2 -2
- package/src/sdk-storage-compatibility.mjs +63 -3
- package/src/source-prep.mjs +37 -7
- package/src/stage-record.mjs +356 -36
- package/src/theme-gate.mjs +3 -3
package/src/progress-node.mjs
CHANGED
|
@@ -14,6 +14,10 @@ export const PROGRESS_ENDPOINT = '/api/progress';
|
|
|
14
14
|
// A projection keeps the first PROGRESS_GATE_LIMIT continuation gates (the snapshot schema's gates maxItems).
|
|
15
15
|
export const PROGRESS_GATE_LIMIT = 16;
|
|
16
16
|
const accepted = (value,values,fallback='unknown')=>values.includes(value)?value:fallback;
|
|
17
|
+
// A next action that is a variant of a fixed action projects onto it: the
|
|
18
|
+
// order-bump QA run is a QA run. Without this, the closed v0 vocabulary would
|
|
19
|
+
// read it as unknown and mark a ready QA continuation blocked.
|
|
20
|
+
const PROGRESS_ACTION_ALIASES = new Map([['qa_run_bump','qa_run']]);
|
|
17
21
|
const hash = value=>typeof value==='string'&&/^(?:sha256:)?[0-9a-f]{64}$/i.test(value)?`sha256:${value.replace(/^sha256:/i,'').toLowerCase()}`:null;
|
|
18
22
|
const id = value=>typeof value==='string'&&/^[A-Za-z0-9_-]{1,64}$/.test(value)?value:null;
|
|
19
23
|
const digest = value=>`sha256:${createHash('sha256').update(value).digest('hex')}`;
|
|
@@ -63,7 +67,7 @@ export function projectProgressObservation({workspace,context,report,doctor,cont
|
|
|
63
67
|
// here (never pass).
|
|
64
68
|
const gateState=status=>accepted(status==='carried_forward'?'not_applicable':status,['pass','blocked','waived','not_applicable']);
|
|
65
69
|
const gates=(Array.isArray(continuation?.gates)?continuation.gates:[]).slice(0,PROGRESS_GATE_LIMIT).map(gate=>({id:accepted(gate?.id,PROGRESS_GATE_IDS),state:PROGRESS_GATE_IDS.includes(gate?.id)?gateState(gate?.status):'unknown'}));
|
|
66
|
-
const actions=[...new Set((Array.isArray(continuation?.next_actions)?continuation.next_actions:[]).slice(0,64).map(action=>accepted(action?.id,PROGRESS_ACTION_IDS)))];
|
|
70
|
+
const actions=[...new Set((Array.isArray(continuation?.next_actions)?continuation.next_actions:[]).slice(0,64).map(action=>accepted(PROGRESS_ACTION_ALIASES.get(action?.id)||action?.id,PROGRESS_ACTION_IDS)))];
|
|
67
71
|
const stage=accepted(continuation?.stage,PROGRESS_CONTINUATIONS);
|
|
68
72
|
const preview=typeof packet?.deploy?.preview_url==='string'&&packet.deploy.preview_url?packet.deploy.preview_url:null;
|
|
69
73
|
return {
|
|
@@ -188,6 +188,27 @@ export async function observeBinding({ source, page, expected, scriptLoader, par
|
|
|
188
188
|
return result(values[0] === expected.value ? 'match' : 'mismatch', 'credential_comparison');
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
// The Campaign Cart SDK sends the page's raw key, with no scheme, as
|
|
192
|
+
// `Authorization` on every Campaigns API call, so the browser pass can see the
|
|
193
|
+
// key a page actually uses, whatever its scripts look like. The value is
|
|
194
|
+
// compared as sent: if the SDK ever adds a scheme, every page reads mismatch
|
|
195
|
+
// rather than passing. The API host is matched by its shape,
|
|
196
|
+
// campaigns.apps.<name>.com, without naming it.
|
|
197
|
+
const SDK_API_HOST = /^campaigns\.apps\.[a-z0-9-]+\.com$/;
|
|
198
|
+
export function isSdkApiRequest(url) {
|
|
199
|
+
try { const parsed = new URL(url); return parsed.protocol === 'https:' && SDK_API_HOST.test(parsed.hostname) && parsed.pathname.startsWith('/api/'); } catch { return false; }
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// The keys a page sent are compared here and dropped; only the outcome is
|
|
203
|
+
// kept. With nothing sent, or no single expected key, the static read stands
|
|
204
|
+
// (null).
|
|
205
|
+
export function sentBinding(sentKeys, expected) {
|
|
206
|
+
if (!sentKeys.length || expected?.conflict || !expected?.value) return null;
|
|
207
|
+
return { schema_version: BINDING_SCHEMA, observation: 'sdk_request',
|
|
208
|
+
outcome: sentKeys.every(value => value === expected.value) ? 'match' : 'mismatch',
|
|
209
|
+
reason: 'credential_comparison', source_kinds: ['sdk_request'], identity: 'not_verified' };
|
|
210
|
+
}
|
|
211
|
+
|
|
191
212
|
export function bindingAssertion(page, evidence) {
|
|
192
213
|
// No source URLs, values, hashes, masked fragments, or inferred App IDs.
|
|
193
214
|
return { id: `page-binding:${page.page_id}`, family: 'api-metadata', page: page.page_id,
|