@portel/photon-core 1.4.0 → 2.1.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.
Files changed (169) hide show
  1. package/README.md +123 -0
  2. package/dist/auto-ui.d.ts +103 -0
  3. package/dist/auto-ui.d.ts.map +1 -0
  4. package/dist/auto-ui.js +275 -0
  5. package/dist/auto-ui.js.map +1 -0
  6. package/dist/base.d.ts +9 -2
  7. package/dist/base.d.ts.map +1 -1
  8. package/dist/base.js +23 -10
  9. package/dist/base.js.map +1 -1
  10. package/dist/cli-ui-renderer.d.ts +31 -0
  11. package/dist/cli-ui-renderer.d.ts.map +1 -0
  12. package/dist/cli-ui-renderer.js +224 -0
  13. package/dist/cli-ui-renderer.js.map +1 -0
  14. package/dist/dependency-manager.d.ts.map +1 -1
  15. package/dist/dependency-manager.js +0 -1
  16. package/dist/dependency-manager.js.map +1 -1
  17. package/dist/design-system/index.d.ts +21 -0
  18. package/dist/design-system/index.d.ts.map +1 -0
  19. package/dist/design-system/index.js +27 -0
  20. package/dist/design-system/index.js.map +1 -0
  21. package/dist/design-system/tokens.d.ts +149 -0
  22. package/dist/design-system/tokens.d.ts.map +1 -0
  23. package/dist/design-system/tokens.js +413 -0
  24. package/dist/design-system/tokens.js.map +1 -0
  25. package/dist/design-system/transaction-ui.d.ts +70 -0
  26. package/dist/design-system/transaction-ui.d.ts.map +1 -0
  27. package/dist/design-system/transaction-ui.js +982 -0
  28. package/dist/design-system/transaction-ui.js.map +1 -0
  29. package/dist/generator.d.ts +58 -8
  30. package/dist/generator.d.ts.map +1 -1
  31. package/dist/generator.js +9 -4
  32. package/dist/generator.js.map +1 -1
  33. package/dist/index.d.ts +10 -7
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +48 -44
  36. package/dist/index.js.map +1 -1
  37. package/dist/io.d.ts +395 -0
  38. package/dist/io.d.ts.map +1 -0
  39. package/dist/io.js +304 -0
  40. package/dist/io.js.map +1 -0
  41. package/dist/path-resolver.d.ts.map +1 -1
  42. package/dist/path-resolver.js +2 -1
  43. package/dist/path-resolver.js.map +1 -1
  44. package/dist/rendering/components.d.ts +29 -0
  45. package/dist/rendering/components.d.ts.map +1 -0
  46. package/dist/rendering/components.js +773 -0
  47. package/dist/rendering/components.js.map +1 -0
  48. package/dist/rendering/field-analyzer.d.ts +48 -0
  49. package/dist/rendering/field-analyzer.d.ts.map +1 -0
  50. package/dist/rendering/field-analyzer.js +270 -0
  51. package/dist/rendering/field-analyzer.js.map +1 -0
  52. package/dist/rendering/field-renderers.d.ts +64 -0
  53. package/dist/rendering/field-renderers.d.ts.map +1 -0
  54. package/dist/rendering/field-renderers.js +317 -0
  55. package/dist/rendering/field-renderers.js.map +1 -0
  56. package/dist/rendering/index.d.ts +28 -0
  57. package/dist/rendering/index.d.ts.map +1 -0
  58. package/dist/rendering/index.js +60 -0
  59. package/dist/rendering/index.js.map +1 -0
  60. package/dist/rendering/layout-selector.d.ts +48 -0
  61. package/dist/rendering/layout-selector.d.ts.map +1 -0
  62. package/dist/rendering/layout-selector.js +347 -0
  63. package/dist/rendering/layout-selector.js.map +1 -0
  64. package/dist/rendering/template-engine.d.ts +41 -0
  65. package/dist/rendering/template-engine.d.ts.map +1 -0
  66. package/dist/rendering/template-engine.js +236 -0
  67. package/dist/rendering/template-engine.js.map +1 -0
  68. package/dist/schema-extractor.d.ts +30 -0
  69. package/dist/schema-extractor.d.ts.map +1 -1
  70. package/dist/schema-extractor.js +205 -12
  71. package/dist/schema-extractor.js.map +1 -1
  72. package/dist/stateful.d.ts +63 -0
  73. package/dist/stateful.d.ts.map +1 -1
  74. package/dist/stateful.js +222 -0
  75. package/dist/stateful.js.map +1 -1
  76. package/dist/types.d.ts +9 -1
  77. package/dist/types.d.ts.map +1 -1
  78. package/dist/types.js.map +1 -1
  79. package/dist/ucp/ap2/handlers.d.ts +242 -0
  80. package/dist/ucp/ap2/handlers.d.ts.map +1 -0
  81. package/dist/ucp/ap2/handlers.js +482 -0
  82. package/dist/ucp/ap2/handlers.js.map +1 -0
  83. package/dist/ucp/ap2/mandates.d.ts +95 -0
  84. package/dist/ucp/ap2/mandates.d.ts.map +1 -0
  85. package/dist/ucp/ap2/mandates.js +234 -0
  86. package/dist/ucp/ap2/mandates.js.map +1 -0
  87. package/dist/ucp/ap2/types.d.ts +305 -0
  88. package/dist/ucp/ap2/types.d.ts.map +1 -0
  89. package/dist/ucp/ap2/types.js +8 -0
  90. package/dist/ucp/ap2/types.js.map +1 -0
  91. package/dist/ucp/capabilities/checkout.d.ts +118 -0
  92. package/dist/ucp/capabilities/checkout.d.ts.map +1 -0
  93. package/dist/ucp/capabilities/checkout.js +344 -0
  94. package/dist/ucp/capabilities/checkout.js.map +1 -0
  95. package/dist/ucp/capabilities/identity.d.ts +130 -0
  96. package/dist/ucp/capabilities/identity.d.ts.map +1 -0
  97. package/dist/ucp/capabilities/identity.js +290 -0
  98. package/dist/ucp/capabilities/identity.js.map +1 -0
  99. package/dist/ucp/capabilities/order.d.ts +142 -0
  100. package/dist/ucp/capabilities/order.d.ts.map +1 -0
  101. package/dist/ucp/capabilities/order.js +383 -0
  102. package/dist/ucp/capabilities/order.js.map +1 -0
  103. package/dist/ucp/index.d.ts +18 -0
  104. package/dist/ucp/index.d.ts.map +1 -0
  105. package/dist/ucp/index.js +19 -0
  106. package/dist/ucp/index.js.map +1 -0
  107. package/dist/ucp/manifest.d.ts +62 -0
  108. package/dist/ucp/manifest.d.ts.map +1 -0
  109. package/dist/ucp/manifest.js +180 -0
  110. package/dist/ucp/manifest.js.map +1 -0
  111. package/dist/ucp/types.d.ts +327 -0
  112. package/dist/ucp/types.d.ts.map +1 -0
  113. package/dist/ucp/types.js +8 -0
  114. package/dist/ucp/types.js.map +1 -0
  115. package/package.json +3 -4
  116. package/src/auto-ui.ts +413 -0
  117. package/src/base.ts +22 -9
  118. package/src/cli-ui-renderer.ts +264 -0
  119. package/src/dependency-manager.ts +0 -1
  120. package/src/design-system/index.ts +30 -0
  121. package/src/design-system/tokens.ts +451 -0
  122. package/src/design-system/transaction-ui.ts +1038 -0
  123. package/src/generator.ts +68 -8
  124. package/src/index.ts +159 -101
  125. package/src/io.ts +493 -0
  126. package/src/path-resolver.ts +2 -1
  127. package/src/rendering/components.ts +785 -0
  128. package/src/rendering/field-analyzer.ts +299 -0
  129. package/src/rendering/field-renderers.ts +356 -0
  130. package/src/rendering/index.ts +63 -0
  131. package/src/rendering/layout-selector.ts +390 -0
  132. package/src/rendering/template-engine.ts +254 -0
  133. package/src/schema-extractor.ts +225 -12
  134. package/src/stateful.ts +301 -0
  135. package/src/types.ts +10 -1
  136. package/src/ucp/ap2/handlers.ts +779 -0
  137. package/src/ucp/ap2/mandates.ts +354 -0
  138. package/src/ucp/ap2/types.ts +441 -0
  139. package/src/ucp/capabilities/checkout.ts +497 -0
  140. package/src/ucp/capabilities/identity.ts +425 -0
  141. package/src/ucp/capabilities/order.ts +549 -0
  142. package/src/ucp/index.ts +27 -0
  143. package/src/ucp/manifest.ts +257 -0
  144. package/src/ucp/types.ts +454 -0
  145. package/dist/cli-formatter.d.ts +0 -92
  146. package/dist/cli-formatter.d.ts.map +0 -1
  147. package/dist/cli-formatter.js +0 -486
  148. package/dist/cli-formatter.js.map +0 -1
  149. package/dist/elicit.d.ts +0 -93
  150. package/dist/elicit.d.ts.map +0 -1
  151. package/dist/elicit.js +0 -373
  152. package/dist/elicit.js.map +0 -1
  153. package/dist/mcp-client.d.ts +0 -218
  154. package/dist/mcp-client.d.ts.map +0 -1
  155. package/dist/mcp-client.js +0 -424
  156. package/dist/mcp-client.js.map +0 -1
  157. package/dist/mcp-sdk-transport.d.ts +0 -88
  158. package/dist/mcp-sdk-transport.d.ts.map +0 -1
  159. package/dist/mcp-sdk-transport.js +0 -360
  160. package/dist/mcp-sdk-transport.js.map +0 -1
  161. package/dist/photon-config.d.ts +0 -86
  162. package/dist/photon-config.d.ts.map +0 -1
  163. package/dist/photon-config.js +0 -156
  164. package/dist/photon-config.js.map +0 -1
  165. package/src/cli-formatter.ts +0 -579
  166. package/src/elicit.ts +0 -438
  167. package/src/mcp-client.ts +0 -561
  168. package/src/mcp-sdk-transport.ts +0 -449
  169. package/src/photon-config.ts +0 -201
