@crvouga/mockingbird-service-stripe 0.1.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.
Files changed (142) hide show
  1. package/README.md +254 -0
  2. package/dist/account.d.ts +8 -0
  3. package/dist/account.d.ts.map +1 -0
  4. package/dist/account.js +13 -0
  5. package/dist/account.js.map +1 -0
  6. package/dist/charges.d.ts +4 -0
  7. package/dist/charges.d.ts.map +1 -0
  8. package/dist/charges.js +89 -0
  9. package/dist/charges.js.map +1 -0
  10. package/dist/checkout-sessions.d.ts +5 -0
  11. package/dist/checkout-sessions.d.ts.map +1 -0
  12. package/dist/checkout-sessions.js +303 -0
  13. package/dist/checkout-sessions.js.map +1 -0
  14. package/dist/constants.d.ts +3 -0
  15. package/dist/constants.d.ts.map +1 -0
  16. package/dist/constants.js +3 -0
  17. package/dist/constants.js.map +1 -0
  18. package/dist/coupons.d.ts +4 -0
  19. package/dist/coupons.d.ts.map +1 -0
  20. package/dist/coupons.js +158 -0
  21. package/dist/coupons.js.map +1 -0
  22. package/dist/customers.d.ts +4 -0
  23. package/dist/customers.d.ts.map +1 -0
  24. package/dist/customers.js +218 -0
  25. package/dist/customers.js.map +1 -0
  26. package/dist/disputes.d.ts +4 -0
  27. package/dist/disputes.d.ts.map +1 -0
  28. package/dist/disputes.js +36 -0
  29. package/dist/disputes.js.map +1 -0
  30. package/dist/errors.d.ts +29 -0
  31. package/dist/errors.d.ts.map +1 -0
  32. package/dist/errors.js +74 -0
  33. package/dist/errors.js.map +1 -0
  34. package/dist/events.d.ts +4 -0
  35. package/dist/events.d.ts.map +1 -0
  36. package/dist/events.js +76 -0
  37. package/dist/events.js.map +1 -0
  38. package/dist/expand.d.ts +11 -0
  39. package/dist/expand.d.ts.map +1 -0
  40. package/dist/expand.js +45 -0
  41. package/dist/expand.js.map +1 -0
  42. package/dist/fields.d.ts +25 -0
  43. package/dist/fields.d.ts.map +1 -0
  44. package/dist/fields.js +117 -0
  45. package/dist/fields.js.map +1 -0
  46. package/dist/generated/openapi.d.ts +7 -0
  47. package/dist/generated/openapi.d.ts.map +1 -0
  48. package/dist/generated/openapi.js +5 -0
  49. package/dist/generated/openapi.js.map +1 -0
  50. package/dist/index.d.ts +43 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +172 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/internal.d.ts +134 -0
  55. package/dist/internal.d.ts.map +1 -0
  56. package/dist/internal.js +460 -0
  57. package/dist/internal.js.map +1 -0
  58. package/dist/invoice-items.d.ts +4 -0
  59. package/dist/invoice-items.d.ts.map +1 -0
  60. package/dist/invoice-items.js +179 -0
  61. package/dist/invoice-items.js.map +1 -0
  62. package/dist/invoices.d.ts +4 -0
  63. package/dist/invoices.d.ts.map +1 -0
  64. package/dist/invoices.js +312 -0
  65. package/dist/invoices.js.map +1 -0
  66. package/dist/list.d.ts +24 -0
  67. package/dist/list.d.ts.map +1 -0
  68. package/dist/list.js +68 -0
  69. package/dist/list.js.map +1 -0
  70. package/dist/params.d.ts +29 -0
  71. package/dist/params.d.ts.map +1 -0
  72. package/dist/params.js +165 -0
  73. package/dist/params.js.map +1 -0
  74. package/dist/payment-intents.d.ts +4 -0
  75. package/dist/payment-intents.d.ts.map +1 -0
  76. package/dist/payment-intents.js +232 -0
  77. package/dist/payment-intents.js.map +1 -0
  78. package/dist/payment-methods.d.ts +4 -0
  79. package/dist/payment-methods.d.ts.map +1 -0
  80. package/dist/payment-methods.js +99 -0
  81. package/dist/payment-methods.js.map +1 -0
  82. package/dist/prices.d.ts +4 -0
  83. package/dist/prices.d.ts.map +1 -0
  84. package/dist/prices.js +176 -0
  85. package/dist/prices.js.map +1 -0
  86. package/dist/products.d.ts +6 -0
  87. package/dist/products.d.ts.map +1 -0
  88. package/dist/products.js +202 -0
  89. package/dist/products.js.map +1 -0
  90. package/dist/promotion-codes.d.ts +4 -0
  91. package/dist/promotion-codes.d.ts.map +1 -0
  92. package/dist/promotion-codes.js +193 -0
  93. package/dist/promotion-codes.js.map +1 -0
  94. package/dist/qa-corpus.d.ts +26 -0
  95. package/dist/qa-corpus.d.ts.map +1 -0
  96. package/dist/qa-corpus.js +42 -0
  97. package/dist/qa-corpus.js.map +1 -0
  98. package/dist/refunds.d.ts +4 -0
  99. package/dist/refunds.d.ts.map +1 -0
  100. package/dist/refunds.js +125 -0
  101. package/dist/refunds.js.map +1 -0
  102. package/dist/render.d.ts +60 -0
  103. package/dist/render.d.ts.map +1 -0
  104. package/dist/render.js +426 -0
  105. package/dist/render.js.map +1 -0
  106. package/dist/reshape-qa.d.ts +8 -0
  107. package/dist/reshape-qa.d.ts.map +1 -0
  108. package/dist/reshape-qa.js +102 -0
  109. package/dist/reshape-qa.js.map +1 -0
  110. package/dist/search.d.ts +32 -0
  111. package/dist/search.d.ts.map +1 -0
  112. package/dist/search.js +64 -0
  113. package/dist/search.js.map +1 -0
  114. package/dist/setup-intents.d.ts +4 -0
  115. package/dist/setup-intents.d.ts.map +1 -0
  116. package/dist/setup-intents.js +129 -0
  117. package/dist/setup-intents.js.map +1 -0
  118. package/dist/state.d.ts +485 -0
  119. package/dist/state.d.ts.map +1 -0
  120. package/dist/state.js +143 -0
  121. package/dist/state.js.map +1 -0
  122. package/dist/subscription-schedules.d.ts +4 -0
  123. package/dist/subscription-schedules.d.ts.map +1 -0
  124. package/dist/subscription-schedules.js +122 -0
  125. package/dist/subscription-schedules.js.map +1 -0
  126. package/dist/subscriptions.d.ts +23 -0
  127. package/dist/subscriptions.d.ts.map +1 -0
  128. package/dist/subscriptions.js +260 -0
  129. package/dist/subscriptions.js.map +1 -0
  130. package/dist/test-tokens.d.ts +27 -0
  131. package/dist/test-tokens.d.ts.map +1 -0
  132. package/dist/test-tokens.js +61 -0
  133. package/dist/test-tokens.js.map +1 -0
  134. package/dist/url.d.ts +6 -0
  135. package/dist/url.d.ts.map +1 -0
  136. package/dist/url.js +38 -0
  137. package/dist/url.js.map +1 -0
  138. package/dist/version.d.ts +3 -0
  139. package/dist/version.d.ts.map +1 -0
  140. package/dist/version.js +3 -0
  141. package/dist/version.js.map +1 -0
  142. package/package.json +72 -0
