@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 +30 -15
- package/dist/index.js +46 -26
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { ApiRequest, FetchRequestInit, FetchResponse, ToastPayload, InvokeAction, ContextData,
|
|
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
|
-
|
|
72
|
-
|
|
73
|
-
|
|
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
|
-
*
|
|
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
|
|
97
|
-
* The callback receives the full
|
|
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
|
|
98
|
+
declare const useIdentityEvent: (eventType: IdentityEventType, handler: (event: IdentityEvent) => void) => void;
|
|
100
99
|
|
|
101
100
|
/**
|
|
102
|
-
*
|
|
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
|
|
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
|
-
*
|
|
108
|
+
* useExtendIdentity((claims) => ({
|
|
110
109
|
* external_id: `shopify_${claims.external_id}`
|
|
111
110
|
* }))
|
|
112
111
|
*/
|
|
113
|
-
|
|
114
|
-
|
|
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,
|
|
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
|
|
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
|
|
33
|
-
|
|
36
|
+
var registerExtendIdentityHandler = (handler) => {
|
|
37
|
+
extendIdentityHandler = handler;
|
|
34
38
|
return () => {
|
|
35
|
-
if (
|
|
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-
|
|
61
|
-
if (
|
|
62
|
+
if (msg?.type === "extend-identity-request") {
|
|
63
|
+
if (extendIdentityHandler) {
|
|
62
64
|
const { id, claims } = msg;
|
|
63
|
-
Promise.resolve(
|
|
64
|
-
window.parent.postMessage({ type: "identity-
|
|
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
|
|
67
|
-
window.parent.postMessage({ type: "identity-
|
|
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)
|
|
113
|
-
|
|
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
|
-
|
|
205
|
-
|
|
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
|
|
231
|
+
var useIdentityEvent = (eventType, handler) => {
|
|
226
232
|
useEffect(() => {
|
|
227
233
|
const unsubscribe = onExtensionEvent((type, payload) => {
|
|
228
|
-
if (type !== eventType)
|
|
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
|
|
242
|
+
var useExtendIdentity = (handler) => {
|
|
235
243
|
useEffect(() => {
|
|
236
|
-
const unregister =
|
|
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,
|
|
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.
|
|
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.
|
|
18
|
+
"@stackable-labs/sdk-extension-contracts": "1.65.0"
|
|
19
19
|
},
|
|
20
20
|
"peerDependencies": {
|
|
21
21
|
"react": ">=18.0.0 <19.0.0",
|