@@ -0,0 +1,354 @@
1
+ /**
2
+ * AP2 Mandate Creation and Validation Helpers
3
+ */
4
+
5
+ import * as crypto from 'crypto';
6
+ import {
7
+ CartMandate,
8
+ CartMandateContents,
9
+ IntentMandate,
10
+ IntentMandateContents,
11
+ PaymentMandate,
12
+ PaymentMandateContents,
13
+ PaymentResponse,
14
+ PaymentMethodType,
15
+ TransactionContext,
16
+ RiskPayload
17
+ } from './types.js';
18
+ import { Money, Address, LineItem } from '../types.js';
19
+
20
+ // ============================================================================
21
+ // Cart Mandate Helpers
22
+ // ============================================================================
23
+
24
+ export interface CreateCartMandateParams {
25
+ items: LineItem[];
26
+ total: Money;
27
+ merchant: {
28
+ id: string;
29
+ name: string;
30
+ url?: string;
31
+ };
32
+ paymentMethods: PaymentMethodType[];
33
+ fulfillment?: {
34
+ method: string;
35
+ destination: Address;
36
+ estimatedDelivery?: string;
37
+ };
38
+ refundPeriodDays?: number;
39
+ }
40
+
41
+ /**
42
+ * Create a new Cart Mandate for human-present transactions
43
+ */
44
+ export function createCartMandate(
45
+ params: CreateCartMandateParams,
46
+ merchantPrivateKey?: string
47
+ ): CartMandate {
48
+ const contents: CartMandateContents = {
49
+ id: `cart_${crypto.randomUUID()}`,
50
+ userSignatureRequired: true,
51
+ paymentRequest: {
52
+ methodData: params.paymentMethods.map(method => ({
53
+ supportedMethods: method,
54
+ data: {}
55
+ })),
56
+ details: {
57
+ id: `order_${crypto.randomUUID()}`,
58
+ displayItems: params.items.map(item => ({
59
+ label: item.label,
60
+ amount: item.totalPrice
61
+ })),
62
+ total: {
63
+ label: 'Total',
64
+ amount: params.total
65
+ }
66
+ }
67
+ },
68
+ merchant: params.merchant,
69
+ fulfillment: params.fulfillment,
70
+ refundConditions: params.refundPeriodDays ? {
71
+ period: params.refundPeriodDays,
72
+ policy: `Full refund within ${params.refundPeriodDays} days of delivery`
73
+ } : undefined
74
+ };
75
+
76
+ const timestamp = new Date().toISOString();
77
+ const merchantSignature = merchantPrivateKey
78
+ ? signMandate(contents, merchantPrivateKey)
79
+ : `sig_merchant_${crypto.randomBytes(16).toString('hex')}`;
80
+
81
+ return {
82
+ contents,
83
+ merchantSignature,
84
+ timestamp
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Add user signature to Cart Mandate
90
+ */
91
+ export function signCartMandate(
92
+ mandate: CartMandate,
93
+ userPrivateKey?: string
94
+ ): CartMandate {
95
+ const userSignature = userPrivateKey
96
+ ? signMandate(mandate.contents, userPrivateKey)
97
+ : `sig_user_${crypto.randomBytes(16).toString('hex')}`;
98
+
99
+ return {
100
+ ...mandate,
101
+ userSignature,
102
+ userSignatureTimestamp: new Date().toISOString()
103
+ };
104
+ }
105
+
106
+ // ============================================================================
107
+ // Intent Mandate Helpers
108
+ // ============================================================================
109
+
110
+ export interface CreateIntentMandateParams {
111
+ description: string;
112
+ productCategories?: string[];
113
+ specificSkus?: string[];
114
+ keywords?: string[];
115
+ maxPrice: Money;
116
+ minPrice?: Money;
117
+ quantity?: { min?: number; max?: number };
118
+ allowedMerchants?: string[];
119
+ validForHours?: number;
120
+ executeWhen?: 'immediately' | 'price_drop' | 'in_stock' | 'scheduled';
121
+ paymentMethods: PaymentMethodType[];
122
+ promptPlayback?: string;
123
+ }
124
+
125
+ /**
126
+ * Create a new Intent Mandate for autonomous agent purchases
127
+ */
128
+ export function createIntentMandate(
129
+ params: CreateIntentMandateParams,
130
+ userPrivateKey?: string
131
+ ): IntentMandate {
132
+ const now = new Date();
133
+ const validUntil = new Date(now.getTime() + (params.validForHours || 24) * 60 * 60 * 1000);
134
+
135
+ const contents: IntentMandateContents = {
136
+ id: `intent_${crypto.randomUUID()}`,
137
+ intent: {
138
+ description: params.description,
139
+ productCategories: params.productCategories,
140
+ specificSkus: params.specificSkus,
141
+ keywords: params.keywords
142
+ },
143
+ constraints: {
144
+ maxPrice: params.maxPrice,
145
+ minPrice: params.minPrice,
146
+ quantity: params.quantity,
147
+ merchants: params.allowedMerchants
148
+ },
149
+ timing: {
150
+ validFrom: now.toISOString(),
151
+ validUntil: validUntil.toISOString(),
152
+ executeWhen: params.executeWhen || 'immediately'
153
+ },
154
+ paymentAuthorization: {
155
+ methodCategories: params.paymentMethods,
156
+ preAuthorizedAmount: params.maxPrice
157
+ },
158
+ promptPlayback: params.promptPlayback
159
+ };
160
+
161
+ const userSignature = userPrivateKey
162
+ ? signMandate(contents, userPrivateKey)
163
+ : `sig_user_${crypto.randomBytes(16).toString('hex')}`;
164
+
165
+ return {
166
+ contents,
167
+ userSignature,
168
+ userSignatureTimestamp: now.toISOString()
169
+ };
170
+ }
171
+
172
+ /**
173
+ * Check if Intent Mandate is still valid
174
+ */
175
+ export function isIntentMandateValid(mandate: IntentMandate): boolean {
176
+ const now = new Date();
177
+ const validFrom = new Date(mandate.contents.timing.validFrom);
178
+ const validUntil = new Date(mandate.contents.timing.validUntil);
179
+
180
+ return now >= validFrom && now <= validUntil;
181
+ }
182
+
183
+ /**
184
+ * Check if a price satisfies Intent Mandate constraints
185
+ */
186
+ export function checkPriceConstraints(
187
+ mandate: IntentMandate,
188
+ price: Money
189
+ ): { valid: boolean; reason?: string } {
190
+ const { constraints } = mandate.contents;
191
+
192
+ if (price.currency !== constraints.maxPrice.currency) {
193
+ return { valid: false, reason: 'Currency mismatch' };
194
+ }
195
+
196
+ if (price.amount > constraints.maxPrice.amount) {
197
+ return { valid: false, reason: `Price ${price.amount} exceeds max ${constraints.maxPrice.amount}` };
198
+ }
199
+
200
+ if (constraints.minPrice && price.amount < constraints.minPrice.amount) {
201
+ return { valid: false, reason: `Price ${price.amount} below min ${constraints.minPrice.amount}` };
202
+ }
203
+
204
+ return { valid: true };
205
+ }
206
+
207
+ // ============================================================================
208
+ // Payment Mandate Helpers
209
+ // ============================================================================
210
+
211
+ export interface CreatePaymentMandateParams {
212
+ sourceMandate: CartMandate | IntentMandate;
213
+ paymentResponse: PaymentResponse;
214
+ agentName?: string;
215
+ }
216
+
217
+ /**
218
+ * Create a Payment Mandate from Cart or Intent Mandate
219
+ */
220
+ export function createPaymentMandate(
221
+ params: CreatePaymentMandateParams,
222
+ userPrivateKey?: string
223
+ ): PaymentMandate {
224
+ const { sourceMandate, paymentResponse, agentName } = params;
225
+
226
+ const isCartMandate = 'merchantSignature' in sourceMandate;
227
+ const sourceMandateType = isCartMandate ? 'cart' : 'intent';
228
+ const sourceMandateId = sourceMandate.contents.id;
229
+
230
+ // Get total from source mandate
231
+ let total: Money;
232
+ if (isCartMandate) {
233
+ total = (sourceMandate as CartMandate).contents.paymentRequest.details.total.amount;
234
+ } else {
235
+ total = (sourceMandate as IntentMandate).contents.constraints.maxPrice;
236
+ }
237
+
238
+ const contents: PaymentMandateContents = {
239
+ paymentMandateId: `pm_${crypto.randomUUID()}`,
240
+ paymentDetailsId: paymentResponse.requestId,
241
+ paymentDetailsTotal: {
242
+ label: 'Total',
243
+ amount: total,
244
+ refundPeriod: isCartMandate
245
+ ? (sourceMandate as CartMandate).contents.refundConditions?.period
246
+ : 30
247
+ },
248
+ paymentResponse,
249
+ merchantAgent: agentName || 'MerchantAgent',
250
+ sourceMandateType,
251
+ sourceMandateId,
252
+ timestamp: new Date().toISOString()
253
+ };
254
+
255
+ const userAuthorization = userPrivateKey
256
+ ? signMandate(contents, userPrivateKey)
257
+ : `auth_${crypto.randomBytes(32).toString('base64url')}`;
258
+
259
+ return {
260
+ paymentMandateContents: contents,
261
+ userAuthorization
262
+ };
263
+ }
264
+
265
+ // ============================================================================
266
+ // Signature Helpers
267
+ // ============================================================================
268
+
269
+ /**
270
+ * Sign mandate contents (simplified - production should use proper PKI)
271
+ */
272
+ function signMandate(contents: any, privateKey: string): string {
273
+ const payload = JSON.stringify(contents);
274
+ const hmac = crypto.createHmac('sha256', privateKey);
275
+ hmac.update(payload);
276
+ return `sig_${hmac.digest('base64url')}`;
277
+ }
278
+
279
+ /**
280
+ * Verify mandate signature
281
+ */
282
+ export function verifyMandateSignature(
283
+ contents: any,
284
+ signature: string,
285
+ publicKey: string
286
+ ): boolean {
287
+ // Simplified verification - production should use proper PKI
288
+ const expectedSig = signMandate(contents, publicKey);
289
+ return signature === expectedSig;
290
+ }
291
+
292
+ // ============================================================================
293
+ // Transaction Context
294
+ // ============================================================================
295
+
296
+ /**
297
+ * Create transaction context for audit trail
298
+ */
299
+ export function createTransactionContext(params: {
300
+ modality: 'human_present' | 'human_not_present';
301
+ initiatedBy: 'user' | 'agent';
302
+ mandates: (CartMandate | IntentMandate | PaymentMandate)[];
303
+ }): TransactionContext {
304
+ return {
305
+ modality: params.modality,
306
+ agentPresent: true,
307
+ initiatedBy: params.initiatedBy,
308
+ sessionId: `session_${crypto.randomUUID()}`,
309
+ startTime: new Date().toISOString(),
310
+ mandateChain: params.mandates.map(mandate => {
311
+ if ('merchantSignature' in mandate) {
312
+ return {
313
+ type: 'cart' as const,
314
+ id: mandate.contents.id,
315
+ timestamp: mandate.timestamp
316
+ };
317
+ } else if ('paymentMandateContents' in mandate) {
318
+ return {
319
+ type: 'payment' as const,
320
+ id: mandate.paymentMandateContents.paymentMandateId,
321
+ timestamp: mandate.paymentMandateContents.timestamp
322
+ };
323
+ } else {
324
+ return {
325
+ type: 'intent' as const,
326
+ id: mandate.contents.id,
327
+ timestamp: mandate.userSignatureTimestamp
328
+ };
329
+ }
330
+ })
331
+ };
332
+ }
333
+
334
+ // ============================================================================
335
+ // Risk Assessment
336
+ // ============================================================================
337
+
338
+ /**
339
+ * Create risk payload for payment authorization
340
+ */
341
+ export function createRiskPayload(params: {
342
+ deviceFingerprint?: string;
343
+ ipAddress?: string;
344
+ userAgent?: string;
345
+ authLevel: 'none' | 'basic' | 'mfa' | 'biometric';
346
+ sessionDuration?: number;
347
+ previousPurchases?: number;
348
+ agentVerified?: boolean;
349
+ }): RiskPayload {
350
+ return {
351
+ ...params,
352
+ authTimestamp: new Date().toISOString()
353
+ };
354
+ }