@lukso/transaction-view-headless 0.2.2-dev.a8c9315
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/.turbo/turbo-build.log +51 -0
- package/CHANGELOG.md +88 -0
- package/COMPONENT_ARCHITECTURE.md +190 -0
- package/COMPONENT_CONVERSION_ANALYSIS.md +371 -0
- package/CONTEXT_VARIANT_GUIDE.md +425 -0
- package/LAZY_LOADING_GUIDE.md +534 -0
- package/LICENSE +201 -0
- package/PLAYBACK_EXAMPLES.md +658 -0
- package/PLAYBACK_GUIDE.md +402 -0
- package/README.md +43 -0
- package/REGISTRY_SUMMARY.md +638 -0
- package/SUFFERING_ECONOMICS.md +346 -0
- package/SUFFERING_ECONOMICS.zip +0 -0
- package/VIEW_REGISTRATION_GUIDE.md +795 -0
- package/dist/composables/index.cjs +1321 -0
- package/dist/composables/index.cjs.map +1 -0
- package/dist/composables/index.d.cts +6 -0
- package/dist/composables/index.d.ts +6 -0
- package/dist/composables/index.js +1276 -0
- package/dist/composables/index.js.map +1 -0
- package/dist/index-CMLU1hKL.d.ts +374 -0
- package/dist/index-CSDjhiKV.d.cts +374 -0
- package/dist/index.cjs +1534 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +93 -0
- package/dist/index.d.ts +93 -0
- package/dist/index.js +1463 -0
- package/dist/index.js.map +1 -0
- package/dist/registry/index.cjs +522 -0
- package/dist/registry/index.cjs.map +1 -0
- package/dist/registry/index.d.cts +46 -0
- package/dist/registry/index.d.ts +46 -0
- package/dist/registry/index.js +487 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/types/index.cjs +19 -0
- package/dist/types/index.cjs.map +1 -0
- package/dist/types/index.d.cts +203 -0
- package/dist/types/index.d.ts +203 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.cjs +217 -0
- package/dist/utils/index.cjs.map +1 -0
- package/dist/utils/index.d.cts +47 -0
- package/dist/utils/index.d.ts +47 -0
- package/dist/utils/index.js +188 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/view-loader-dD86QAlQ.d.cts +121 -0
- package/dist/view-loader-ii8AxiQR.d.ts +121 -0
- package/package.json +64 -0
- package/publish.log +0 -0
- package/src/composables/index.ts +59 -0
- package/src/composables/use-image-loader.ts +315 -0
- package/src/composables/use-transaction-playback.ts +396 -0
- package/src/composables/use-transaction-view.ts +309 -0
- package/src/config/lukso-config.ts +171 -0
- package/src/examples/context-aware-views.ts +300 -0
- package/src/examples/example-views.ts +197 -0
- package/src/examples/lit-plus-rn-strategy.ts +448 -0
- package/src/examples/lsp7-custom-matcher-examples.ts +174 -0
- package/src/examples/opt-in-context-examples.ts +372 -0
- package/src/examples/optimized-view-definitions.ts +408 -0
- package/src/examples/vue-to-lit-compilation.ts +358 -0
- package/src/hooks/useAddressQuery.ts +135 -0
- package/src/hooks/useAddressResolution.ts +437 -0
- package/src/index.ts +36 -0
- package/src/registry/index.ts +13 -0
- package/src/registry/view-loader.ts +305 -0
- package/src/registry/view-registry.ts +135 -0
- package/src/types/index.ts +16 -0
- package/src/types/view-contexts.ts +72 -0
- package/src/types/view-matching.ts +173 -0
- package/src/utils/context-matcher.ts +165 -0
- package/src/utils/index.ts +5 -0
- package/src/utils/view-matcher.ts +338 -0
- package/tsconfig.json +20 -0
- package/tsup.config.ts +34 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { DecoderResult } from '@lukso/transaction-decoder';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Different contexts WHERE transaction views are displayed
|
|
5
|
+
*
|
|
6
|
+
* Context determines the environment/location, which affects:
|
|
7
|
+
* - Available space
|
|
8
|
+
* - User intent
|
|
9
|
+
* - Security requirements
|
|
10
|
+
* - Interaction patterns
|
|
11
|
+
*/
|
|
12
|
+
type ViewContext = 'approval' | 'feed' | 'list' | 'detail' | 'review' | 'notification' | 'embed' | 'batch-summary';
|
|
13
|
+
/**
|
|
14
|
+
* Different variants of HOW transaction views are displayed
|
|
15
|
+
*
|
|
16
|
+
* Variant determines the presentation style within a context:
|
|
17
|
+
* - Same transaction can have different variants in different contexts
|
|
18
|
+
* - Example: 'collapsed' in feed vs 'collapsed' in approval are different
|
|
19
|
+
*/
|
|
20
|
+
type ViewVariant = 'full' | 'collapsed' | 'minimal' | 'icon-only' | 'compact' | 'expanded' | string;
|
|
21
|
+
/**
|
|
22
|
+
* Context-specific display requirements
|
|
23
|
+
*/
|
|
24
|
+
interface ViewContextRequirements {
|
|
25
|
+
/** Maximum height constraint */
|
|
26
|
+
maxHeight?: number;
|
|
27
|
+
/** Whether to show action buttons */
|
|
28
|
+
showActions?: boolean;
|
|
29
|
+
/** Level of detail to display */
|
|
30
|
+
detailLevel: 'minimal' | 'summary' | 'full' | 'debug';
|
|
31
|
+
/** Whether user can expand for more details */
|
|
32
|
+
expandable?: boolean;
|
|
33
|
+
/** Color scheme preference */
|
|
34
|
+
colorScheme?: 'light' | 'dark' | 'auto';
|
|
35
|
+
/** Whether to emphasize security warnings */
|
|
36
|
+
emphasizeSecurity?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type DecoderRecordForSelection = DecoderResult & {
|
|
40
|
+
recordType?: string;
|
|
41
|
+
functionName?: string;
|
|
42
|
+
contractAddress?: string;
|
|
43
|
+
standard?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Criteria that can be used to match transactions to views
|
|
48
|
+
*/
|
|
49
|
+
interface ViewMatchCriteria {
|
|
50
|
+
/** LSP standard (e.g., 'LSP7', 'LSP8', 'LSP0') */
|
|
51
|
+
standard?: string | string[];
|
|
52
|
+
/** Function name from ABI (e.g., 'transfer', 'setData', 'execute') */
|
|
53
|
+
functionName?: string | string[];
|
|
54
|
+
/** Record type from decoder (e.g., 'lsp7-transfer', 'set-data') */
|
|
55
|
+
recordType?: string | string[];
|
|
56
|
+
/** Contract address (for specific contract implementations) */
|
|
57
|
+
contractAddress?: string | string[];
|
|
58
|
+
/** Chain ID (for network-specific views) */
|
|
59
|
+
chainId?: number | number[];
|
|
60
|
+
/** Display context (opt-in) - WHERE to display (feed, approval, list, etc.) */
|
|
61
|
+
context?: ViewContext | ViewContext[];
|
|
62
|
+
/** Display variant (opt-in) - HOW to display (collapsed, minimal, full, etc.) */
|
|
63
|
+
variant?: ViewVariant | ViewVariant[];
|
|
64
|
+
/** Context requirements (opt-in) - additional constraints for context matching */
|
|
65
|
+
contextRequirements?: Partial<ViewContextRequirements>;
|
|
66
|
+
/**
|
|
67
|
+
* Custom matcher function for complex synchronous logic.
|
|
68
|
+
* Returns the number of conditions that matched (higher = better match).
|
|
69
|
+
*
|
|
70
|
+
* IMPORTANT: Must be synchronous and only use data from DecoderResult.
|
|
71
|
+
* For async operations, populate transaction.custom in an enhancer.
|
|
72
|
+
*
|
|
73
|
+
* @returns Number of matching conditions (0 = no match, higher = stronger match)
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Match token transfers (tokenType === 0)
|
|
77
|
+
* customMatcher: (tx) => {
|
|
78
|
+
* let matches = 0
|
|
79
|
+
* if (tx.custom?.tokenType === 0) matches++
|
|
80
|
+
* if (BigInt(tx.value || 0) > 0) matches++
|
|
81
|
+
* return matches
|
|
82
|
+
* }
|
|
83
|
+
*/
|
|
84
|
+
customMatcher?: (transaction: DecoderResult) => number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Framework-agnostic view definition
|
|
88
|
+
*/
|
|
89
|
+
interface ViewDefinition {
|
|
90
|
+
/** Unique identifier for this view */
|
|
91
|
+
id: string;
|
|
92
|
+
/** Human-readable name */
|
|
93
|
+
name: string;
|
|
94
|
+
/** Criteria for matching transactions to this view */
|
|
95
|
+
criteria: ViewMatchCriteria;
|
|
96
|
+
/** Priority when multiple views match (higher = preferred) */
|
|
97
|
+
priority: number;
|
|
98
|
+
/** Supported frameworks for this view */
|
|
99
|
+
frameworks: FrameworkSupport;
|
|
100
|
+
/** Optional description */
|
|
101
|
+
description?: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Framework-specific loading configurations
|
|
105
|
+
*
|
|
106
|
+
* Strategic Framework Selection (Suffering Economics Optimized):
|
|
107
|
+
* - lit: Universal web components (works in Vue, React, Angular, Svelte, etc.)
|
|
108
|
+
* - vue: Native Vue components (optional, for Vue-specific optimizations)
|
|
109
|
+
* - rn: React Native components (mobile-native, optional - falls back to WebView)
|
|
110
|
+
*
|
|
111
|
+
* Lit is the universal fallback. Vue and React Native are optional native implementations
|
|
112
|
+
* that get priority when available in their respective environments.
|
|
113
|
+
*/
|
|
114
|
+
interface FrameworkSupport {
|
|
115
|
+
lit: FrameworkViewConfig;
|
|
116
|
+
vue?: FrameworkViewConfig;
|
|
117
|
+
rn?: FrameworkViewConfig;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Configuration for loading a view in a specific framework
|
|
121
|
+
*/
|
|
122
|
+
interface FrameworkViewConfig {
|
|
123
|
+
/** Loading method */
|
|
124
|
+
loader: ViewLoader;
|
|
125
|
+
/** Component name/identifier */
|
|
126
|
+
component: string;
|
|
127
|
+
/** Package where the component is located */
|
|
128
|
+
package?: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Different ways to load a view component
|
|
132
|
+
*
|
|
133
|
+
* Loaders support both static and lazy loading:
|
|
134
|
+
* - Static: `path: './Component.vue'` - bundled with app
|
|
135
|
+
* - Lazy: `path: () => import('./Component.vue')` - loaded on demand
|
|
136
|
+
*/
|
|
137
|
+
type ViewLoader = {
|
|
138
|
+
type: 'dynamic-import';
|
|
139
|
+
path: string | (() => Promise<any>);
|
|
140
|
+
} | {
|
|
141
|
+
type: 'static-import';
|
|
142
|
+
path: string | (() => Promise<any>);
|
|
143
|
+
} | {
|
|
144
|
+
type: 'custom-element';
|
|
145
|
+
tagName: string;
|
|
146
|
+
} | {
|
|
147
|
+
type: 'registry-lookup';
|
|
148
|
+
registryKey: string;
|
|
149
|
+
} | {
|
|
150
|
+
type: 'custom';
|
|
151
|
+
loader: (config: FrameworkViewConfig) => Promise<any>;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Result of matching a transaction against registered views
|
|
155
|
+
*/
|
|
156
|
+
interface ViewMatch {
|
|
157
|
+
/** The view definition that matched */
|
|
158
|
+
view: ViewDefinition;
|
|
159
|
+
/** Score indicating how well this view matches (0-1) */
|
|
160
|
+
score: number;
|
|
161
|
+
/** Which criteria matched */
|
|
162
|
+
matchedCriteria: (keyof ViewMatchCriteria)[];
|
|
163
|
+
/** Framework-specific loading config */
|
|
164
|
+
frameworkConfig?: FrameworkViewConfig;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Options for view matching
|
|
168
|
+
*/
|
|
169
|
+
interface ViewMatchOptions {
|
|
170
|
+
/** Target framework */
|
|
171
|
+
framework: 'lit' | 'vue' | 'rn';
|
|
172
|
+
/** Display context (optional) - WHERE to display (feed, approval, list, etc.) */
|
|
173
|
+
context?: ViewContext;
|
|
174
|
+
/** Display variant (optional) - HOW to display (collapsed, minimal, full, etc.) */
|
|
175
|
+
variant?: ViewVariant;
|
|
176
|
+
/** Context requirements (optional) - additional constraints for context-aware matching */
|
|
177
|
+
contextRequirements?: Partial<ViewContextRequirements>;
|
|
178
|
+
/** Minimum score threshold (0-1) */
|
|
179
|
+
minScore?: number;
|
|
180
|
+
/** Maximum number of matches to return */
|
|
181
|
+
maxMatches?: number;
|
|
182
|
+
/** Whether to include framework config in results */
|
|
183
|
+
includeFrameworkConfig?: boolean;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Registry for managing view definitions
|
|
187
|
+
*/
|
|
188
|
+
interface ViewRegistry {
|
|
189
|
+
/** Register a new view */
|
|
190
|
+
register(view: ViewDefinition): void;
|
|
191
|
+
/** Unregister a view by ID */
|
|
192
|
+
unregister(viewId: string): void;
|
|
193
|
+
/** Get all registered views */
|
|
194
|
+
getAllViews(): ViewDefinition[];
|
|
195
|
+
/** Find best matching views for a transaction */
|
|
196
|
+
findMatches(transaction: DecoderResult, options: ViewMatchOptions): ViewMatch[];
|
|
197
|
+
/** Get a specific view by ID */
|
|
198
|
+
getView(viewId: string): ViewDefinition | undefined;
|
|
199
|
+
/** Clear all registered views */
|
|
200
|
+
clear(): void;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export type { DecoderRecordForSelection, FrameworkSupport, FrameworkViewConfig, ViewContext, ViewContextRequirements, ViewDefinition, ViewLoader, ViewMatch, ViewMatchCriteria, ViewMatchOptions, ViewRegistry, ViewVariant };
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { DecoderResult } from '@lukso/transaction-decoder';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Different contexts WHERE transaction views are displayed
|
|
5
|
+
*
|
|
6
|
+
* Context determines the environment/location, which affects:
|
|
7
|
+
* - Available space
|
|
8
|
+
* - User intent
|
|
9
|
+
* - Security requirements
|
|
10
|
+
* - Interaction patterns
|
|
11
|
+
*/
|
|
12
|
+
type ViewContext = 'approval' | 'feed' | 'list' | 'detail' | 'review' | 'notification' | 'embed' | 'batch-summary';
|
|
13
|
+
/**
|
|
14
|
+
* Different variants of HOW transaction views are displayed
|
|
15
|
+
*
|
|
16
|
+
* Variant determines the presentation style within a context:
|
|
17
|
+
* - Same transaction can have different variants in different contexts
|
|
18
|
+
* - Example: 'collapsed' in feed vs 'collapsed' in approval are different
|
|
19
|
+
*/
|
|
20
|
+
type ViewVariant = 'full' | 'collapsed' | 'minimal' | 'icon-only' | 'compact' | 'expanded' | string;
|
|
21
|
+
/**
|
|
22
|
+
* Context-specific display requirements
|
|
23
|
+
*/
|
|
24
|
+
interface ViewContextRequirements {
|
|
25
|
+
/** Maximum height constraint */
|
|
26
|
+
maxHeight?: number;
|
|
27
|
+
/** Whether to show action buttons */
|
|
28
|
+
showActions?: boolean;
|
|
29
|
+
/** Level of detail to display */
|
|
30
|
+
detailLevel: 'minimal' | 'summary' | 'full' | 'debug';
|
|
31
|
+
/** Whether user can expand for more details */
|
|
32
|
+
expandable?: boolean;
|
|
33
|
+
/** Color scheme preference */
|
|
34
|
+
colorScheme?: 'light' | 'dark' | 'auto';
|
|
35
|
+
/** Whether to emphasize security warnings */
|
|
36
|
+
emphasizeSecurity?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type DecoderRecordForSelection = DecoderResult & {
|
|
40
|
+
recordType?: string;
|
|
41
|
+
functionName?: string;
|
|
42
|
+
contractAddress?: string;
|
|
43
|
+
standard?: string;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Criteria that can be used to match transactions to views
|
|
48
|
+
*/
|
|
49
|
+
interface ViewMatchCriteria {
|
|
50
|
+
/** LSP standard (e.g., 'LSP7', 'LSP8', 'LSP0') */
|
|
51
|
+
standard?: string | string[];
|
|
52
|
+
/** Function name from ABI (e.g., 'transfer', 'setData', 'execute') */
|
|
53
|
+
functionName?: string | string[];
|
|
54
|
+
/** Record type from decoder (e.g., 'lsp7-transfer', 'set-data') */
|
|
55
|
+
recordType?: string | string[];
|
|
56
|
+
/** Contract address (for specific contract implementations) */
|
|
57
|
+
contractAddress?: string | string[];
|
|
58
|
+
/** Chain ID (for network-specific views) */
|
|
59
|
+
chainId?: number | number[];
|
|
60
|
+
/** Display context (opt-in) - WHERE to display (feed, approval, list, etc.) */
|
|
61
|
+
context?: ViewContext | ViewContext[];
|
|
62
|
+
/** Display variant (opt-in) - HOW to display (collapsed, minimal, full, etc.) */
|
|
63
|
+
variant?: ViewVariant | ViewVariant[];
|
|
64
|
+
/** Context requirements (opt-in) - additional constraints for context matching */
|
|
65
|
+
contextRequirements?: Partial<ViewContextRequirements>;
|
|
66
|
+
/**
|
|
67
|
+
* Custom matcher function for complex synchronous logic.
|
|
68
|
+
* Returns the number of conditions that matched (higher = better match).
|
|
69
|
+
*
|
|
70
|
+
* IMPORTANT: Must be synchronous and only use data from DecoderResult.
|
|
71
|
+
* For async operations, populate transaction.custom in an enhancer.
|
|
72
|
+
*
|
|
73
|
+
* @returns Number of matching conditions (0 = no match, higher = stronger match)
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* // Match token transfers (tokenType === 0)
|
|
77
|
+
* customMatcher: (tx) => {
|
|
78
|
+
* let matches = 0
|
|
79
|
+
* if (tx.custom?.tokenType === 0) matches++
|
|
80
|
+
* if (BigInt(tx.value || 0) > 0) matches++
|
|
81
|
+
* return matches
|
|
82
|
+
* }
|
|
83
|
+
*/
|
|
84
|
+
customMatcher?: (transaction: DecoderResult) => number;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Framework-agnostic view definition
|
|
88
|
+
*/
|
|
89
|
+
interface ViewDefinition {
|
|
90
|
+
/** Unique identifier for this view */
|
|
91
|
+
id: string;
|
|
92
|
+
/** Human-readable name */
|
|
93
|
+
name: string;
|
|
94
|
+
/** Criteria for matching transactions to this view */
|
|
95
|
+
criteria: ViewMatchCriteria;
|
|
96
|
+
/** Priority when multiple views match (higher = preferred) */
|
|
97
|
+
priority: number;
|
|
98
|
+
/** Supported frameworks for this view */
|
|
99
|
+
frameworks: FrameworkSupport;
|
|
100
|
+
/** Optional description */
|
|
101
|
+
description?: string;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Framework-specific loading configurations
|
|
105
|
+
*
|
|
106
|
+
* Strategic Framework Selection (Suffering Economics Optimized):
|
|
107
|
+
* - lit: Universal web components (works in Vue, React, Angular, Svelte, etc.)
|
|
108
|
+
* - vue: Native Vue components (optional, for Vue-specific optimizations)
|
|
109
|
+
* - rn: React Native components (mobile-native, optional - falls back to WebView)
|
|
110
|
+
*
|
|
111
|
+
* Lit is the universal fallback. Vue and React Native are optional native implementations
|
|
112
|
+
* that get priority when available in their respective environments.
|
|
113
|
+
*/
|
|
114
|
+
interface FrameworkSupport {
|
|
115
|
+
lit: FrameworkViewConfig;
|
|
116
|
+
vue?: FrameworkViewConfig;
|
|
117
|
+
rn?: FrameworkViewConfig;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Configuration for loading a view in a specific framework
|
|
121
|
+
*/
|
|
122
|
+
interface FrameworkViewConfig {
|
|
123
|
+
/** Loading method */
|
|
124
|
+
loader: ViewLoader;
|
|
125
|
+
/** Component name/identifier */
|
|
126
|
+
component: string;
|
|
127
|
+
/** Package where the component is located */
|
|
128
|
+
package?: string;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Different ways to load a view component
|
|
132
|
+
*
|
|
133
|
+
* Loaders support both static and lazy loading:
|
|
134
|
+
* - Static: `path: './Component.vue'` - bundled with app
|
|
135
|
+
* - Lazy: `path: () => import('./Component.vue')` - loaded on demand
|
|
136
|
+
*/
|
|
137
|
+
type ViewLoader = {
|
|
138
|
+
type: 'dynamic-import';
|
|
139
|
+
path: string | (() => Promise<any>);
|
|
140
|
+
} | {
|
|
141
|
+
type: 'static-import';
|
|
142
|
+
path: string | (() => Promise<any>);
|
|
143
|
+
} | {
|
|
144
|
+
type: 'custom-element';
|
|
145
|
+
tagName: string;
|
|
146
|
+
} | {
|
|
147
|
+
type: 'registry-lookup';
|
|
148
|
+
registryKey: string;
|
|
149
|
+
} | {
|
|
150
|
+
type: 'custom';
|
|
151
|
+
loader: (config: FrameworkViewConfig) => Promise<any>;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Result of matching a transaction against registered views
|
|
155
|
+
*/
|
|
156
|
+
interface ViewMatch {
|
|
157
|
+
/** The view definition that matched */
|
|
158
|
+
view: ViewDefinition;
|
|
159
|
+
/** Score indicating how well this view matches (0-1) */
|
|
160
|
+
score: number;
|
|
161
|
+
/** Which criteria matched */
|
|
162
|
+
matchedCriteria: (keyof ViewMatchCriteria)[];
|
|
163
|
+
/** Framework-specific loading config */
|
|
164
|
+
frameworkConfig?: FrameworkViewConfig;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Options for view matching
|
|
168
|
+
*/
|
|
169
|
+
interface ViewMatchOptions {
|
|
170
|
+
/** Target framework */
|
|
171
|
+
framework: 'lit' | 'vue' | 'rn';
|
|
172
|
+
/** Display context (optional) - WHERE to display (feed, approval, list, etc.) */
|
|
173
|
+
context?: ViewContext;
|
|
174
|
+
/** Display variant (optional) - HOW to display (collapsed, minimal, full, etc.) */
|
|
175
|
+
variant?: ViewVariant;
|
|
176
|
+
/** Context requirements (optional) - additional constraints for context-aware matching */
|
|
177
|
+
contextRequirements?: Partial<ViewContextRequirements>;
|
|
178
|
+
/** Minimum score threshold (0-1) */
|
|
179
|
+
minScore?: number;
|
|
180
|
+
/** Maximum number of matches to return */
|
|
181
|
+
maxMatches?: number;
|
|
182
|
+
/** Whether to include framework config in results */
|
|
183
|
+
includeFrameworkConfig?: boolean;
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Registry for managing view definitions
|
|
187
|
+
*/
|
|
188
|
+
interface ViewRegistry {
|
|
189
|
+
/** Register a new view */
|
|
190
|
+
register(view: ViewDefinition): void;
|
|
191
|
+
/** Unregister a view by ID */
|
|
192
|
+
unregister(viewId: string): void;
|
|
193
|
+
/** Get all registered views */
|
|
194
|
+
getAllViews(): ViewDefinition[];
|
|
195
|
+
/** Find best matching views for a transaction */
|
|
196
|
+
findMatches(transaction: DecoderResult, options: ViewMatchOptions): ViewMatch[];
|
|
197
|
+
/** Get a specific view by ID */
|
|
198
|
+
getView(viewId: string): ViewDefinition | undefined;
|
|
199
|
+
/** Clear all registered views */
|
|
200
|
+
clear(): void;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export type { DecoderRecordForSelection, FrameworkSupport, FrameworkViewConfig, ViewContext, ViewContextRequirements, ViewDefinition, ViewLoader, ViewMatch, ViewMatchCriteria, ViewMatchOptions, ViewRegistry, ViewVariant };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/utils/index.ts
|
|
21
|
+
var utils_exports = {};
|
|
22
|
+
__export(utils_exports, {
|
|
23
|
+
CRITERIA_WEIGHTS: () => CRITERIA_WEIGHTS,
|
|
24
|
+
calculateMatchScore: () => calculateMatchScore,
|
|
25
|
+
findMatchingViews: () => findMatchingViews
|
|
26
|
+
});
|
|
27
|
+
module.exports = __toCommonJS(utils_exports);
|
|
28
|
+
|
|
29
|
+
// src/utils/view-matcher.ts
|
|
30
|
+
var CRITERIA_WEIGHTS = {
|
|
31
|
+
recordType: 0.25,
|
|
32
|
+
// Most specific to transaction type
|
|
33
|
+
functionName: 0.2,
|
|
34
|
+
// Function-level specificity
|
|
35
|
+
context: 0.2,
|
|
36
|
+
// Context specificity (when opt-in)
|
|
37
|
+
standard: 0.15,
|
|
38
|
+
// LSP standard specificity
|
|
39
|
+
contractAddress: 0.1,
|
|
40
|
+
// Contract-specific logic
|
|
41
|
+
contextRequirements: 0.05,
|
|
42
|
+
// Context requirement matching
|
|
43
|
+
chainId: 0.03,
|
|
44
|
+
// Network-specific behavior
|
|
45
|
+
customMatcher: 0.02
|
|
46
|
+
// Custom logic (lowest weight due to unpredictability)
|
|
47
|
+
};
|
|
48
|
+
function calculateMatchScore(transaction, view, options) {
|
|
49
|
+
const { criteria } = view;
|
|
50
|
+
const matchedCriteria = [];
|
|
51
|
+
let totalWeight = 0;
|
|
52
|
+
let matchedWeight = 0;
|
|
53
|
+
for (const [criterion, weight] of Object.entries(CRITERIA_WEIGHTS)) {
|
|
54
|
+
const criterionKey = criterion;
|
|
55
|
+
const criterionValue = criteria[criterionKey];
|
|
56
|
+
if (criterionValue === void 0) continue;
|
|
57
|
+
totalWeight += weight;
|
|
58
|
+
if (criterionKey === "customMatcher" && typeof criterionValue === "function") {
|
|
59
|
+
try {
|
|
60
|
+
const matchCount = criterionValue(transaction);
|
|
61
|
+
if (matchCount > 0) {
|
|
62
|
+
matchedCriteria.push(criterionKey);
|
|
63
|
+
const normalizedScore = Math.min(matchCount / 10, 1);
|
|
64
|
+
matchedWeight += weight * normalizedScore;
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.warn("Custom matcher threw error:", error);
|
|
68
|
+
}
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
if (doesCriterionMatch(transaction, criterionKey, criterionValue, options)) {
|
|
72
|
+
matchedCriteria.push(criterionKey);
|
|
73
|
+
matchedWeight += weight;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const viewHasContext = criteria.context !== void 0;
|
|
77
|
+
const requestHasContext = options?.context !== void 0;
|
|
78
|
+
if (viewHasContext && !requestHasContext) {
|
|
79
|
+
matchedWeight *= 0.1;
|
|
80
|
+
} else if (!viewHasContext && requestHasContext) {
|
|
81
|
+
matchedWeight *= 0.9;
|
|
82
|
+
}
|
|
83
|
+
if (totalWeight === 0) return { score: 0, matchedCriteria: [] };
|
|
84
|
+
const score = matchedWeight / totalWeight;
|
|
85
|
+
return { score, matchedCriteria };
|
|
86
|
+
}
|
|
87
|
+
function doesCriterionMatch(transaction, criterion, criterionValue, options) {
|
|
88
|
+
switch (criterion) {
|
|
89
|
+
case "recordType":
|
|
90
|
+
return matchesStringOrArray(
|
|
91
|
+
transaction.recordType,
|
|
92
|
+
criterionValue
|
|
93
|
+
);
|
|
94
|
+
case "functionName":
|
|
95
|
+
return matchesStringOrArray(
|
|
96
|
+
transaction.functionName,
|
|
97
|
+
criterionValue
|
|
98
|
+
);
|
|
99
|
+
case "standard":
|
|
100
|
+
return matchesStringOrArray(
|
|
101
|
+
transaction.standard,
|
|
102
|
+
criterionValue
|
|
103
|
+
);
|
|
104
|
+
case "contractAddress":
|
|
105
|
+
return matchesStringOrArray(
|
|
106
|
+
transaction.contractAddress,
|
|
107
|
+
criterionValue
|
|
108
|
+
);
|
|
109
|
+
case "chainId":
|
|
110
|
+
return matchesNumberOrArray(transaction.chainId, criterionValue);
|
|
111
|
+
case "context":
|
|
112
|
+
if (!options?.context) return false;
|
|
113
|
+
return matchesStringOrArray(options.context, criterionValue);
|
|
114
|
+
case "contextRequirements":
|
|
115
|
+
if (!options?.contextRequirements || !criterionValue) return false;
|
|
116
|
+
return areContextRequirementsCompatible(
|
|
117
|
+
options.contextRequirements,
|
|
118
|
+
criterionValue
|
|
119
|
+
);
|
|
120
|
+
case "customMatcher":
|
|
121
|
+
if (typeof criterionValue === "function") {
|
|
122
|
+
try {
|
|
123
|
+
const matchCount = criterionValue(transaction);
|
|
124
|
+
return matchCount > 0;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.warn("Custom matcher threw error:", error);
|
|
127
|
+
return false;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return false;
|
|
131
|
+
default:
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function matchesStringOrArray(value, criteria) {
|
|
136
|
+
if (!value || !criteria) return false;
|
|
137
|
+
if (Array.isArray(criteria)) {
|
|
138
|
+
return criteria.includes(value);
|
|
139
|
+
}
|
|
140
|
+
return value === criteria;
|
|
141
|
+
}
|
|
142
|
+
function matchesNumberOrArray(value, criteria) {
|
|
143
|
+
if (value === void 0 || criteria === void 0) return false;
|
|
144
|
+
if (Array.isArray(criteria)) {
|
|
145
|
+
return criteria.includes(value);
|
|
146
|
+
}
|
|
147
|
+
return value === criteria;
|
|
148
|
+
}
|
|
149
|
+
function areContextRequirementsCompatible(requested, viewRequirements) {
|
|
150
|
+
if (requested.detailLevel && viewRequirements.detailLevel) {
|
|
151
|
+
const detailOrder = ["minimal", "summary", "full", "debug"];
|
|
152
|
+
const requestedLevel = detailOrder.indexOf(requested.detailLevel);
|
|
153
|
+
const viewLevel = detailOrder.indexOf(viewRequirements.detailLevel);
|
|
154
|
+
if (viewLevel < requestedLevel) return false;
|
|
155
|
+
}
|
|
156
|
+
if (requested.maxHeight && viewRequirements.maxHeight) {
|
|
157
|
+
if (viewRequirements.maxHeight > requested.maxHeight) return false;
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
function calculateNativeFrameworkBonus(view, requestedFramework) {
|
|
162
|
+
if (requestedFramework === "lit") {
|
|
163
|
+
return 0;
|
|
164
|
+
}
|
|
165
|
+
if (requestedFramework === "vue" && view.frameworks.vue) {
|
|
166
|
+
return 0.15;
|
|
167
|
+
}
|
|
168
|
+
if (requestedFramework === "rn" && view.frameworks.rn) {
|
|
169
|
+
return 0.15;
|
|
170
|
+
}
|
|
171
|
+
return 0;
|
|
172
|
+
}
|
|
173
|
+
function findMatchingViews(transaction, views, options) {
|
|
174
|
+
const matches = [];
|
|
175
|
+
const minScore = options.minScore ?? 0;
|
|
176
|
+
for (const view of views) {
|
|
177
|
+
if (!view.frameworks[options.framework]) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const { score, matchedCriteria } = calculateMatchScore(transaction, view, {
|
|
181
|
+
context: options.context,
|
|
182
|
+
contextRequirements: options.contextRequirements
|
|
183
|
+
});
|
|
184
|
+
if (score < minScore) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const frameworkBonus = calculateNativeFrameworkBonus(
|
|
188
|
+
view,
|
|
189
|
+
options.framework
|
|
190
|
+
);
|
|
191
|
+
const finalScore = Math.min(1, score + frameworkBonus);
|
|
192
|
+
const match = {
|
|
193
|
+
view,
|
|
194
|
+
score: finalScore,
|
|
195
|
+
matchedCriteria,
|
|
196
|
+
frameworkConfig: options.includeFrameworkConfig ? view.frameworks[options.framework] : void 0
|
|
197
|
+
};
|
|
198
|
+
matches.push(match);
|
|
199
|
+
}
|
|
200
|
+
matches.sort((a, b) => {
|
|
201
|
+
if (a.score !== b.score) {
|
|
202
|
+
return b.score - a.score;
|
|
203
|
+
}
|
|
204
|
+
return b.view.priority - a.view.priority;
|
|
205
|
+
});
|
|
206
|
+
if (options.maxMatches) {
|
|
207
|
+
return matches.slice(0, options.maxMatches);
|
|
208
|
+
}
|
|
209
|
+
return matches;
|
|
210
|
+
}
|
|
211
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
212
|
+
0 && (module.exports = {
|
|
213
|
+
CRITERIA_WEIGHTS,
|
|
214
|
+
calculateMatchScore,
|
|
215
|
+
findMatchingViews
|
|
216
|
+
});
|
|
217
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/index.ts","../../src/utils/view-matcher.ts"],"sourcesContent":["export {\n CRITERIA_WEIGHTS,\n calculateMatchScore,\n findMatchingViews,\n} from './view-matcher'\n","import type { DecoderResult } from '@lukso/transaction-decoder'\nimport type {\n DecoderRecordForSelection,\n ViewDefinition,\n ViewMatch,\n ViewMatchCriteria,\n ViewMatchOptions,\n} from '../types/view-matching'\n\n/**\n * Weights for different matching criteria (higher = more important)\n * Context is optional - only weighted when both view and request specify context\n */\nexport const CRITERIA_WEIGHTS = {\n recordType: 0.25, // Most specific to transaction type\n functionName: 0.2, // Function-level specificity\n context: 0.2, // Context specificity (when opt-in)\n standard: 0.15, // LSP standard specificity\n contractAddress: 0.1, // Contract-specific logic\n contextRequirements: 0.05, // Context requirement matching\n chainId: 0.03, // Network-specific behavior\n customMatcher: 0.02, // Custom logic (lowest weight due to unpredictability)\n} as const\n\n/**\n * Calculate how well a view matches a transaction and context\n *\n * Context matching is opt-in:\n * - If view specifies context criteria, request MUST provide matching context\n * - If view has no context criteria, it matches any context (universal view)\n * - If request has no context, context-specific views are deprioritized\n *\n * Note: For batch operations (executeBatch, setDataBatch, etc.), this matches\n * against the parent transaction. Future enhancement could include matching\n * against child transactions for more granular view selection.\n */\nexport function calculateMatchScore(\n transaction: DecoderResult,\n view: ViewDefinition,\n options?: Pick<ViewMatchOptions, 'context' | 'contextRequirements'>\n): { score: number; matchedCriteria: (keyof ViewMatchCriteria)[] } {\n const { criteria } = view\n const matchedCriteria: (keyof ViewMatchCriteria)[] = []\n let totalWeight = 0\n let matchedWeight = 0\n\n // Check each criterion and accumulate scores\n for (const [criterion, weight] of Object.entries(CRITERIA_WEIGHTS)) {\n const criterionKey = criterion as keyof ViewMatchCriteria\n const criterionValue = criteria[criterionKey]\n\n if (criterionValue === undefined) continue\n\n totalWeight += weight\n\n // Special handling for customMatcher - use match count\n if (\n criterionKey === 'customMatcher' &&\n typeof criterionValue === 'function'\n ) {\n try {\n const matchCount = criterionValue(transaction)\n if (matchCount > 0) {\n matchedCriteria.push(criterionKey)\n // Normalize match count to 0-1 range (cap at 10 conditions)\n const normalizedScore = Math.min(matchCount / 10, 1)\n matchedWeight += weight * normalizedScore\n }\n } catch (error) {\n console.warn('Custom matcher threw error:', error)\n }\n continue\n }\n\n if (\n doesCriterionMatch(transaction, criterionKey, criterionValue, options)\n ) {\n matchedCriteria.push(criterionKey)\n matchedWeight += weight\n }\n }\n\n // Handle context opt-in logic\n const viewHasContext = criteria.context !== undefined\n const requestHasContext = options?.context !== undefined\n\n if (viewHasContext && !requestHasContext) {\n // View requires specific context, but none provided - penalize heavily\n matchedWeight *= 0.1 // Reduce score by 90%\n } else if (!viewHasContext && requestHasContext) {\n // Universal view matching specific context - slight penalty to prefer context-specific views\n matchedWeight *= 0.9 // Reduce score by 10%\n }\n\n // If no criteria are defined, this view doesn't match\n if (totalWeight === 0) return { score: 0, matchedCriteria: [] }\n\n // Calculate final score (0-1)\n const score = matchedWeight / totalWeight\n\n return { score, matchedCriteria }\n}\n\n/**\n * Check if a specific criterion matches the transaction\n */\nfunction doesCriterionMatch(\n transaction: DecoderResult,\n criterion: keyof ViewMatchCriteria,\n criterionValue: any,\n options?: Pick<ViewMatchOptions, 'context' | 'contextRequirements'>\n): boolean {\n switch (criterion) {\n case 'recordType':\n return matchesStringOrArray(\n (transaction as DecoderRecordForSelection).recordType,\n criterionValue\n )\n\n case 'functionName':\n return matchesStringOrArray(\n (transaction as DecoderRecordForSelection).functionName,\n criterionValue\n )\n\n case 'standard':\n return matchesStringOrArray(\n (transaction as DecoderRecordForSelection).standard,\n criterionValue\n )\n\n case 'contractAddress':\n return matchesStringOrArray(\n (transaction as DecoderRecordForSelection).contractAddress,\n criterionValue\n )\n\n case 'chainId':\n return matchesNumberOrArray(transaction.chainId, criterionValue)\n\n case 'context':\n if (!options?.context) return false // No context provided, can't match\n return matchesStringOrArray(options.context, criterionValue)\n\n case 'contextRequirements':\n if (!options?.contextRequirements || !criterionValue) return false\n return areContextRequirementsCompatible(\n options.contextRequirements,\n criterionValue\n )\n\n case 'customMatcher':\n if (typeof criterionValue === 'function') {\n try {\n const matchCount = criterionValue(transaction)\n // Match if any conditions matched (> 0)\n // The actual count contributes to the score in calculateMatchScore\n return matchCount > 0\n } catch (error) {\n console.warn('Custom matcher threw error:', error)\n return false\n }\n }\n return false\n\n default:\n return false\n }\n}\n\n/**\n * Helper to match string values against string or array criteria\n */\nfunction matchesStringOrArray(\n value: string | undefined,\n criteria: string | string[]\n): boolean {\n if (!value || !criteria) return false\n\n if (Array.isArray(criteria)) {\n return criteria.includes(value)\n }\n\n return value === criteria\n}\n\n/**\n * Helper to match number values against number or array criteria\n */\nfunction matchesNumberOrArray(\n value: number | undefined,\n criteria: number | number[]\n): boolean {\n if (value === undefined || criteria === undefined) return false\n\n if (Array.isArray(criteria)) {\n return criteria.includes(value)\n }\n\n return value === criteria\n}\n\n/**\n * Check if context requirements are compatible\n */\nfunction areContextRequirementsCompatible(\n requested: any,\n viewRequirements: any\n): boolean {\n // Simple compatibility check - can be extended\n if (requested.detailLevel && viewRequirements.detailLevel) {\n const detailOrder = ['minimal', 'summary', 'full', 'debug']\n const requestedLevel = detailOrder.indexOf(requested.detailLevel)\n const viewLevel = detailOrder.indexOf(viewRequirements.detailLevel)\n if (viewLevel < requestedLevel) return false\n }\n\n if (requested.maxHeight && viewRequirements.maxHeight) {\n if (viewRequirements.maxHeight > requested.maxHeight) return false\n }\n\n return true\n}\n\n/**\n * Calculate native framework priority bonus\n *\n * Native framework implementations (Vue, React Native) get priority over Lit fallbacks:\n * - Vue: +0.15 bonus when view has Vue implementation\n * - React Native (rn): +0.15 bonus when view has RN implementation\n * - Lit: NO bonus (Lit is the universal fallback)\n *\n * This ensures that when both native and Lit views exist for the same transaction:\n * - Vue app prefers Vue view (Vue score + 0.15 > Lit score)\n * - React Native app prefers RN view (RN score + 0.15 > Lit score)\n * - Other frameworks use Lit view (universal compatibility)\n */\nfunction calculateNativeFrameworkBonus(\n view: ViewDefinition,\n requestedFramework: 'lit' | 'vue' | 'rn'\n): number {\n // Lit gets no bonus - it's the universal fallback\n if (requestedFramework === 'lit') {\n return 0\n }\n\n // Vue gets bonus if view has Vue implementation\n if (requestedFramework === 'vue' && view.frameworks.vue) {\n return 0.15\n }\n\n // React Native gets bonus if view has RN implementation\n if (requestedFramework === 'rn' && view.frameworks.rn) {\n return 0.15\n }\n\n return 0\n}\n\n/**\n * Find and score all matching views for a transaction\n *\n * Views are matched and sorted by:\n * 1. Match score (how well criteria match the transaction)\n * 2. Native framework bonus (Vue/RN get +0.15, Lit gets 0)\n * 3. View priority (manually set priority)\n *\n * This ensures that native framework views are preferred when available,\n * while Lit serves as a universal fallback.\n */\nexport function findMatchingViews(\n transaction: DecoderResult,\n views: ViewDefinition[],\n options: ViewMatchOptions\n): ViewMatch[] {\n const matches: ViewMatch[] = []\n const minScore = options.minScore ?? 0\n\n for (const view of views) {\n // Skip if framework is not supported\n if (!view.frameworks[options.framework]) {\n continue\n }\n\n const { score, matchedCriteria } = calculateMatchScore(transaction, view, {\n context: options.context,\n contextRequirements: options.contextRequirements,\n })\n\n // Skip if score is below threshold\n if (score < minScore) {\n continue\n }\n\n // Apply native framework bonus (Vue/RN only, NOT Lit)\n const frameworkBonus = calculateNativeFrameworkBonus(\n view,\n options.framework\n )\n const finalScore = Math.min(1, score + frameworkBonus)\n\n const match: ViewMatch = {\n view,\n score: finalScore,\n matchedCriteria,\n frameworkConfig: options.includeFrameworkConfig\n ? view.frameworks[options.framework]\n : undefined,\n }\n\n matches.push(match)\n }\n\n // Sort by score (descending), then by priority (descending)\n matches.sort((a, b) => {\n if (a.score !== b.score) {\n return b.score - a.score\n }\n return b.view.priority - a.view.priority\n })\n\n // Limit results if requested\n if (options.maxMatches) {\n return matches.slice(0, options.maxMatches)\n }\n\n return matches\n}\n\n/**\n * TODO: Future enhancement for batch operations\n *\n * For batch operations like executeBatch, setDataBatch, we might want to:\n * 1. Match against the batch container (current behavior)\n * 2. Also match against child transactions for more specific views\n * 3. Allow views to specify whether they handle batches vs individual items\n * 4. Support composite views that render both batch info + child items\n */\n"],"mappings":"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","names":[]}
|