spine-framework-cortex 0.1.18 → 0.1.19

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 CHANGED
@@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ---
6
6
 
7
+ ## [0.1.19] — 2026-06-10
8
+ - Added `session_signals` link type + link creation in `upsertAnonymousSession()`
9
+ - Fixed scoring data path — flattened `scoring_components` to match `funnel_signal` schema (raw_score_rating, engagement_type, recency_window, etc.)
10
+
7
11
  ## [0.1.18] — 2026-06-10
8
12
  - Fixed `custom_funnel-signal.ts` — added required `account_id` to anonymous_session insert (links to unidentified-visitors account)
9
13
 
@@ -47,13 +47,14 @@ export async function processSignal(
47
47
  const payload = validation.data
48
48
 
49
49
  // 2. RESOLVE IDs (read-only type/account lookups)
50
- const [signalTypeId, sessionTypeId, queueTypeId, signalLinkTypeId, opportunityLinkTypeId, unidentifiedAccountId] =
50
+ const [signalTypeId, sessionTypeId, queueTypeId, signalLinkTypeId, opportunityLinkTypeId, sessionLinkTypeId, unidentifiedAccountId] =
51
51
  await Promise.all([
52
52
  resolveTypeId('funnel_signal'),
53
53
  resolveTypeId('anonymous_session'),
54
54
  resolveTypeId('opportunity_queue'),
55
55
  resolveLinkTypeId('account_signals'),
56
56
  resolveLinkTypeId('account_opportunities'),
57
+ resolveLinkTypeId('session_signals'),
57
58
  resolveUnidentifiedAccountId(),
58
59
  ])
59
60
 
@@ -94,11 +95,17 @@ export async function processSignal(
94
95
  action_description: payload.action_description || null,
95
96
  url: payload.url || null,
96
97
  },
97
- scoring_components: {
98
- engagement: { type: engagement.type, context: engagement.context, session_depth: engagement.session_depth, prior_session_count: engagement.prior_session_count || 0 },
99
- recency: { divisor: recency.divisor, age_days: recency.age_days, window: recency.window },
100
- raw_score: { calculated: scoring.calculated, max_possible: scoring.max_possible, rating: scoring.rating },
101
- },
98
+ // Scoring - flattened to match schema field names
99
+ raw_score_calculated: scoring.calculated,
100
+ raw_score_max_possible: scoring.max_possible,
101
+ raw_score_rating: scoring.rating,
102
+ engagement_type: engagement.type,
103
+ engagement_context: engagement.context,
104
+ engagement_session_depth: engagement.session_depth,
105
+ engagement_prior_session_count: engagement.prior_session_count || 0,
106
+ recency_divisor: recency.divisor,
107
+ recency_age_days: recency.age_days,
108
+ recency_window: recency.window,
102
109
  attribution: {
103
110
  immediate_referrer: payload.referrer || null,
104
111
  first_touch_referrer_domain: referrerDomain,
@@ -144,7 +151,7 @@ export async function processSignal(
144
151
  await createLink(signalLinkTypeId, 'account', payload.account_id, 'item', signalId)
145
152
  }
146
153
  } else if (payload.anonymous_id && sessionTypeId && unidentifiedAccountId) {
147
- await upsertAnonymousSession(payload, sessionTypeId, unidentifiedAccountId, signalId, scoring, engagement, referrerDomain, referrerCategory, scoredAt)
154
+ await upsertAnonymousSession(payload, sessionTypeId, unidentifiedAccountId, signalId, scoring, engagement, referrerDomain, referrerCategory, scoredAt, sessionLinkTypeId)
148
155
  }
149
156
 
150
157
  // 7. EVALUATE QUEUE — if rating >= 4
@@ -287,7 +294,8 @@ async function updateAccountFunnel(
287
294
  async function upsertAnonymousSession(
288
295
  payload: SignalPayload, sessionTypeId: string, accountId: string, signalId: string,
289
296
  scoring: { calculated: number; max_possible: number; rating: number },
290
- engagement: any, referrerDomain: string, referrerCategory: string, now: string
297
+ engagement: any, referrerDomain: string, referrerCategory: string, now: string,
298
+ sessionLinkTypeId: string | null
291
299
  ): Promise<void> {
292
300
  const { data: existing } = await adminDb
293
301
  .from('items')
@@ -318,8 +326,12 @@ async function upsertAnonymousSession(
318
326
  } : {}),
319
327
  },
320
328
  }).eq('id', existing.id)
329
+ // Link existing session to new signal
330
+ if (sessionLinkTypeId) {
331
+ await createLink(sessionLinkTypeId, 'item', existing.id, 'item', signalId)
332
+ }
321
333
  } else {
322
- await adminDb.from('items').insert({
334
+ const { data: newSession } = await adminDb.from('items').insert({
323
335
  type_id: sessionTypeId,
324
336
  account_id: accountId,
325
337
  title: `Anonymous: ${payload.anonymous_id!.slice(0, 8)}`,
@@ -348,7 +360,11 @@ async function upsertAnonymousSession(
348
360
  retention_retention_days: 90,
349
361
  retention_purge_after: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString(),
350
362
  },
351
- })
363
+ }).select('id').single()
364
+ // Link new session to signal
365
+ if (sessionLinkTypeId && newSession) {
366
+ await createLink(sessionLinkTypeId, 'item', newSession.id, 'item', signalId)
367
+ }
352
368
  }
353
369
  }
354
370
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework-cortex",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
4
4
  "description": "Cortex — AI-powered support, CRM, and knowledge base app for Spine Framework",
5
5
  "type": "module",
6
6
  "license": "SEE LICENSE IN LICENSE.md",