@stackable-labs/sdk-extension-react 1.63.0 → 1.65.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { ApiRequest, FetchRequestInit, FetchResponse, ToastPayload, InvokeAction, ContextData, AuthState, AuthEventType, AuthEvent, AllowedIconName } from '@stackable-labs/sdk-extension-contracts';
2
+ import { ApiRequest, FetchRequestInit, FetchResponse, ToastPayload, InvokeAction, ContextData, IdentityBaseClaims, IdentityEventType, IdentityEvent, MessagingEventType, MessagingEvent, AllowedIconName } from '@stackable-labs/sdk-extension-contracts';
3
3
  import * as react_jsx_runtime from 'react/jsx-runtime';
4
4
 
5
5
  /**
@@ -68,10 +68,9 @@ declare const useCapabilities: () => {
68
68
  context: {
69
69
  read: () => Promise<ContextData>;
70
70
  };
71
- identity: {
72
- read: () => Promise<AuthState>;
73
- extend: (payload: {
74
- claims: Record<string, unknown>;
71
+ extend: {
72
+ identity: (payload: {
73
+ claims: IdentityBaseClaims;
75
74
  }) => Promise<{
76
75
  additionalClaims: Record<string, unknown>;
77
76
  }>;
@@ -87,31 +86,47 @@ declare const useStore: <T, S = T>(store: Store<T>, selector?: (state: T) => S)
87
86
  declare const useExtension: () => ExtensionContextValue;
88
87
 
89
88
  /**
90
- * useAuthEvent — subscribe to identity events pushed from the host.
89
+ * useIdentityEvent — subscribe to identity events pushed from the host.
91
90
  *
92
91
  * Spike-only: no encryption, no loading state management.
93
92
  */
94
93
 
95
94
  /**
96
- * Register a callback for a specific auth event type (e.g. 'identity.login').
97
- * The callback receives the full AuthEvent payload.
95
+ * Register a callback for a specific identity event type (e.g. 'identity.login').
96
+ * The callback receives the full IdentityEvent payload.
98
97
  */
99
- declare const useAuthEvent: (eventType: AuthEventType, handler: (event: AuthEvent) => void) => void;
98
+ declare const useIdentityEvent: (eventType: IdentityEventType, handler: (event: IdentityEvent) => void) => void;
100
99
 
101
100
  /**
102
- * useIdentityExtend — register a handler for identity claim enrichment.
101
+ * useExtendIdentity — register a handler for identity claim enrichment.
103
102
  *
104
103
  * When the host platform detects a customer login, it sends base claims
105
- * (external_id, email, name) to extensions with the identity:extend permission.
104
+ * (external_id, email, name) to extensions with the extend:identity permission.
106
105
  * The handler returns additional claims to merge into the JWT before signing.
107
106
  *
108
107
  * @example
109
- * useIdentityExtend((claims) => ({
108
+ * useExtendIdentity((claims) => ({
110
109
  * external_id: `shopify_${claims.external_id}`
111
110
  * }))
112
111
  */
113
- type IdentityExtendHandler = (claims: Record<string, unknown>) => Record<string, unknown> | Promise<Record<string, unknown>>;
114
- declare const useIdentityExtend: (handler: IdentityExtendHandler) => void;
112
+
113
+ type ExtendIdentityHandler = (claims: IdentityBaseClaims) => Record<string, unknown> | Promise<Record<string, unknown>>;
114
+ declare const useExtendIdentity: (handler: ExtendIdentityHandler) => void;
115
+
116
+ /**
117
+ * useMessagingEvent — subscribe to messaging events pushed from the host.
118
+ *
119
+ * Supports both wildcard ('postback') and specific ('postback:add_to_cart') subscriptions.
120
+ * Host-side filtering ensures only matching events cross the sandbox boundary;
121
+ * this hook applies a secondary actionName match within the extension.
122
+ */
123
+
124
+ /**
125
+ * Register a callback for messaging events.
126
+ * - 'postback' — receive ALL postback events (requires elevated marketplace review)
127
+ * - 'postback:<actionName>' — receive only events matching actionName
128
+ */
129
+ declare const useMessagingEvent: (eventType: MessagingEventType, handler: (event: MessagingEvent) => void) => void;
115
130
 
