@carrierllc/sdk 0.2.14 → 0.2.16

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.
@@ -2950,7 +2950,7 @@
2950
2950
  "method": "PATCH",
2951
2951
  "path": "/v1/storefronts/{id}/plans/{slug}",
2952
2952
  "tag": "Storefront",
2953
- "summary": "Change the price, sale state, or display order of an existing plan. Omitted fields stay as stored. A plan on another storefront is not found.",
2953
+ "summary": "Change the price, sale state, display order, or stored Stripe Price of an existing plan. The Price id and its mode are set together; null clears both. The Price is stored, not yet charged. Omitted fields stay as stored. A plan on another storefront is not found.",
2954
2954
  "security": "bearer",
2955
2955
  "body": true,
2956
2956
  "bodyRequired": true,
@@ -14,6 +14,16 @@ export interface StorefrontBrandInput {
14
14
  tagline?: string;
15
15
  supportEmail?: string;
16
16
  legalName?: string;
17
+ address?: string;
18
+ locale?: "en" | "nl";
19
+ intro?: string;
20
+ ctaLabel?: string;
21
+ howHeading?: string;
22
+ plansHeading?: string;
23
+ buyLabel?: string;
24
+ emptyPlansText?: string;
25
+ searchHeading?: string;
26
+ searchPlaceholder?: string;
17
27
  }
