Skip to content

Commit

Permalink
Merge changes from stripe/stripe-node master
Browse files Browse the repository at this point in the history
  • Loading branch information
ramya-stripe committed Oct 11, 2024
2 parents dfd7189 + 0c896ed commit f1ecdb1
Show file tree
Hide file tree
Showing 11 changed files with 329 additions and 25 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## 17.2.0 - 2024-10-09
* [#2201](https://github.com/stripe/stripe-node/pull/2201) Add fetchRelatedObject to V2 Events if needed
* `fetchRelatedObject` is added to events retrieved using `stripe.v2.core.events` and can be used to easily fetch the Stripe object related to a retrieved event

## 17.2.0-beta.2 - 2024-10-08
* [#2180](https://github.com/stripe/stripe-node/pull/2180) Update generated code for beta
* Add support for `submit_card` test helper method on resource `Issuing.Card`
Expand Down
21 changes: 21 additions & 0 deletions examples/snippets/example_template.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* example_template.py - This is a template for defining new examples. It is not intended to be used directly.
* <describe what this example does>
* In this example, we:
* - <key step 1>
* - <key step 2
* - ...
* <describe assumptions about the user's stripe account, environment, or configuration;
* or things to watch out for when running>
*/

import {Stripe} from 'stripe';

const apiKey = '{{API_KEY}}';

console.log('Hello World');
// const client = new Stripe(apiKey);
// client.v2....
12 changes: 12 additions & 0 deletions examples/snippets/meter_event_stream.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
/**
* meter_event_stream.ts - Use the high-throughput meter event stream to report create billing meter events.
*
* In this example, we:
* - create a meter event session and store the session's authentication token
* - define an event with a payload
* - use the meterEventStream service to create an event stream that reports this event
*
* This example expects a billing meter with an event_name of 'alpaca_ai_tokens'. If you have
* a different meter event name, you can change it before running this example.
*/

import {Stripe} from 'stripe';

const apiKey = '{{API_KEY}}';
Expand Down
7 changes: 0 additions & 7 deletions examples/snippets/new_example.ts

This file was deleted.

2 changes: 1 addition & 1 deletion examples/snippets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"license": "ISC",
"dependencies": {
"express": "^4.21.0",
"stripe": "file:../../",
"stripe": "file:../..",
"ts-node": "^10.9.2",
"typescript": "^5.6.2"
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
/**
* thinevent_webhook_handler.js - receive and process thin events like the
* v1.billing.meter.error_report_triggered event.
* In this example, we:
* - create a Stripe client object called client
* - use client.parseThinEvent to parse the received thin event webhook body
* - call client.v2.core.events.retrieve to retrieve the full event object
* - if it is a v1.billing.meter.error_report_triggered event type, call
* event.fetchRelatedObject to retrieve the Billing Meter object associated
* with the event.
*/

const express = require('express');
const {Stripe} = require('stripe');

Expand All @@ -20,11 +32,10 @@ app.post(
// Fetch the event data to understand the failure
const event = await client.v2.core.events.retrieve(thinEvent.id);
if (event.type == 'v1.billing.meter.error_report_triggered') {
const meter = await client.billing.meters.retrieve(
event.related_object.id
);
const meter = await event.fetchRelatedObject();
const meterId = meter.id;
console.log(`Success! ${meterId}`);

// Record the failures and alert your team
// Add your logic here
}
Expand Down
8 changes: 4 additions & 4 deletions examples/snippets/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,9 @@
integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==

"@types/node@>=8.1.0":
version "22.6.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.6.1.tgz#e531a45f4d78f14a8468cb9cdc29dc9602afc7ac"
integrity sha512-V48tCfcKb/e6cVUigLAaJDAILdMP0fUW6BidkPK4GpGjXcfbnoHasCZDwz3N3yVt5we2RHm4XTQCpv0KJz9zqw==
version "22.7.5"
resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b"
integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==
dependencies:
undici-types "~6.19.2"

Expand Down Expand Up @@ -524,7 +524,7 @@ statuses@2.0.1:
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==

"stripe@file:../..":
version "16.12.0"
version "17.0.0"
dependencies:
"@types/node" ">=8.1.0"
qs "^6.11.0"
Expand Down
68 changes: 60 additions & 8 deletions src/resources/V2/Core/Events.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,64 @@
// File generated from our OpenAPI spec

// This file is manually maintained
import {StripeResource} from '../../../StripeResource.js';

const stripeMethod = StripeResource.method;

export const Events = StripeResource.extend({
retrieve: stripeMethod({method: 'GET', fullPath: '/v2/core/events/{id}'}),
list: stripeMethod({
method: 'GET',
fullPath: '/v2/core/events',
methodType: 'list',
}),
retrieve(...args: any[]) {
const transformResponseData = (response: any): any => {
return this.addFetchRelatedObjectIfNeeded(response);
};
return stripeMethod({
method: 'GET',
fullPath: '/v2/core/events/{id}',
transformResponseData,
}).apply(this, args);
},

list(...args: any[]) {
const transformResponseData = (response: any): any => {
return {
...response,
data: response.data.map(this.addFetchRelatedObjectIfNeeded.bind(this)),
};
};
return stripeMethod({
method: 'GET',
fullPath: '/v2/core/events',
methodType: 'list',
transformResponseData,
}).apply(this, args);
},

/**
* @private
*
* For internal use in stripe-node.
*
* @param pulledEvent The retrieved event object
* @returns The retrieved event object with a fetchRelatedObject method,
* if pulledEvent.related_object is valid (non-null and has a url)
*/
addFetchRelatedObjectIfNeeded(pulledEvent: any) {
if (!pulledEvent.related_object || !pulledEvent.related_object.url) {
return pulledEvent;
}
return {
...pulledEvent,
fetchRelatedObject: (): Promise<null | any> =>
// call stripeMethod with 'this' resource to fetch
// the related object. 'this' is needed to construct
// and send the request, but the method spec controls
// the url endpoint and method, so it doesn't matter
// that 'this' is an Events resource object here
stripeMethod({
method: 'GET',
fullPath: pulledEvent.related_object.url,
}).apply(this, [
{
stripeAccount: pulledEvent.context,
},
]),
};
},
});
209 changes: 209 additions & 0 deletions test/resources/V2/Core/Events.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
'use strict';

const testUtils = require('../../../testUtils.js');
const expect = require('chai').expect;

const stripe = testUtils.getSpyableStripe();

const v2EventPayloadWithoutRelatedObject = `
{
"context": "context",
"created": "1970-01-12T21:42:34.472Z",
"id": "obj_123",
"livemode": true,
"object":"v2.core.event",
"reason":
{
"type": "request",
"request":
{
"id": "obj_123",
"idempotency_key": "idempotency_key"
}
},
"type": "type"
}
`;

const v2EventPayloadWithRelatedObject = `
{
"context": "context",
"created": "1970-01-12T21:42:34.472Z",
"id": "obj_123",
"livemode": true,
"object":"v2.core.event",
"reason":
{
"type": "request",
"request":
{
"id": "obj_123",
"idempotency_key": "idempotency_key"
}
},
"type": "type",
"related_object":
{
"id": "obj_123",
"type": "thing",
"url": "/v1/things/obj_123"
}
}
`;

describe('V2 Core Events Resource', () => {
describe('retrieve', () => {
it('Sends the correct request', () => {
stripe.v2.core.events.retrieve('eventIdBaz');
expect(stripe.LAST_REQUEST).to.deep.equal({
method: 'GET',
url: '/v2/core/events/eventIdBaz',
headers: {},
data: null,
settings: {},
});
});

it('Does not have fetchRelatedObject if not needed', async () => {
const mockStripe = testUtils.createMockClient([
{
method: 'GET',
path: '/v2/core/events/ll_123',
response: v2EventPayloadWithoutRelatedObject,
},
]);
const event = await mockStripe.v2.core.events.retrieve('ll_123');
expect(event).ok;
expect(event.fetchRelatedObject).to.be.undefined;
});

it('Has fetchRelatedObject if needed', async () => {
const mockStripe = testUtils.createMockClient([
{
method: 'GET',
path: '/v2/core/events/ll_123',
response: v2EventPayloadWithRelatedObject,
},
]);
const event = await mockStripe.v2.core.events.retrieve('ll_123');
expect(event).ok;
expect(event.fetchRelatedObject).ok;
});

it('Can call fetchRelatedObject', async () => {
const mockStripe = testUtils.createMockClient([
{
method: 'GET',
path: '/v2/core/events/ll_123',
response: v2EventPayloadWithRelatedObject,
},
{
method: 'GET',
path: '/v1/things/obj_123',
response: '{"id": "obj_123"}',
},
]);
const event = await mockStripe.v2.core.events.retrieve('ll_123');
expect(event).ok;
expect(event.fetchRelatedObject).ok;
const obj = await event.fetchRelatedObject();
expect(obj.id).to.equal('obj_123');
});
});

describe('list', () => {
it('Sends the correct request', () => {
stripe.v2.core.events.list({object_id: 'foo'});
expect(stripe.LAST_REQUEST).to.deep.equal({
method: 'GET',
url: '/v2/core/events?object_id=foo',
headers: {},
data: null,
settings: {},
});
});

it('Does not have fetchRelatedObject if not needed', async () => {
const mockStripe = testUtils.createMockClient([
{
method: 'GET',
path: '/v2/core/events?object_id=foo',
response: `{
"data": [
${v2EventPayloadWithoutRelatedObject},
${v2EventPayloadWithoutRelatedObject},
${v2EventPayloadWithoutRelatedObject}
],
"next_page_url": null
}`,
},
]);
const resp = await mockStripe.v2.core.events.list({object_id: 'foo'});
expect(resp).ok;
expect(resp.data.length).is.equal(3);
for (const event of resp.data) {
expect(event.fetchRelatedObject).not.ok;
}
});

it('Has fetchRelatedObject if needed', async () => {
const mockStripe = testUtils.createMockClient([
{
method: 'GET',
path: '/v2/core/events?object_id=foo',
response: `{
"data": [
${v2EventPayloadWithRelatedObject},
${v2EventPayloadWithRelatedObject},
${v2EventPayloadWithRelatedObject}
],
"next_page_url": null
}`,
},
]);
const resp = await mockStripe.v2.core.events.list({object_id: 'foo'});
expect(resp).ok;
expect(resp.data.length).is.equal(3);
for (const event of resp.data) {
expect(event.fetchRelatedObject).ok;
}
});

it('Has fetchRelatedObject added to autoPaginate results', async () => {
const mockStripe = testUtils.createMockClient([
{
method: 'GET',
path: '/v2/core/events?object_id=foo',
response: `{
"data": [
${v2EventPayloadWithRelatedObject},
${v2EventPayloadWithRelatedObject},
${v2EventPayloadWithRelatedObject}
],
"next_page_url": "/next_page"
}`,
},
{
method: 'GET',
path: '/next_page',
response: `{
"data": [
${v2EventPayloadWithRelatedObject},
${v2EventPayloadWithRelatedObject},
${v2EventPayloadWithRelatedObject}
],
"next_page_url": null
}`,
},
]);
const respProm = mockStripe.v2.core.events.list({object_id: 'foo'});
expect(respProm).ok;
let totalEvents = 0;
await respProm.autoPagingEach(function(event) {
totalEvents += 1;
expect(event.fetchRelatedObject).ok;
});
expect(totalEvents).is.equal(6);
});
});
});
Loading

0 comments on commit f1ecdb1

Please sign in to comment.