@rune-kit/rune 2.10.0 → 2.11.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/LICENSE +21 -21
- package/README.md +8 -6
- package/commands/rune.md +168 -168
- package/contexts/dev.md +34 -34
- package/contexts/research.md +43 -43
- package/contexts/review.md +55 -55
- package/extensions/ai-ml/PACK.md +88 -88
- package/extensions/ai-ml/skills/ai-agents.md +172 -172
- package/extensions/ai-ml/skills/code-sandbox.md +187 -187
- package/extensions/ai-ml/skills/deep-research.md +146 -146
- package/extensions/ai-ml/skills/embedding-search.md +66 -66
- package/extensions/ai-ml/skills/fine-tuning-guide.md +74 -74
- package/extensions/ai-ml/skills/llm-architect.md +125 -125
- package/extensions/ai-ml/skills/llm-integration.md +64 -64
- package/extensions/ai-ml/skills/prompt-patterns.md +72 -72
- package/extensions/ai-ml/skills/rag-patterns.md +66 -66
- package/extensions/ai-ml/skills/web-extraction.md +114 -114
- package/extensions/analytics/PACK.md +92 -92
- package/extensions/analytics/skills/ab-testing.md +72 -72
- package/extensions/analytics/skills/dashboard-patterns.md +83 -83
- package/extensions/analytics/skills/data-validation.md +68 -68
- package/extensions/analytics/skills/funnel-analysis.md +81 -81
- package/extensions/analytics/skills/sql-patterns.md +57 -57
- package/extensions/analytics/skills/statistical-analysis.md +79 -79
- package/extensions/analytics/skills/tracking-setup.md +71 -71
- package/extensions/backend/PACK.md +104 -104
- package/extensions/backend/skills/api-patterns.md +84 -84
- package/extensions/backend/skills/async-pipeline.md +193 -193
- package/extensions/backend/skills/auth-patterns.md +97 -97
- package/extensions/backend/skills/background-jobs.md +133 -133
- package/extensions/backend/skills/caching-patterns.md +108 -108
- package/extensions/backend/skills/cli-generation.md +133 -133
- package/extensions/backend/skills/database-patterns.md +87 -87
- package/extensions/backend/skills/middleware-patterns.md +104 -104
- package/extensions/chrome-ext/PACK.md +93 -93
- package/extensions/chrome-ext/skills/cws-preflight.md +143 -143
- package/extensions/chrome-ext/skills/cws-publish.md +104 -104
- package/extensions/chrome-ext/skills/ext-ai-integration.md +251 -251
- package/extensions/chrome-ext/skills/ext-messaging.md +139 -139
- package/extensions/chrome-ext/skills/ext-storage.md +133 -133
- package/extensions/chrome-ext/skills/mv3-scaffold.md +164 -164
- package/extensions/content/PACK.md +96 -96
- package/extensions/content/skills/blog-patterns.md +88 -88
- package/extensions/content/skills/cms-integration.md +131 -131
- package/extensions/content/skills/content-scoring.md +107 -107
- package/extensions/content/skills/i18n.md +83 -83
- package/extensions/content/skills/mdx-authoring.md +137 -137
- package/extensions/content/skills/reference.md +1014 -1014
- package/extensions/content/skills/seo-patterns.md +67 -67
- package/extensions/content/skills/video-repurpose.md +153 -153
- package/extensions/devops/PACK.md +101 -101
- package/extensions/devops/skills/chaos-testing.md +67 -67
- package/extensions/devops/skills/ci-cd.md +75 -75
- package/extensions/devops/skills/docker.md +58 -58
- package/extensions/devops/skills/edge-serverless.md +163 -163
- package/extensions/devops/skills/infra-as-code.md +158 -158
- package/extensions/devops/skills/kubernetes.md +110 -110
- package/extensions/devops/skills/monitoring.md +57 -57
- package/extensions/devops/skills/server-setup.md +64 -64
- package/extensions/devops/skills/ssl-domain.md +42 -42
- package/extensions/ecommerce/PACK.md +116 -116
- package/extensions/ecommerce/skills/cart-system.md +79 -79
- package/extensions/ecommerce/skills/inventory-mgmt.md +102 -102
- package/extensions/ecommerce/skills/order-management.md +126 -126
- package/extensions/ecommerce/skills/payment-integration.md +472 -472
- package/extensions/ecommerce/skills/shopify-dev.md +69 -69
- package/extensions/ecommerce/skills/subscription-billing.md +93 -93
- package/extensions/ecommerce/skills/tax-compliance.md +117 -117
- package/extensions/gamedev/PACK.md +142 -142
- package/extensions/gamedev/skills/asset-pipeline.md +74 -74
- package/extensions/gamedev/skills/audio-system.md +129 -129
- package/extensions/gamedev/skills/camera-system.md +87 -87
- package/extensions/gamedev/skills/ecs.md +98 -98
- package/extensions/gamedev/skills/game-loops.md +72 -72
- package/extensions/gamedev/skills/input-system.md +199 -199
- package/extensions/gamedev/skills/multiplayer.md +180 -180
- package/extensions/gamedev/skills/particles.md +105 -105
- package/extensions/gamedev/skills/physics-engine.md +89 -89
- package/extensions/gamedev/skills/scene-management.md +146 -146
- package/extensions/gamedev/skills/threejs-patterns.md +90 -90
- package/extensions/gamedev/skills/webgl.md +71 -71
- package/extensions/mobile/PACK.md +106 -106
- package/extensions/mobile/skills/app-store-connect.md +152 -152
- package/extensions/mobile/skills/app-store-prep.md +66 -66
- package/extensions/mobile/skills/deep-linking.md +109 -109
- package/extensions/mobile/skills/flutter.md +60 -60
- package/extensions/mobile/skills/ios-build-pipeline.md +142 -142
- package/extensions/mobile/skills/native-bridge.md +66 -66
- package/extensions/mobile/skills/ota-updates.md +97 -97
- package/extensions/mobile/skills/push-notifications.md +111 -111
- package/extensions/mobile/skills/react-native.md +82 -82
- package/extensions/saas/PACK.md +116 -116
- package/extensions/saas/skills/billing-integration.md +200 -200
- package/extensions/saas/skills/feature-flags.md +130 -130
- package/extensions/saas/skills/multi-tenant.md +103 -103
- package/extensions/saas/skills/onboarding-flow.md +139 -139
- package/extensions/saas/skills/subscription-flow.md +95 -95
- package/extensions/saas/skills/team-management.md +144 -144
- package/extensions/security/PACK.md +99 -99
- package/extensions/security/skills/api-security.md +140 -140
- package/extensions/security/skills/compliance.md +68 -68
- package/extensions/security/skills/owasp-audit.md +64 -64
- package/extensions/security/skills/pentest-patterns.md +77 -77
- package/extensions/security/skills/secret-mgmt.md +65 -65
- package/extensions/security/skills/supply-chain.md +65 -65
- package/extensions/trading/PACK.md +80 -80
- package/extensions/trading/skills/chart-components.md +55 -55
- package/extensions/trading/skills/experiment-loop.md +125 -125
- package/extensions/trading/skills/fintech-patterns.md +47 -47
- package/extensions/trading/skills/indicator-library.md +58 -58
- package/extensions/trading/skills/quant-analysis.md +111 -111
- package/extensions/trading/skills/realtime-data.md +58 -58
- package/extensions/trading/skills/trade-logic.md +104 -104
- package/extensions/ui/PACK.md +130 -130
- package/extensions/ui/skills/a11y-audit.md +91 -91
- package/extensions/ui/skills/animation-patterns.md +127 -127
- package/extensions/ui/skills/component-patterns.md +100 -100
- package/extensions/ui/skills/design-decision.md +108 -108
- package/extensions/ui/skills/design-system.md +68 -68
- package/extensions/ui/skills/landing-patterns.md +155 -155
- package/extensions/ui/skills/palette-picker.md +173 -173
- package/extensions/ui/skills/react-health.md +90 -90
- package/extensions/ui/skills/type-system.md +125 -125
- package/extensions/ui/skills/web-vitals.md +153 -153
- package/extensions/zalo/PACK.md +145 -145
- package/extensions/zalo/skills/zalo-oa-mcp.md +317 -317
- package/extensions/zalo/skills/zalo-oa-messaging.md +429 -429
- package/extensions/zalo/skills/zalo-oa-setup.md +236 -236
- package/extensions/zalo/skills/zalo-oa-webhook.md +189 -189
- package/extensions/zalo/skills/zalo-personal-messaging.md +194 -194
- package/extensions/zalo/skills/zalo-personal-setup.md +153 -153
- package/extensions/zalo/skills/zalo-rate-guard.md +219 -219
- package/hooks/auto-format/index.cjs +48 -48
- package/hooks/hooks.json +111 -111
- package/hooks/post-session-reflect/index.cjs +189 -189
- package/hooks/pre-compact/index.cjs +95 -95
- package/hooks/run-hook.cmd +1 -1
- package/hooks/secrets-scan/index.cjs +100 -100
- package/hooks/session-start/index.cjs +71 -71
- package/hooks/typecheck/index.cjs +65 -65
- package/package.json +63 -63
- package/references/ui-pro-max-data/LICENSE-UI-PRO-MAX +21 -21
- package/references/ui-pro-max-data/charts.csv +26 -26
- package/references/ui-pro-max-data/colors.csv +161 -161
- package/references/ui-pro-max-data/styles.csv +68 -68
- package/references/ui-pro-max-data/typography.csv +74 -74
- package/references/ui-pro-max-data/ui-reasoning.csv +162 -162
- package/references/ui-pro-max-data/ux-guidelines.csv +99 -99
- package/skills/adversary/SKILL.md +283 -283
- package/skills/asset-creator/SKILL.md +157 -157
- package/skills/audit/SKILL.md +147 -2
- package/skills/autopsy/SKILL.md +335 -335
- package/skills/brainstorm/SKILL.md +342 -342
- package/skills/browser-pilot/SKILL.md +168 -168
- package/skills/constraint-check/SKILL.md +165 -165
- package/skills/context-engine/SKILL.md +404 -404
- package/skills/cook/SKILL.md +917 -863
- package/skills/db/SKILL.md +273 -273
- package/skills/debug/SKILL.md +465 -465
- package/skills/dependency-doctor/SKILL.md +265 -235
- package/skills/deploy/SKILL.md +274 -231
- package/skills/design/DESIGN-REFERENCE.md +365 -365
- package/skills/design/SKILL.md +589 -589
- package/skills/doc-processor/SKILL.md +254 -254
- package/skills/docs/SKILL.md +374 -374
- package/skills/docs-seeker/SKILL.md +177 -177
- package/skills/fix/SKILL.md +330 -330
- package/skills/git/SKILL.md +339 -339
- package/skills/hallucination-guard/SKILL.md +219 -219
- package/skills/incident/SKILL.md +254 -253
- package/skills/integrity-check/SKILL.md +169 -169
- package/skills/journal/SKILL.md +240 -240
- package/skills/launch/SKILL.md +344 -344
- package/skills/logic-guardian/SKILL.md +251 -251
- package/skills/marketing/SKILL.md +290 -289
- package/skills/mcp-builder/SKILL.md +425 -425
- package/skills/neural-memory/SKILL.md +362 -362
- package/skills/onboard/SKILL.md +404 -403
- package/skills/perf/SKILL.md +346 -346
- package/skills/plan/SKILL.md +433 -428
- package/skills/preflight/SKILL.md +415 -415
- package/skills/problem-solver/SKILL.md +380 -284
- package/skills/rescue/SKILL.md +474 -474
- package/skills/retro/SKILL.md +3 -1
- package/skills/review/SKILL.md +612 -588
- package/skills/review-intake/SKILL.md +249 -249
- package/skills/safeguard/SKILL.md +200 -200
- package/skills/sast/SKILL.md +190 -190
- package/skills/scaffold/SKILL.md +328 -287
- package/skills/scope-guard/SKILL.md +180 -180
- package/skills/scout/SKILL.md +263 -263
- package/skills/sentinel/SKILL.md +382 -381
- package/skills/sentinel-env/SKILL.md +254 -254
- package/skills/sequential-thinking/SKILL.md +234 -234
- package/skills/session-bridge/SKILL.md +543 -543
- package/skills/skill-forge/SKILL.md +581 -581
- package/skills/skill-router/SKILL.md +3 -0
- package/skills/surgeon/SKILL.md +215 -215
- package/skills/team/SKILL.md +556 -537
- package/skills/test/SKILL.md +614 -614
- package/skills/trend-scout/SKILL.md +145 -145
- package/skills/verification/SKILL.md +326 -326
- package/skills/video-creator/SKILL.md +201 -201
- package/skills/watchdog/SKILL.md +168 -168
- package/skills/worktree/SKILL.md +140 -140
|
@@ -1,126 +1,126 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: "order-management"
|
|
3
|
-
pack: "@rune/ecommerce"
|
|
4
|
-
description: "Order lifecycle — state machine, fulfillment workflows, refund/return flows, email notifications, reconciliation, webhook fan-out."
|
|
5
|
-
model: sonnet
|
|
6
|
-
tools: [Read, Edit, Write, Grep, Glob, Bash]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# order-management
|
|
10
|
-
|
|
11
|
-
Order lifecycle — state machine, fulfillment workflows, refund/return flows, email notifications, reconciliation, webhook fan-out.
|
|
12
|
-
|
|
13
|
-
#### Workflow
|
|
14
|
-
|
|
15
|
-
**Step 1 — Detect order model**
|
|
16
|
-
Use Grep to find: `order`, `fulfillment`, `shipment`, `refund`, `return`, `order_status`, `OrderStatus`. Read schema to understand: order states, fulfillment model (self-ship, 3PL, dropship), and refund handling.
|
|
17
|
-
|
|
18
|
-
**Step 2 — Audit order lifecycle**
|
|
19
|
-
Check for:
|
|
20
|
-
- No explicit state machine: order status updated with raw string assignment (typos, invalid transitions)
|
|
21
|
-
- Missing reconciliation: payment succeeded but order creation failed (payment taken, no order)
|
|
22
|
-
- Partial fulfillment not handled: multi-item order with one item backordered
|
|
23
|
-
- Refund without inventory return: money refunded but stock not incremented back
|
|
24
|
-
- No email notifications on state transitions (customer has no visibility)
|
|
25
|
-
- Cancellation after partial fulfillment: must refund only unfulfilled items
|
|
26
|
-
|
|
27
|
-
**Step 3 — Emit order patterns**
|
|
28
|
-
Emit: typed state machine with valid transitions, reconciliation job, partial fulfillment handler, and refund flow with inventory return.
|
|
29
|
-
|
|
30
|
-
#### Example
|
|
31
|
-
|
|
32
|
-
```typescript
|
|
33
|
-
// Order state machine with valid transitions
|
|
34
|
-
type OrderStatus = 'pending' | 'confirmed' | 'processing' | 'partially_shipped' |
|
|
35
|
-
'shipped' | 'delivered' | 'cancelled' | 'refunded';
|
|
36
|
-
|
|
37
|
-
const VALID_TRANSITIONS: Record<OrderStatus, OrderStatus[]> = {
|
|
38
|
-
pending: ['confirmed', 'cancelled'],
|
|
39
|
-
confirmed: ['processing', 'cancelled'],
|
|
40
|
-
processing: ['partially_shipped', 'shipped', 'cancelled'],
|
|
41
|
-
partially_shipped: ['shipped', 'cancelled'],
|
|
42
|
-
shipped: ['delivered', 'refunded'],
|
|
43
|
-
delivered: ['refunded'],
|
|
44
|
-
cancelled: [],
|
|
45
|
-
refunded: [],
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
async function transitionOrder(orderId: string, newStatus: OrderStatus) {
|
|
49
|
-
const order = await prisma.order.findUniqueOrThrow({ where: { id: orderId } });
|
|
50
|
-
const currentStatus = order.status as OrderStatus;
|
|
51
|
-
|
|
52
|
-
if (!VALID_TRANSITIONS[currentStatus]?.includes(newStatus)) {
|
|
53
|
-
throw new Error(`Invalid transition: ${currentStatus} → ${newStatus}`);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const updated = await prisma.$transaction(async (tx) => {
|
|
57
|
-
const result = await tx.order.update({
|
|
58
|
-
where: { id: orderId },
|
|
59
|
-
data: {
|
|
60
|
-
status: newStatus,
|
|
61
|
-
statusHistory: { push: { from: currentStatus, to: newStatus, at: new Date() } },
|
|
62
|
-
},
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
// Side effects per transition
|
|
66
|
-
if (newStatus === 'cancelled') {
|
|
67
|
-
await releaseOrderReservations(tx, orderId);
|
|
68
|
-
}
|
|
69
|
-
if (newStatus === 'refunded') {
|
|
70
|
-
await processRefund(tx, orderId);
|
|
71
|
-
await returnInventory(tx, orderId);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return result;
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// Notifications (outside transaction — don't block on email)
|
|
78
|
-
await notificationService.orderStatusChanged(updated);
|
|
79
|
-
return updated;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// Reconciliation job — find payments without orders
|
|
83
|
-
async function reconcilePayments() {
|
|
84
|
-
const recentIntents = await stripe.paymentIntents.list({
|
|
85
|
-
created: { gte: Math.floor(Date.now() / 1000) - 3600 }, // last hour
|
|
86
|
-
limit: 100,
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
for (const intent of recentIntents.data) {
|
|
90
|
-
if (intent.status !== 'succeeded') continue;
|
|
91
|
-
const cartId = intent.metadata.cartId;
|
|
92
|
-
const order = await prisma.order.findFirst({ where: { paymentIntentId: intent.id } });
|
|
93
|
-
|
|
94
|
-
if (!order) {
|
|
95
|
-
// Payment succeeded but order not created — create it now
|
|
96
|
-
await orderService.createFromIntent(intent);
|
|
97
|
-
await alertService.trigger('RECONCILED_ORDER', { intentId: intent.id, cartId });
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Webhook fan-out for order status changes — notify 3PLs, ERPs, analytics
|
|
103
|
-
async function webhookFanOut(payload: Record<string, unknown>, topic: string) {
|
|
104
|
-
const endpoints = await db.webhookEndpoint.findMany({
|
|
105
|
-
where: { topics: { has: topic }, active: true },
|
|
106
|
-
});
|
|
107
|
-
await Promise.allSettled(
|
|
108
|
-
endpoints.map(ep =>
|
|
109
|
-
fetch(ep.url, {
|
|
110
|
-
method: 'POST',
|
|
111
|
-
headers: {
|
|
112
|
-
'Content-Type': 'application/json',
|
|
113
|
-
'X-Rune-Signature': signPayload(payload, ep.secret),
|
|
114
|
-
'X-Rune-Topic': topic,
|
|
115
|
-
'X-Rune-Timestamp': String(Date.now()),
|
|
116
|
-
},
|
|
117
|
-
body: JSON.stringify(payload),
|
|
118
|
-
signal: AbortSignal.timeout(5000),
|
|
119
|
-
}).catch(err => {
|
|
120
|
-
// Log failure but don't throw — one bad endpoint shouldn't block others
|
|
121
|
-
console.error(`Webhook delivery failed for ${ep.url}:`, err.message);
|
|
122
|
-
})
|
|
123
|
-
)
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
```
|
|
1
|
+
---
|
|
2
|
+
name: "order-management"
|
|
3
|
+
pack: "@rune/ecommerce"
|
|
4
|
+
description: "Order lifecycle — state machine, fulfillment workflows, refund/return flows, email notifications, reconciliation, webhook fan-out."
|
|
5
|
+
model: sonnet
|
|
6
|
+
tools: [Read, Edit, Write, Grep, Glob, Bash]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# order-management
|
|
10
|
+
|
|
11
|
+
Order lifecycle — state machine, fulfillment workflows, refund/return flows, email notifications, reconciliation, webhook fan-out.
|
|
12
|
+
|
|
13
|
+
#### Workflow
|
|
14
|
+
|
|
15
|
+
**Step 1 — Detect order model**
|
|
16
|
+
Use Grep to find: `order`, `fulfillment`, `shipment`, `refund`, `return`, `order_status`, `OrderStatus`. Read schema to understand: order states, fulfillment model (self-ship, 3PL, dropship), and refund handling.
|
|
17
|
+
|
|
18
|
+
**Step 2 — Audit order lifecycle**
|
|
19
|
+
Check for:
|
|
20
|
+
- No explicit state machine: order status updated with raw string assignment (typos, invalid transitions)
|
|
21
|
+
- Missing reconciliation: payment succeeded but order creation failed (payment taken, no order)
|
|
22
|
+
- Partial fulfillment not handled: multi-item order with one item backordered
|
|
23
|
+
- Refund without inventory return: money refunded but stock not incremented back
|
|
24
|
+
- No email notifications on state transitions (customer has no visibility)
|
|
25
|
+
- Cancellation after partial fulfillment: must refund only unfulfilled items
|
|
26
|
+
|
|
27
|
+
**Step 3 — Emit order patterns**
|
|
28
|
+
Emit: typed state machine with valid transitions, reconciliation job, partial fulfillment handler, and refund flow with inventory return.
|
|
29
|
+
|
|
30
|
+
#### Example
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
// Order state machine with valid transitions
|
|
34
|
+
type OrderStatus = 'pending' | 'confirmed' | 'processing' | 'partially_shipped' |
|
|
35
|
+
'shipped' | 'delivered' | 'cancelled' | 'refunded';
|
|
36
|
+
|
|
37
|
+
const VALID_TRANSITIONS: Record<OrderStatus, OrderStatus[]> = {
|
|
38
|
+
pending: ['confirmed', 'cancelled'],
|
|
39
|
+
confirmed: ['processing', 'cancelled'],
|
|
40
|
+
processing: ['partially_shipped', 'shipped', 'cancelled'],
|
|
41
|
+
partially_shipped: ['shipped', 'cancelled'],
|
|
42
|
+
shipped: ['delivered', 'refunded'],
|
|
43
|
+
delivered: ['refunded'],
|
|
44
|
+
cancelled: [],
|
|
45
|
+
refunded: [],
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
async function transitionOrder(orderId: string, newStatus: OrderStatus) {
|
|
49
|
+
const order = await prisma.order.findUniqueOrThrow({ where: { id: orderId } });
|
|
50
|
+
const currentStatus = order.status as OrderStatus;
|
|
51
|
+
|
|
52
|
+
if (!VALID_TRANSITIONS[currentStatus]?.includes(newStatus)) {
|
|
53
|
+
throw new Error(`Invalid transition: ${currentStatus} → ${newStatus}`);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const updated = await prisma.$transaction(async (tx) => {
|
|
57
|
+
const result = await tx.order.update({
|
|
58
|
+
where: { id: orderId },
|
|
59
|
+
data: {
|
|
60
|
+
status: newStatus,
|
|
61
|
+
statusHistory: { push: { from: currentStatus, to: newStatus, at: new Date() } },
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// Side effects per transition
|
|
66
|
+
if (newStatus === 'cancelled') {
|
|
67
|
+
await releaseOrderReservations(tx, orderId);
|
|
68
|
+
}
|
|
69
|
+
if (newStatus === 'refunded') {
|
|
70
|
+
await processRefund(tx, orderId);
|
|
71
|
+
await returnInventory(tx, orderId);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return result;
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Notifications (outside transaction — don't block on email)
|
|
78
|
+
await notificationService.orderStatusChanged(updated);
|
|
79
|
+
return updated;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Reconciliation job — find payments without orders
|
|
83
|
+
async function reconcilePayments() {
|
|
84
|
+
const recentIntents = await stripe.paymentIntents.list({
|
|
85
|
+
created: { gte: Math.floor(Date.now() / 1000) - 3600 }, // last hour
|
|
86
|
+
limit: 100,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
for (const intent of recentIntents.data) {
|
|
90
|
+
if (intent.status !== 'succeeded') continue;
|
|
91
|
+
const cartId = intent.metadata.cartId;
|
|
92
|
+
const order = await prisma.order.findFirst({ where: { paymentIntentId: intent.id } });
|
|
93
|
+
|
|
94
|
+
if (!order) {
|
|
95
|
+
// Payment succeeded but order not created — create it now
|
|
96
|
+
await orderService.createFromIntent(intent);
|
|
97
|
+
await alertService.trigger('RECONCILED_ORDER', { intentId: intent.id, cartId });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Webhook fan-out for order status changes — notify 3PLs, ERPs, analytics
|
|
103
|
+
async function webhookFanOut(payload: Record<string, unknown>, topic: string) {
|
|
104
|
+
const endpoints = await db.webhookEndpoint.findMany({
|
|
105
|
+
where: { topics: { has: topic }, active: true },
|
|
106
|
+
});
|
|
107
|
+
await Promise.allSettled(
|
|
108
|
+
endpoints.map(ep =>
|
|
109
|
+
fetch(ep.url, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: {
|
|
112
|
+
'Content-Type': 'application/json',
|
|
113
|
+
'X-Rune-Signature': signPayload(payload, ep.secret),
|
|
114
|
+
'X-Rune-Topic': topic,
|
|
115
|
+
'X-Rune-Timestamp': String(Date.now()),
|
|
116
|
+
},
|
|
117
|
+
body: JSON.stringify(payload),
|
|
118
|
+
signal: AbortSignal.timeout(5000),
|
|
119
|
+
}).catch(err => {
|
|
120
|
+
// Log failure but don't throw — one bad endpoint shouldn't block others
|
|
121
|
+
console.error(`Webhook delivery failed for ${ep.url}:`, err.message);
|
|
122
|
+
})
|
|
123
|
+
)
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
```
|