ad2app-lib 1.35.0 → 1.36.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.
@@ -75,6 +75,9 @@ export declare const EVENTS: {
75
75
  readonly POST_RESCHEDULED: "post_rescheduled";
76
76
  readonly ACCOUNT_DISCONNECTED: "account_disconnected";
77
77
  readonly NOTIFICATION_PREFERENCES_UPDATED: "notification_preferences_updated";
78
+ readonly NATIVE_SESSION_LAUNCHED: "native_session_launched";
79
+ readonly NATIVE_SESSION_RENEWED: "native_session_renewed";
80
+ readonly NATIVE_SESSION_ENDED: "native_session_ended";
78
81
  };
79
82
  export type EventName = (typeof EVENTS)[keyof typeof EVENTS];
80
83
  /** Which email program a send belongs to (spec 120). Wire values — do not rename. */
@@ -472,6 +475,13 @@ export interface EventProperties {
472
475
  enabled?: boolean;
473
476
  success: boolean;
474
477
  };
478
+ [EVENTS.NATIVE_SESSION_LAUNCHED]: {
479
+ outcome: 'restored' | 'none' | 'degraded';
480
+ };
481
+ [EVENTS.NATIVE_SESSION_RENEWED]: Record<string, never>;
482
+ [EVENTS.NATIVE_SESSION_ENDED]: {
483
+ cause: 'rejected' | 'sign_out';
484
+ };
475
485
  }
476
486
  /** Canonical person property keys (set via identify / $set). */
