spine-framework-cortex 0.1.17 → 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,13 @@ 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
+
11
+ ## [0.1.18] — 2026-06-10
12
+ - Fixed `custom_funnel-signal.ts` — added required `account_id` to anonymous_session insert (links to unidentified-visitors account)
13
+
7
14
  ## [0.1.17] — 2026-06-10
8
15
  - Fixed `custom_funnel-signal.ts` — moved `anonymous_id` from nested `data.identity.anonymous_id` to root `data.anonymous_id` to match `anonymous_session` type schema (required field)
9
16
 
@@ -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,
@@ -143,8 +150,8 @@ export async function processSignal(
143
150
  if (signalLinkTypeId) {
144
151
  await createLink(signalLinkTypeId, 'account', payload.account_id, 'item', signalId)
145
152
  }
146
- } else if (payload.anonymous_id && sessionTypeId) {
147
- await upsertAnonymousSession(payload, sessionTypeId, signalId, scoring, engagement, referrerDomain, referrerCategory, scoredAt)
153
+ } else if (payload.anonymous_id && sessionTypeId && unidentifiedAccountId) {
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
@@ -285,15 +292,16 @@ async function updateAccountFunnel(
285
292
  // ============================================
286
293
 
287
294
  async function upsertAnonymousSession(
288
- payload: SignalPayload, sessionTypeId: string, signalId: string,
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')
294
302
  .select('id, data')
295
303
  .eq('type_id', sessionTypeId)
296
- .eq('data->identity->>anonymous_id' as any, payload.anonymous_id!)
304
+ .eq('data->>anonymous_id' as any, payload.anonymous_id!)
297
305
  .order('created_at', { ascending: false })
298
306
  .limit(1)
299
307
  .maybeSingle()
@@ -318,9 +326,14 @@ 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,
336
+ account_id: accountId,
324
337
  title: `Anonymous: ${payload.anonymous_id!.slice(0, 8)}`,
325
338
  data: {
326
339
  anonymous_id: payload.anonymous_id,
@@ -347,7 +360,11 @@ async function upsertAnonymousSession(
347
360
  retention_retention_days: 90,
348
361
  retention_purge_after: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString(),
349
362
  },
350
- })
363
+ }).select('id').single()
364
+ // Link new session to signal
365
+ if (sessionLinkTypeId && newSession) {
366
+ await createLink(sessionLinkTypeId, 'item', newSession.id, 'item', signalId)
367
+ }
351
368
  }
352
369
  }
353
370
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-framework-cortex",
3
- "version": "0.1.17",
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",