@stripe/extensibility-dev-tools 0.23.7 → 0.24.3

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 (38) hide show
  1. package/dist/bin/build-custom-object-definitions.cjs +56 -21
  2. package/dist/bin/build-custom-object-definitions.js +56 -21
  3. package/dist/bin/create-upload-image.cjs +63 -25
  4. package/dist/bin/create-upload-image.js +63 -25
  5. package/dist/bin/dev-tools-rpc.cjs +8 -7
  6. package/dist/bin/dev-tools-rpc.js +8 -7
  7. package/dist/bin/gen-workspace.cjs +8 -7
  8. package/dist/bin/gen-workspace.js +8 -7
  9. package/dist/bin/template-info.cjs +8 -7
  10. package/dist/bin/template-info.js +8 -7
  11. package/dist/custom-objects/build-definitions.d.ts.map +1 -1
  12. package/dist/custom-objects/to-proto-json.d.ts +2 -1
  13. package/dist/custom-objects/to-proto-json.d.ts.map +1 -1
  14. package/dist/dependencies/index.d.ts +7 -7
  15. package/dist/index.cjs +8 -7
  16. package/dist/index.js +8 -7
  17. package/dist/manifest/manifest-v2.d.ts +8 -3
  18. package/dist/templates/diff-viewer/types.d.ts +2 -2
  19. package/dist/templates/extensions/base.d.ts +4 -2
  20. package/dist/templates/extensions/core.workflows.custom_action.d.ts.map +1 -1
  21. package/dist/templates/extensions/types.d.ts +9 -3
  22. package/dist/templates/file-writer.d.ts +2 -2
  23. package/dist/templates/index.cjs +8 -7
  24. package/dist/templates/index.js +8 -7
  25. package/dist/templates/root/index.d.ts +1 -1
  26. package/dist/tsconfig.build.tsbuildinfo +1 -1
  27. package/dist/workspace/index.cjs +8 -7
  28. package/dist/workspace/index.d.ts +34 -30
  29. package/dist/workspace/index.js +8 -7
  30. package/package.json +3 -3
  31. package/templates/extensions/billing.bill.discount_calculation/index.ts +1 -1
  32. package/templates/extensions/billing.customer_balance_application/index.ts +1 -1
  33. package/templates/extensions/billing.invoice_collection_setting/index.ts +1 -1
  34. package/templates/extensions/billing.prorations/index.ts +1 -1
  35. package/templates/extensions/billing.recurring_billing_item_handling/index.ts +1 -1
  36. package/templates/extensions/core.workflows.custom_action/index.ts +1 -1
  37. package/templates/extensions/extend.workflows.custom_action/index.ts +1 -1
  38. package/dist/api-surface.d.ts.map +0 -1
