@wopr-network/platform-core 1.42.1 → 1.42.3
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/fleet/instance.d.ts +2 -0
- package/dist/fleet/instance.js +15 -0
- package/dist/monetization/stripe/webhook.js +14 -7
- package/dist/monetization/stripe/webhook.test.js +7 -2
- package/package.json +1 -1
- package/src/fleet/instance.ts +16 -0
- package/src/monetization/stripe/webhook.test.ts +7 -2
- package/src/monetization/stripe/webhook.ts +14 -7
package/dist/fleet/instance.d.ts
CHANGED
|
@@ -39,6 +39,8 @@ export declare class Instance {
|
|
|
39
39
|
/** Simple per-instance mutex to serialize start/stop/restart/remove. */
|
|
40
40
|
private lockPromise;
|
|
41
41
|
constructor(deps: InstanceDeps);
|
|
42
|
+
/** Serialize to a plain object safe for JSON.stringify / tRPC responses. */
|
|
43
|
+
toJSON(): Record<string, unknown>;
|
|
42
44
|
/**
|
|
43
45
|
* Remote instances have containerId like "remote:node-3".
|
|
44
46
|
* Local Docker operations are not supported — callers (e.g. wopr-platform)
|
package/dist/fleet/instance.js
CHANGED
|
@@ -25,6 +25,21 @@ export class Instance {
|
|
|
25
25
|
this.eventEmitter = deps.eventEmitter;
|
|
26
26
|
this.botMetricsTracker = deps.botMetricsTracker;
|
|
27
27
|
}
|
|
28
|
+
/** Serialize to a plain object safe for JSON.stringify / tRPC responses. */
|
|
29
|
+
toJSON() {
|
|
30
|
+
return {
|
|
31
|
+
id: this.id,
|
|
32
|
+
containerId: this.containerId,
|
|
33
|
+
containerName: this.containerName,
|
|
34
|
+
url: this.url,
|
|
35
|
+
name: this.profile.name,
|
|
36
|
+
image: this.profile.image,
|
|
37
|
+
tenantId: this.profile.tenantId,
|
|
38
|
+
env: this.profile.env,
|
|
39
|
+
restartPolicy: this.profile.restartPolicy,
|
|
40
|
+
nodeId: this.profile.nodeId,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
28
43
|
/**
|
|
29
44
|
* Remote instances have containerId like "remote:node-3".
|
|
30
45
|
* Local Docker operations are not supported — callers (e.g. wopr-platform)
|
|
@@ -61,16 +61,23 @@ export async function handleWebhookEvent(deps, event) {
|
|
|
61
61
|
case "checkout.session.completed": {
|
|
62
62
|
const session = event.data.object;
|
|
63
63
|
const tenant = session.client_reference_id ?? session.metadata?.wopr_tenant;
|
|
64
|
-
if (!tenant
|
|
64
|
+
if (!tenant) {
|
|
65
65
|
result = { handled: false, event_type: event.type };
|
|
66
66
|
break;
|
|
67
67
|
}
|
|
68
|
-
const customerId =
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
68
|
+
const customerId = session.customer
|
|
69
|
+
? typeof session.customer === "string"
|
|
70
|
+
? session.customer
|
|
71
|
+
: session.customer.id
|
|
72
|
+
: null;
|
|
73
|
+
// Upsert tenant-to-customer mapping only when a customer ID is present
|
|
74
|
+
// (guest checkouts have no Stripe customer).
|
|
75
|
+
if (customerId) {
|
|
76
|
+
await deps.tenantRepo.upsert({
|
|
77
|
+
tenant,
|
|
78
|
+
processorCustomerId: customerId,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
74
81
|
// Determine credit amount from price metadata or payment amount.
|
|
75
82
|
const amountPaid = session.amount_total; // in cents
|
|
76
83
|
if (amountPaid == null || amountPaid <= 0) {
|
|
@@ -126,12 +126,17 @@ describe("handleWebhookEvent (credit model)", () => {
|
|
|
126
126
|
event_type: "checkout.session.completed",
|
|
127
127
|
});
|
|
128
128
|
});
|
|
129
|
-
it("
|
|
129
|
+
it("handles guest checkout when customer is null (tenant known via client_reference_id)", async () => {
|
|
130
130
|
const event = createCheckoutEvent({
|
|
131
131
|
customer: null,
|
|
132
132
|
});
|
|
133
133
|
const result = await handleWebhookEvent(deps, event);
|
|
134
|
-
|
|
134
|
+
// Guest checkout: no Stripe customer, but tenant is known — should still credit.
|
|
135
|
+
expect(result.handled).toBe(true);
|
|
136
|
+
expect(result.tenant).toBeDefined();
|
|
137
|
+
// No customer mapping should be stored for a guest checkout.
|
|
138
|
+
const mapping = await tenantRepo.getByTenant(result.tenant ?? "");
|
|
139
|
+
expect(mapping).toBeNull();
|
|
135
140
|
});
|
|
136
141
|
it("returns creditedCents:0 when amount_total is 0", async () => {
|
|
137
142
|
const event = createCheckoutEvent({
|
package/package.json
CHANGED
package/src/fleet/instance.ts
CHANGED
|
@@ -59,6 +59,22 @@ export class Instance {
|
|
|
59
59
|
this.botMetricsTracker = deps.botMetricsTracker;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/** Serialize to a plain object safe for JSON.stringify / tRPC responses. */
|
|
63
|
+
toJSON(): Record<string, unknown> {
|
|
64
|
+
return {
|
|
65
|
+
id: this.id,
|
|
66
|
+
containerId: this.containerId,
|
|
67
|
+
containerName: this.containerName,
|
|
68
|
+
url: this.url,
|
|
69
|
+
name: this.profile.name,
|
|
70
|
+
image: this.profile.image,
|
|
71
|
+
tenantId: this.profile.tenantId,
|
|
72
|
+
env: this.profile.env,
|
|
73
|
+
restartPolicy: this.profile.restartPolicy,
|
|
74
|
+
nodeId: this.profile.nodeId,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
62
78
|
/**
|
|
63
79
|
* Remote instances have containerId like "remote:node-3".
|
|
64
80
|
* Local Docker operations are not supported — callers (e.g. wopr-platform)
|
|
@@ -171,13 +171,18 @@ describe("handleWebhookEvent (credit model)", () => {
|
|
|
171
171
|
});
|
|
172
172
|
});
|
|
173
173
|
|
|
174
|
-
it("
|
|
174
|
+
it("handles guest checkout when customer is null (tenant known via client_reference_id)", async () => {
|
|
175
175
|
const event = createCheckoutEvent({
|
|
176
176
|
customer: null,
|
|
177
177
|
});
|
|
178
178
|
const result = await handleWebhookEvent(deps, event);
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
// Guest checkout: no Stripe customer, but tenant is known — should still credit.
|
|
181
|
+
expect(result.handled).toBe(true);
|
|
182
|
+
expect(result.tenant).toBeDefined();
|
|
183
|
+
// No customer mapping should be stored for a guest checkout.
|
|
184
|
+
const mapping = await tenantRepo.getByTenant(result.tenant ?? "");
|
|
185
|
+
expect(mapping).toBeNull();
|
|
181
186
|
});
|
|
182
187
|
|
|
183
188
|
it("returns creditedCents:0 when amount_total is 0", async () => {
|
|
@@ -127,18 +127,25 @@ export async function handleWebhookEvent(deps: WebhookDeps, event: Stripe.Event)
|
|
|
127
127
|
const session = event.data.object as Stripe.Checkout.Session;
|
|
128
128
|
const tenant = session.client_reference_id ?? session.metadata?.wopr_tenant;
|
|
129
129
|
|
|
130
|
-
if (!tenant
|
|
130
|
+
if (!tenant) {
|
|
131
131
|
result = { handled: false, event_type: event.type };
|
|
132
132
|
break;
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
const customerId =
|
|
135
|
+
const customerId = session.customer
|
|
136
|
+
? typeof session.customer === "string"
|
|
137
|
+
? session.customer
|
|
138
|
+
: session.customer.id
|
|
139
|
+
: null;
|
|
136
140
|
|
|
137
|
-
// Upsert tenant-to-customer mapping
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
141
|
+
// Upsert tenant-to-customer mapping only when a customer ID is present
|
|
142
|
+
// (guest checkouts have no Stripe customer).
|
|
143
|
+
if (customerId) {
|
|
144
|
+
await deps.tenantRepo.upsert({
|
|
145
|
+
tenant,
|
|
146
|
+
processorCustomerId: customerId,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
142
149
|
|
|
143
150
|
// Determine credit amount from price metadata or payment amount.
|
|
144
151
|
const amountPaid = session.amount_total; // in cents
|