116
131
  interface SurfaceProps {
117
132
  /** The extension point target ID (e.g., "slot.header") */
@@ -524,4 +539,4 @@ type UseContextDataResult = ContextData & {
524
539
  };
525
540
  declare const useContextData: () => UseContextDataResult;
526
541
 
527
- export { type Store, Surface, createExtension, createStore, ui, useAuthEvent, useCapabilities, useContextData, useExtension, useIdentityExtend, useStore, useSurfaceContext };
542
+ export { type Store, Surface, createExtension, createStore, ui, useCapabilities, useContextData, useExtendIdentity, useExtension, useIdentityEvent, useMessagingEvent, useStore, useSurfaceContext };
package/dist/index.js CHANGED
@@ -20,7 +20,11 @@ var getWebCrypto = () => _webCrypto ??= new WebCrypto({ crypto: globalThis.crypt
20
20
  var requestCounter = 0;
21
21
  var registeredExtensionId = "unknown";
22
22
  var encryptionKey = null;
23
- var identityExtendHandler = null;
23
+ var extendIdentityHandler = null;
24
+ var setEncryptionKey = async (keyBase64) => {
25
+ encryptionKey = await getWebCrypto().importRawKey("secret", base64ToBytes(keyBase64), { extractable: false });
26
+ };
27
+ var generateRequestId = () => `req_${++requestCounter}_${Date.now()}`;
24
28
  var pendingRequests = /* @__PURE__ */ new Map();
25
29
  var extensionEventHandlers = /* @__PURE__ */ new Set();
26
30
  var onExtensionEvent = (handler) => {
@@ -29,16 +33,14 @@ var onExtensionEvent = (handler) => {
29
33
  extensionEventHandlers.delete(handler);
30
34
  };
31
35
  };
32
- var registerIdentityExtendHandler = (handler) => {
33
- identityExtendHandler = handler;
36
+ var registerExtendIdentityHandler = (handler) => {
37
+ extendIdentityHandler = handler;
34
38
  return () => {
35
- if (identityExtendHandler === handler) identityExtendHandler = null;
39
+ if (extendIdentityHandler === handler) {
40
+ extendIdentityHandler = null;
41
+ }
36
42
  };
37
43
  };
38
- var generateRequestId = () => `req_${++requestCounter}_${Date.now()}`;
39
- var setEncryptionKey = async (keyBase64) => {
40
- encryptionKey = await getWebCrypto().importRawKey("secret", base64ToBytes(keyBase64), { extractable: false });
41
- };
42
44
  var initRpcListener = (extensionId) => {
43
45
  registeredExtensionId = extensionId;
44
46
  window.addEventListener("message", (event) => {
@@ -57,14 +59,14 @@ var initRpcListener = (extensionId) => {
57
59
  }
58
60
  return;
59
61
  }
60
- if (msg?.type === "identity-extend-request") {
61
- if (identityExtendHandler) {
62
+ if (msg?.type === "extend-identity-request") {
63
+ if (extendIdentityHandler) {
62
64
  const { id, claims } = msg;
63
- Promise.resolve(identityExtendHandler(claims)).then((additionalClaims) => {
64
- window.parent.postMessage({ type: "identity-extend-response", id, additionalClaims }, "*");
65
+ Promise.resolve(extendIdentityHandler(claims)).then((additionalClaims) => {
66
+ window.parent.postMessage({ type: "extend-identity-response", id, additionalClaims }, "*");
65
67
  }).catch((e) => {
66
- console.error("[rpc-client] identity-extend handler error:", e);
67
- window.parent.postMessage({ type: "identity-extend-response", id, additionalClaims: {} }, "*");
68
+ console.error("[rpc-client] extend-identity handler error:", e);
69
+ window.parent.postMessage({ type: "extend-identity-response", id, additionalClaims: {} }, "*");
68
70
  });
69
71
  }
70
72
  return;
@@ -92,10 +94,10 @@ var sendCapabilityRequest = (capability, payload) => new Promise((resolve, rejec
92
94
  });
93
95
  const request = {
94
96
  type: "capability-request",
95
- id,
96
97
  extensionId: registeredExtensionId,
97
98
  capability,
98
- payload
99
+ payload,
100
+ id
99
101
  };
100
102
  window.parent.postMessage(request, "*");
101
103
  setTimeout(() => {
@@ -109,8 +111,13 @@ var callCapability = async (capability, payload) => {
109
111
  let actualPayload = payload;
110
112
  if (capability === "data.fetch" && encryptionKey) {
111
113
  const encrypted = await getWebCrypto().encryptMessage(JSON.stringify(payload), encryptionKey);
112
- if (!encrypted) throw new Error("Failed to encrypt data.fetch payload");
113
- actualPayload = { encrypted: true, data: encrypted };
114
+ if (!encrypted) {
115
+ throw new Error("Failed to encrypt data.fetch payload");
116
+ }
117
+ actualPayload = {
118
+ encrypted: true,
119
+ data: encrypted
120
+ };
114
121
  }
115
122
  const result = await sendCapabilityRequest(capability, actualPayload);
116
123
  if (capability === "data.fetch" && encryptionKey) {
@@ -201,9 +208,8 @@ var useCapabilities = () => ({
201
208
  context: {
202
209
  read: () => callCapability("context.read")
203
210
  },
204
- identity: {
205
- read: () => callCapability("identity.read"),
206
- extend: (payload) => callCapability("identity.extend", payload)
211
+ extend: {
212
+ identity: (payload) => callCapability("extend.identity", payload)
207
213
  }
208
214
  });
209
215
  var useStore = (store, selector) => {
@@ -222,21 +228,35 @@ var useExtension = () => {
222
228
  }
223
229
  return ctx;
224
230
  };
225
- var useAuthEvent = (eventType, handler) => {
231
+ var useIdentityEvent = (eventType, handler) => {
226
232
  useEffect(() => {
227
233
  const unsubscribe = onExtensionEvent((type, payload) => {
228
- if (type !== eventType) return;
234
+ if (type !== eventType) {
235
+ return;
236
+ }
229
237
  handler(payload);
230
238
  });
231
239
  return unsubscribe;
232
240
  }, [eventType, handler]);
233
241
  };
234
- var useIdentityExtend = (handler) => {
242
+ var useExtendIdentity = (handler) => {
235
243
  useEffect(() => {
236
- const unregister = registerIdentityExtendHandler(handler);
244
+ const unregister = registerExtendIdentityHandler(handler);
237
245
  return unregister;
238
246
  }, [handler]);
239
247
  };
248
+ var useMessagingEvent = (eventType, handler) => {
249
+ useEffect(() => {
250
+ const unsubscribe = onExtensionEvent((type, payload) => {
251
+ if (type !== "messaging:postback") return;
252
+ const event = payload;
253
+ if (eventType === "postback" || eventType === `postback:${event.actionName}`) {
254
+ handler(event);
255
+ }
256
+ });
257
+ return unsubscribe;
258
+ }, [eventType, handler]);
259
+ };
240
260
  var useExtensionId = () => {
241
261
  const ctx = React2.useContext(ExtensionContext);
242
262
  return ctx?.extensionId ?? "unknown";
@@ -476,4 +496,4 @@ var useContextData = () => {
476
496
  return { ...contextData, loading };
477
497
  };
478
498
 
479
- export { Surface, createExtension, createStore, ui_exports as ui, useAuthEvent, useCapabilities, useContextData, useExtension, useIdentityExtend, useStore, useSurfaceContext };
499
+ export { Surface, createExtension, createStore, ui_exports as ui, useCapabilities, useContextData, useExtendIdentity, useExtension, useIdentityEvent, useMessagingEvent, useStore, useSurfaceContext };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackable-labs/sdk-extension-react",
3
- "version": "1.63.0",
3
+ "version": "1.65.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "@agnostack/verifyd": "alpha",
16
16
  "@remote-dom/core": "1.x",
17
17
  "@remote-dom/react": "1.x",
18
- "@stackable-labs/sdk-extension-contracts": "1.63.0"
18
+ "@stackable-labs/sdk-extension-contracts": "1.65.0"
19
19
  },
20
20
  "peerDependencies": {
21
21
  "react": ">=18.0.0 <19.0.0",