package/dist/prices.js ADDED
@@ -0,0 +1,176 @@
1
+ import { jsonResponse, } from "@crvouga/mockingbird-service";
2
+ import { invalidRequest, parameterInvalidEmpty, resourceMissing } from "./errors.js";
3
+ import { applyExpand } from "./expand.js";
4
+ import { mergeMetadata, optionalBoolean, parseUnitAmountDecimal, strip } from "./fields.js";
5
+ import { requestScope } from "./internal.js";
6
+ import { matchesCreated, paginate } from "./list.js";
7
+ import { bodyParams, queryParams, SUPPORTED_CURRENCIES } from "./params.js";
8
+ import { requireProduct } from "./products.js";
9
+ import { renderPrice, renderProduct } from "./render.js";
10
+ import { seconds } from "./state.js";
11
+ /** Stripe caps recurring periods at three years. */
12
+ const MAX_INTERVAL_COUNT = {
13
+ day: { limit: 1095, adjective: "daily" },
14
+ week: { limit: 156, adjective: "weekly" },
15
+ month: { limit: 36, adjective: "monthly" },
16
+ year: { limit: 3, adjective: "yearly" },
17
+ };
18
+ const normalizeCurrency = (raw, param = "currency") => {
19
+ const currency = raw.toLowerCase();
20
+ if (!SUPPORTED_CURRENCIES.includes(currency))
21
+ throw invalidRequest(`Invalid currency: ${raw}. Stripe currently supports these currencies: ${SUPPORTED_CURRENCIES.join(", ")}`, param);
22
+ return currency;
23
+ };
24
+ const parseRecurring = (raw) => {
25
+ const input = raw;
26
+ const interval_count = input.interval_count ?? 1;
27
+ const cap = MAX_INTERVAL_COUNT[input.interval];
28
+ if (interval_count > cap.limit)
29
+ throw invalidRequest(`The interval_count for ${cap.adjective} prices can't be greater than ${cap.limit}`, "recurring[interval_count]");
30
+ const usage_type = input.usage_type ?? "licensed";
31
+ if (usage_type === "metered")
32
+ throw invalidRequest("Starting with Stripe version `2025-03-31.basil`, metered prices must be backed by meters.");
33
+ return { interval: input.interval, interval_count, usage_type };
34
+ };
35
+ const assertLookupKeyFree = (scope, lookupKey, selfId, transfer) => {
36
+ const clashes = scope.account.prices.list({
37
+ where: (price) => price.lookup_key === lookupKey && price.id !== selfId,
38
+ });
39
+ const clash = clashes[0];
40
+ if (!clash)
41
+ return;
42
+ if (transfer) {
43
+ scope.account.prices.update(clash.id, { ...clash.value, lookup_key: null });
44
+ return;
45
+ }
46
+ throw invalidRequest(`A price (\`${clash.id}\`) already uses that lookup key.`, "lookup_key");
47
+ };
48
+ const applyShared = (scope, current, params) => {
49
+ const next = { ...current };
50
+ next.active = optionalBoolean(params, "active", current.active) ?? true;
51
+ if (params.lookup_key !== undefined) {
52
+ const lookupKey = strip(params.lookup_key) === "" ? null : params.lookup_key;
53
+ if (lookupKey !== null && lookupKey !== current.lookup_key)
54
+ assertLookupKeyFree(scope, lookupKey, current.id, params.transfer_lookup_key === true);
55
+ next.lookup_key = lookupKey;
56
+ }
57
+ next.metadata = mergeMetadata(current.metadata, params.metadata);
58
+ if (params.nickname !== undefined)
59
+ next.nickname = strip(params.nickname);
60
+ if (params.tax_behavior !== undefined)
61
+ next.tax_behavior = params.tax_behavior;
62
+ return next;
63
+ };
64
+ const expanders = (scope) => ({
65
+ product: (id) => {
66
+ const product = scope.account.products.get(id);
67
+ return product ? renderProduct(product) : undefined;
68
+ },
69
+ });
70
+ export const priceHandlers = (services) => {
71
+ const render = (scope, price, params) => applyExpand(renderPrice(price), params.expand, expanders(scope));
72
+ return {
73
+ PostPrices: async (context) => {
74
+ const scope = requestScope(services, context);
75
+ const params = bodyParams(context);
76
+ if (params.product === undefined)
77
+ throw invalidRequest("You must specify either `product` or `product_data` when creating a price.");
78
+ if (params.product === "")
79
+ throw parameterInvalidEmpty("product");
80
+ const product = requireProduct(scope, params.product, "product", 400);
81
+ const currency = normalizeCurrency(params.currency);
82
+ const hasAmount = params.unit_amount !== undefined;
83
+ const hasDecimal = params.unit_amount_decimal !== undefined;
84
+ if (hasAmount && hasDecimal)
85
+ throw invalidRequest("You may only specify one of these parameters: unit_amount, unit_amount_decimal.", "unit_amount");
86
+ if (!hasAmount && !hasDecimal)
87
+ throw invalidRequest("Prices require an `unit_amount` or `unit_amount_decimal` parameter to be set.");
88
+ let unit_amount_decimal;
89
+ if (hasAmount) {
90
+ const amount = params.unit_amount;
91
+ if (amount < 0)
92
+ throw invalidRequest("Invalid non-negative integer", "unit_amount");
93
+ unit_amount_decimal = String(amount);
94
+ }
95
+ else {
96
+ unit_amount_decimal = parseUnitAmountDecimal(params.unit_amount_decimal, "unit_amount_decimal");
97
+ }
98
+ const recurring = params.recurring === undefined || params.recurring === ""
99
+ ? null
100
+ : parseRecurring(params.recurring);
101
+ const id = scope.ids.next("price_", 24);
102
+ const base = {
103
+ id,
104
+ active: true,
105
+ created: seconds(scope.now),
106
+ currency,
107
+ lookup_key: null,
108
+ metadata: {},
109
+ nickname: null,
110
+ product: product.id,
111
+ recurring,
112
+ tax_behavior: "unspecified",
113
+ unit_amount_decimal,
114
+ };
115
+ const price = applyShared(scope, base, params);
116
+ scope.account.prices.insert(id, price);
117
+ scope.emit("price.created", render(scope, price, params));
118
+ return jsonResponse(200, render(scope, price, params));
119
+ },
120
+ GetPrices: async (context) => {
121
+ const scope = requestScope(services, context);
122
+ const params = queryParams(context);
123
+ const currency = typeof params.currency === "string" ? normalizeCurrency(params.currency) : undefined;
124
+ const productId = params.product;
125
+ if (typeof productId === "string" && productId !== "")
126
+ requireProduct(scope, productId, "product", 400);
127
+ const lookupKeys = params.lookup_keys;
128
+ const recurring = params.recurring;
129
+ const page = await paginate(scope.account.prices, params, {
130
+ url: "/v1/prices",
131
+ kind: "price",
132
+ where: (price) => matchesCreated(price.created, params.created) &&
133
+ (params.active === undefined || price.active === params.active) &&
134
+ (currency === undefined || price.currency === currency) &&
135
+ (typeof productId !== "string" || productId === "" || price.product === productId) &&
136
+ (params.type === undefined ||
137
+ params.type === "" ||
138
+ (price.recurring === null ? "one_time" : "recurring") === params.type) &&
139
+ (lookupKeys === undefined ||
140
+ (price.lookup_key !== null && lookupKeys.includes(price.lookup_key))) &&
141
+ (recurring === undefined ||
142
+ recurring === "" ||
143
+ ((recurring.interval === undefined ||
144
+ recurring.interval === "" ||
145
+ price.recurring?.interval === recurring.interval) &&
146
+ (recurring.usage_type === undefined ||
147
+ recurring.usage_type === "" ||
148
+ price.recurring?.usage_type === recurring.usage_type))),
149
+ render: renderPrice,
150
+ });
151
+ return jsonResponse(200, applyExpand(page, params.expand, expanders(scope)));
152
+ },
153
+ GetPricesPrice: async (context) => {
154
+ const scope = requestScope(services, context);
155
+ const params = queryParams(context);
156
+ const id = context.params.price ?? "";
157
+ const price = scope.account.prices.get(id);
158
+ if (!price)
159
+ throw resourceMissing("price", id, "price");
160
+ return jsonResponse(200, render(scope, price, params));
161
+ },
162
+ PostPricesPrice: async (context) => {
163
+ const scope = requestScope(services, context);
164
+ const params = bodyParams(context);
165
+ const id = context.params.price ?? "";
166
+ const current = scope.account.prices.get(id);
167
+ if (!current)
168
+ throw resourceMissing("price", id, "price");
169
+ const price = applyShared(scope, current, params);
170
+ scope.account.prices.update(id, price);
171
+ scope.emit("price.updated", render(scope, price, params));
172
+ return jsonResponse(200, render(scope, price, params));
173
+ },
174
+ };
175
+ };
176
+ //# sourceMappingURL=prices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prices.js","sourceRoot":"","sources":["../src/prices.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type OperationHandler } from "@crvouga/mockingbird-service";
2
+ import { type RequestScope, type Services } from "./internal.js";
3
+ import { type ProductRecord } from "./state.js";
4
+ export declare const requireProduct: (scope: RequestScope, id: string, param: string, status?: number) => ProductRecord;
5
+ export declare const productHandlers: (services: Services) => Record<string, OperationHandler>;
6
+ //# sourceMappingURL=products.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.d.ts","sourceRoot":"","sources":["../src/products.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAA;AAgBrC,OAAO,EAAE,KAAK,YAAY,EAAgB,KAAK,QAAQ,EAAE,MAAM,eAAe,CAAA;AAK9E,OAAO,EAA0B,KAAK,aAAa,EAAW,MAAM,YAAY,CAAA;AAwFhF,eAAO,MAAM,cAAc,GACzB,OAAO,YAAY,EACnB,IAAI,MAAM,EACV,OAAO,MAAM,EACb,eAAY,KACX,aAIF,CAAA;AASD,eAAO,MAAM,eAAe,GAAI,UAAU,QAAQ,KAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAiHnF,CAAA"}
@@ -0,0 +1,202 @@
1
+ import { jsonResponse, } from "@crvouga/mockingbird-service";
2
+ import { invalidRequest, parameterInvalidEmpty, parameterMissing, resourceMissing, } from "./errors.js";
3
+ import { applyExpand } from "./expand.js";
4
+ import { mergeMetadata, optionalBoolean, optionalString, strip, strippedString, validateStatementDescriptor, } from "./fields.js";
5
+ import { requestScope } from "./internal.js";
6
+ import { matchesCreated, paginate } from "./list.js";
7
+ import { bodyParams, queryParams } from "./params.js";
8
+ import { renderDeletedProduct, renderPrice, renderProduct } from "./render.js";
9
+ import { searchRecords } from "./search.js";
10
+ import { seconds } from "./state.js";
11
+ import { validateUrl } from "./url.js";
12
+ const PRODUCT_URL_LENGTH_LIMIT = 800;
13
+ const CREATE_NON_UNSETTABLE = {
14
+ description: true,
15
+ unit_label: true,
16
+ url: true,
17
+ };
18
+ /** Order in which Stripe validates product parameters (observed, not alphabetical). */
19
+ const PRODUCT_PARAM_ORDER = [
20
+ "name",
21
+ "description",
22
+ "metadata",
23
+ "active",
24
+ "images",
25
+ "shippable",
26
+ "url",
27
+ "package_dimensions",
28
+ "statement_descriptor",
29
+ "unit_label",
30
+ "marketing_features",
31
+ ];
32
+ const productValidators = (mode, current) => {
33
+ const notEmpty = (key) => (params) => {
34
+ if (params[key] === "" && (mode === "create" ? CREATE_NON_UNSETTABLE[key] === true : false))
35
+ throw parameterInvalidEmpty(key);
36
+ };
37
+ return {
38
+ name: (params) => {
39
+ if (mode === "create" && params.name === undefined)
40
+ throw parameterMissing("name");
41
+ if (typeof params.name === "string" && strip(params.name) === "")
42
+ throw parameterInvalidEmpty("name");
43
+ },
44
+ description: notEmpty("description"),
45
+ unit_label: notEmpty("unit_label"),
46
+ images: (params) => {
47
+ if (!Array.isArray(params.images))
48
+ return;
49
+ params.images.forEach((image, index) => {
50
+ if (typeof image === "string")
51
+ validateUrl(image, `images[${index}]`);
52
+ });
53
+ },
54
+ url: notEmpty("url"),
55
+ statement_descriptor: (params) => {
56
+ const descriptor = params.statement_descriptor;
57
+ if (typeof descriptor !== "string" || descriptor === "")
58
+ return;
59
+ if (descriptor !== current?.statement_descriptor)
60
+ validateStatementDescriptor(descriptor);
61
+ },
62
+ };
63
+ };
64
+ /** Stripe validates the URL itself only after every other parameter has been accepted. */
65
+ const validateProductUrl = (params) => {
66
+ if (typeof params.url === "string" && params.url !== "")
67
+ validateUrl(params.url, "url", PRODUCT_URL_LENGTH_LIMIT);
68
+ };
69
+ const apply = (current, params, now) => {
70
+ const next = { ...current, updated: now };
71
+ next.active = optionalBoolean(params, "active", current.active) ?? true;
72
+ next.description = optionalString(params, "description", current.description);
73
+ if (params.images !== undefined)
74
+ next.images = params.images === "" ? [] : params.images;
75
+ if (params.marketing_features !== undefined)
76
+ next.marketing_features =
77
+ params.marketing_features === "" ? [] : params.marketing_features;
78
+ next.metadata = mergeMetadata(current.metadata, params.metadata);
79
+ if (typeof params.name === "string")
80
+ next.name = strip(params.name);
81
+ if (params.package_dimensions !== undefined) {
82
+ next.package_dimensions =
83
+ params.package_dimensions === "" ? null : params.package_dimensions;
84
+ }
85
+ next.shippable = optionalBoolean(params, "shippable", current.shippable);
86
+ next.statement_descriptor = strippedString(params, "statement_descriptor", current.statement_descriptor);
87
+ next.unit_label = optionalString(params, "unit_label", current.unit_label);
88
+ if (params.url !== undefined)
89
+ next.url = params.url;
90
+ return next;
91
+ };
92
+ export const requireProduct = (scope, id, param, status = 404) => {
93
+ const product = scope.account.products.get(id);
94
+ if (!product)
95
+ throw resourceMissing("product", id, param, status);
96
+ return product;
97
+ };
98
+ const expanders = (scope) => ({
99
+ default_price: (id) => {
100
+ const price = scope.account.prices.get(id);
101
+ return price ? renderPrice(price) : undefined;
102
+ },
103
+ });
104
+ export const productHandlers = (services) => {
105
+ const render = (scope, product, params) => applyExpand(renderProduct(product), params.expand, expanders(scope));
106
+ return {
107
+ PostProducts: async (context) => {
108
+ const scope = requestScope(services, context);
109
+ const params = bodyParams(context, {
110
+ order: PRODUCT_PARAM_ORDER,
111
+ validate: productValidators("create", undefined),
112
+ after: validateProductUrl,
113
+ });
114
+ const now = seconds(scope.now);
115
+ const id = scope.ids.next("prod_");
116
+ const base = {
117
+ id,
118
+ active: true,
119
+ created: now,
120
+ description: null,
121
+ images: [],
122
+ marketing_features: [],
123
+ metadata: {},
124
+ name: "",
125
+ package_dimensions: null,
126
+ shippable: null,
127
+ statement_descriptor: null,
128
+ unit_label: null,
129
+ updated: now,
130
+ url: null,
131
+ };
132
+ const product = apply(base, params, now);
133
+ scope.account.products.insert(id, product);
134
+ scope.emit("product.created", render(scope, product, params));
135
+ return jsonResponse(200, render(scope, product, params));
136
+ },
137
+ GetProducts: async (context) => {
138
+ const scope = requestScope(services, context);
139
+ const params = queryParams(context);
140
+ const ids = params.ids;
141
+ if (ids !== undefined) {
142
+ for (const cursor of ["starting_after", "ending_before"]) {
143
+ if (typeof params[cursor] === "string" && params[cursor] !== "")
144
+ throw invalidRequest(`You may only specify one of these parameters: ids, ${cursor}.`, "ids");
145
+ }
146
+ }
147
+ const url = params.url;
148
+ const page = await paginate(scope.account.products, params, {
149
+ url: "/v1/products",
150
+ kind: "product",
151
+ where: (product) => matchesCreated(product.created, params.created) &&
152
+ (params.active === undefined || product.active === params.active) &&
153
+ (params.shippable === undefined || product.shippable === params.shippable) &&
154
+ (url === undefined || url === "" || product.url === url) &&
155
+ (ids === undefined || ids.includes(product.id)),
156
+ render: renderProduct,
157
+ });
158
+ return jsonResponse(200, applyExpand(page, params.expand, expanders(scope)));
159
+ },
160
+ GetProductsSearch: async (context) => {
161
+ const scope = requestScope(services, context);
162
+ const params = queryParams(context);
163
+ const records = scope.account.products.list({ order: "newest" }).map((entry) => entry.value);
164
+ const page = searchRecords(records, params, {
165
+ url: "/v1/products/search",
166
+ render: renderProduct,
167
+ });
168
+ return jsonResponse(200, applyExpand(page, params.expand, expanders(scope)));
169
+ },
170
+ GetProductsId: async (context) => {
171
+ const scope = requestScope(services, context);
172
+ const params = queryParams(context);
173
+ return jsonResponse(200, render(scope, requireProduct(scope, context.params.id ?? "", "id"), params));
174
+ },
175
+ PostProductsId: async (context) => {
176
+ const scope = requestScope(services, context);
177
+ const id = context.params.id ?? "";
178
+ const current = requireProduct(scope, id, "id");
179
+ const params = bodyParams(context, {
180
+ order: PRODUCT_PARAM_ORDER,
181
+ validate: productValidators("update", current),
182
+ after: validateProductUrl,
183
+ });
184
+ const product = apply(current, params, seconds(scope.now));
185
+ scope.account.products.update(id, product);
186
+ scope.emit("product.updated", render(scope, product, params));
187
+ return jsonResponse(200, render(scope, product, params));
188
+ },
189
+ DeleteProductsId: async (context) => {
190
+ const scope = requestScope(services, context);
191
+ const id = context.params.id ?? "";
192
+ requireProduct(scope, id, "id");
193
+ const prices = scope.account.prices.list({ where: (price) => price.product === id });
194
+ if (prices.length > 0)
195
+ throw invalidRequest("This product cannot be deleted because it has one or more user-created prices.");
196
+ scope.account.products.delete(id);
197
+ scope.emit("product.deleted", renderDeletedProduct(id));
198
+ return jsonResponse(200, renderDeletedProduct(id));
199
+ },
200
+ };
201
+ };
202
+ //# sourceMappingURL=products.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"products.js","sourceRoot":"","sources":["../src/products.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { type OperationHandler } from "@crvouga/mockingbird-service";
2
+ import { type Services } from "./internal.js";
3
+ export declare const promotionCodeHandlers: (services: Services) => Record<string, OperationHandler>;
4
+ //# sourceMappingURL=promotion-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-codes.d.ts","sourceRoot":"","sources":["../src/promotion-codes.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAML,KAAK,QAAQ,EACd,MAAM,eAAe,CAAA;AA8HtB,eAAO,MAAM,qBAAqB,GAAI,UAAU,QAAQ,KAAG,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAwFzF,CAAA"}
@@ -0,0 +1,193 @@
1
+ import { jsonResponse, } from "@crvouga/mockingbird-service";
2
+ import { parameterMissing, resourceMissing } from "./errors.js";
3
+ import { mergeRecordMetadata, requestScope, requireCoupon, requireLiveCustomer, } from "./internal.js";
4
+ import { matchesCreated, paginate } from "./list.js";
5
+ import { bodyParams, queryParams } from "./params.js";
6
+ import { renderCoupon, renderCustomer, renderProduct, renderPromotionCode } from "./render.js";
7
+ import { seconds } from "./state.js";
8
+ const formRecord = (context) => {
9
+ if (context.body.kind !== "form" ||
10
+ typeof context.body.value !== "object" ||
11
+ context.body.value === null)
12
+ return {};
13
+ return context.body.value;
14
+ };
15
+ const parsedBody = (context, omitted, injectPromotion) => {
16
+ const raw = formRecord(context);
17
+ const value = { ...raw };
18
+ for (const key of omitted) {
19
+ // The schema now accepts open nested objects; strip only empty strings, which Stripe treats
20
+ // as an unset value and which the object parser otherwise rejects.
21
+ if (value[key] === "")
22
+ delete value[key];
23
+ }
24
+ if (injectPromotion && value.promotion === undefined) {
25
+ const coupon = raw.coupon;
26
+ value.promotion = { type: "coupon", coupon: typeof coupon === "string" ? coupon : "" };
27
+ }
28
+ return bodyParams({ ...context, body: { kind: "form", value } });
29
+ };
30
+ const stringOf = (params, key) => {
31
+ const value = params[key];
32
+ return typeof value === "string" && value !== "" ? value : null;
33
+ };
34
+ const boolOf = (value, fallback) => {
35
+ if (typeof value === "boolean")
36
+ return value;
37
+ if (typeof value === "string")
38
+ return value === "true";
39
+ return fallback;
40
+ };
41
+ const numberOrNull = (value) => {
42
+ if (typeof value === "number" && Number.isFinite(value))
43
+ return Math.trunc(value);
44
+ if (typeof value === "string" && value !== "") {
45
+ const parsed = Number(value);
46
+ if (Number.isFinite(parsed))
47
+ return Math.trunc(parsed);
48
+ }
49
+ return null;
50
+ };
51
+ const restrictionsOf = (value) => {
52
+ if (value === undefined)
53
+ return undefined;
54
+ if (value === "" || typeof value !== "object" || value === null || Array.isArray(value))
55
+ return { first_time_transaction: false, minimum_amount: null, minimum_amount_currency: null };
56
+ const source = value;
57
+ const currency = source.minimum_amount_currency;
58
+ return {
59
+ first_time_transaction: boolOf(source.first_time_transaction, false),
60
+ minimum_amount: numberOrNull(source.minimum_amount),
61
+ minimum_amount_currency: typeof currency === "string" && currency !== "" ? currency : null,
62
+ };
63
+ };
64
+ const expansionPaths = (expand) => Array.isArray(expand)
65
+ ? expand.filter((path) => typeof path === "string")
66
+ : typeof expand === "string" && expand !== ""
67
+ ? [expand]
68
+ : [];
69
+ const renderCouponWithProducts = (scope, coupon) => {
70
+ const rendered = renderCoupon(coupon);
71
+ rendered.applies_to = {
72
+ products: coupon.applies_to_products.map((id) => {
73
+ const product = scope.account.products.get(id);
74
+ return product ? renderProduct(product) : id;
75
+ }),
76
+ };
77
+ return rendered;
78
+ };
79
+ const renderPromotionExpanded = (scope, promotion, expand) => {
80
+ const rendered = renderPromotionCode(promotion);
81
+ const paths = expansionPaths(expand);
82
+ const couponPath = paths.some((path) => path === "coupon" ||
83
+ path === "data.coupon" ||
84
+ path === "coupon.applies_to" ||
85
+ path === "data.coupon.applies_to");
86
+ if (couponPath) {
87
+ const coupon = scope.account.coupons.get(promotion.coupon);
88
+ if (coupon) {
89
+ rendered.coupon = paths.some((path) => path === "coupon.applies_to" || path === "data.coupon.applies_to")
90
+ ? renderCouponWithProducts(scope, coupon)
91
+ : renderCoupon(coupon);
92
+ }
93
+ }
94
+ if (paths.some((path) => path === "customer" || path === "data.customer") &&
95
+ promotion.customer !== null) {
96
+ const customer = scope.account.customers.get(promotion.customer);
97
+ if (customer?.kind === "live")
98
+ rendered.customer = renderCustomer(customer.customer);
99
+ }
100
+ return rendered;
101
+ };
102
+ export const promotionCodeHandlers = (services) => {
103
+ const create = async (context) => {
104
+ const scope = requestScope(services, context);
105
+ const params = parsedBody(context, ["metadata", "restrictions"], true);
106
+ const raw = formRecord(context);
107
+ const promotion = raw.promotion;
108
+ const nestedCoupon = typeof promotion === "object" && promotion !== null && !Array.isArray(promotion)
109
+ ? promotion.coupon
110
+ : undefined;
111
+ const couponId = typeof raw.coupon === "string" && raw.coupon !== "" ? raw.coupon : nestedCoupon;
112
+ if (typeof couponId !== "string" || couponId === "")
113
+ throw parameterMissing("coupon");
114
+ requireCoupon(scope, couponId);
115
+ const customer = stringOf(params, "customer");
116
+ if (customer !== null)
117
+ requireLiveCustomer(scope, customer);
118
+ const code = stringOf(params, "code");
119
+ if (code === null)
120
+ throw parameterMissing("code");
121
+ const restrictions = restrictionsOf(raw.restrictions) ?? {
122
+ first_time_transaction: false,
123
+ minimum_amount: null,
124
+ minimum_amount_currency: null,
125
+ };
126
+ const id = scope.ids.next("promo_");
127
+ const record = {
128
+ id,
129
+ active: typeof params.active === "boolean" ? params.active : true,
130
+ code,
131
+ coupon: couponId,
132
+ created: seconds(scope.now),
133
+ customer,
134
+ expires_at: typeof params.expires_at === "number" ? params.expires_at : null,
135
+ max_redemptions: typeof params.max_redemptions === "number" ? params.max_redemptions : null,
136
+ metadata: mergeRecordMetadata({}, raw.metadata),
137
+ restrictions,
138
+ times_redeemed: 0,
139
+ };
140
+ scope.account.promotionCodes.insert(id, record);
141
+ return jsonResponse(200, renderPromotionExpanded(scope, record, params.expand));
142
+ };
143
+ return {
144
+ GetPromotionCodes: async (context) => {
145
+ const scope = requestScope(services, context);
146
+ const params = queryParams(context);
147
+ const code = stringOf(params, "code");
148
+ const customer = stringOf(params, "customer");
149
+ const coupon = stringOf(params, "coupon");
150
+ const active = typeof params.active === "boolean" ? params.active : undefined;
151
+ const page = await paginate(scope.account.promotionCodes, params, {
152
+ url: "/v1/promotion_codes",
153
+ kind: "promotion_code",
154
+ where: (record) => matchesCreated(record.created, params.created) &&
155
+ (code === null || record.code === code) &&
156
+ (customer === null || record.customer === customer) &&
157
+ (coupon === null || record.coupon === coupon) &&
158
+ (active === undefined || record.active === active),
159
+ render: (record) => renderPromotionExpanded(scope, record, params.expand),
160
+ });
161
+ return jsonResponse(200, page);
162
+ },
163
+ PostPromotionCodes: create,
164
+ GetPromotionCodesPromotionCode: async (context) => {
165
+ const scope = requestScope(services, context);
166
+ const params = queryParams(context);
167
+ const id = context.params.promotion_code ?? "";
168
+ const record = scope.account.promotionCodes.get(id);
169
+ if (!record)
170
+ throw resourceMissing("promotion_code", id, "promotion_code");
171
+ return jsonResponse(200, renderPromotionExpanded(scope, record, params.expand));
172
+ },
173
+ PostPromotionCodesPromotionCode: async (context) => {
174
+ const scope = requestScope(services, context);
175
+ const params = parsedBody(context, ["metadata", "restrictions"], false);
176
+ const id = context.params.promotion_code ?? "";
177
+ const current = scope.account.promotionCodes.get(id);
178
+ if (!current)
179
+ throw resourceMissing("promotion_code", id, "promotion_code");
180
+ const raw = formRecord(context);
181
+ const restrictions = restrictionsOf(raw.restrictions);
182
+ const next = {
183
+ ...current,
184
+ active: typeof params.active === "boolean" ? params.active : current.active,
185
+ metadata: mergeRecordMetadata(current.metadata, raw.metadata),
186
+ restrictions: restrictions ?? current.restrictions,
187
+ };
188
+ scope.account.promotionCodes.update(id, next);
189
+ return jsonResponse(200, renderPromotionExpanded(scope, next, params.expand));
190
+ },
191
+ };
192
+ };
193
+ //# sourceMappingURL=promotion-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"promotion-codes.js","sourceRoot":"","sources":["../src/promotion-codes.ts"],"names":[],"mappings":"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"}