@@ -328,7 +328,7 @@ describe('MyDiscountCalculation', () => {
328
328
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
329
329
 
330
330
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
331
- interface MyDiscountCalculationConfig extends Record<string, unknown> {}
331
+ interface MyDiscountCalculationConfig {}
332
332
 
333
333
  export default class MyDiscountCalculation implements Billing.Bill
334
334
  .DiscountCalculation<MyDiscountCalculationConfig> {
@@ -370,7 +370,7 @@ describe('MyBalanceApp', () => {
370
370
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
371
371
 
372
372
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
373
- interface MyBalanceAppConfig extends Record<string, unknown> {}
373
+ interface MyBalanceAppConfig {}
374
374
 
375
375
  export default class MyBalanceApp implements Billing.CustomerBalanceApplication<MyBalanceAppConfig> {
376
376
  computeAppliedCustomerBalance(
@@ -411,7 +411,7 @@ describe('MyInvoiceCollectionSetting', () => {
411
411
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
412
412
 
413
413
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
414
- interface MyInvoiceCollectionSettingConfig extends Record<string, unknown> {}
414
+ interface MyInvoiceCollectionSettingConfig {}
415
415
 
416
416
  export default class MyInvoiceCollectionSetting implements Billing.InvoiceCollectionSetting<MyInvoiceCollectionSettingConfig> {
417
417
  collectionOverride(
@@ -450,7 +450,7 @@ describe('MyProrations', () => {
450
450
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
451
451
 
452
452
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
453
- interface MyProrationsConfig extends Record<string, unknown> {}
453
+ interface MyProrationsConfig {}
454
454
 
455
455
  export default class MyProrations implements Billing.Prorations<MyProrationsConfig> {
456
456
  prorateItems(
@@ -491,7 +491,7 @@ describe('MyRecurringBillingItemHandling', () => {
491
491
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
492
492
 
493
493
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
494
- interface MyRecurringBillingItemHandlingConfig extends Record<string, unknown> {}
494
+ interface MyRecurringBillingItemHandlingConfig {}
495
495
 
496
496
  export default class MyRecurringBillingItemHandling implements Billing.RecurringBillingItemHandling<MyRecurringBillingItemHandlingConfig> {
497
497
  beforeItemCreation(
@@ -741,7 +741,7 @@ describe('MyCustomAction', () => {
741
741
  content: `import type { Core, Context } from '@stripe/extensibility-sdk';
742
742
 
743
743
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
744
- interface MyCustomActionConfig extends Record<string, unknown> {}
744
+ interface MyCustomActionConfig {}
745
745
 
746
746
  export default class MyCustomAction implements Core.Workflows
747
747
  .CustomAction<MyCustomActionConfig> {
@@ -804,7 +804,7 @@ describe('MyCustomAction', () => {
804
804
  content: `import type { Extend, Context } from '@stripe/extensibility-sdk';
805
805
 
806
806
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
807
- interface MyCustomActionConfig extends Record<string, unknown> {}
807
+ interface MyCustomActionConfig {}
808
808
 
809
809
  export default class MyCustomAction implements Extend.Workflows
810
810
  .CustomAction<MyCustomActionConfig> {
@@ -1328,6 +1328,7 @@ function _createBaseOutput(params, context) {
1328
1328
  // src/templates/extensions/core.workflows.custom_action.ts
1329
1329
  var EXTENSION_INTERFACE_ID = "core.workflows.custom_action";
1330
1330
  var customActionTemplate = {
1331
+ deprecated: true,
1331
1332
  methods: {
1332
1333
  execute: { implementation_types: ["script", "remote-function"] },
1333
1334
  get_form_state: { implementation_types: ["script", "remote-function"] }
@@ -1784,10 +1785,11 @@ function mapActions(actions) {
1784
1785
  }
1785
1786
  function mapProperties(schema) {
1786
1787
  const result = {};
1787
- const requiredSet = new Set(schema?.required ?? []);
1788
- if (!schema?.properties) return result;
1789
- const defs = schema.$defs ?? {};
1790
- for (const [key, propSchema] of Object.entries(schema.properties)) {
1788
+ const resolvedSchema = schema === null || schema === void 0 ? schema : resolveRef(schema, schema.$defs ?? {});
1789
+ const requiredSet = new Set(resolvedSchema?.required ?? []);
1790
+ if (!resolvedSchema?.properties) return result;
1791
+ const defs = resolvedSchema.$defs ?? {};
1792
+ for (const [key, propSchema] of Object.entries(resolvedSchema.properties)) {
1791
1793
  result[key] = toFieldSchema(resolveRef(propSchema, defs), requiredSet.has(key));
1792
1794
  }
1793
1795
  return result;
@@ -1831,7 +1833,13 @@ function toFieldSchema(schema, required) {
1831
1833
  fieldSchema.valuesPresence = FieldPresence.PRESENT;
1832
1834
  }
1833
1835
  if (schema.default !== void 0) {
1834
- fieldSchema.default = toDefaultValue(schema.default, fieldSchema.type);
1836
+ if (dataType === DataType.ENUM_TYPE && enumValues) {
1837
+ validateEnumDefault(schema.default, enumValues);
1838
+ }
1839
+ if (dataType === DataType.DATETIME_TYPE) {
1840
+ validateDatetimeDefault(schema.default);
1841
+ }
1842
+ fieldSchema.default = toDefaultValue(schema.default, dataType);
1835
1843
  }
1836
1844
  return fieldSchema;
1837
1845
  }
@@ -1843,7 +1851,6 @@ function resolveDataType(schema, enumValues, refTarget) {
1843
1851
  if (schema.format === "date-time") return DataType.DATETIME_TYPE;
1844
1852
  return DataType.STRING_TYPE;
1845
1853
  case "integer":
1846
- case "number":
1847
1854
  return DataType.INTEGER_TYPE;
1848
1855
  case "boolean":
1849
1856
  return DataType.BOOLEAN_TYPE;
@@ -1880,33 +1887,61 @@ function extractSingleLiteral(schema) {
1880
1887
  return null;
1881
1888
  }
1882
1889
  function extractEnumValues(schema) {
1883
- if (schema.enum) {
1890
+ if (Array.isArray(schema.enum) && schema.enum.every((value) => typeof value === "string")) {
1884
1891
  return schema.enum.map(String);
1885
1892
  }
1886
- if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every((item) => "const" in item)) {
1893
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every(
1894
+ (item) => "const" in item && typeof item.const === "string"
1895
+ )) {
1887
1896
  return schema.oneOf.map((item) => String(item.const));
1888
1897
  }
1889
1898
  return null;
1890
1899
  }
1900
+ function validateEnumDefault(value, enumValues) {
1901
+ if (typeof value !== "string" || !enumValues.includes(value)) {
1902
+ throw new Error(
1903
+ `Default value ${JSON.stringify(value)} is not a valid enum value. Expected one of: ${enumValues.join(", ")}`
1904
+ );
1905
+ }
1906
+ }
1907
+ var DATETIME_UTC_MS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|\+00:00)$/;
1908
+ function validateDatetimeDefault(value) {
1909
+ if (typeof value !== "string" || !DATETIME_UTC_MS_RE.test(value)) {
1910
+ throw new Error(
1911
+ `Default value ${JSON.stringify(value)} is not a valid ISO 8601 UTC datetime with millisecond precision. Expected format: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ss.sss+00:00`
1912
+ );
1913
+ }
1914
+ }
1891
1915
  function toValueBoundary(value) {
1892
1916
  if (!Number.isInteger(value)) {
1893
1917
  throw new Error(
1894
1918
  `ValueBoundary only supports integers, got ${String(value)}. Custom object numeric fields are integer-only.`
1895
1919
  );
1896
1920
  }
1897
- return { value: { $case: "integerBoundary", value } };
1921
+ return { integerBoundary: value };
1898
1922
  }
1899
1923
  function toDefaultValue(value, dataType) {
1900
1924
  if (dataType === DataType.STRING_TYPE && typeof value === "string") {
1901
- return { value: { $case: "stringDefault", value } };
1925
+ return { stringDefault: value };
1926
+ }
1927
+ if (dataType === DataType.ENUM_TYPE && typeof value === "string") {
1928
+ return { stringDefault: value };
1929
+ }
1930
+ if (dataType === DataType.DATETIME_TYPE && typeof value === "string") {
1931
+ return { stringDefault: value };
1902
1932
  }
1903
1933
  if (dataType === DataType.INTEGER_TYPE && typeof value === "number") {
1904
- return { value: { $case: "integerDefault", value } };
1934
+ if (!Number.isInteger(value)) {
1935
+ throw new Error(
1936
+ `Integer default values must be whole numbers, got ${JSON.stringify(value)}.`
1937
+ );
1938
+ }
1939
+ return { integerDefault: value };
1905
1940
  }
1906
1941
  if (dataType === DataType.BOOLEAN_TYPE && typeof value === "boolean") {
1907
- return { value: { $case: "booleanDefault", value } };
1942
+ return { booleanDefault: value };
1908
1943
  }
1909
- return { value: void 0 };
1944
+ return {};
1910
1945
  }
1911
1946
 
1912
1947
  // src/custom-objects/build-definitions.ts
@@ -1936,7 +1971,7 @@ async function analyzeAndInjectManifest(options) {
1936
1971
  (diagnostic) => diagnostic.severity === "error"
1937
1972
  );
1938
1973
  if (errorDiagnostics.length > 0) {
1939
- const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("; ");
1974
+ const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("\n");
1940
1975
  throw new Error(details);
1941
1976
  }
1942
1977
  const coPackageJsonPath = path2.join(projectRoot, "custom-objects", "package.json");
@@ -305,7 +305,7 @@ describe('MyDiscountCalculation', () => {
305
305
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
306
306
 
307
307
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
308
- interface MyDiscountCalculationConfig extends Record<string, unknown> {}
308
+ interface MyDiscountCalculationConfig {}
309
309
 
310
310
  export default class MyDiscountCalculation implements Billing.Bill
311
311
  .DiscountCalculation<MyDiscountCalculationConfig> {
@@ -347,7 +347,7 @@ describe('MyBalanceApp', () => {
347
347
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
348
348
 
349
349
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
350
- interface MyBalanceAppConfig extends Record<string, unknown> {}
350
+ interface MyBalanceAppConfig {}
351
351
 
352
352
  export default class MyBalanceApp implements Billing.CustomerBalanceApplication<MyBalanceAppConfig> {
353
353
  computeAppliedCustomerBalance(
@@ -388,7 +388,7 @@ describe('MyInvoiceCollectionSetting', () => {
388
388
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
389
389
 
390
390
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
391
- interface MyInvoiceCollectionSettingConfig extends Record<string, unknown> {}
391
+ interface MyInvoiceCollectionSettingConfig {}
392
392
 
393
393
  export default class MyInvoiceCollectionSetting implements Billing.InvoiceCollectionSetting<MyInvoiceCollectionSettingConfig> {
394
394
  collectionOverride(
@@ -427,7 +427,7 @@ describe('MyProrations', () => {
427
427
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
428
428
 
429
429
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
430
- interface MyProrationsConfig extends Record<string, unknown> {}
430
+ interface MyProrationsConfig {}
431
431
 
432
432
  export default class MyProrations implements Billing.Prorations<MyProrationsConfig> {
433
433
  prorateItems(
@@ -468,7 +468,7 @@ describe('MyRecurringBillingItemHandling', () => {
468
468
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
469
469
 
470
470
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
471
- interface MyRecurringBillingItemHandlingConfig extends Record<string, unknown> {}
471
+ interface MyRecurringBillingItemHandlingConfig {}
472
472
 
473
473
  export default class MyRecurringBillingItemHandling implements Billing.RecurringBillingItemHandling<MyRecurringBillingItemHandlingConfig> {
474
474
  beforeItemCreation(
@@ -718,7 +718,7 @@ describe('MyCustomAction', () => {
718
718
  content: `import type { Core, Context } from '@stripe/extensibility-sdk';
719
719
 
720
720
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
721
- interface MyCustomActionConfig extends Record<string, unknown> {}
721
+ interface MyCustomActionConfig {}
722
722
 
723
723
  export default class MyCustomAction implements Core.Workflows
724
724
  .CustomAction<MyCustomActionConfig> {
@@ -781,7 +781,7 @@ describe('MyCustomAction', () => {
781
781
  content: `import type { Extend, Context } from '@stripe/extensibility-sdk';
782
782
 
783
783
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
784
- interface MyCustomActionConfig extends Record<string, unknown> {}
784
+ interface MyCustomActionConfig {}
785
785
 
786
786
  export default class MyCustomAction implements Extend.Workflows
787
787
  .CustomAction<MyCustomActionConfig> {
@@ -1305,6 +1305,7 @@ function _createBaseOutput(params, context) {
1305
1305
  // src/templates/extensions/core.workflows.custom_action.ts
1306
1306
  var EXTENSION_INTERFACE_ID = "core.workflows.custom_action";
1307
1307
  var customActionTemplate = {
1308
+ deprecated: true,
1308
1309
  methods: {
1309
1310
  execute: { implementation_types: ["script", "remote-function"] },
1310
1311
  get_form_state: { implementation_types: ["script", "remote-function"] }
@@ -1761,10 +1762,11 @@ function mapActions(actions) {
1761
1762
  }
1762
1763
  function mapProperties(schema) {
1763
1764
  const result = {};
1764
- const requiredSet = new Set(schema?.required ?? []);
1765
- if (!schema?.properties) return result;
1766
- const defs = schema.$defs ?? {};
1767
- for (const [key, propSchema] of Object.entries(schema.properties)) {
1765
+ const resolvedSchema = schema === null || schema === void 0 ? schema : resolveRef(schema, schema.$defs ?? {});
1766
+ const requiredSet = new Set(resolvedSchema?.required ?? []);
1767
+ if (!resolvedSchema?.properties) return result;
1768
+ const defs = resolvedSchema.$defs ?? {};
1769
+ for (const [key, propSchema] of Object.entries(resolvedSchema.properties)) {
1768
1770
  result[key] = toFieldSchema(resolveRef(propSchema, defs), requiredSet.has(key));
1769
1771
  }
1770
1772
  return result;
@@ -1808,7 +1810,13 @@ function toFieldSchema(schema, required) {
1808
1810
  fieldSchema.valuesPresence = FieldPresence.PRESENT;
1809
1811
  }
1810
1812
  if (schema.default !== void 0) {
1811
- fieldSchema.default = toDefaultValue(schema.default, fieldSchema.type);
1813
+ if (dataType === DataType.ENUM_TYPE && enumValues) {
1814
+ validateEnumDefault(schema.default, enumValues);
1815
+ }
1816
+ if (dataType === DataType.DATETIME_TYPE) {
1817
+ validateDatetimeDefault(schema.default);
1818
+ }
1819
+ fieldSchema.default = toDefaultValue(schema.default, dataType);
1812
1820
  }
1813
1821
  return fieldSchema;
1814
1822
  }
@@ -1820,7 +1828,6 @@ function resolveDataType(schema, enumValues, refTarget) {
1820
1828
  if (schema.format === "date-time") return DataType.DATETIME_TYPE;
1821
1829
  return DataType.STRING_TYPE;
1822
1830
  case "integer":
1823
- case "number":
1824
1831
  return DataType.INTEGER_TYPE;
1825
1832
  case "boolean":
1826
1833
  return DataType.BOOLEAN_TYPE;
@@ -1857,33 +1864,61 @@ function extractSingleLiteral(schema) {
1857
1864
  return null;
1858
1865
  }
1859
1866
  function extractEnumValues(schema) {
1860
- if (schema.enum) {
1867
+ if (Array.isArray(schema.enum) && schema.enum.every((value) => typeof value === "string")) {
1861
1868
  return schema.enum.map(String);
1862
1869
  }
1863
- if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every((item) => "const" in item)) {
1870
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every(
1871
+ (item) => "const" in item && typeof item.const === "string"
1872
+ )) {
1864
1873
  return schema.oneOf.map((item) => String(item.const));
1865
1874
  }
1866
1875
  return null;
1867
1876
  }
1877
+ function validateEnumDefault(value, enumValues) {
1878
+ if (typeof value !== "string" || !enumValues.includes(value)) {
1879
+ throw new Error(
1880
+ `Default value ${JSON.stringify(value)} is not a valid enum value. Expected one of: ${enumValues.join(", ")}`
1881
+ );
1882
+ }
1883
+ }
1884
+ var DATETIME_UTC_MS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|\+00:00)$/;
1885
+ function validateDatetimeDefault(value) {
1886
+ if (typeof value !== "string" || !DATETIME_UTC_MS_RE.test(value)) {
1887
+ throw new Error(
1888
+ `Default value ${JSON.stringify(value)} is not a valid ISO 8601 UTC datetime with millisecond precision. Expected format: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ss.sss+00:00`
1889
+ );
1890
+ }
1891
+ }
1868
1892
  function toValueBoundary(value) {
1869
1893
  if (!Number.isInteger(value)) {
1870
1894
  throw new Error(
1871
1895
  `ValueBoundary only supports integers, got ${String(value)}. Custom object numeric fields are integer-only.`
1872
1896
  );
1873
1897
  }
1874
- return { value: { $case: "integerBoundary", value } };
1898
+ return { integerBoundary: value };
1875
1899
  }
1876
1900
  function toDefaultValue(value, dataType) {
1877
1901
  if (dataType === DataType.STRING_TYPE && typeof value === "string") {
1878
- return { value: { $case: "stringDefault", value } };
1902
+ return { stringDefault: value };
1903
+ }
1904
+ if (dataType === DataType.ENUM_TYPE && typeof value === "string") {
1905
+ return { stringDefault: value };
1906
+ }
1907
+ if (dataType === DataType.DATETIME_TYPE && typeof value === "string") {
1908
+ return { stringDefault: value };
1879
1909
  }
1880
1910
  if (dataType === DataType.INTEGER_TYPE && typeof value === "number") {
1881
- return { value: { $case: "integerDefault", value } };
1911
+ if (!Number.isInteger(value)) {
1912
+ throw new Error(
1913
+ `Integer default values must be whole numbers, got ${JSON.stringify(value)}.`
1914
+ );
1915
+ }
1916
+ return { integerDefault: value };
1882
1917
  }
1883
1918
  if (dataType === DataType.BOOLEAN_TYPE && typeof value === "boolean") {
1884
- return { value: { $case: "booleanDefault", value } };
1919
+ return { booleanDefault: value };
1885
1920
  }
1886
- return { value: void 0 };
1921
+ return {};
1887
1922
  }
1888
1923
 
1889
1924
  // src/custom-objects/build-definitions.ts
@@ -1913,7 +1948,7 @@ async function analyzeAndInjectManifest(options) {
1913
1948
  (diagnostic) => diagnostic.severity === "error"
1914
1949
  );
1915
1950
  if (errorDiagnostics.length > 0) {
1916
- const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("; ");
1951
+ const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("\n");
1917
1952
  throw new Error(details);
1918
1953
  }
1919
1954
  const coPackageJsonPath = path2.join(projectRoot, "custom-objects", "package.json");
@@ -28,6 +28,7 @@ var import_node_child_process2 = require("child_process");
28
28
  var fs3 = __toESM(require("fs"), 1);
29
29
  var os2 = __toESM(require("os"), 1);
30
30
  var path3 = __toESM(require("path"), 1);
31
+ var import_extensibility_tool_utils8 = require("@stripe/extensibility-tool-utils");
31
32
 
32
33
  // src/custom-objects/build-definitions.ts
33
34
  var fs2 = __toESM(require("fs"), 1);
@@ -331,7 +332,7 @@ describe('MyDiscountCalculation', () => {
331
332
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
332
333
 
333
334
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
334
- interface MyDiscountCalculationConfig extends Record<string, unknown> {}
335
+ interface MyDiscountCalculationConfig {}
335
336
 
336
337
  export default class MyDiscountCalculation implements Billing.Bill
337
338
  .DiscountCalculation<MyDiscountCalculationConfig> {
@@ -373,7 +374,7 @@ describe('MyBalanceApp', () => {
373
374
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
374
375
 
375
376
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
376
- interface MyBalanceAppConfig extends Record<string, unknown> {}
377
+ interface MyBalanceAppConfig {}
377
378
 
378
379
  export default class MyBalanceApp implements Billing.CustomerBalanceApplication<MyBalanceAppConfig> {
379
380
  computeAppliedCustomerBalance(
@@ -414,7 +415,7 @@ describe('MyInvoiceCollectionSetting', () => {
414
415
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
415
416
 
416
417
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
417
- interface MyInvoiceCollectionSettingConfig extends Record<string, unknown> {}
418
+ interface MyInvoiceCollectionSettingConfig {}
418
419
 
419
420
  export default class MyInvoiceCollectionSetting implements Billing.InvoiceCollectionSetting<MyInvoiceCollectionSettingConfig> {
420
421
  collectionOverride(
@@ -453,7 +454,7 @@ describe('MyProrations', () => {
453
454
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
454
455
 
455
456
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
456
- interface MyProrationsConfig extends Record<string, unknown> {}
457
+ interface MyProrationsConfig {}
457
458
 
458
459
  export default class MyProrations implements Billing.Prorations<MyProrationsConfig> {
459
460
  prorateItems(
@@ -494,7 +495,7 @@ describe('MyRecurringBillingItemHandling', () => {
494
495
  content: `import type { Billing, Context } from '@stripe/extensibility-sdk';
495
496
 
496
497
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
497
- interface MyRecurringBillingItemHandlingConfig extends Record<string, unknown> {}
498
+ interface MyRecurringBillingItemHandlingConfig {}
498
499
 
499
500
  export default class MyRecurringBillingItemHandling implements Billing.RecurringBillingItemHandling<MyRecurringBillingItemHandlingConfig> {
500
501
  beforeItemCreation(
@@ -744,7 +745,7 @@ describe('MyCustomAction', () => {
744
745
  content: `import type { Core, Context } from '@stripe/extensibility-sdk';
745
746
 
746
747
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
747
- interface MyCustomActionConfig extends Record<string, unknown> {}
748
+ interface MyCustomActionConfig {}
748
749
 
749
750
  export default class MyCustomAction implements Core.Workflows
750
751
  .CustomAction<MyCustomActionConfig> {
@@ -807,7 +808,7 @@ describe('MyCustomAction', () => {
807
808
  content: `import type { Extend, Context } from '@stripe/extensibility-sdk';
808
809
 
809
810
  // eslint-disable-next-line @typescript-eslint/no-empty-object-type
810
- interface MyCustomActionConfig extends Record<string, unknown> {}
811
+ interface MyCustomActionConfig {}
811
812
 
812
813
  export default class MyCustomAction implements Extend.Workflows
813
814
  .CustomAction<MyCustomActionConfig> {
@@ -1331,6 +1332,7 @@ function _createBaseOutput(params, context) {
1331
1332
  // src/templates/extensions/core.workflows.custom_action.ts
1332
1333
  var EXTENSION_INTERFACE_ID = "core.workflows.custom_action";
1333
1334
  var customActionTemplate = {
1335
+ deprecated: true,
1334
1336
  methods: {
1335
1337
  execute: { implementation_types: ["script", "remote-function"] },
1336
1338
  get_form_state: { implementation_types: ["script", "remote-function"] }
@@ -1787,10 +1789,11 @@ function mapActions(actions) {
1787
1789
  }
1788
1790
  function mapProperties(schema) {
1789
1791
  const result = {};
1790
- const requiredSet = new Set(schema?.required ?? []);
1791
- if (!schema?.properties) return result;
1792
- const defs = schema.$defs ?? {};
1793
- for (const [key, propSchema] of Object.entries(schema.properties)) {
1792
+ const resolvedSchema = schema === null || schema === void 0 ? schema : resolveRef(schema, schema.$defs ?? {});
1793
+ const requiredSet = new Set(resolvedSchema?.required ?? []);
1794
+ if (!resolvedSchema?.properties) return result;
1795
+ const defs = resolvedSchema.$defs ?? {};
1796
+ for (const [key, propSchema] of Object.entries(resolvedSchema.properties)) {
1794
1797
  result[key] = toFieldSchema(resolveRef(propSchema, defs), requiredSet.has(key));
1795
1798
  }
1796
1799
  return result;
@@ -1834,7 +1837,13 @@ function toFieldSchema(schema, required) {
1834
1837
  fieldSchema.valuesPresence = FieldPresence.PRESENT;
1835
1838
  }
1836
1839
  if (schema.default !== void 0) {
1837
- fieldSchema.default = toDefaultValue(schema.default, fieldSchema.type);
1840
+ if (dataType === DataType.ENUM_TYPE && enumValues) {
1841
+ validateEnumDefault(schema.default, enumValues);
1842
+ }
1843
+ if (dataType === DataType.DATETIME_TYPE) {
1844
+ validateDatetimeDefault(schema.default);
1845
+ }
1846
+ fieldSchema.default = toDefaultValue(schema.default, dataType);
1838
1847
  }
1839
1848
  return fieldSchema;
1840
1849
  }
@@ -1846,7 +1855,6 @@ function resolveDataType(schema, enumValues, refTarget) {
1846
1855
  if (schema.format === "date-time") return DataType.DATETIME_TYPE;
1847
1856
  return DataType.STRING_TYPE;
1848
1857
  case "integer":
1849
- case "number":
1850
1858
  return DataType.INTEGER_TYPE;
1851
1859
  case "boolean":
1852
1860
  return DataType.BOOLEAN_TYPE;
@@ -1883,33 +1891,61 @@ function extractSingleLiteral(schema) {
1883
1891
  return null;
1884
1892
  }
1885
1893
  function extractEnumValues(schema) {
1886
- if (schema.enum) {
1894
+ if (Array.isArray(schema.enum) && schema.enum.every((value) => typeof value === "string")) {
1887
1895
  return schema.enum.map(String);
1888
1896
  }
1889
- if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every((item) => "const" in item)) {
1897
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every(
1898
+ (item) => "const" in item && typeof item.const === "string"
1899
+ )) {
1890
1900
  return schema.oneOf.map((item) => String(item.const));
1891
1901
  }
1892
1902
  return null;
1893
1903
  }
1904
+ function validateEnumDefault(value, enumValues) {
1905
+ if (typeof value !== "string" || !enumValues.includes(value)) {
1906
+ throw new Error(
1907
+ `Default value ${JSON.stringify(value)} is not a valid enum value. Expected one of: ${enumValues.join(", ")}`
1908
+ );
1909
+ }
1910
+ }
1911
+ var DATETIME_UTC_MS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|\+00:00)$/;
1912
+ function validateDatetimeDefault(value) {
1913
+ if (typeof value !== "string" || !DATETIME_UTC_MS_RE.test(value)) {
1914
+ throw new Error(
1915
+ `Default value ${JSON.stringify(value)} is not a valid ISO 8601 UTC datetime with millisecond precision. Expected format: YYYY-MM-DDTHH:mm:ss.sssZ or YYYY-MM-DDTHH:mm:ss.sss+00:00`
1916
+ );
1917
+ }
1918
+ }
1894
1919
  function toValueBoundary(value) {
1895
1920
  if (!Number.isInteger(value)) {
1896
1921
  throw new Error(
1897
1922
  `ValueBoundary only supports integers, got ${String(value)}. Custom object numeric fields are integer-only.`
1898
1923
  );
1899
1924
  }
1900
- return { value: { $case: "integerBoundary", value } };
1925
+ return { integerBoundary: value };
1901
1926
  }
1902
1927
  function toDefaultValue(value, dataType) {
1903
1928
  if (dataType === DataType.STRING_TYPE && typeof value === "string") {
1904
- return { value: { $case: "stringDefault", value } };
1929
+ return { stringDefault: value };
1930
+ }
1931
+ if (dataType === DataType.ENUM_TYPE && typeof value === "string") {
1932
+ return { stringDefault: value };
1933
+ }
1934
+ if (dataType === DataType.DATETIME_TYPE && typeof value === "string") {
1935
+ return { stringDefault: value };
1905
1936
  }
1906
1937
  if (dataType === DataType.INTEGER_TYPE && typeof value === "number") {
1907
- return { value: { $case: "integerDefault", value } };
1938
+ if (!Number.isInteger(value)) {
1939
+ throw new Error(
1940
+ `Integer default values must be whole numbers, got ${JSON.stringify(value)}.`
1941
+ );
1942
+ }
1943
+ return { integerDefault: value };
1908
1944
  }
1909
1945
  if (dataType === DataType.BOOLEAN_TYPE && typeof value === "boolean") {
1910
- return { value: { $case: "booleanDefault", value } };
1946
+ return { booleanDefault: value };
1911
1947
  }
1912
- return { value: void 0 };
1948
+ return {};
1913
1949
  }
1914
1950
 
1915
1951
  // src/custom-objects/build-definitions.ts
@@ -1939,7 +1975,7 @@ async function analyzeAndInjectManifest(options) {
1939
1975
  (diagnostic) => diagnostic.severity === "error"
1940
1976
  );
1941
1977
  if (errorDiagnostics.length > 0) {
1942
- const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("; ");
1978
+ const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("\n");
1943
1979
  throw new Error(details);
1944
1980
  }
1945
1981
  const coPackageJsonPath = path2.join(projectRoot, "custom-objects", "package.json");
@@ -2076,16 +2112,18 @@ function readPackageDependencies(packageJsonPath) {
2076
2112
  }
2077
2113
 
2078
2114
  // src/bin/create-upload-image.ts
2115
+ var logger = (0, import_extensibility_tool_utils8._createLogger)({ name: "create-upload-image" });
2079
2116
  async function main() {
2117
+ const ctx = (0, import_extensibility_tool_utils8._createCliContext)();
2080
2118
  const targetPath = process.argv[2];
2081
2119
  if (!targetPath) {
2082
- console.error("Usage: create-upload-image <target-path>");
2120
+ ctx.ux.error("Usage: create-upload-image <target-path>");
2083
2121
  process.exit(1);
2084
2122
  }
2085
2123
  let state = null;
2086
2124
  const manifestPath = "stripe-app.yaml";
2087
2125
  if (fs3.existsSync(manifestPath)) {
2088
- state = await analyzeAndInjectManifest({ manifestPath });
2126
+ state = await analyzeAndInjectManifest({ manifestPath, context: ctx });
2089
2127
  }
2090
2128
  fs3.mkdirSync(targetPath, { recursive: true });
2091
2129
  const tarball = path3.join(os2.tmpdir(), `upload-image-${String(Date.now())}.tgz`);
@@ -2118,7 +2156,7 @@ async function main() {
2118
2156
  }
2119
2157
  }
2120
2158
  if (state) {
2121
- await writeCustomObjectArtifacts({ targetPath }, state);
2159
+ await writeCustomObjectArtifacts({ targetPath, context: ctx }, state);
2122
2160
  }
2123
2161
  const imageMetadata = JSON.stringify(
2124
2162
  { image: { version: "1.0", built: (/* @__PURE__ */ new Date()).toISOString() } },
@@ -2128,6 +2166,6 @@ async function main() {
2128
2166
  fs3.writeFileSync(path3.join(targetPath, ".image.json"), imageMetadata + "\n");
2129
2167
  }
2130
2168
  main().catch((err) => {
2131
- console.error(err);
2169
+ logger.error({ err }, "Unexpected error");
2132
2170
  process.exit(1);
2133
2171
  });