@apex-inc/sdk 0.20.1 → 0.21.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/dist/esm/index.js +35 -8
- package/dist/esm/management.js +31 -45
- package/dist/generated/event-payloads.d.ts +17 -572
- package/dist/generated/event-payloads.d.ts.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +35 -8
- package/dist/index.js.map +1 -1
- package/dist/management.d.ts +39 -37
- package/dist/management.d.ts.map +1 -1
- package/dist/management.js +31 -45
- package/dist/management.js.map +1 -1
- package/package.json +1 -1
- package/skills/apex-adoption/SKILL.md +31 -99
- package/skills/apex-communications/SKILL.md +3 -3
- package/skills/apex-experimentation/SKILL.md +12 -2
- package/skills/apex-integration-cookbook/SKILL.md +4 -4
- package/skills/graduation-pipeline/SKILL.md +5 -1
package/dist/esm/index.js
CHANGED
|
@@ -381,6 +381,22 @@ function getExperimentPreview(search) {
|
|
|
381
381
|
const resolved = search ?? (isBrowser ? window.location.search : "");
|
|
382
382
|
return readExperimentPreview(resolved);
|
|
383
383
|
}
|
|
384
|
+
async function fetchExperimentLineIds(apiBase, experimentId, workspaceKey) {
|
|
385
|
+
try {
|
|
386
|
+
const res = await fetch(`${apiBase}/api/experiments/${experimentId}/line?source=sdk`, {
|
|
387
|
+
credentials: "include",
|
|
388
|
+
headers: workspaceKey ? { "x-apex-workspace": workspaceKey } : {},
|
|
389
|
+
});
|
|
390
|
+
if (!res.ok)
|
|
391
|
+
return null;
|
|
392
|
+
const body = (await res.json());
|
|
393
|
+
const ids = body.data?.lineMemberIds ?? body.lineMemberIds;
|
|
394
|
+
return Array.isArray(ids) && ids.length > 0 ? ids : null;
|
|
395
|
+
}
|
|
396
|
+
catch {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
384
400
|
// DBS-1 — durable browser session id (`apex_sid`), GA4-parity 30-min
|
|
385
401
|
// inactivity rotation. Mirrors the snippet's cookie format
|
|
386
402
|
// (`<id>.<startedAtMs>.<lastActivityMs>.<sessionNumber>.<utmSig>`) so a page
|
|
@@ -540,12 +556,19 @@ export async function getVariant(experimentId, opts = {}) {
|
|
|
540
556
|
const buildId = opts.buildId ?? config?.buildId;
|
|
541
557
|
// 1. Preview mode — author previewing, not a real exposure. Runs
|
|
542
558
|
// before the browser/consent gates so SSR and a declined cookie
|
|
543
|
-
// banner still show the URL arm.
|
|
559
|
+
// banner still show the URL arm. A family member's `_apex_exp`
|
|
560
|
+
// applies once we know the line.
|
|
544
561
|
const preview = getExperimentPreview(opts.search);
|
|
545
|
-
if (preview
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
562
|
+
if (preview) {
|
|
563
|
+
const lineIds = opts.lineMemberIds ??
|
|
564
|
+
(isBrowser && preview.expId && preview.expId !== experimentId
|
|
565
|
+
? await fetchExperimentLineIds(apiBase, experimentId, workspaceKey)
|
|
566
|
+
: null);
|
|
567
|
+
if (!preview.expId ||
|
|
568
|
+
preview.expId === experimentId ||
|
|
569
|
+
(lineIds && lineIds.includes(experimentId) && lineIds.includes(preview.expId))) {
|
|
570
|
+
return preview.variant;
|
|
571
|
+
}
|
|
549
572
|
return "control";
|
|
550
573
|
}
|
|
551
574
|
if (!isBrowser)
|
|
@@ -574,18 +597,22 @@ export async function getVariant(experimentId, opts = {}) {
|
|
|
574
597
|
if (!res.ok)
|
|
575
598
|
throw new Error(`${res.status}`);
|
|
576
599
|
const data = (await res.json());
|
|
600
|
+
const runId = data.experimentId || experimentId;
|
|
577
601
|
if (data.eligible === false) {
|
|
578
602
|
// Staging / TestFlight / localhost: serve the arm so they can QA.
|
|
579
603
|
// Do not fire an exposure — that is what would move the result.
|
|
580
604
|
if (data.reason === "non_production_audience") {
|
|
581
|
-
localStorage.setItem(
|
|
605
|
+
localStorage.setItem(`apex_var_${runId}`, data.variant);
|
|
582
606
|
return data.variant;
|
|
583
607
|
}
|
|
584
608
|
localStorage.setItem(cacheKey, "control");
|
|
585
609
|
return "control";
|
|
586
610
|
}
|
|
587
|
-
|
|
588
|
-
|
|
611
|
+
if (runId !== experimentId) {
|
|
612
|
+
localStorage.removeItem(cacheKey);
|
|
613
|
+
}
|
|
614
|
+
localStorage.setItem(`apex_var_${runId}`, data.variant);
|
|
615
|
+
fireExperimentExposure(runId, data.variant, apiBase, workspaceKey, buildId);
|
|
589
616
|
return data.variant;
|
|
590
617
|
}
|
|
591
618
|
catch {
|
package/dist/esm/management.js
CHANGED
|
@@ -344,59 +344,45 @@ export function createManagementClient(cfg) {
|
|
|
344
344
|
return json.data.milestone;
|
|
345
345
|
},
|
|
346
346
|
/**
|
|
347
|
-
* Create a
|
|
348
|
-
*
|
|
349
|
-
*
|
|
350
|
-
* `scaffold` selects which legs to create:
|
|
351
|
-
* - `"both"` (recommended) — the nudge (audience_entry over "hasn't
|
|
352
|
-
* adopted within N days") AND the celebration (fires once on
|
|
353
|
-
* adoption). This is what the dashboard on-ramp produces.
|
|
354
|
-
* - `"celebration"` (default) — celebration leg only.
|
|
355
|
-
* - `"nudge"` — nudge leg only.
|
|
356
|
-
* - `"none"` — milestone only, no journey.
|
|
357
|
-
*
|
|
358
|
-
* `journeyName` applies only to single-leg scaffolds; for `"both"` each
|
|
359
|
-
* leg takes its template's default (deduped server-side). Every
|
|
360
|
-
* scaffolded journey is a draft — publish it from the canvas.
|
|
347
|
+
* Create a Milestone AND stamp one Adaptive Journey (Trigger → Wait
|
|
348
|
+
* until they finish → Celebration and/or Nudge). Draft only — publish
|
|
349
|
+
* from the canvas. `scaffold: "none"` is just-track (no journey).
|
|
361
350
|
*/
|
|
362
351
|
async compose(params) {
|
|
363
|
-
const { scaffold = "
|
|
352
|
+
const { scaffold = "both", journeyName, nudgeClocks, ...createParams } = params;
|
|
364
353
|
const milestone = await this.create(createParams);
|
|
365
354
|
if (scaffold === "none") {
|
|
366
|
-
return {
|
|
355
|
+
return {
|
|
356
|
+
milestone,
|
|
357
|
+
journeyId: null,
|
|
358
|
+
nudgeJourneyId: null,
|
|
359
|
+
celebrationJourneyId: null,
|
|
360
|
+
sends: [],
|
|
361
|
+
};
|
|
367
362
|
}
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
}),
|
|
377
|
-
})
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
const
|
|
384
|
-
const wantsCelebration = scaffold === "celebration" || scaffold === "both";
|
|
385
|
-
// Single-leg scaffolds honor journeyName; "both" lets each leg default.
|
|
386
|
-
const legName = scaffold === "both" ? undefined : journeyName;
|
|
387
|
-
const nudgeJourneyId = wantsNudge ? await scaffoldLeg("adoption-nudge", legName) : null;
|
|
388
|
-
const celebrationJourneyId = wantsCelebration
|
|
389
|
-
? await scaffoldLeg("adoption-celebration", legName)
|
|
390
|
-
: null;
|
|
391
|
-
// Re-read so the returned milestone carries the nudge/celebration
|
|
392
|
-
// back-references the scaffolds just stamped.
|
|
363
|
+
const res = await fetch(`${root}/api/journeys/from-template`, {
|
|
364
|
+
method: "POST",
|
|
365
|
+
headers,
|
|
366
|
+
body: JSON.stringify({
|
|
367
|
+
templateId: "adoption-nudge",
|
|
368
|
+
milestoneId: milestone.id,
|
|
369
|
+
scaffold,
|
|
370
|
+
name: journeyName ?? milestone.name,
|
|
371
|
+
...(nudgeClocks ? { nudgeClocks } : {}),
|
|
372
|
+
}),
|
|
373
|
+
});
|
|
374
|
+
if (!res.ok) {
|
|
375
|
+
throw new Error(`Apex adoption.compose (journey scaffold) failed (${res.status}): ${await res.text().catch(() => "")}`);
|
|
376
|
+
}
|
|
377
|
+
const journey = (await res.json());
|
|
378
|
+
const journeyId = journey.id ?? null;
|
|
393
379
|
const refreshed = (await this.get(milestone.id)) ?? milestone;
|
|
394
380
|
return {
|
|
395
381
|
milestone: refreshed,
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
382
|
+
journeyId,
|
|
383
|
+
nudgeJourneyId: journeyId,
|
|
384
|
+
celebrationJourneyId: null,
|
|
385
|
+
sends: journey.sends ?? [],
|
|
400
386
|
};
|
|
401
387
|
},
|
|
402
388
|
/** Patch a milestone (name, priority, active, gapPolicy, adoptedWhen, ...). */
|