Skip to content

Commit 449cad9

Browse files
committed
feat(api): add event subject list endpoint
1 parent 50c8999 commit 449cad9

33 files changed

Lines changed: 2126 additions & 689 deletions

api/spec/packages/aip-client-javascript/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,11 @@ The full call path, HTTP route, and a short description are listed below.
113113

114114
### Events
115115

116-
| Method | HTTP | Description |
117-
| ---------------------- | ------------------------ | ---------------------------------------------------------------------------- |
118-
| `client.events.list` | `GET /openmeter/events` | List ingested events. |
119-
| `client.events.ingest` | `POST /openmeter/events` | Ingests an event or batch of events following the CloudEvents specification. |
116+
| Method | HTTP | Description |
117+
| ---------------------------- | -------------------------------- | ------------------------------------------------------------------------------------- |
118+
| `client.events.list` | `GET /openmeter/events` | List ingested events. |
119+
| `client.events.ingest` | `POST /openmeter/events` | Ingests an event or batch of events following the CloudEvents specification. |
120+
| `client.events.listSubjects` | `GET /openmeter/events/subjects` | List the subjects of the ingested events. Subjects are ordered by key alphabetically. |
120121

121122
### Meters
122123

api/spec/packages/aip-client-javascript/src/funcs/events.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type {
77
ListMeteringEventsResponse,
88
IngestMeteringEventsRequest,
99
IngestMeteringEventsResponse,
10+
ListEventSubjectsRequest,
11+
ListEventSubjectsResponse,
1012
} from '../models/operations/events.js'
1113

1214
export function listMeteringEvents(
@@ -35,3 +37,19 @@ export function ingestMeteringEvents(
3537
await http(client).post('openmeter/events', { ...options, json: req })
3638
})
3739
}
40+
41+
export function listEventSubjects(
42+
client: Client,
43+
req: ListEventSubjectsRequest = {},
44+
options?: RequestOptions,
45+
): Promise<Result<ListEventSubjectsResponse>> {
46+
const searchParams = toURLSearchParams({
47+
page: req.page,
48+
filter: req.filter,
49+
})
50+
return request(() =>
51+
http(client)
52+
.get('openmeter/events/subjects', { ...options, searchParams })
53+
.json<ListEventSubjectsResponse>(),
54+
)
55+
}

