@reactionary/source 0.3.1 → 0.3.2

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.
@@ -1,3 +1,4 @@
1
+ import type { AnonymousIdentity } from './schemas/index.js';
1
2
  import type { RequestContext } from './schemas/session.schema.js';
2
3
 
3
4
  export function createInitialRequestContext(): RequestContext {
@@ -17,7 +18,9 @@ export function createInitialRequestContext(): RequestContext {
17
18
  },
18
19
  session: {
19
20
  identityContext: {
20
- identifier: { userId: '' },
21
+ identity: {
22
+ type: 'Anonymous'
23
+ } satisfies AnonymousIdentity,
21
24
  lastUpdated: new Date(),
22
25
  personalizationKey: crypto.randomUUID(),
23
26
  },
@@ -13,4 +13,9 @@ export abstract class IdentityProvider extends BaseProvider {
13
13
  protected override getResourceName(): string {
14
14
  return 'identity';
15
15
  }
16
+
17
+ protected updateIdentityContext(identity: Identity) {
18
+ this.context.session.identityContext.lastUpdated = new Date();
19
+ this.context.session.identityContext.identity = identity;
20
+ }
16
21
  }
@@ -1,6 +1,7 @@
1
1
  import { z } from 'zod';
2
2
  import { IdentityIdentifierSchema, WebStoreIdentifierSchema } from './models/identifiers.model.js';
3
3
  import { CurrencySchema } from './models/currency.model.js';
4
+ import { IdentitySchema } from './models/identity.model.js';
4
5
 
5
6
  /**
6
7
  * The language and locale context for the current request.
@@ -11,7 +12,7 @@ export const LanguageContextSchema = z.looseObject( {
11
12
  });
12
13
 
13
14
  export const IdentityContextSchema = z.looseObject({
14
- identifier: IdentityIdentifierSchema,
15
+ identity: IdentitySchema,
15
16
  personalizationKey: z.string(),
16
17
  lastUpdated: z.date()
17
18
  });
@@ -6,4 +6,4 @@ Reactionary takes the approach that tracking customer data should be structured
6
6
  - Structure: it should be possible to reason about what is tracked on the site, how it is tracked and when it is tracked without having to visit seven different tag managers.
7
7
  - Security: pulling in all the embedded and inline scripts from every tag manager is a security incident waiting to happen.
8
8
 
9
- To this end the client exposes a single provider in the form of `client.analytics`. This client is internally responsible for delegating events to all relevant subscribers capabilities used to build the client. This means that a single call to record a pageview or attribution will be enough, even if that data internally needs to be multiplexed to GA4, Algolia and Posthog as an example.
9
+ To this end the client exposes a single provider in the form of `client.analytics`. This client is internally responsible for delegating events to all relevant subscribers capabilities used to build the client. This means that a single call to record a pageview or attribution will be enough, even if that data internally needs to be multiplexed to GA4, Algolia and Posthog as an example.
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@reactionary/examples-node",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "dependencies": {
7
- "@reactionary/core": "0.3.1",
8
- "@reactionary/provider-commercetools": "0.3.1",
9
- "@reactionary/provider-algolia": "0.3.1",
10
- "@reactionary/provider-medusa": "0.3.1",
11
- "@reactionary/provider-meilisearch": "0.3.1"
7
+ "@reactionary/core": "0.3.2",
8
+ "@reactionary/provider-commercetools": "0.3.2",
9
+ "@reactionary/provider-algolia": "0.3.2",
10
+ "@reactionary/provider-medusa": "0.3.2",
11
+ "@reactionary/provider-meilisearch": "0.3.2"
12
12
  },
13
13
  "type": "module"
14
14
  }
@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest';
2
2
  import { ClientBuilder, createInitialRequestContext, NoOpCache } from '@reactionary/core';
3
3
  import { FakeProductProvider, withFakeCapabilities } from '@reactionary/provider-fake';
4
4
  import { CommercetoolsCartProvider, withCommercetoolsCapabilities } from '@reactionary/provider-commercetools';
5
- import { AlgoliaSearchProvider, withAlgoliaCapabilities } from '@reactionary/provider-algolia';
5
+ import { AlgoliaProductSearchProvider, withAlgoliaCapabilities } from '@reactionary/provider-algolia';
6
6
 
7
7
  describe('client creation', () => {
8
8
  it('should be able to mix providers and get a valid, typed client', async () => {
@@ -48,6 +48,6 @@ describe('client creation', () => {
48
48
 
49
49
  expect(client.cart).toBeInstanceOf(CommercetoolsCartProvider);
50
50
  expect(client.product).toBeInstanceOf(FakeProductProvider);
51
- expect(client.productSearch).toBeInstanceOf(AlgoliaSearchProvider);
51
+ expect(client.productSearch).toBeInstanceOf(AlgoliaProductSearchProvider);
52
52
  });
53
53
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@reactionary/source",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "license": "MIT",
5
5
  "private": false,
6
6
  "dependencies": {
@@ -38,11 +38,19 @@ You can have more, for use with facets, and additional searchable fields, but th
38
38
 
39
39
  The `objectID` corrosponds to your productIdentifier, and `variantID` should match your SKU
40
40
 
41
+ ## Analytics
41
42
 
42
- ## Building
43
+ The Algolia analytics provider maps the following tracked event types to data tracked in Algolia:
43
44
 
44
- Run `nx build provider-algolia` to build the library.
45
+ - AnalyticsMutationProductSummaryViewEvent => ViewedObjectIDs
46
+ - AnalyticsMutationProductSummaryClickEvent => ClickedObjectIDsAfterSearch / ClickedObjectIDs
47
+ - AnalyticsMutationProductAddToCartEvent => AddedToCartObjectIDsAfterSearch / AddedToCartObjectIDs
48
+ - AnalyticsMutationPurchaseEvent => PurchasedObjectIDs
45
49
 
46
- ## Running unit tests
50
+ The `AfterSearch` variants are (with the exception of purchase) preferred by the provider in the cases where Algolia is the source of the events. For search or recommendation this would typically be the case, but not necesarily for users arriving on a PDP as a direct target from a search or a link.
47
51
 
48
- Run `nx test provider-algolia` to execute the unit tests via [Jest](https://jestjs.io).
52
+ Note that we do not map `PurchasedObjectIDsAfterSearch` as it would require us to persist the search query ID that lead to the add-to-cart occuring on the cart items. This currently seems like an excess burden to impose on the cart interface.
53
+
54
+ The `ConvertedObjectIDs` and `ConvertedObjectIDsAfterSearch` are not mapped as they seem superfluous by all accounts in a product-purchase based flow. They could likely be used for other types of conversions in a more general setup, such as a customer finishing reading an article.
55
+
56
+ Finally the events that are related to filtering are not mapped, as they are by all accounts deprecated and no longer influence any of the recommendation or personalization features.
@@ -1,5 +1,5 @@
1
1
  import type { Cache, ClientFromCapabilities, RequestContext } from "@reactionary/core";
2
- import { AlgoliaSearchProvider } from "../providers/product-search.provider.js";
2
+ import { AlgoliaProductSearchProvider } from "../providers/product-search.provider.js";
3
3
  import type { AlgoliaCapabilities } from "../schema/capabilities.schema.js";
4
4
  import type { AlgoliaConfiguration } from "../schema/configuration.schema.js";
5
5
  import { AlgoliaAnalyticsProvider } from "../providers/analytics.provider.js";
@@ -9,7 +9,7 @@ export function withAlgoliaCapabilities<T extends AlgoliaCapabilities>(configura
9
9
  const client: any = {};
10
10
 
11
11
  if (capabilities.productSearch) {
12
- client.productSearch = new AlgoliaSearchProvider(configuration, cache, context);
12
+ client.productSearch = new AlgoliaProductSearchProvider(cache, context, configuration);
13
13
  }
14
14
 
15
15
  if (capabilities.analytics) {
@@ -8,12 +8,12 @@ import {
8
8
  type RequestContext,
9
9
  } from '@reactionary/core';
10
10
  import {
11
- insightsClient,
12
11
  type InsightsClient,
13
12
  type ViewedObjectIDs,
14
13
  type ClickedObjectIDsAfterSearch,
15
14
  type AddedToCartObjectIDsAfterSearch,
16
15
  type PurchasedObjectIDs,
16
+ algoliasearch,
17
17
  } from 'algoliasearch';
18
18
  import type { AlgoliaConfiguration } from '../schema/configuration.schema.js';
19
19
  import type { AlgoliaProductSearchIdentifier } from '../schema/search.schema.js';
@@ -30,7 +30,7 @@ export class AlgoliaAnalyticsProvider extends AnalyticsProvider {
30
30
  super(cache, requestContext);
31
31
 
32
32
  this.config = config;
33
- this.client = insightsClient(this.config.appId, this.config.apiKey);
33
+ this.client = algoliasearch(this.config.appId, this.config.apiKey).initInsights({});
34
34
  }
35
35
 
36
36
  protected override async processProductAddToCart(
@@ -48,7 +48,7 @@ export class AlgoliaAnalyticsProvider extends AnalyticsProvider {
48
48
  .key,
49
49
  } satisfies AddedToCartObjectIDsAfterSearch;
50
50
 
51
- this.client.pushEvents({
51
+ const response = await this.client.pushEvents({
52
52
  events: [algoliaEvent],
53
53
  });
54
54
  }
@@ -69,7 +69,7 @@ export class AlgoliaAnalyticsProvider extends AnalyticsProvider {
69
69
  .key,
70
70
  } satisfies ClickedObjectIDsAfterSearch;
71
71
 
72
- this.client.pushEvents({
72
+ const response = await this.client.pushEvents({
73
73
  events: [algoliaEvent],
74
74
  });
75
75
  }
@@ -87,7 +87,7 @@ export class AlgoliaAnalyticsProvider extends AnalyticsProvider {
87
87
  userToken: this.context.session.identityContext.personalizationKey,
88
88
  } satisfies ViewedObjectIDs;
89
89
 
90
- this.client.pushEvents({
90
+ const response = await this.client.pushEvents({
91
91
  events: [algoliaEvent],
92
92
  });
93
93
  }
@@ -96,16 +96,18 @@ export class AlgoliaAnalyticsProvider extends AnalyticsProvider {
96
96
  protected override async processPurchase(
97
97
  event: AnalyticsMutationPurchaseEvent
98
98
  ): Promise<void> {
99
+ // TODO: Figure out how to handle the problem below. From the order we have the SKUs,
100
+ // but in Algolia we have the products indexed, and we can't really resolve it here...
99
101
  const algoliaEvent = {
100
102
  eventName: 'purchase',
101
103
  eventType: 'conversion',
102
104
  eventSubtype: 'purchase',
103
105
  index: this.config.indexName,
104
- objectIDs: event.order.items.map((x) => x.identifier.key),
106
+ objectIDs: event.order.items.map((x) => x.variant.sku),
105
107
  userToken: this.context.session.identityContext.personalizationKey,
106
108
  } satisfies PurchasedObjectIDs;
107
109
 
108
- this.client.pushEvents({
110
+ const response = await this.client.pushEvents({
109
111
  events: [algoliaEvent],
110
112
  });
111
113
  }
@@ -40,10 +40,10 @@ interface AlgoliaNativeRecord {
40
40
  }
41
41
 
42
42
 
43
- export class AlgoliaSearchProvider extends ProductSearchProvider {
43
+ export class AlgoliaProductSearchProvider extends ProductSearchProvider {
44
44
  protected config: AlgoliaConfiguration;
45
45
 
46
- constructor(config: AlgoliaConfiguration, cache: Cache, context: RequestContext) {
46
+ constructor(cache: Cache, context: RequestContext, config: AlgoliaConfiguration) {
47
47
  super(cache, context);
48
48
  this.config = config;
49
49
  }
@@ -195,7 +195,8 @@ export class AlgoliaSearchProvider extends ProductSearchProvider {
195
195
  facets: query.search.facets,
196
196
  filters: query.search.filters,
197
197
  paginationOptions: query.search.paginationOptions,
198
-
198
+ index: body.index || '',
199
+ key: body.queryID || '',
199
200
  },
200
201
  pageNumber: (body.page || 0) + 1,
201
202
  pageSize: body.hitsPerPage || 0,
@@ -203,7 +204,7 @@ export class AlgoliaSearchProvider extends ProductSearchProvider {
203
204
  totalPages: body.nbPages || 0,
204
205
  items: items,
205
206
  facets,
206
- } satisfies ProductSearchResult;
207
+ } satisfies AlgoliaProductSearchResult;
207
208
 
208
209
  return result;
209
210
  }
@@ -0,0 +1,138 @@
1
+ import { describe, it, assert } from 'vitest';
2
+ import { AlgoliaAnalyticsProvider } from '../providers/analytics.provider.js';
3
+ import { createInitialRequestContext, NoOpCache } from '@reactionary/core';
4
+ import type { AlgoliaConfiguration } from '../schema/configuration.schema.js';
5
+ import { AlgoliaProductSearchProvider } from '../providers/product-search.provider.js';
6
+
7
+ describe('Analytics event tracking', async () => {
8
+ const config = {
9
+ apiKey: process.env['ALGOLIA_API_KEY'] || '',
10
+ appId: process.env['ALGOLIA_APP_ID'] || '',
11
+ indexName: process.env['ALGOLIA_INDEX'] || '',
12
+ } satisfies AlgoliaConfiguration;
13
+ const cache = new NoOpCache();
14
+ const context = createInitialRequestContext();
15
+
16
+ const search = new AlgoliaProductSearchProvider(cache, context, config);
17
+ const analytics = new AlgoliaAnalyticsProvider(cache, context, config);
18
+ const searchResult = await search.queryByTerm({
19
+ search: {
20
+ facets: [],
21
+ filters: [],
22
+ paginationOptions: {
23
+ pageNumber: 1,
24
+ pageSize: 10,
25
+ },
26
+ term: 'q',
27
+ },
28
+ });
29
+
30
+ if (!searchResult.success) {
31
+ assert.fail();
32
+ }
33
+
34
+ it('can track summary clicks', async () => {
35
+ await analytics.track({
36
+ event: 'product-summary-click',
37
+ product: searchResult.value.items[0].identifier,
38
+ position: 1,
39
+ source: {
40
+ type: 'search',
41
+ identifier: searchResult.value.identifier,
42
+ },
43
+ });
44
+ });
45
+
46
+ it('can track summary views', async () => {
47
+ await analytics.track({
48
+ event: 'product-summary-view',
49
+ products: searchResult.value.items.map((x) => x.identifier),
50
+ source: {
51
+ type: 'search',
52
+ identifier: searchResult.value.identifier,
53
+ },
54
+ });
55
+ });
56
+
57
+ it('can track add to cart', async () => {
58
+ await analytics.track({
59
+ event: 'product-cart-add',
60
+ product: searchResult.value.items[0].identifier,
61
+ source: {
62
+ type: 'search',
63
+ identifier: searchResult.value.identifier,
64
+ },
65
+ });
66
+ });
67
+
68
+ it('can track purchase', async () => {
69
+ await analytics.track({
70
+ event: 'purchase',
71
+ order: {
72
+ identifier: {
73
+ key: crypto.randomUUID(),
74
+ },
75
+ inventoryStatus: 'Allocated',
76
+ items: [
77
+ {
78
+ identifier: {
79
+ key: crypto.randomUUID(),
80
+ },
81
+ inventoryStatus: 'Allocated',
82
+ price: {
83
+ unitPrice: {
84
+ currency: 'USD',
85
+ value: 50,
86
+ },
87
+ totalDiscount: {
88
+ currency: 'USD',
89
+ value: 0,
90
+ },
91
+ totalPrice: {
92
+ currency: 'USD',
93
+ value: 50,
94
+ },
95
+ unitDiscount: {
96
+ currency: 'USD',
97
+ value: 0,
98
+ },
99
+ },
100
+ quantity: 1,
101
+ variant: searchResult.value.items[0].variants[0].variant,
102
+ },
103
+ ],
104
+ orderStatus: 'Shipped',
105
+ paymentInstructions: [],
106
+ price: {
107
+ grandTotal: {
108
+ currency: 'USD',
109
+ value: 50,
110
+ },
111
+ totalDiscount: {
112
+ currency: 'USD',
113
+ value: 0,
114
+ },
115
+ totalProductPrice: {
116
+ currency: 'USD',
117
+ value: 50,
118
+ },
119
+ totalShipping: {
120
+ currency: 'USD',
121
+ value: 0,
122
+ },
123
+ totalSurcharge: {
124
+ currency: 'USD',
125
+ value: 0,
126
+ },
127
+ totalTax: {
128
+ currency: 'USD',
129
+ value: 0,
130
+ },
131
+ },
132
+ userId: {
133
+ userId: crypto.randomUUID()
134
+ }
135
+ },
136
+ });
137
+ });
138
+ });
@@ -15,7 +15,6 @@ import {
15
15
  success,
16
16
  } from '@reactionary/core';
17
17
  import type { CommercetoolsConfiguration } from '../schema/configuration.schema.js';
18
- import type z from 'zod';
19
18
  import type { CommercetoolsAPI } from '../core/client.js';
20
19
 
21
20
  export class CommercetoolsIdentityProvider extends IdentityProvider {
@@ -41,6 +40,8 @@ export class CommercetoolsIdentityProvider extends IdentityProvider {
41
40
  public override async getSelf(payload: IdentityQuerySelf): Promise<Result<Identity>> {
42
41
  const identity = await this.commercetools.introspect();
43
42
 
43
+ this.updateIdentityContext(identity);
44
+
44
45
  return success(identity);
45
46
  }
46
47
 
@@ -54,6 +55,8 @@ export class CommercetoolsIdentityProvider extends IdentityProvider {
54
55
  payload.password
55
56
  );
56
57
 
58
+ this.updateIdentityContext(identity);
59
+
57
60
  return success(identity);
58
61
  }
59
62
 
@@ -63,6 +66,8 @@ export class CommercetoolsIdentityProvider extends IdentityProvider {
63
66
  public override async logout(payload: Record<string, never>): Promise<Result<Identity>> {
64
67
  const identity = await this.commercetools.logout();
65
68
 
69
+ this.updateIdentityContext(identity);
70
+
66
71
  return success(identity);
67
72
  }
68
73
 
@@ -78,6 +83,8 @@ export class CommercetoolsIdentityProvider extends IdentityProvider {
78
83
  payload.password
79
84
  );
80
85
 
86
+ this.updateIdentityContext(identity);
87
+
81
88
  return success(identity);
82
89
  }
83
90
  }
@@ -8,7 +8,7 @@ import {
8
8
  type ProductSearchQueryByTerm,
9
9
  } from '@reactionary/core';
10
10
  import { CommercetoolsProductProvider } from '../providers/product.provider.js';
11
- import { CommercetoolsClient } from '../core/client.js';
11
+ import { CommercetoolsAPI } from '../core/client.js';
12
12
  import { CommercetoolsSearchProvider } from '../providers/product-search.provider.js';
13
13
 
14
14
  describe('Caching', () => {
@@ -16,7 +16,7 @@ describe('Caching', () => {
16
16
  const config = getCommercetoolsTestConfiguration();
17
17
  const context = createInitialRequestContext();
18
18
  const cache = new MemoryCache();
19
- const client = new CommercetoolsClient(config, context);
19
+ const client = new CommercetoolsAPI(config, context);
20
20
  const provider = new CommercetoolsProductProvider(config, cache, context, client);
21
21
 
22
22
  const identifier = {
@@ -48,7 +48,7 @@ describe('Caching', () => {
48
48
  const config = getCommercetoolsTestConfiguration();
49
49
  const context = createInitialRequestContext();
50
50
  const cache = new MemoryCache();
51
- const client = new CommercetoolsClient(config, context);
51
+ const client = new CommercetoolsAPI(config, context);
52
52
  const provider = new CommercetoolsSearchProvider(config, cache, context, client);
53
53
 
54
54
  const query = {
@@ -1,6 +1,6 @@
1
1
  import 'dotenv/config';
2
2
  import { describe, expect, it } from 'vitest';
3
- import { CommercetoolsClient } from '../core/client.js';
3
+ import { CommercetoolsAPI } from '../core/client.js';
4
4
  import { getCommercetoolsTestConfiguration } from './test-utils.js';
5
5
  import {
6
6
  createInitialRequestContext,
@@ -12,7 +12,7 @@ import type { CommercetoolsConfiguration } from '../schema/configuration.schema.
12
12
  function setup() {
13
13
  const config = getCommercetoolsTestConfiguration();
14
14
  const context = createInitialRequestContext();
15
- const root = new CommercetoolsClient(config, context);
15
+ const root = new CommercetoolsAPI(config, context);
16
16
 
17
17
  return {
18
18
  config,
@@ -7,12 +7,6 @@
7
7
  "@reactionary/core": "0.0.1",
8
8
  "zod": "4.1.9"
9
9
  },
10
- "devDependencies": {
11
- "vitest": "*",
12
- "@vitest/ui": "*",
13
- "@vitest/coverage-v8": "*",
14
- "vite-tsconfig-paths": "*"
15
- },
16
10
  "type": "module",
17
11
  "sideEffects": false
18
12
  }
@@ -19,7 +19,6 @@ import {
19
19
  success,
20
20
  } from '@reactionary/core';
21
21
  import type { MedusaConfiguration } from '../schema/configuration.schema.js';
22
- import type z from 'zod';
23
22
  import type { MedusaAPI } from '../core/client.js';
24
23
  import createDebug from 'debug';
25
24
 
@@ -60,7 +59,10 @@ export class MedusaIdentityProvider extends IdentityProvider {
60
59
 
61
60
  if (!token) {
62
61
  debug('No active session token found, returning anonymous identity');
63
- return success(this.createAnonymousIdentity());
62
+ const identity = this.createAnonymousIdentity();
63
+ this.updateIdentityContext(identity);
64
+
65
+ return success(identity);
64
66
  }
65
67
 
66
68
  // Try to fetch customer details to verify authentication
@@ -68,18 +70,30 @@ export class MedusaIdentityProvider extends IdentityProvider {
68
70
 
69
71
  if (customerResponse.customer) {
70
72
  debug('Customer authenticated:', customerResponse.customer.email);
71
- return success({
73
+
74
+ const identity = {
72
75
  id: {
73
76
  userId: customerResponse.customer.id,
74
77
  },
75
78
  type: 'Registered',
76
- } satisfies RegisteredIdentity);
79
+ } satisfies RegisteredIdentity;
80
+
81
+ this.updateIdentityContext(identity);
82
+
83
+ return success(identity);
77
84
  }
78
85
 
79
- return success(this.createAnonymousIdentity());
86
+ const identity = this.createAnonymousIdentity();
87
+ this.updateIdentityContext(identity);
88
+
89
+ return success(identity);
80
90
  } catch (error) {
81
91
  debug('getSelf failed, returning anonymous identity:', error);
82
- return success(this.createAnonymousIdentity());
92
+
93
+ const identity = this.createAnonymousIdentity();
94
+ this.updateIdentityContext(identity);
95
+
96
+ return success(identity);
83
97
  }
84
98
  }
85
99
 
@@ -87,13 +101,17 @@ export class MedusaIdentityProvider extends IdentityProvider {
87
101
  inputSchema: IdentityMutationLoginSchema,
88
102
  outputSchema: IdentitySchema,
89
103
  })
90
- public override async login(payload: IdentityMutationLogin): Promise<Result<Identity>> {
104
+ public override async login(
105
+ payload: IdentityMutationLogin
106
+ ): Promise<Result<Identity>> {
91
107
  debug('Attempting login for user:', payload.username);
92
- const identity = await this.medusaApi.login(
108
+ const identity = (await this.medusaApi.login(
93
109
  payload.username,
94
110
  payload.password,
95
111
  this.context
96
- ) satisfies Identity;
112
+ )) satisfies Identity;
113
+
114
+ this.updateIdentityContext(identity);
97
115
 
98
116
  return success(identity);
99
117
  }
@@ -102,10 +120,14 @@ export class MedusaIdentityProvider extends IdentityProvider {
102
120
  inputSchema: IdentityMutationLogoutSchema,
103
121
  outputSchema: IdentitySchema,
104
122
  })
105
- public override async logout(_payload: IdentityMutationLogout): Promise<Result<Identity>> {
123
+ public override async logout(
124
+ _payload: IdentityMutationLogout
125
+ ): Promise<Result<Identity>> {
106
126
  debug('Logging out user');
107
127
  const identity = await this.medusaApi.logout(this.context);
108
128
 
129
+ this.updateIdentityContext(identity);
130
+
109
131
  return success(identity);
110
132
  }
111
133
 
@@ -132,6 +154,8 @@ export class MedusaIdentityProvider extends IdentityProvider {
132
154
  this.context
133
155
  );
134
156
 
157
+ this.updateIdentityContext(identity);
158
+
135
159
  return success(identity);
136
160
  }
137
161
  }