ad2app-lib 1.35.0 → 1.37.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. */
@@ -251,7 +254,7 @@ export interface EventProperties {
251
254
  role: string;
252
255
  };
253
256
  [EVENTS.LOGGED_IN]: {
254
- method?: 'email' | 'google';
257
+ method?: 'email' | 'google' | 'apple';
255
258
  };
256
259
  [EVENTS.SOCIAL_ACCOUNT_CONNECTED]: {
257
260
  platform: string;
@@ -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.37.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,
@@ -86,7 +86,9 @@ const EVENT_PROPERTY_WITNESS: { [E in keyof EventProperties]: EventProperties[E]
86
86
  [EVENTS.PLAYBOOK_DOWNLOADED]: {},
87
87
  [EVENTS.SIGNED_UP]: { method: "email", role: "creator" },
88
88
  [EVENTS.PROFILE_COMPLETED]: { role: "creator" },
89
- [EVENTS.LOGGED_IN]: {},
89
+ // Spec 161 T010: proves 'apple' type-checks alongside the pre-existing
90
+ // 'email' | 'google' union (compile-time, enforced by `tsc --noEmit`).
91
+ [EVENTS.LOGGED_IN]: { method: "apple" },
90
92
  [EVENTS.SOCIAL_ACCOUNT_CONNECTED]: { platform: "instagram" },
91
93
  [EVENTS.COMPOSE_STARTED]: {},
92
94
  [EVENTS.COMPOSE_STEP_VIEWED]: { step: "content" },
@@ -133,6 +135,10 @@ const EVENT_PROPERTY_WITNESS: { [E in keyof EventProperties]: EventProperties[E]
133
135
  [EVENTS.POST_RESCHEDULED]: { success: true },
134
136
  [EVENTS.ACCOUNT_DISCONNECTED]: { platform: "instagram", success: true },
135
137
  [EVENTS.NOTIFICATION_PREFERENCES_UPDATED]: { success: true },
138
+ // 159 native session lifecycle
139
+ [EVENTS.NATIVE_SESSION_LAUNCHED]: { outcome: "restored" },
140
+ [EVENTS.NATIVE_SESSION_RENEWED]: {},
141
+ [EVENTS.NATIVE_SESSION_ENDED]: { cause: "rejected" },
136
142
  };
137
143
 
138
144
  test("EVENTS values are 1:1 with EventProperties keys (no missing or typo'd event)", () => {
@@ -455,3 +461,47 @@ test("120 playbook events carry the edition stamp", () => {
455
461
  assert.equal(opened.edition_version, "2026.08");
456
462
  assert.equal(downloaded.format, "pdf");
457
463
  });
464
+
465
+ // 159: the native session lifecycle + build attribution.
466
+
467
+ test("159 native session wire names are locked", () => {
468
+ assert.equal(EVENTS.NATIVE_SESSION_LAUNCHED, "native_session_launched");
469
+ assert.equal(EVENTS.NATIVE_SESSION_RENEWED, "native_session_renewed");
470
+ assert.equal(EVENTS.NATIVE_SESSION_ENDED, "native_session_ended");
471
+ });
472
+
473
+ test("159 native_session_launched carries a closed outcome — restored, none, or degraded", () => {
474
+ const restored: EventProperties[typeof EVENTS.NATIVE_SESSION_LAUNCHED] = { outcome: "restored" };
475
+ const none: EventProperties[typeof EVENTS.NATIVE_SESSION_LAUNCHED] = { outcome: "none" };
476
+ const degraded: EventProperties[typeof EVENTS.NATIVE_SESSION_LAUNCHED] = { outcome: "degraded" };
477
+ assert.equal(restored.outcome, "restored");
478
+ assert.equal(none.outcome, "none");
479
+ assert.equal(degraded.outcome, "degraded");
480
+ });
481
+
482
+ test("159 native_session_ended carries its cause — rejected or sign_out, never bare", () => {
483
+ const rejected: EventProperties[typeof EVENTS.NATIVE_SESSION_ENDED] = { cause: "rejected" };
484
+ const signOut: EventProperties[typeof EVENTS.NATIVE_SESSION_ENDED] = { cause: "sign_out" };
485
+ assert.equal(rejected.cause, "rejected");
486
+ assert.equal(signOut.cause, "sign_out");
487
+ });
488
+
489
+ test("159 native_session_renewed carries no properties (the fact of the renewal is the whole report)", () => {
490
+ const renewed: EventProperties[typeof EVENTS.NATIVE_SESSION_RENEWED] = {};
491
+ assert.deepEqual(renewed, {});
492
+ });
493
+
494
+ test("161 logged_in.method accepts all three sign-in methods, and stays optional", () => {
495
+ const email: EventProperties[typeof EVENTS.LOGGED_IN] = { method: "email" };
496
+ const google: EventProperties[typeof EVENTS.LOGGED_IN] = { method: "google" };
497
+ const apple: EventProperties[typeof EVENTS.LOGGED_IN] = { method: "apple" };
498
+ const unset: EventProperties[typeof EVENTS.LOGGED_IN] = {};
499
+ assert.equal(email.method, "email");
500
+ assert.equal(google.method, "google");
501
+ assert.equal(apple.method, "apple");
502
+ assert.deepEqual(unset, {});
503
+ });
504
+
505
+ test("159 LAUNCH_CONTEXT_PROPS governs the build-attribution key (no raw 'app_build' string at the call site)", () => {
506
+ assert.equal(LAUNCH_CONTEXT_PROPS.APP_BUILD, "app_build");
507
+ });
@@ -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];
@@ -334,7 +341,11 @@ export interface EventProperties {
334
341
  [EVENTS.PLAYBOOK_DOWNLOADED]: { edition_version?: string; format?: string };
335
342
  [EVENTS.SIGNED_UP]: { method: 'email' | 'google'; role: string };
336
343
  [EVENTS.PROFILE_COMPLETED]: { role: string };
337
- [EVENTS.LOGGED_IN]: { method?: 'email' | 'google' };
344
+ // Spec 161: widened to include 'apple' the value was already missing from
345
+ // this union (Google/email only) even though native Apple sign-in has
346
+ // existed since spec 136; this closes that gap rather than inventing a new
347
+ // property.
348
+ [EVENTS.LOGGED_IN]: { method?: 'email' | 'google' | 'apple' };
338
349
  [EVENTS.SOCIAL_ACCOUNT_CONNECTED]: {
339
350
  platform: string;
340
351
  account_count?: number;
@@ -500,6 +511,16 @@ export interface EventProperties {
500
511
 
501
512
  // Settings — which preference toggled and its new state.
502
513
  [EVENTS.NOTIFICATION_PREFERENCES_UPDATED]: { preference?: string; enabled?: boolean; success: boolean };
514
+
515
+ // Native session lifecycle (159, contract session-reports.md). `outcome`
516
+ // covers all three launch reports in one event (restored / none / degraded)
517
+ // rather than three near-duplicate event names — the same pattern as
518
+ // ACCESS_DENIED's `reason`. `cause` on the ending is mandatory (contract
519
+ // Rule 1): an ending without a cause tells a reader nothing a bug and a
520
+ // person didn't already look identical.
521
+ [EVENTS.NATIVE_SESSION_LAUNCHED]: { outcome: 'restored' | 'none' | 'degraded' };
522
+ [EVENTS.NATIVE_SESSION_RENEWED]: Record<string, never>;
523
+ [EVENTS.NATIVE_SESSION_ENDED]: { cause: 'rejected' | 'sign_out' };
503
524
  }
504
525
 
505
526
  /** Canonical person property keys (set via identify / $set). */
@@ -516,6 +537,19 @@ export const PERSON_PROPS = {
516
537
 
517
538
  export type PersonPropKey = (typeof PERSON_PROPS)[keyof typeof PERSON_PROPS];
518
539
 
540
+ /**
541
+ * Canonical launch-context SUPER-property keys (159 US2). Registered once per
542
+ * session (like `is_pwa` / `display_mode` / `app_platform` in
543
+ * registerLaunchContext), so they ride every event without a per-event field.
544
+ * `APP_BUILD` is the only one governed here today — the value MUST come from
545
+ * the build itself (contract Rule 4), never a hand-maintained constant.
546
+ */
547
+ export const LAUNCH_CONTEXT_PROPS = {
548
+ APP_BUILD: 'app_build',
549
+ } as const;
550
+
551
+ export type LaunchContextPropKey = (typeof LAUNCH_CONTEXT_PROPS)[keyof typeof LAUNCH_CONTEXT_PROPS];
552
+
519
553
  /**
520
554
  * Compile-time taxonomy contract (AD2-952). These are pure type-level assertions:
521
555
  * if EVENTS and EventProperties ever drift, the `tsc --noEmit` CI gate fails the