@ingram-tech/luma 0.1.0 → 0.3.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/README.md +43 -27
- package/dist/index.d.ts +7700 -117
- package/dist/index.js +133 -86
- package/dist/index.js.map +1 -1
- package/package.json +7 -5
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ var LumaApiError = class extends Error {
|
|
|
40
40
|
// src/client.ts
|
|
41
41
|
var serializeQueryValue = (value) => value instanceof Date ? value.toISOString() : String(value);
|
|
42
42
|
var toIso = (value) => value instanceof Date ? value.toISOString() : value;
|
|
43
|
+
var toIsoNullable = (value) => value == null ? value : toIso(value);
|
|
43
44
|
var collect = async (source) => {
|
|
44
45
|
const out = [];
|
|
45
46
|
for await (const item of source) {
|
|
@@ -78,7 +79,7 @@ var LumaClient = class _LumaClient {
|
|
|
78
79
|
}
|
|
79
80
|
/**
|
|
80
81
|
* Low-level request against any Luma endpoint. `path` is taken relative to
|
|
81
|
-
* the base URL, e.g. `/v1/
|
|
82
|
+
* the base URL, e.g. `/v1/events/get`.
|
|
82
83
|
*/
|
|
83
84
|
async request(path, init = {}) {
|
|
84
85
|
const url = new URL(path.startsWith("/") ? path : `/${path}`, this.baseUrl);
|
|
@@ -162,33 +163,33 @@ var LumaClient = class _LumaClient {
|
|
|
162
163
|
}
|
|
163
164
|
}
|
|
164
165
|
// ─── calendar ────────────────────────────────────────────────────────
|
|
166
|
+
//
|
|
167
|
+
// The calendar is inferred from the API key, so these take no calendar id.
|
|
165
168
|
calendar = {
|
|
166
|
-
/** Iterate every event
|
|
167
|
-
listEvents: (options) => this.paginate("/v1/
|
|
168
|
-
calendar_api_id: options.calendarApiId,
|
|
169
|
+
/** Iterate every event the calendar manages. */
|
|
170
|
+
listEvents: (options = {}) => this.paginate("/v1/calendars/events/list", {
|
|
169
171
|
after: options.after,
|
|
170
172
|
before: options.before,
|
|
173
|
+
status: options.status,
|
|
174
|
+
access: options.access,
|
|
175
|
+
platforms: options.platforms,
|
|
176
|
+
sort_direction: options.sortDirection,
|
|
171
177
|
pagination_limit: options.paginationLimit,
|
|
172
178
|
pagination_cursor: options.paginationCursor
|
|
173
179
|
}),
|
|
174
|
-
/** Collect every event
|
|
175
|
-
listAllEvents: (options) => collect(this.calendar.listEvents(options)),
|
|
176
|
-
/** Iterate every
|
|
177
|
-
|
|
178
|
-
|
|
180
|
+
/** Collect every event the calendar manages into an array. */
|
|
181
|
+
listAllEvents: (options = {}) => collect(this.calendar.listEvents(options)),
|
|
182
|
+
/** Iterate every contact on the calendar. */
|
|
183
|
+
listContacts: (options = {}) => this.paginate("/v1/calendars/contacts/list", {
|
|
184
|
+
query: options.query,
|
|
185
|
+
sort_direction: options.sortDirection,
|
|
179
186
|
pagination_limit: options.paginationLimit,
|
|
180
187
|
pagination_cursor: options.paginationCursor
|
|
181
188
|
}),
|
|
182
|
-
/** Collect every
|
|
183
|
-
|
|
189
|
+
/** Collect every contact on the calendar into an array. */
|
|
190
|
+
listAllContacts: (options = {}) => collect(this.calendar.listContacts(options)),
|
|
184
191
|
/** Iterate every coupon on the calendar tied to the API key. */
|
|
185
|
-
listCoupons:
|
|
186
|
-
for await (const entry of this.paginate(
|
|
187
|
-
"/v1/calendar/coupons"
|
|
188
|
-
)) {
|
|
189
|
-
yield normalizeCoupon(entry);
|
|
190
|
-
}
|
|
191
|
-
}.bind(this),
|
|
192
|
+
listCoupons: () => this.paginate("/v1/calendars/coupons/list"),
|
|
192
193
|
/** Find a calendar coupon by its code, or `null` if none matches. */
|
|
193
194
|
findCouponByCode: async (code) => {
|
|
194
195
|
const target = code.toLowerCase();
|
|
@@ -199,93 +200,139 @@ var LumaClient = class _LumaClient {
|
|
|
199
200
|
}
|
|
200
201
|
return null;
|
|
201
202
|
},
|
|
202
|
-
/** Create a calendar coupon. */
|
|
203
|
-
createCoupon:
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
code: input.code,
|
|
218
|
-
remaining_count: input.remainingCount,
|
|
219
|
-
valid_start_at: input.validStartAt ? toIso(input.validStartAt) : void 0,
|
|
220
|
-
valid_end_at: input.validEndAt ? toIso(input.validEndAt) : void 0,
|
|
221
|
-
discount
|
|
222
|
-
}
|
|
203
|
+
/** Create a calendar coupon (applies to any event the calendar manages). */
|
|
204
|
+
createCoupon: (input) => this.request("/v1/calendars/coupons/create", {
|
|
205
|
+
method: "POST",
|
|
206
|
+
body: {
|
|
207
|
+
code: input.code,
|
|
208
|
+
remaining_count: input.remainingCount,
|
|
209
|
+
valid_start_at: toIsoNullable(input.validStartAt),
|
|
210
|
+
valid_end_at: toIsoNullable(input.validEndAt),
|
|
211
|
+
discount: input.discount.type === "percent" ? {
|
|
212
|
+
discount_type: "percent",
|
|
213
|
+
percent_off: input.discount.percentOff
|
|
214
|
+
} : {
|
|
215
|
+
discount_type: "amount",
|
|
216
|
+
cents_off: input.discount.centsOff,
|
|
217
|
+
currency: input.discount.currency.toLowerCase()
|
|
223
218
|
}
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
}
|
|
219
|
+
}
|
|
220
|
+
})
|
|
227
221
|
};
|
|
228
222
|
// ─── events ──────────────────────────────────────────────────────────
|
|
229
223
|
events = {
|
|
230
|
-
/** Fetch a single event by its `
|
|
231
|
-
get:
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
{ query: { api_id: eventApiId } }
|
|
235
|
-
);
|
|
236
|
-
return response.event ?? response;
|
|
237
|
-
},
|
|
224
|
+
/** Fetch a single event by its id (`evt-…`). */
|
|
225
|
+
get: (eventId) => this.request("/v1/events/get", {
|
|
226
|
+
query: { event_id: eventId }
|
|
227
|
+
}),
|
|
238
228
|
/** Iterate every guest of an event. */
|
|
239
|
-
listGuests: (options) =>
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
pagination_cursor: options.paginationCursor
|
|
247
|
-
}
|
|
248
|
-
)) {
|
|
249
|
-
const guest = entry.guest ?? entry;
|
|
250
|
-
yield guest;
|
|
251
|
-
}
|
|
252
|
-
}.call(this),
|
|
229
|
+
listGuests: (options) => this.paginate("/v1/events/guests/list", {
|
|
230
|
+
event_id: options.eventId,
|
|
231
|
+
approval_status: options.approvalStatus,
|
|
232
|
+
sort_direction: options.sortDirection,
|
|
233
|
+
pagination_limit: options.paginationLimit,
|
|
234
|
+
pagination_cursor: options.paginationCursor
|
|
235
|
+
}),
|
|
253
236
|
/** Collect every guest of an event into an array. */
|
|
254
237
|
listAllGuests: (options) => collect(this.events.listGuests(options)),
|
|
255
|
-
/** Fetch a single guest
|
|
256
|
-
getGuest:
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
238
|
+
/** Fetch a single guest (with order detail) by its guest id. */
|
|
239
|
+
getGuest: (options) => this.request("/v1/events/guests/get", {
|
|
240
|
+
query: { event_id: options.eventId, id: options.guestId }
|
|
241
|
+
}),
|
|
242
|
+
/** Update a guest's approval status (approve, decline, waitlist…). */
|
|
243
|
+
updateGuestStatus: async (options) => {
|
|
244
|
+
await this.request("/v1/events/guests/update-status", {
|
|
245
|
+
method: "POST",
|
|
246
|
+
body: {
|
|
247
|
+
event_id: options.eventId,
|
|
248
|
+
guest_id: options.guestId,
|
|
249
|
+
status: options.status,
|
|
250
|
+
should_refund: options.shouldRefund,
|
|
251
|
+
send_email: options.sendEmail,
|
|
252
|
+
message: options.message
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
},
|
|
256
|
+
/**
|
|
257
|
+
* Add guests to an event (host-side). Registers people directly — this
|
|
258
|
+
* does NOT take payment; Luma owns checkout/payment on its hosted flow.
|
|
259
|
+
* By default guests are added as approved ("Going") and emailed. Pass a
|
|
260
|
+
* `ticketTypeId` to assign each guest a ticket of that type.
|
|
261
|
+
*/
|
|
262
|
+
addGuests: async (options) => {
|
|
263
|
+
await this.request("/v1/events/guests/add", {
|
|
264
|
+
method: "POST",
|
|
265
|
+
body: {
|
|
266
|
+
event_id: options.eventId,
|
|
267
|
+
guests: options.guests.map((guest) => ({
|
|
268
|
+
email: guest.email,
|
|
269
|
+
name: guest.name,
|
|
270
|
+
registration_answers: guest.registrationAnswers
|
|
271
|
+
})),
|
|
272
|
+
ticket: options.ticketTypeId ? { event_ticket_type_id: options.ticketTypeId } : void 0,
|
|
273
|
+
approval_status: options.approvalStatus,
|
|
274
|
+
send_email: options.sendEmail
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
},
|
|
278
|
+
/**
|
|
279
|
+
* List an event's ticket types (tiers), including prices. Pass
|
|
280
|
+
* `includeHidden` to include ticket types not shown on the public page.
|
|
281
|
+
*/
|
|
282
|
+
listTicketTypes: async (options) => {
|
|
260
283
|
const response = await this.request(
|
|
261
|
-
"/v1/
|
|
284
|
+
"/v1/events/ticket-types/list",
|
|
262
285
|
{
|
|
263
286
|
query: {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
email: options.email
|
|
287
|
+
event_id: options.eventId,
|
|
288
|
+
include_hidden: options.includeHidden
|
|
267
289
|
}
|
|
268
290
|
}
|
|
269
291
|
);
|
|
270
|
-
return response.
|
|
292
|
+
return response.entries ?? [];
|
|
271
293
|
},
|
|
272
|
-
/**
|
|
273
|
-
|
|
274
|
-
|
|
294
|
+
/** Fetch a single ticket type by its id. */
|
|
295
|
+
getTicketType: (ticketTypeId) => this.request("/v1/events/ticket-types/get", {
|
|
296
|
+
query: { event_ticket_type_id: ticketTypeId }
|
|
297
|
+
}),
|
|
298
|
+
/** Create a ticket type on an event. */
|
|
299
|
+
createTicketType: (input) => this.request("/v1/events/ticket-types/create", {
|
|
300
|
+
method: "POST",
|
|
301
|
+
body: ticketTypeBody(
|
|
302
|
+
{ event_id: input.eventId, type: input.type },
|
|
303
|
+
input
|
|
304
|
+
)
|
|
305
|
+
}),
|
|
306
|
+
/** Update an existing ticket type. */
|
|
307
|
+
updateTicketType: (input) => this.request("/v1/events/ticket-types/update", {
|
|
308
|
+
method: "POST",
|
|
309
|
+
body: ticketTypeBody(
|
|
310
|
+
{ event_ticket_type_id: input.ticketTypeId, type: input.type },
|
|
311
|
+
input
|
|
312
|
+
)
|
|
313
|
+
}),
|
|
314
|
+
/** Delete a ticket type by its id. */
|
|
315
|
+
deleteTicketType: async (ticketTypeId) => {
|
|
316
|
+
await this.request("/v1/events/ticket-types/delete", {
|
|
275
317
|
method: "POST",
|
|
276
|
-
body: {
|
|
277
|
-
event_api_id: options.eventApiId,
|
|
278
|
-
guest_api_id: options.guestApiId,
|
|
279
|
-
status: options.status
|
|
280
|
-
}
|
|
318
|
+
body: { event_ticket_type_id: ticketTypeId }
|
|
281
319
|
});
|
|
282
320
|
}
|
|
283
321
|
};
|
|
284
322
|
};
|
|
285
|
-
var
|
|
286
|
-
...
|
|
287
|
-
|
|
288
|
-
|
|
323
|
+
var ticketTypeBody = (base, fields) => ({
|
|
324
|
+
...base,
|
|
325
|
+
name: fields.name,
|
|
326
|
+
cents: fields.cents,
|
|
327
|
+
currency: fields.currency == null ? fields.currency : fields.currency.toLowerCase(),
|
|
328
|
+
require_approval: fields.requireApproval,
|
|
329
|
+
is_hidden: fields.isHidden,
|
|
330
|
+
description: fields.description,
|
|
331
|
+
is_flexible: fields.isFlexible,
|
|
332
|
+
min_cents: fields.minCents,
|
|
333
|
+
max_capacity: fields.maxCapacity,
|
|
334
|
+
valid_start_at: toIsoNullable(fields.validStartAt),
|
|
335
|
+
valid_end_at: toIsoNullable(fields.validEndAt)
|
|
289
336
|
});
|
|
290
337
|
export {
|
|
291
338
|
LUMA_API_BASE_URL,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["/** Base URL for the Luma public API. */\nexport const LUMA_API_BASE_URL = \"https://public-api.luma.com\";\n\n/** Header Luma expects the API key in. */\nexport const LUMA_API_KEY_HEADER = \"x-luma-api-key\";\n\n/** API version path segment prepended to every endpoint. */\nexport const LUMA_API_VERSION = \"v1\";\n","/**\n * Thrown when the Luma API responds with a non-2xx status, or when a response\n * body cannot be parsed as JSON.\n */\nexport class LumaApiError extends Error {\n\t/** HTTP status code returned by Luma (0 if the request never completed). */\n\treadonly status: number;\n\t/** Raw, untruncated response body. */\n\treadonly body: string;\n\t/** API path that produced the error, e.g. `/v1/event/get-guests`. */\n\treadonly path: string;\n\n\tconstructor(params: {\n\t\tmessage: string;\n\t\tstatus: number;\n\t\tbody: string;\n\t\tpath: string;\n\t}) {\n\t\tsuper(params.message);\n\t\tthis.name = \"LumaApiError\";\n\t\tthis.status = params.status;\n\t\tthis.body = params.body;\n\t\tthis.path = params.path;\n\t}\n\n\t/** True for 401/403 — the API key is missing, invalid, or lacks scope. */\n\tget isAuthError(): boolean {\n\t\treturn this.status === 401 || this.status === 403;\n\t}\n\n\t/** True for 429 — the caller is being rate limited. */\n\tget isRateLimited(): boolean {\n\t\treturn this.status === 429;\n\t}\n\n\t/**\n\t * True when Luma rejected a coupon create because the code already exists.\n\t * Luma surfaces this as a 400/409 whose body mentions the code already\n\t * existing; matched permissively so callers can treat it as idempotent.\n\t */\n\tget isDuplicateCouponCode(): boolean {\n\t\tconst lower = this.body.toLowerCase();\n\t\treturn (\n\t\t\t(this.status === 400 || this.status === 409) &&\n\t\t\tlower.includes(\"code\") &&\n\t\t\t(lower.includes(\"exist\") || lower.includes(\"already\"))\n\t\t);\n\t}\n}\n","import { LUMA_API_BASE_URL, LUMA_API_KEY_HEADER } from \"./constants\";\nimport { LumaApiError } from \"./errors\";\nimport type {\n\tCreateCalendarCouponInput,\n\tGetEventGuestOptions,\n\tListCalendarEventsOptions,\n\tListCalendarPeopleOptions,\n\tListEventGuestsOptions,\n\tLumaCalendarEntry,\n\tLumaCoupon,\n\tLumaCouponEntry,\n\tLumaEvent,\n\tLumaGuest,\n\tLumaGuestEntry,\n\tLumaPaginatedResponse,\n\tLumaPerson,\n\tUpdateGuestStatusOptions,\n} from \"./types\";\n\nexport interface LumaClientOptions {\n\t/** Luma API key. Found under Calendar Settings → API on a Luma Plus plan. */\n\tapiKey: string;\n\t/** Override the API base URL. Defaults to {@link LUMA_API_BASE_URL}. */\n\tbaseUrl?: string;\n\t/**\n\t * Fetch implementation to use. Defaults to the global `fetch`. Pass a\n\t * custom one to inject Next.js cache hints, retries, or a test double.\n\t */\n\tfetch?: typeof fetch;\n}\n\n/** Per-request options for {@link LumaClient.request}. */\nexport interface LumaRequestInit {\n\tmethod?: string;\n\t/** Query parameters. `undefined`/`null` values are dropped; `Date`s are\n\t * serialised as ISO strings. */\n\tquery?: Record<string, unknown>;\n\t/** JSON request body. Sets `content-type: application/json`. */\n\tbody?: unknown;\n\tsignal?: AbortSignal;\n\t/** Extra `fetch` init merged last — e.g. Next.js `{ next: { revalidate } }`. */\n\tfetchInit?: RequestInit;\n}\n\nconst serializeQueryValue = (value: unknown): string =>\n\tvalue instanceof Date ? value.toISOString() : String(value);\n\nconst toIso = (value: Date | string): string =>\n\tvalue instanceof Date ? value.toISOString() : value;\n\n/** Drain an async generator into an array. */\nexport const collect = async <T>(source: AsyncIterable<T>): Promise<T[]> => {\n\tconst out: T[] = [];\n\tfor await (const item of source) {\n\t\tout.push(item);\n\t}\n\treturn out;\n};\n\n/**\n * Typed client for the Luma (lu.ma) public API.\n *\n * The typed resource methods cover the endpoints this client is built around;\n * for anything not modelled here, {@link LumaClient.request} and\n * {@link LumaClient.paginate} are public escape hatches that work against any\n * endpoint.\n */\nexport class LumaClient {\n\treadonly baseUrl: string;\n\tprivate readonly apiKey: string;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(options: LumaClientOptions) {\n\t\tif (!options.apiKey) {\n\t\t\tthrow new Error(\"LumaClient requires an `apiKey`\");\n\t\t}\n\t\tthis.apiKey = options.apiKey;\n\t\tthis.baseUrl = options.baseUrl ?? LUMA_API_BASE_URL;\n\t\tconst fetchImpl = options.fetch ?? globalThis.fetch;\n\t\tif (typeof fetchImpl !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"No global `fetch` available; pass one via LumaClientOptions.fetch\",\n\t\t\t);\n\t\t}\n\t\tthis.fetchImpl = fetchImpl;\n\t}\n\n\t/**\n\t * Construct a client from environment variables. Reads `LUMA_API_KEY` and,\n\t * optionally, `LUMA_API_BASE_URL`.\n\t */\n\tstatic fromEnv(\n\t\tenv: Record<string, string | undefined> = typeof process !== \"undefined\"\n\t\t\t? process.env\n\t\t\t: {},\n\t): LumaClient {\n\t\tconst apiKey = env.LUMA_API_KEY;\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(\"LUMA_API_KEY is not set\");\n\t\t}\n\t\treturn new LumaClient({ apiKey, baseUrl: env.LUMA_API_BASE_URL });\n\t}\n\n\t/**\n\t * Low-level request against any Luma endpoint. `path` is taken relative to\n\t * the base URL, e.g. `/v1/event/get`.\n\t */\n\tasync request<T>(path: string, init: LumaRequestInit = {}): Promise<T> {\n\t\tconst url = new URL(path.startsWith(\"/\") ? path : `/${path}`, this.baseUrl);\n\t\tif (init.query) {\n\t\t\tfor (const [key, value] of Object.entries(init.query)) {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.set(key, serializeQueryValue(value));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t[LUMA_API_KEY_HEADER]: this.apiKey,\n\t\t\taccept: \"application/json\",\n\t\t};\n\t\tlet body: string | undefined;\n\t\tif (init.body !== undefined) {\n\t\t\theaders[\"content-type\"] = \"application/json\";\n\t\t\tbody = JSON.stringify(init.body);\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await this.fetchImpl(url, {\n\t\t\t\tmethod: init.method ?? \"GET\",\n\t\t\t\theaders,\n\t\t\t\tbody,\n\t\t\t\tsignal: init.signal,\n\t\t\t\t...init.fetchInit,\n\t\t\t});\n\t\t} catch (cause) {\n\t\t\tthrow new LumaApiError({\n\t\t\t\tmessage: `Luma API request to ${path} failed: ${\n\t\t\t\t\tcause instanceof Error ? cause.message : String(cause)\n\t\t\t\t}`,\n\t\t\t\tstatus: 0,\n\t\t\t\tbody: \"\",\n\t\t\t\tpath,\n\t\t\t});\n\t\t}\n\n\t\tconst text = await response.text();\n\t\tif (!response.ok) {\n\t\t\tthrow new LumaApiError({\n\t\t\t\tmessage: `Luma API responded ${response.status} for ${path}`,\n\t\t\t\tstatus: response.status,\n\t\t\t\tbody: text,\n\t\t\t\tpath,\n\t\t\t});\n\t\t}\n\t\tif (text.length === 0) {\n\t\t\treturn undefined as T;\n\t\t}\n\t\ttry {\n\t\t\treturn JSON.parse(text) as T;\n\t\t} catch {\n\t\t\tthrow new LumaApiError({\n\t\t\t\tmessage: `Luma API returned a non-JSON body for ${path}`,\n\t\t\t\tstatus: response.status,\n\t\t\t\tbody: text,\n\t\t\t\tpath,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Iterate a cursor-paginated endpoint, yielding each entry. Follows\n\t * `next_cursor` while `has_more` is true.\n\t */\n\tasync *paginate<T>(\n\t\tpath: string,\n\t\tquery: Record<string, unknown> = {},\n\t): AsyncGenerator<T> {\n\t\tlet cursor: string | null | undefined;\n\t\t// Hard stop so a misbehaving endpoint cannot loop forever.\n\t\tfor (let page = 0; page < 10_000; page += 1) {\n\t\t\tconst pageQuery = { ...query };\n\t\t\tif (cursor) {\n\t\t\t\tpageQuery.pagination_cursor = cursor;\n\t\t\t}\n\t\t\tconst result = await this.request<LumaPaginatedResponse<T>>(path, {\n\t\t\t\tquery: pageQuery,\n\t\t\t});\n\t\t\tfor (const entry of result.entries ?? []) {\n\t\t\t\tyield entry;\n\t\t\t}\n\t\t\tif (!result.has_more || !result.next_cursor) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcursor = result.next_cursor;\n\t\t}\n\t}\n\n\t// ─── calendar ────────────────────────────────────────────────────────\n\n\treadonly calendar = {\n\t\t/** Iterate every event on a calendar. */\n\t\tlistEvents: (options: ListCalendarEventsOptions) =>\n\t\t\tthis.paginate<LumaCalendarEntry>(\"/v1/calendar/list-events\", {\n\t\t\t\tcalendar_api_id: options.calendarApiId,\n\t\t\t\tafter: options.after,\n\t\t\t\tbefore: options.before,\n\t\t\t\tpagination_limit: options.paginationLimit,\n\t\t\t\tpagination_cursor: options.paginationCursor,\n\t\t\t}),\n\n\t\t/** Collect every event on a calendar into an array. */\n\t\tlistAllEvents: (options: ListCalendarEventsOptions) =>\n\t\t\tcollect(this.calendar.listEvents(options)),\n\n\t\t/** Iterate every person who has interacted with a calendar. */\n\t\tlistPeople: (options: ListCalendarPeopleOptions) =>\n\t\t\tthis.paginate<LumaPerson>(\"/v1/calendar/list-people\", {\n\t\t\t\tcalendar_api_id: options.calendarApiId,\n\t\t\t\tpagination_limit: options.paginationLimit,\n\t\t\t\tpagination_cursor: options.paginationCursor,\n\t\t\t}),\n\n\t\t/** Collect every person on a calendar into an array. */\n\t\tlistAllPeople: (options: ListCalendarPeopleOptions) =>\n\t\t\tcollect(this.calendar.listPeople(options)),\n\n\t\t/** Iterate every coupon on the calendar tied to the API key. */\n\t\tlistCoupons: async function* (this: LumaClient): AsyncGenerator<LumaCoupon> {\n\t\t\tfor await (const entry of this.paginate<LumaCouponEntry>(\n\t\t\t\t\"/v1/calendar/coupons\",\n\t\t\t)) {\n\t\t\t\tyield normalizeCoupon(entry);\n\t\t\t}\n\t\t}.bind(this),\n\n\t\t/** Find a calendar coupon by its code, or `null` if none matches. */\n\t\tfindCouponByCode: async (code: string): Promise<LumaCoupon | null> => {\n\t\t\tconst target = code.toLowerCase();\n\t\t\tfor await (const coupon of this.calendar.listCoupons()) {\n\t\t\t\tif (coupon.code.toLowerCase() === target) {\n\t\t\t\t\treturn coupon;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\n\t\t/** Create a calendar coupon. */\n\t\tcreateCoupon: async (input: CreateCalendarCouponInput): Promise<LumaCoupon> => {\n\t\t\tconst discount =\n\t\t\t\tinput.discount.type === \"percent\"\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tdiscount_type: \"percent\" as const,\n\t\t\t\t\t\t\tpercent_off: input.discount.percentOff,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {\n\t\t\t\t\t\t\tdiscount_type: \"amount\" as const,\n\t\t\t\t\t\t\tcents_off: input.discount.centsOff,\n\t\t\t\t\t\t\tcurrency: input.discount.currency.toLowerCase(),\n\t\t\t\t\t\t};\n\t\t\tconst response = await this.request<{ coupon?: LumaCouponEntry }>(\n\t\t\t\t\"/v1/calendar/coupons/create\",\n\t\t\t\t{\n\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tcode: input.code,\n\t\t\t\t\t\tremaining_count: input.remainingCount,\n\t\t\t\t\t\tvalid_start_at: input.validStartAt\n\t\t\t\t\t\t\t? toIso(input.validStartAt)\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tvalid_end_at: input.validEndAt\n\t\t\t\t\t\t\t? toIso(input.validEndAt)\n\t\t\t\t\t\t\t: undefined,\n\t\t\t\t\t\tdiscount,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn normalizeCoupon(response.coupon ?? {}, input.code);\n\t\t},\n\t};\n\n\t// ─── events ──────────────────────────────────────────────────────────\n\n\treadonly events = {\n\t\t/** Fetch a single event by its `api_id`. */\n\t\tget: async (eventApiId: string): Promise<LumaEvent> => {\n\t\t\tconst response = await this.request<{ event?: LumaEvent } & LumaEvent>(\n\t\t\t\t\"/v1/event/get\",\n\t\t\t\t{ query: { api_id: eventApiId } },\n\t\t\t);\n\t\t\treturn response.event ?? response;\n\t\t},\n\n\t\t/** Iterate every guest of an event. */\n\t\tlistGuests: (options: ListEventGuestsOptions) =>\n\t\t\tasync function* (this: LumaClient): AsyncGenerator<LumaGuest> {\n\t\t\t\tfor await (const entry of this.paginate<LumaGuestEntry>(\n\t\t\t\t\t\"/v1/event/get-guests\",\n\t\t\t\t\t{\n\t\t\t\t\t\tevent_api_id: options.eventApiId,\n\t\t\t\t\t\tapproval_status: options.approvalStatus,\n\t\t\t\t\t\tpagination_limit: options.paginationLimit,\n\t\t\t\t\t\tpagination_cursor: options.paginationCursor,\n\t\t\t\t\t},\n\t\t\t\t)) {\n\t\t\t\t\tconst guest = entry.guest ?? (entry as unknown as LumaGuest);\n\t\t\t\t\tyield guest;\n\t\t\t\t}\n\t\t\t}.call(this),\n\n\t\t/** Collect every guest of an event into an array. */\n\t\tlistAllGuests: (options: ListEventGuestsOptions) =>\n\t\t\tcollect(this.events.listGuests(options)),\n\n\t\t/** Fetch a single guest, by guest `api_id` or by registration email. */\n\t\tgetGuest: async (options: GetEventGuestOptions): Promise<LumaGuest> => {\n\t\t\tif (!options.guestApiId && !options.email) {\n\t\t\t\tthrow new Error(\"getGuest requires either `guestApiId` or `email`\");\n\t\t\t}\n\t\t\tconst response = await this.request<{ guest?: LumaGuest } & LumaGuest>(\n\t\t\t\t\"/v1/event/get-guest\",\n\t\t\t\t{\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tevent_api_id: options.eventApiId,\n\t\t\t\t\t\tapi_id: options.guestApiId,\n\t\t\t\t\t\temail: options.email,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn response.guest ?? response;\n\t\t},\n\n\t\t/** Update a guest's approval status (approve, decline, waitlist…). */\n\t\tupdateGuestStatus: async (options: UpdateGuestStatusOptions): Promise<void> => {\n\t\t\tawait this.request(\"/v1/event/update-guest-status\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: {\n\t\t\t\t\tevent_api_id: options.eventApiId,\n\t\t\t\t\tguest_api_id: options.guestApiId,\n\t\t\t\t\tstatus: options.status,\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\t};\n}\n\nconst normalizeCoupon = (\n\tentry: LumaCouponEntry,\n\tfallbackCode?: string,\n): LumaCoupon => ({\n\t...entry,\n\tapi_id: entry.api_id ?? entry.id ?? \"\",\n\tcode: entry.code ?? fallbackCode ?? \"\",\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/constants.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["/** Base URL for the Luma public API. */\nexport const LUMA_API_BASE_URL = \"https://public-api.luma.com\";\n\n/** Header Luma expects the API key in. */\nexport const LUMA_API_KEY_HEADER = \"x-luma-api-key\";\n\n/** API version path segment prepended to every endpoint. */\nexport const LUMA_API_VERSION = \"v1\";\n","/**\n * Thrown when the Luma API responds with a non-2xx status, or when a response\n * body cannot be parsed as JSON.\n */\nexport class LumaApiError extends Error {\n\t/** HTTP status code returned by Luma (0 if the request never completed). */\n\treadonly status: number;\n\t/** Raw, untruncated response body. */\n\treadonly body: string;\n\t/** API path that produced the error, e.g. `/v1/event/get-guests`. */\n\treadonly path: string;\n\n\tconstructor(params: {\n\t\tmessage: string;\n\t\tstatus: number;\n\t\tbody: string;\n\t\tpath: string;\n\t}) {\n\t\tsuper(params.message);\n\t\tthis.name = \"LumaApiError\";\n\t\tthis.status = params.status;\n\t\tthis.body = params.body;\n\t\tthis.path = params.path;\n\t}\n\n\t/** True for 401/403 — the API key is missing, invalid, or lacks scope. */\n\tget isAuthError(): boolean {\n\t\treturn this.status === 401 || this.status === 403;\n\t}\n\n\t/** True for 429 — the caller is being rate limited. */\n\tget isRateLimited(): boolean {\n\t\treturn this.status === 429;\n\t}\n\n\t/**\n\t * True when Luma rejected a coupon create because the code already exists.\n\t * Luma surfaces this as a 400/409 whose body mentions the code already\n\t * existing; matched permissively so callers can treat it as idempotent.\n\t */\n\tget isDuplicateCouponCode(): boolean {\n\t\tconst lower = this.body.toLowerCase();\n\t\treturn (\n\t\t\t(this.status === 400 || this.status === 409) &&\n\t\t\tlower.includes(\"code\") &&\n\t\t\t(lower.includes(\"exist\") || lower.includes(\"already\"))\n\t\t);\n\t}\n}\n","import { LUMA_API_BASE_URL, LUMA_API_KEY_HEADER } from \"./constants\";\nimport { LumaApiError } from \"./errors\";\nimport type {\n\tAddGuestsOptions,\n\tCreateCalendarCouponInput,\n\tCreateTicketTypeInput,\n\tGetEventGuestOptions,\n\tListCalendarEventsOptions,\n\tListContactsOptions,\n\tListEventGuestsOptions,\n\tListTicketTypesOptions,\n\tLumaCalendarEvent,\n\tLumaContact,\n\tLumaCoupon,\n\tLumaEvent,\n\tLumaGuest,\n\tLumaGuestDetail,\n\tLumaPaginatedResponse,\n\tLumaTicketType,\n\tUpdateGuestStatusOptions,\n\tUpdateTicketTypeInput,\n} from \"./types\";\n\nexport interface LumaClientOptions {\n\t/** Luma API key. Found under Calendar Settings → API on a Luma Plus plan. */\n\tapiKey: string;\n\t/** Override the API base URL. Defaults to {@link LUMA_API_BASE_URL}. */\n\tbaseUrl?: string;\n\t/**\n\t * Fetch implementation to use. Defaults to the global `fetch`. Pass a\n\t * custom one to inject Next.js cache hints, retries, or a test double.\n\t */\n\tfetch?: typeof fetch;\n}\n\n/** Per-request options for {@link LumaClient.request}. */\nexport interface LumaRequestInit {\n\tmethod?: string;\n\t/** Query parameters. `undefined`/`null` values are dropped; `Date`s are\n\t * serialised as ISO strings. */\n\tquery?: Record<string, unknown>;\n\t/** JSON request body. Sets `content-type: application/json`. */\n\tbody?: unknown;\n\tsignal?: AbortSignal;\n\t/** Extra `fetch` init merged last — e.g. Next.js `{ next: { revalidate } }`. */\n\tfetchInit?: RequestInit;\n}\n\nconst serializeQueryValue = (value: unknown): string =>\n\tvalue instanceof Date ? value.toISOString() : String(value);\n\nconst toIso = (value: Date | string): string =>\n\tvalue instanceof Date ? value.toISOString() : value;\n\n/** Like {@link toIso} but passes `null`/`undefined` through untouched, so a\n * caller can clear a field (`null`) or leave it unset (`undefined`). */\nconst toIsoNullable = (\n\tvalue: Date | string | null | undefined,\n): string | null | undefined => (value == null ? value : toIso(value));\n\n/** Drain an async generator into an array. */\nexport const collect = async <T>(source: AsyncIterable<T>): Promise<T[]> => {\n\tconst out: T[] = [];\n\tfor await (const item of source) {\n\t\tout.push(item);\n\t}\n\treturn out;\n};\n\n/**\n * Typed client for the Luma (lu.ma) public API.\n *\n * The typed resource methods cover the endpoints this client is built around;\n * for anything not modelled here, {@link LumaClient.request} and\n * {@link LumaClient.paginate} are public escape hatches that work against any\n * endpoint.\n */\nexport class LumaClient {\n\treadonly baseUrl: string;\n\tprivate readonly apiKey: string;\n\tprivate readonly fetchImpl: typeof fetch;\n\n\tconstructor(options: LumaClientOptions) {\n\t\tif (!options.apiKey) {\n\t\t\tthrow new Error(\"LumaClient requires an `apiKey`\");\n\t\t}\n\t\tthis.apiKey = options.apiKey;\n\t\tthis.baseUrl = options.baseUrl ?? LUMA_API_BASE_URL;\n\t\tconst fetchImpl = options.fetch ?? globalThis.fetch;\n\t\tif (typeof fetchImpl !== \"function\") {\n\t\t\tthrow new Error(\n\t\t\t\t\"No global `fetch` available; pass one via LumaClientOptions.fetch\",\n\t\t\t);\n\t\t}\n\t\tthis.fetchImpl = fetchImpl;\n\t}\n\n\t/**\n\t * Construct a client from environment variables. Reads `LUMA_API_KEY` and,\n\t * optionally, `LUMA_API_BASE_URL`.\n\t */\n\tstatic fromEnv(\n\t\tenv: Record<string, string | undefined> = typeof process !== \"undefined\"\n\t\t\t? process.env\n\t\t\t: {},\n\t): LumaClient {\n\t\tconst apiKey = env.LUMA_API_KEY;\n\t\tif (!apiKey) {\n\t\t\tthrow new Error(\"LUMA_API_KEY is not set\");\n\t\t}\n\t\treturn new LumaClient({ apiKey, baseUrl: env.LUMA_API_BASE_URL });\n\t}\n\n\t/**\n\t * Low-level request against any Luma endpoint. `path` is taken relative to\n\t * the base URL, e.g. `/v1/events/get`.\n\t */\n\tasync request<T>(path: string, init: LumaRequestInit = {}): Promise<T> {\n\t\tconst url = new URL(path.startsWith(\"/\") ? path : `/${path}`, this.baseUrl);\n\t\tif (init.query) {\n\t\t\tfor (const [key, value] of Object.entries(init.query)) {\n\t\t\t\tif (value !== undefined && value !== null) {\n\t\t\t\t\turl.searchParams.set(key, serializeQueryValue(value));\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst headers: Record<string, string> = {\n\t\t\t[LUMA_API_KEY_HEADER]: this.apiKey,\n\t\t\taccept: \"application/json\",\n\t\t};\n\t\tlet body: string | undefined;\n\t\tif (init.body !== undefined) {\n\t\t\theaders[\"content-type\"] = \"application/json\";\n\t\t\tbody = JSON.stringify(init.body);\n\t\t}\n\n\t\tlet response: Response;\n\t\ttry {\n\t\t\tresponse = await this.fetchImpl(url, {\n\t\t\t\tmethod: init.method ?? \"GET\",\n\t\t\t\theaders,\n\t\t\t\tbody,\n\t\t\t\tsignal: init.signal,\n\t\t\t\t...init.fetchInit,\n\t\t\t});\n\t\t} catch (cause) {\n\t\t\tthrow new LumaApiError({\n\t\t\t\tmessage: `Luma API request to ${path} failed: ${\n\t\t\t\t\tcause instanceof Error ? cause.message : String(cause)\n\t\t\t\t}`,\n\t\t\t\tstatus: 0,\n\t\t\t\tbody: \"\",\n\t\t\t\tpath,\n\t\t\t});\n\t\t}\n\n\t\tconst text = await response.text();\n\t\tif (!response.ok) {\n\t\t\tthrow new LumaApiError({\n\t\t\t\tmessage: `Luma API responded ${response.status} for ${path}`,\n\t\t\t\tstatus: response.status,\n\t\t\t\tbody: text,\n\t\t\t\tpath,\n\t\t\t});\n\t\t}\n\t\tif (text.length === 0) {\n\t\t\treturn undefined as T;\n\t\t}\n\t\ttry {\n\t\t\treturn JSON.parse(text) as T;\n\t\t} catch {\n\t\t\tthrow new LumaApiError({\n\t\t\t\tmessage: `Luma API returned a non-JSON body for ${path}`,\n\t\t\t\tstatus: response.status,\n\t\t\t\tbody: text,\n\t\t\t\tpath,\n\t\t\t});\n\t\t}\n\t}\n\n\t/**\n\t * Iterate a cursor-paginated endpoint, yielding each entry. Follows\n\t * `next_cursor` while `has_more` is true.\n\t */\n\tasync *paginate<T>(\n\t\tpath: string,\n\t\tquery: Record<string, unknown> = {},\n\t): AsyncGenerator<T> {\n\t\tlet cursor: string | null | undefined;\n\t\t// Hard stop so a misbehaving endpoint cannot loop forever.\n\t\tfor (let page = 0; page < 10_000; page += 1) {\n\t\t\tconst pageQuery = { ...query };\n\t\t\tif (cursor) {\n\t\t\t\tpageQuery.pagination_cursor = cursor;\n\t\t\t}\n\t\t\tconst result = await this.request<LumaPaginatedResponse<T>>(path, {\n\t\t\t\tquery: pageQuery,\n\t\t\t});\n\t\t\tfor (const entry of result.entries ?? []) {\n\t\t\t\tyield entry;\n\t\t\t}\n\t\t\tif (!result.has_more || !result.next_cursor) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tcursor = result.next_cursor;\n\t\t}\n\t}\n\n\t// ─── calendar ────────────────────────────────────────────────────────\n\t//\n\t// The calendar is inferred from the API key, so these take no calendar id.\n\n\treadonly calendar = {\n\t\t/** Iterate every event the calendar manages. */\n\t\tlistEvents: (options: ListCalendarEventsOptions = {}) =>\n\t\t\tthis.paginate<LumaCalendarEvent>(\"/v1/calendars/events/list\", {\n\t\t\t\tafter: options.after,\n\t\t\t\tbefore: options.before,\n\t\t\t\tstatus: options.status,\n\t\t\t\taccess: options.access,\n\t\t\t\tplatforms: options.platforms,\n\t\t\t\tsort_direction: options.sortDirection,\n\t\t\t\tpagination_limit: options.paginationLimit,\n\t\t\t\tpagination_cursor: options.paginationCursor,\n\t\t\t}),\n\n\t\t/** Collect every event the calendar manages into an array. */\n\t\tlistAllEvents: (options: ListCalendarEventsOptions = {}) =>\n\t\t\tcollect(this.calendar.listEvents(options)),\n\n\t\t/** Iterate every contact on the calendar. */\n\t\tlistContacts: (options: ListContactsOptions = {}) =>\n\t\t\tthis.paginate<LumaContact>(\"/v1/calendars/contacts/list\", {\n\t\t\t\tquery: options.query,\n\t\t\t\tsort_direction: options.sortDirection,\n\t\t\t\tpagination_limit: options.paginationLimit,\n\t\t\t\tpagination_cursor: options.paginationCursor,\n\t\t\t}),\n\n\t\t/** Collect every contact on the calendar into an array. */\n\t\tlistAllContacts: (options: ListContactsOptions = {}) =>\n\t\t\tcollect(this.calendar.listContacts(options)),\n\n\t\t/** Iterate every coupon on the calendar tied to the API key. */\n\t\tlistCoupons: (): AsyncGenerator<LumaCoupon> =>\n\t\t\tthis.paginate<LumaCoupon>(\"/v1/calendars/coupons/list\"),\n\n\t\t/** Find a calendar coupon by its code, or `null` if none matches. */\n\t\tfindCouponByCode: async (code: string): Promise<LumaCoupon | null> => {\n\t\t\tconst target = code.toLowerCase();\n\t\t\tfor await (const coupon of this.calendar.listCoupons()) {\n\t\t\t\tif (coupon.code.toLowerCase() === target) {\n\t\t\t\t\treturn coupon;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\n\t\t/** Create a calendar coupon (applies to any event the calendar manages). */\n\t\tcreateCoupon: (input: CreateCalendarCouponInput): Promise<LumaCoupon> =>\n\t\t\tthis.request<LumaCoupon>(\"/v1/calendars/coupons/create\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: {\n\t\t\t\t\tcode: input.code,\n\t\t\t\t\tremaining_count: input.remainingCount,\n\t\t\t\t\tvalid_start_at: toIsoNullable(input.validStartAt),\n\t\t\t\t\tvalid_end_at: toIsoNullable(input.validEndAt),\n\t\t\t\t\tdiscount:\n\t\t\t\t\t\tinput.discount.type === \"percent\"\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tdiscount_type: \"percent\",\n\t\t\t\t\t\t\t\t\tpercent_off: input.discount.percentOff,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {\n\t\t\t\t\t\t\t\t\tdiscount_type: \"amount\",\n\t\t\t\t\t\t\t\t\tcents_off: input.discount.centsOff,\n\t\t\t\t\t\t\t\t\tcurrency: input.discount.currency.toLowerCase(),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}),\n\t};\n\n\t// ─── events ──────────────────────────────────────────────────────────\n\n\treadonly events = {\n\t\t/** Fetch a single event by its id (`evt-…`). */\n\t\tget: (eventId: string): Promise<LumaEvent> =>\n\t\t\tthis.request<LumaEvent>(\"/v1/events/get\", {\n\t\t\t\tquery: { event_id: eventId },\n\t\t\t}),\n\n\t\t/** Iterate every guest of an event. */\n\t\tlistGuests: (options: ListEventGuestsOptions) =>\n\t\t\tthis.paginate<LumaGuest>(\"/v1/events/guests/list\", {\n\t\t\t\tevent_id: options.eventId,\n\t\t\t\tapproval_status: options.approvalStatus,\n\t\t\t\tsort_direction: options.sortDirection,\n\t\t\t\tpagination_limit: options.paginationLimit,\n\t\t\t\tpagination_cursor: options.paginationCursor,\n\t\t\t}),\n\n\t\t/** Collect every guest of an event into an array. */\n\t\tlistAllGuests: (options: ListEventGuestsOptions) =>\n\t\t\tcollect(this.events.listGuests(options)),\n\n\t\t/** Fetch a single guest (with order detail) by its guest id. */\n\t\tgetGuest: (options: GetEventGuestOptions): Promise<LumaGuestDetail> =>\n\t\t\tthis.request<LumaGuestDetail>(\"/v1/events/guests/get\", {\n\t\t\t\tquery: { event_id: options.eventId, id: options.guestId },\n\t\t\t}),\n\n\t\t/** Update a guest's approval status (approve, decline, waitlist…). */\n\t\tupdateGuestStatus: async (options: UpdateGuestStatusOptions): Promise<void> => {\n\t\t\tawait this.request(\"/v1/events/guests/update-status\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: {\n\t\t\t\t\tevent_id: options.eventId,\n\t\t\t\t\tguest_id: options.guestId,\n\t\t\t\t\tstatus: options.status,\n\t\t\t\t\tshould_refund: options.shouldRefund,\n\t\t\t\t\tsend_email: options.sendEmail,\n\t\t\t\t\tmessage: options.message,\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * Add guests to an event (host-side). Registers people directly — this\n\t\t * does NOT take payment; Luma owns checkout/payment on its hosted flow.\n\t\t * By default guests are added as approved (\"Going\") and emailed. Pass a\n\t\t * `ticketTypeId` to assign each guest a ticket of that type.\n\t\t */\n\t\taddGuests: async (options: AddGuestsOptions): Promise<void> => {\n\t\t\tawait this.request(\"/v1/events/guests/add\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: {\n\t\t\t\t\tevent_id: options.eventId,\n\t\t\t\t\tguests: options.guests.map((guest) => ({\n\t\t\t\t\t\temail: guest.email,\n\t\t\t\t\t\tname: guest.name,\n\t\t\t\t\t\tregistration_answers: guest.registrationAnswers,\n\t\t\t\t\t})),\n\t\t\t\t\tticket: options.ticketTypeId\n\t\t\t\t\t\t? { event_ticket_type_id: options.ticketTypeId }\n\t\t\t\t\t\t: undefined,\n\t\t\t\t\tapproval_status: options.approvalStatus,\n\t\t\t\t\tsend_email: options.sendEmail,\n\t\t\t\t},\n\t\t\t});\n\t\t},\n\n\t\t/**\n\t\t * List an event's ticket types (tiers), including prices. Pass\n\t\t * `includeHidden` to include ticket types not shown on the public page.\n\t\t */\n\t\tlistTicketTypes: async (\n\t\t\toptions: ListTicketTypesOptions,\n\t\t): Promise<LumaTicketType[]> => {\n\t\t\tconst response = await this.request<{ entries?: LumaTicketType[] }>(\n\t\t\t\t\"/v1/events/ticket-types/list\",\n\t\t\t\t{\n\t\t\t\t\tquery: {\n\t\t\t\t\t\tevent_id: options.eventId,\n\t\t\t\t\t\tinclude_hidden: options.includeHidden,\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t);\n\t\t\treturn response.entries ?? [];\n\t\t},\n\n\t\t/** Fetch a single ticket type by its id. */\n\t\tgetTicketType: (ticketTypeId: string): Promise<LumaTicketType> =>\n\t\t\tthis.request<LumaTicketType>(\"/v1/events/ticket-types/get\", {\n\t\t\t\tquery: { event_ticket_type_id: ticketTypeId },\n\t\t\t}),\n\n\t\t/** Create a ticket type on an event. */\n\t\tcreateTicketType: (input: CreateTicketTypeInput): Promise<LumaTicketType> =>\n\t\t\tthis.request<LumaTicketType>(\"/v1/events/ticket-types/create\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: ticketTypeBody(\n\t\t\t\t\t{ event_id: input.eventId, type: input.type },\n\t\t\t\t\tinput,\n\t\t\t\t),\n\t\t\t}),\n\n\t\t/** Update an existing ticket type. */\n\t\tupdateTicketType: (input: UpdateTicketTypeInput): Promise<LumaTicketType> =>\n\t\t\tthis.request<LumaTicketType>(\"/v1/events/ticket-types/update\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: ticketTypeBody(\n\t\t\t\t\t{ event_ticket_type_id: input.ticketTypeId, type: input.type },\n\t\t\t\t\tinput,\n\t\t\t\t),\n\t\t\t}),\n\n\t\t/** Delete a ticket type by its id. */\n\t\tdeleteTicketType: async (ticketTypeId: string): Promise<void> => {\n\t\t\tawait this.request(\"/v1/events/ticket-types/delete\", {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\tbody: { event_ticket_type_id: ticketTypeId },\n\t\t\t});\n\t\t},\n\t};\n}\n\n/** Build the snake_case body shared by ticket-type create and update. Keys\n * left `undefined` are dropped by `JSON.stringify`; explicit `null` is sent. */\nconst ticketTypeBody = (\n\tbase: Record<string, unknown>,\n\tfields: {\n\t\tname?: string;\n\t\tcents?: number | null;\n\t\tcurrency?: string | null;\n\t\trequireApproval?: boolean;\n\t\tisHidden?: boolean;\n\t\tdescription?: string | null;\n\t\tisFlexible?: boolean;\n\t\tminCents?: number | null;\n\t\tmaxCapacity?: number | null;\n\t\tvalidStartAt?: Date | string | null;\n\t\tvalidEndAt?: Date | string | null;\n\t},\n): Record<string, unknown> => ({\n\t...base,\n\tname: fields.name,\n\tcents: fields.cents,\n\tcurrency: fields.currency == null ? fields.currency : fields.currency.toLowerCase(),\n\trequire_approval: fields.requireApproval,\n\tis_hidden: fields.isHidden,\n\tdescription: fields.description,\n\tis_flexible: fields.isFlexible,\n\tmin_cents: fields.minCents,\n\tmax_capacity: fields.maxCapacity,\n\tvalid_start_at: toIsoNullable(fields.validStartAt),\n\tvalid_end_at: toIsoNullable(fields.validEndAt),\n});\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingram-tech/luma",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "TypeScript client for the Luma (lu.ma) public API.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ingram Technologies",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsup",
|
|
38
38
|
"prepack": "bun run build",
|
|
39
|
+
"generate": "curl -sSf https://public-api.luma.com/openapi.json -o openapi.json && openapi-typescript openapi.json -o src/generated/openapi.ts && biome format --write src/generated/openapi.ts",
|
|
39
40
|
"lint": "biome check .",
|
|
40
41
|
"format": "biome format --write .",
|
|
41
42
|
"type-check": "tsc --noEmit",
|
|
@@ -47,10 +48,11 @@
|
|
|
47
48
|
"node": ">=18"
|
|
48
49
|
},
|
|
49
50
|
"devDependencies": {
|
|
50
|
-
"@biomejs/biome": "^2.
|
|
51
|
-
"@types/node": "^
|
|
52
|
-
"
|
|
51
|
+
"@biomejs/biome": "^2.5.1",
|
|
52
|
+
"@types/node": "^26.0.1",
|
|
53
|
+
"openapi-typescript": "^7.13.0",
|
|
54
|
+
"tsup": "^8.5.1",
|
|
53
55
|
"typescript": "^5.9.3",
|
|
54
|
-
"vitest": "^4.
|
|
56
|
+
"vitest": "^4.1.9"
|
|
55
57
|
}
|
|
56
58
|
}
|