477
487
  export declare const PERSON_PROPS: {
@@ -482,3 +492,14 @@ export declare const PERSON_PROPS: {
482
492
  readonly PAYWALL_HITS: "paywall_hits";
483
493
  };
484
494
  export type PersonPropKey = (typeof PERSON_PROPS)[keyof typeof PERSON_PROPS];
495
+ /**
496
+ * Canonical launch-context SUPER-property keys (159 US2). Registered once per
497
+ * session (like `is_pwa` / `display_mode` / `app_platform` in
498
+ * registerLaunchContext), so they ride every event without a per-event field.
499
+ * `APP_BUILD` is the only one governed here today — the value MUST come from
500
+ * the build itself (contract Rule 4), never a hand-maintained constant.
501
+ */
502
+ export declare const LAUNCH_CONTEXT_PROPS: {
503
+ readonly APP_BUILD: "app_build";
504
+ };
505
+ export type LaunchContextPropKey = (typeof LAUNCH_CONTEXT_PROPS)[keyof typeof LAUNCH_CONTEXT_PROPS];
@@ -10,7 +10,7 @@
10
10
  * Do NOT rename events after they ship — historical data does not migrate.
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.PERSON_PROPS = exports.CONNECT_BLOCK_REASONS = exports.ONBOARDING_COMPLETED_AT = exports.EMAIL_PROPS = exports.EVENTS = void 0;
13
+ exports.LAUNCH_CONTEXT_PROPS = exports.PERSON_PROPS = exports.CONNECT_BLOCK_REASONS = exports.ONBOARDING_COMPLETED_AT = exports.EMAIL_PROPS = exports.EVENTS = void 0;
14
14
  /** Canonical PostHog event names. */
15
15
  exports.EVENTS = {
16
16
  // Acquisition (landing)
@@ -110,6 +110,12 @@ exports.EVENTS = {
110
110
  ACCOUNT_DISCONNECTED: 'account_disconnected',
111
111
  // Settings.
112
112
  NOTIFICATION_PREFERENCES_UPDATED: 'notification_preferences_updated',
113
+ // Native session lifecycle (159) — the iOS wrapper's Keychain-backed session,
114
+ // reported so "does it survive" is a query instead of an inference from login
115
+ // counts. Native only; the web session's posture is unchanged (contract Rule 5).
116
+ NATIVE_SESSION_LAUNCHED: 'native_session_launched',
117
+ NATIVE_SESSION_RENEWED: 'native_session_renewed',
118
+ NATIVE_SESSION_ENDED: 'native_session_ended',
113
119
  };
114
120
  /**
115
121
  * Canonical email event property KEYS (spec 120 T001). Emitters and tests
@@ -157,3 +163,13 @@ exports.PERSON_PROPS = {
157
163
  // stored here would rewrite the value on every historical paywall_shown event.
158
164
  PAYWALL_HITS: 'paywall_hits',
159
165
  };
166
+ /**
167
+ * Canonical launch-context SUPER-property keys (159 US2). Registered once per
168
+ * session (like `is_pwa` / `display_mode` / `app_platform` in
169
+ * registerLaunchContext), so they ride every event without a per-event field.
170
+ * `APP_BUILD` is the only one governed here today — the value MUST come from
171
+ * the build itself (contract Rule 4), never a hand-maintained constant.
172
+ */
173
+ exports.LAUNCH_CONTEXT_PROPS = {
174
+ APP_BUILD: 'app_build',
175
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ad2app-lib",
3
- "version": "1.35.0",
3
+ "version": "1.36.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "type": "commonjs",
@@ -8,7 +8,7 @@
8
8
  import assert from "node:assert/strict";
9
9
  import { test } from "node:test";
10
10
 
11
- import { EVENTS, PERSON_PROPS, EMAIL_PROPS } from "./index";
11
+ import { EVENTS, PERSON_PROPS, EMAIL_PROPS, LAUNCH_CONTEXT_PROPS } from "./index";
12
12
  import type {
13
13
  EventProperties,
14
14
  EmailEventProperties,
@@ -133,6 +133,10 @@ const EVENT_PROPERTY_WITNESS: { [E in keyof EventProperties]: EventProperties[E]
133
133
  [EVENTS.POST_RESCHEDULED]: { success: true },
134
134
  [EVENTS.ACCOUNT_DISCONNECTED]: { platform: "instagram", success: true },
135
135
  [EVENTS.NOTIFICATION_PREFERENCES_UPDATED]: { success: true },
136
+ // 159 native session lifecycle
137
+ [EVENTS.NATIVE_SESSION_LAUNCHED]: { outcome: "restored" },
138
+ [EVENTS.NATIVE_SESSION_RENEWED]: {},
139
+ [EVENTS.NATIVE_SESSION_ENDED]: { cause: "rejected" },
136
140
  };
137
141
 
138
142
  test("EVENTS values are 1:1 with EventProperties keys (no missing or typo'd event)", () => {
@@ -455,3 +459,36 @@ test("120 playbook events carry the edition stamp", () => {
455
459
  assert.equal(opened.edition_version, "2026.08");
456
460
  assert.equal(downloaded.format, "pdf");
457
461
  });
462
+
463
+ // 159: the native session lifecycle + build attribution.
464
+
465
+ test("159 native session wire names are locked", () => {
466
+ assert.equal(EVENTS.NATIVE_SESSION_LAUNCHED, "native_session_launched");
467
+ assert.equal(EVENTS.NATIVE_SESSION_RENEWED, "native_session_renewed");
468
+ assert.equal(EVENTS.NATIVE_SESSION_ENDED, "native_session_ended");
469
+ });
470
+
471
+ test("159 native_session_launched carries a closed outcome — restored, none, or degraded", () => {
472
+ const restored: EventProperties[typeof EVENTS.NATIVE_SESSION_LAUNCHED] = { outcome: "restored" };
473
+ const none: EventProperties[typeof EVENTS.NATIVE_SESSION_LAUNCHED] = { outcome: "none" };
474
+ const degraded: EventProperties[typeof EVENTS.NATIVE_SESSION_LAUNCHED] = { outcome: "degraded" };
475
+ assert.equal(restored.outcome, "restored");
476
+ assert.equal(none.outcome, "none");
477
+ assert.equal(degraded.outcome, "degraded");
478
+ });
479
+
480
+ test("159 native_session_ended carries its cause — rejected or sign_out, never bare", () => {
481
+ const rejected: EventProperties[typeof EVENTS.NATIVE_SESSION_ENDED] = { cause: "rejected" };
482
+ const signOut: EventProperties[typeof EVENTS.NATIVE_SESSION_ENDED] = { cause: "sign_out" };
483
+ assert.equal(rejected.cause, "rejected");
484
+ assert.equal(signOut.cause, "sign_out");
485
+ });
486
+
487
+ test("159 native_session_renewed carries no properties (the fact of the renewal is the whole report)", () => {
488
+ const renewed: EventProperties[typeof EVENTS.NATIVE_SESSION_RENEWED] = {};
489
+ assert.deepEqual(renewed, {});
490
+ });
491
+
492
+ test("159 LAUNCH_CONTEXT_PROPS governs the build-attribution key (no raw 'app_build' string at the call site)", () => {
493
+ assert.equal(LAUNCH_CONTEXT_PROPS.APP_BUILD, "app_build");
494
+ });
@@ -121,6 +121,13 @@ export const EVENTS = {
121
121
 
122
122
  // Settings.
123
123
  NOTIFICATION_PREFERENCES_UPDATED: 'notification_preferences_updated',
124
+
125
+ // Native session lifecycle (159) — the iOS wrapper's Keychain-backed session,
126
+ // reported so "does it survive" is a query instead of an inference from login
127
+ // counts. Native only; the web session's posture is unchanged (contract Rule 5).
128
+ NATIVE_SESSION_LAUNCHED: 'native_session_launched',
129
+ NATIVE_SESSION_RENEWED: 'native_session_renewed',
130
+ NATIVE_SESSION_ENDED: 'native_session_ended',
124
131
  } as const;
125
132
 
126
133
  export type EventName = (typeof EVENTS)[keyof typeof EVENTS];
@@ -500,6 +507,16 @@ export interface EventProperties {
500
507
 
501
508
  // Settings — which preference toggled and its new state.
502
509
  [EVENTS.NOTIFICATION_PREFERENCES_UPDATED]: { preference?: string; enabled?: boolean; success: boolean };
510
+
511
+ // Native session lifecycle (159, contract session-reports.md). `outcome`
512
+ // covers all three launch reports in one event (restored / none / degraded)
513
+ // rather than three near-duplicate event names — the same pattern as
514
+ // ACCESS_DENIED's `reason`. `cause` on the ending is mandatory (contract
515
+ // Rule 1): an ending without a cause tells a reader nothing a bug and a
516
+ // person didn't already look identical.
517
+ [EVENTS.NATIVE_SESSION_LAUNCHED]: { outcome: 'restored' | 'none' | 'degraded' };
518
+ [EVENTS.NATIVE_SESSION_RENEWED]: Record<string, never>;
519
+ [EVENTS.NATIVE_SESSION_ENDED]: { cause: 'rejected' | 'sign_out' };
503
520
  }
504
521
 
505
522
  /** Canonical person property keys (set via identify / $set). */
@@ -516,6 +533,19 @@ export const PERSON_PROPS = {
516
533
 
517
534
  export type PersonPropKey = (typeof PERSON_PROPS)[keyof typeof PERSON_PROPS];
518
535
 
536
+ /**
537
+ * Canonical launch-context SUPER-property keys (159 US2). Registered once per
538
+ * session (like `is_pwa` / `display_mode` / `app_platform` in
539
+ * registerLaunchContext), so they ride every event without a per-event field.
540
+ * `APP_BUILD` is the only one governed here today — the value MUST come from
541
+ * the build itself (contract Rule 4), never a hand-maintained constant.
542
+ */
543
+ export const LAUNCH_CONTEXT_PROPS = {
544
+ APP_BUILD: 'app_build',
545
+ } as const;
546
+
547
+ export type LaunchContextPropKey = (typeof LAUNCH_CONTEXT_PROPS)[keyof typeof LAUNCH_CONTEXT_PROPS];
548
+
519
549
  /**
520
550
  * Compile-time taxonomy contract (AD2-952). These are pure type-level assertions:
521
551
  * if EVENTS and EventProperties ever drift, the `tsc --noEmit` CI gate fails the