18
28
  export interface StorefrontPlanInput {
19
29
  productId?: string;
@@ -32,6 +42,16 @@ export interface StorefrontPlanInput {
32
42
  active?: boolean;
33
43
  /** Display order on the storefront (ascending). Defaults to 0; ties fall back to slug. */
34
44
  sortOrder?: number;
45
+ /** Optional display section/group on the storefront. */
46
+ group?: string | null;
47
+ /** Optional ISO-8601 start timestamp from which the plan is visible. */
48
+ availableFrom?: string | null;
49
+ /** Optional ISO-8601 end timestamp until which the plan is visible. */
50
+ availableUntil?: string | null;
51
+ /** Existing Stripe Price id (`price_…`), stored, not yet charged. Null clears the id and the mode. Set with stripePriceMode. */
52
+ stripePriceId?: string | null;
53
+ /** `test` or `live`. Null clears the id and the mode. Set with stripePriceId. */
54
+ stripePriceMode?: "test" | "live" | null;
35
55
  }
36
56
  export interface ExistingStorefrontBrand {
37
57
  theme?: Record<string, unknown>;
@@ -52,6 +72,11 @@ export interface StorefrontPlanBody {
52
72
  description?: string;
53
73
  active?: boolean;
54
74
  sort_order?: number;
75
+ group?: string | null;
76
+ available_from?: string | null;
77
+ available_until?: string | null;
78
+ stripe_price_id?: string | null;
79
+ stripe_price_mode?: "test" | "live" | null;
55
80
  }
56
81
  export declare function storefrontBrandPatch(input: StorefrontBrandInput, existing?: ExistingStorefrontBrand): {
57
82
  theme?: Record<string, unknown>;
@@ -4,6 +4,8 @@
4
4
  * onto the store already saved before it is sent.
5
5
  */
6
6
  export { logoFileDataUrl, logoReference, majorToCents, parseCountryInput, parseDataGb, parseValidityDays, } from "./storefront-labels.js";
7
+ const STRIPE_PRICE_ID_RE = /^price_[A-Za-z0-9_]+$/;
8
+ const STRIPE_PRICE_ID_MAX_LENGTH = 255;
7
9
  const THEME_FIELDS = [
8
10
  ["accent", "accent"],
9
11
  ["accentDark", "accentDark"],
@@ -16,6 +18,16 @@ const COPY_FIELDS = [
16
18
  ["tagline", "tagline"],
17
19
  ["supportEmail", "supportEmail"],
18
20
  ["legalName", "legalName"],
21
+ ["address", "address"],
22
+ ["locale", "locale"],
23
+ ["intro", "intro"],
24
+ ["ctaLabel", "ctaLabel"],
25
+ ["howHeading", "howHeading"],
26
+ ["plansHeading", "plansHeading"],
27
+ ["buyLabel", "buyLabel"],
28
+ ["emptyPlansText", "emptyPlansText"],
29
+ ["searchHeading", "searchHeading"],
30
+ ["searchPlaceholder", "searchPlaceholder"],
19
31
  ];
20
32
  export function storefrontBrandPatch(input, existing) {
21
33
  const theme = overlay(existing?.theme, input, THEME_FIELDS);
@@ -43,6 +55,11 @@ export function completePlanInput(input, plans) {
43
55
  input.description,
44
56
  input.active,
45
57
  input.sortOrder,
58
+ input.group,
59
+ input.availableFrom,
60
+ input.availableUntil,
61
+ input.stripePriceId,
62
+ input.stripePriceMode,
46
63
  ].some((value) => value !== undefined);
47
64
  if (!touched)
48
65
  return input;
@@ -72,6 +89,12 @@ export function storefrontPlanBody(input) {
72
89
  if (input.accountId !== undefined && (!Number.isSafeInteger(input.accountId) || input.accountId <= 0)) {
73
90
  return { error: "OCS account id must be a positive integer." };
74
91
  }
92
+ const stripe = stripePriceFields(input.stripePriceId, input.stripePriceMode);
93
+ if (stripe && "error" in stripe)
94
+ return stripe;
95
+ const windowFields = planWindowFields(input);
96
+ if (windowFields && "error" in windowFields)
97
+ return windowFields;
75
98
  const productId = input.productId?.trim() ?? "";
76
99
  if (productId !== "") {
77
100
  const body = { product_id: productId };
@@ -83,7 +106,7 @@ export function storefrontPlanBody(input) {
83
106
  body.active = input.active;
84
107
  if (input.sortOrder !== undefined)
85
108
  body.sort_order = input.sortOrder;
86
- return body;
109
+ return { ...body, ...(windowFields ?? {}), ...(stripe ?? {}) };
87
110
  }
88
111
  const touched = [
89
112
  input.slug,
@@ -99,6 +122,11 @@ export function storefrontPlanBody(input) {
99
122
  input.description,
100
123
  input.active,
101
124
  input.sortOrder,
125
+ input.group,
126
+ input.availableFrom,
127
+ input.availableUntil,
128
+ input.stripePriceId,
129
+ input.stripePriceMode,
102
130
  ].some((value) => value !== undefined);
103
131
  if (!touched)
104
132
  return null;
@@ -135,7 +163,67 @@ export function storefrontPlanBody(input) {
135
163
  body.active = input.active;
136
164
  if (input.sortOrder !== undefined)
137
165
  body.sort_order = input.sortOrder;
138
- return body;
166
+ return { ...body, ...(windowFields ?? {}), ...(stripe ?? {}) };
167
+ }
168
+ function planWindowFields(input) {
169
+ const out = {};
170
+ let touched = false;
171
+ if (input.group !== undefined) {
172
+ out.group = input.group === null || input.group.trim() === "" ? null : input.group.trim().slice(0, 80);
173
+ touched = true;
174
+ }
175
+ if (input.availableFrom !== undefined) {
176
+ if (input.availableFrom === null || input.availableFrom.trim() === "") {
177
+ out.available_from = null;
178
+ }
179
+ else {
180
+ const ms = Date.parse(input.availableFrom.trim());
181
+ if (!Number.isFinite(ms))
182
+ return { error: "available_from must be an ISO-8601 date or timestamp." };
183
+ out.available_from = new Date(ms).toISOString();
184
+ }
185
+ touched = true;
186
+ }
187
+ if (input.availableUntil !== undefined) {
188
+ if (input.availableUntil === null || input.availableUntil.trim() === "") {
189
+ out.available_until = null;
190
+ }
191
+ else {
192
+ const trimmed = input.availableUntil.trim();
193
+ const expanded = /^\d{4}-\d{2}-\d{2}$/.test(trimmed) ? `${trimmed}T23:59:59.999Z` : trimmed;
194
+ const ms = Date.parse(expanded);
195
+ if (!Number.isFinite(ms))
196
+ return { error: "available_until must be an ISO-8601 date or timestamp." };
197
+ out.available_until = new Date(ms).toISOString();
198
+ }
199
+ touched = true;
200
+ }
201
+ if (out.available_from && out.available_until && Date.parse(out.available_from) > Date.parse(out.available_until)) {
202
+ return { error: "available_from must not be after available_until." };
203
+ }
204
+ return touched ? out : undefined;
205
+ }
206
+ /** Null clears both fields. A Price id and its mode are sent together. */
207
+ function stripePriceFields(id, mode) {
208
+ if (id === undefined && mode === undefined)
209
+ return undefined;
210
+ if (typeof id === "string") {
211
+ const trimmed = id.trim();
212
+ if (trimmed.length < 1 || trimmed.length > STRIPE_PRICE_ID_MAX_LENGTH || !STRIPE_PRICE_ID_RE.test(trimmed)) {
213
+ return { error: "stripe_price_id must look like price_… and be 1-255 characters." };
214
+ }
215
+ id = trimmed;
216
+ }
217
+ if (id === null || mode === null) {
218
+ if ((id !== undefined && id !== null) || (mode !== undefined && mode !== null)) {
219
+ return { error: "Sending null clears both stripe_price_id and stripe_price_mode." };
220
+ }
221
+ return { stripe_price_id: null, stripe_price_mode: null };
222
+ }
223
+ if (id === undefined || mode === undefined) {
224
+ return { error: "stripe_price_id and stripe_price_mode must be set together." };
225
+ }
226
+ return { stripe_price_id: id, stripe_price_mode: mode };
139
227
  }
140
228
  export function isStorefrontPlanError(value) {
141
229
  return value !== null && "error" in value;
package/dist/types.d.ts CHANGED
@@ -71,9 +71,11 @@ export interface HostedStorefront {
71
71
  ocs_package_template_id: number;
72
72
  ocs_account_id: number | null;
73
73
  account_status: "owned" | "not_owned" | "unset" | "unknown";
74
+ stripe_price_id?: string | null;
75
+ stripe_price_mode?: "test" | "live" | null;
74
76
  }>;
75
77
  }
76
- export type StorefrontPlanUpdateParams = Pick<StorefrontPlanParams, "price_cents" | "active" | "ocs_account_id"> & {
78
+ export type StorefrontPlanUpdateParams = Pick<StorefrontPlanParams, "price_cents" | "active" | "ocs_account_id" | "stripe_price_id" | "stripe_price_mode"> & {
77
79
  sort_order?: number;
78
80
  };
79
81
  export interface StorefrontPlanParams {
@@ -91,6 +93,10 @@ export interface StorefrontPlanParams {
91
93
  validity_days?: number;
92
94
  regions?: string[];
93
95
  active?: boolean;
96
+ /** Existing Stripe Price id (`price_…`), stored, not yet charged. Null clears the id and the mode. Set together with stripe_price_mode. */
97
+ stripe_price_id?: string | null;
98
+ /** `test` or `live`. Null clears the id and the mode. Set together with stripe_price_id. */
99
+ stripe_price_mode?: "test" | "live" | null;
94
100
  }
95
101
  export interface StorefrontCreateParams {
96
102
  slug: string;
package/dist/version.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Published version. Keep this equal to package.json. */
2
- export declare const SDK_VERSION = "0.2.14";
3
- export declare const USER_AGENT = "@carrierllc/sdk/0.2.14";
2
+ export declare const SDK_VERSION = "0.2.16";
3
+ export declare const USER_AGENT = "@carrierllc/sdk/0.2.16";
package/dist/version.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /** Published version. Keep this equal to package.json. */
2
- export const SDK_VERSION = "0.2.14";
2
+ export const SDK_VERSION = "0.2.16";
3
3
  export const USER_AGENT = `@carrierllc/sdk/${SDK_VERSION}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carrierllc/sdk",
3
- "version": "0.2.14",
3
+ "version": "0.2.16",
4
4
  "description": "TypeScript client for the Carrier API, MCP server, and CLI.",
5
5
  "license": "MIT",
6
6
  "type": "module",