api/spec/packages/aip-client-javascript/src/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export type {
5555
IngestedEventValidationError,
5656
CursorMetaPage,
5757
BaseError,
58+
EventSubject,
5859
PageMeta,
5960
QueryFilterString,
6061
AppStripeCheckoutSessionCustomTextParams,
@@ -140,6 +141,7 @@ export type {
140141
Internal,
141142
NotImplemented,
142143
NotAvailable,
144+
ListSubjectsParamsFilter,
143145
CreateCreditGrantFilters,
144146
CreditGrantFilters,
145147
UpsertPlanAddonRequest,
@@ -212,6 +214,7 @@ export type {
212214
IngestedEvent,
213215
MeterQueryResult,
214216
FeatureCostQueryResult,
217+
SubjectPaginatedResponse,
215218
MeterPagePaginatedResponse,
216219
CostBasisPagePaginatedResponse,
217220
MeterQueryFilters,

api/spec/packages/aip-client-javascript/src/models/operations/events.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@ import type {
55
EventInput,
66
IngestedEventPaginatedResponse,
77
ListEventsParamsFilter,
8+
ListSubjectsParamsFilter,
89
SortQueryInput,
10+
SubjectPaginatedResponse,
911
} from '../types.js'
1012

1113
export interface ListMeteringEventsQuery {
@@ -21,3 +23,12 @@ export type ListMeteringEventsResponse = IngestedEventPaginatedResponse
2123

2224
export type IngestMeteringEventsRequest = EventInput | EventInput[]
2325
export type IngestMeteringEventsResponse = void
26+
27+
export interface ListEventSubjectsQuery {
28+
page?: CursorPaginationQueryPage
29+
/** Filter subjects returned in the response. To filter subjects by key add the following query param: filter[key][contains]=customer */
30+
filter?: ListSubjectsParamsFilter
31+
}
32+
33+
export type ListEventSubjectsRequest = ListEventSubjectsQuery
34+
export type ListEventSubjectsResponse = SubjectPaginatedResponse

api/spec/packages/aip-client-javascript/src/models/schemas.ts

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,23 @@ export const baseError = z
253253
)
254254
.describe('Standard error response.')
255255

256+
export const booleanFieldFilter = z
257+
.union([
258+
z.boolean(),
259+
z.object({
260+
eq: z
261+
.boolean()
262+
.describe('Value strictly equals the given boolean value.'),
263+
}),
264+
])
265+
.describe('Filter by a boolean value (true/false).')
266+
267+
export const eventSubject = z
268+
.object({
269+
key: z.string().min(1).describe('The key of the subject.'),
270+
})
271+
.describe('Subject of an event.')
272+
256273
export const resourceKey = z
257274
.string()
258275
.min(1)
@@ -1045,17 +1062,6 @@ export const publicLabels = z
10451062
'Public labels store information about an entity that can be used for filtering a list of objects.',
10461063
)
10471064

1048-
export const booleanFieldFilter = z
1049-
.union([
1050-
z.boolean(),
1051-
z.object({
1052-
eq: z
1053-
.boolean()
1054-
.describe('Value strictly equals the given boolean value.'),
1055-
}),
1056-
])
1057-
.describe('Filter by a boolean value (true/false).')
1058-
10591065
export const numericFieldFilter = z
10601066
.union([
10611067
z.number(),
@@ -1927,6 +1933,13 @@ export const notImplemented = baseError.describe('Not Implemented.')
19271933

19281934
export const notAvailable = baseError.describe('Not Available.')
19291935

1936+
export const listSubjectsParamsFilter = z
1937+
.object({
1938+
key: stringFieldFilter.optional(),
1939+
attributed: booleanFieldFilter.optional(),
1940+
})
1941+
.describe('Filter options for listing subjects.')
1942+
19301943
export const createCreditGrantFilters = z
19311944
.object({
19321945
features: z
@@ -3152,6 +3165,13 @@ export const featureCostQueryResult = z
31523165
})
31533166
.describe('Result of a feature cost query.')
31543167

3168+
export const subjectPaginatedResponse = z
3169+
.object({
3170+
data: z.array(eventSubject),
3171+
meta: cursorMeta,
3172+
})
3173+
.describe('Cursor paginated response.')
3174+
31553175
export const invalidParameter = z
31563176
.union([
31573177
invalidParameterStandard,
@@ -4624,6 +4644,16 @@ export const listMeteringEventsResponse = z.object({
46244644

46254645
export const ingestMeteringEventsBody = event
46264646

4647+
export const listEventSubjectsQueryParams = z.object({
4648+
page: cursorPaginationQueryPage.optional(),
4649+
filter: listSubjectsParamsFilter.optional(),
4650+
})
4651+
4652+
export const listEventSubjectsResponse = z.object({
4653+
data: z.array(eventSubject),
4654+
meta: cursorMeta,
4655+
})
4656+
46274657
export const createMeterBody = createMeterRequest
46284658

46294659
export const createMeterResponse = meter

api/spec/packages/aip-client-javascript/src/models/types.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@ export interface BaseError {
5858
[key: string]: unknown
5959
}
6060

61+
/** Subject of an event. */
62+
export interface EventSubject {
63+
/** The key of the subject. */
64+
key: string
65+
}
66+
6167
/** Pagination information. */
6268
export interface PageMeta {
6369
/** Page number. */
@@ -938,6 +944,27 @@ export interface NotImplemented extends BaseError {}
938944
/** Not Available. */
939945
export interface NotAvailable extends BaseError {}
940946

947+
/** Filter options for listing subjects. */
948+
export interface ListSubjectsParamsFilter {
949+
/** Filter subjects by key. */
950+
key?:
951+
| string
952+
| {
953+
eq?: string
954+
neq?: string
955+
contains?: string
956+
ocontains?: string[]
957+
oeq?: string[]
958+
gt?: string
959+
gte?: string
960+
lt?: string
961+
lte?: string
962+
exists?: boolean
963+
}
964+
/** Filter subjects by whether they are attributed to a customer. */
965+
attributed?: boolean | { eq: boolean }
966+
}
967+
941968
/** Filters for the credit grant. */
942969
export interface CreateCreditGrantFilters {
943970
/** Limit the credit grant to specific features. If no features are specified, the credit grant can be used for any feature. */
@@ -2089,6 +2116,12 @@ export interface FeatureCostQueryResult {
20892116
data: FeatureCostQueryRow[]
20902117
}
20912118

2119+
/** Cursor paginated response. */
2120+
export interface SubjectPaginatedResponse {
2121+
data: EventSubject[]
2122+
meta: CursorMeta
2123+
}
2124+
20922125
/** Page paginated response. */
20932126
export interface MeterPagePaginatedResponse {
20942127
data: Meter[]

api/spec/packages/aip-client-javascript/src/sdk/events.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
11
import { type Client } from '../core.js'
22
import { unwrap, type RequestOptions } from '../lib/types.js'
3-
import { listMeteringEvents, ingestMeteringEvents } from '../funcs/events.js'
3+
import {
4+
listMeteringEvents,
5+
ingestMeteringEvents,
6+
listEventSubjects,
7+
} from '../funcs/events.js'
48
import type {
59
ListMeteringEventsRequest,
610
ListMeteringEventsResponse,
711
IngestMeteringEventsRequest,
812
IngestMeteringEventsResponse,
13+
ListEventSubjectsRequest,
14+
ListEventSubjectsResponse,
915
} from '../models/operations/events.js'
1016

1117
export class Events {
@@ -24,4 +30,11 @@ export class Events {
2430
): Promise<IngestMeteringEventsResponse> {
2531
return unwrap(await ingestMeteringEvents(this._client, request, options))
2632
}
33+
34+
async listSubjects(
35+
request?: ListEventSubjectsRequest,
36+
options?: RequestOptions,
37+
): Promise<ListEventSubjectsResponse> {
38+
return unwrap(await listEventSubjects(this._client, request, options))
39+
}
2740
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import "./event.tsp";
2+
import "./subject.tsp";
23
import "./operations.tsp";

api/spec/packages/aip/src/events/operations.tsp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import "../common/pagination.tsp";
77
import "../common/parameters.tsp";
88
import "../shared/index.tsp";
99
import "./event.tsp";
10+
import "./subject.tsp";
1011

1112
using TypeSpec.Http;
1213
using TypeSpec.OpenAPI;
@@ -132,3 +133,43 @@ interface EventsOperations {
132133
@body body: MeteringEvent | MeteringEvent[],
133134
): IngestEventsResponse | Common.ErrorResponses;
134135
}
136+
137+
/**
138+
* Filter options for listing subjects.
139+
*/
140+
@friendlyName("ListSubjectsParamsFilter")
141+
model ListSubjectsParamsFilter {
142+
/**
143+
* Filter subjects by key.
144+
*/
145+
key?: Common.StringFieldFilter;
146+
147+
/**
148+
* Filter subjects by whether they are attributed to a customer.
149+
*/
150+
attributed?: Common.BooleanFieldFilter;
151+
}
152+
153+
interface EventsSubjectsOperations {
154+
/**
155+
* List the subjects of the ingested events. Subjects are ordered by key
156+
* alphabetically.
157+
*/
158+
@extension(Shared.UnstableExtension, true)
159+
@extension(Shared.InternalExtension, true)
160+
@get
161+
@operationId("list-event-subjects")
162+
@summary("List event subjects")
163+
list(
164+
...Common.CursorPaginationQuery,
165+
166+
/**
167+
* Filter subjects returned in the response.
168+
*
169+
* To filter subjects by key add the following query param:
170+
* filter[key][contains]=customer
171+
*/
172+
@query(#{ style: "deepObject", explode: true })
173+
filter?: ListSubjectsParamsFilter,
174+
): Shared.CursorPaginatedResponse<Subject> | Common.ErrorResponses;
175+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import "@typespec/openapi";
2+
import "@typespec/openapi3";
3+
import "../shared/index.tsp";
4+
import "../customers/index.tsp";
5+
6+
namespace Events;
7+
8+
/**
9+
* Subject of an event.
10+
*/
11+
@friendlyName("MeteringEventSubject")
12+
model Subject {
13+
/**
14+
* The key of the subject.
15+
*/
16+
@minLength(1)
17+
@visibility(Lifecycle.Read)
18+
@summary("Key")
19+
@example("customer-id")
20+
key: string;
21+
}

0 commit comments

Comments
 (0)