@stripe/extensibility-dev-tools 0.24.2 → 0.25.1

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 (62) hide show
  1. package/dist/bin/build-custom-object-definitions.cjs +203 -46
  2. package/dist/bin/build-custom-object-definitions.js +194 -37
  3. package/dist/bin/create-upload-image.cjs +206 -46
  4. package/dist/bin/create-upload-image.js +201 -41
  5. package/dist/bin/dev-tools-rpc.cjs +199 -59
  6. package/dist/bin/dev-tools-rpc.js +174 -34
  7. package/dist/bin/gen-workspace.cjs +187 -47
  8. package/dist/bin/gen-workspace.js +174 -34
  9. package/dist/bin/template-info.cjs +161 -30
  10. package/dist/bin/template-info.js +156 -25
  11. package/dist/custom-objects/build-definitions.d.ts.map +1 -1
  12. package/dist/custom-objects/generated/proto/custom_objects/pub/api/app_api/object_definitions_app_service.pb.d.ts +32 -0
  13. package/dist/custom-objects/generated/proto/custom_objects/pub/api/app_api/object_definitions_app_service.pb.d.ts.map +1 -1
  14. package/dist/custom-objects/generated/proto/google/protobuf/descriptor.pb.d.ts +2 -2
  15. package/dist/custom-objects/generated/proto/google/protobuf/wrappers.pb.d.ts +168 -0
  16. package/dist/custom-objects/generated/proto/google/protobuf/wrappers.pb.d.ts.map +1 -0
  17. package/dist/custom-objects/generated/proto/proto/extensions.pb.d.ts +4 -4
  18. package/dist/custom-objects/generated/proto/proto/extensions.pb.d.ts.map +1 -1
  19. package/dist/custom-objects/generated/proto/vendor/proto/model/common/common_model.pb.d.ts +1553 -0
  20. package/dist/custom-objects/generated/proto/vendor/proto/model/common/common_model.pb.d.ts.map +1 -0
  21. package/dist/custom-objects/generated/proto/vendor/proto/model/common/kronos_model.pb.d.ts +1372 -0
  22. package/dist/custom-objects/generated/proto/vendor/proto/model/common/kronos_model.pb.d.ts.map +1 -0
  23. package/dist/custom-objects/generated/proto/vendor/publicapi/api_group_enum.pb.d.ts +2 -0
  24. package/dist/custom-objects/generated/proto/vendor/publicapi/api_group_enum.pb.d.ts.map +1 -1
  25. package/dist/custom-objects/generated/proto/vendor/publicapi/extension_interface.pb.d.ts +2 -0
  26. package/dist/custom-objects/generated/proto/vendor/publicapi/extension_interface.pb.d.ts.map +1 -1
  27. package/dist/custom-objects/generated/proto/vendor/publicapi/feature_enum.pb.d.ts +14 -2
  28. package/dist/custom-objects/generated/proto/vendor/publicapi/feature_enum.pb.d.ts.map +1 -1
  29. package/dist/custom-objects/generated/proto/vendor/publicapi/http_error_status.pb.d.ts +6 -0
  30. package/dist/custom-objects/generated/proto/vendor/publicapi/http_error_status.pb.d.ts.map +1 -1
  31. package/dist/custom-objects/generated/proto/vendor/publicapi/rollout_configs.pb.d.ts +74 -0
  32. package/dist/custom-objects/generated/proto/vendor/publicapi/rollout_configs.pb.d.ts.map +1 -1
  33. package/dist/custom-objects/generated/proto/vendor/publicapi/v2ext.pb.d.ts +10 -3
  34. package/dist/custom-objects/generated/proto/vendor/publicapi/v2ext.pb.d.ts.map +1 -1
  35. package/dist/custom-objects/generated/proto/vendor/vext/privacy_unified_annotations.pb.d.ts +1 -0
  36. package/dist/custom-objects/generated/proto/vendor/vext/privacy_unified_annotations.pb.d.ts.map +1 -1
  37. package/dist/index.cjs +192 -52
  38. package/dist/index.js +174 -34
  39. package/dist/templates/extensions/billing.invoice_collection_options.d.ts +6 -0
  40. package/dist/templates/extensions/billing.invoice_collection_options.d.ts.map +1 -0
  41. package/dist/templates/index.cjs +174 -34
  42. package/dist/templates/index.js +172 -32
  43. package/dist/templates/root/index.d.ts.map +1 -1
  44. package/dist/tsconfig.build.tsbuildinfo +1 -1
  45. package/dist/workspace/index.cjs +183 -43
  46. package/dist/workspace/index.d.ts.map +1 -1
  47. package/dist/workspace/index.js +174 -34
  48. package/dist/workspace-versions.d.ts +26 -0
  49. package/dist/workspace-versions.d.ts.map +1 -0
  50. package/package.json +4 -4
  51. package/templates/extensions/billing.invoice_collection_options/index.test.ts +15 -0
  52. package/templates/extensions/billing.invoice_collection_options/index.ts +16 -0
  53. package/templates/root/custom-objects/eslint.config.mts +89 -0
  54. package/templates/root/custom-objects/package.json.mustache +2 -0
  55. package/templates/root/custom-objects/tsconfig.json +1 -0
  56. package/templates/root/custom-objects/vitest.config.mts +7 -0
  57. package/templates/root/package.json.mustache +1 -1
  58. package/templates/root/tools/test.mts +4 -2
  59. package/dist/templates/extensions/billing.invoice_collection_setting.d.ts +0 -6
  60. package/dist/templates/extensions/billing.invoice_collection_setting.d.ts.map +0 -1
  61. package/templates/extensions/billing.invoice_collection_setting/index.test.ts +0 -15
  62. package/templates/extensions/billing.invoice_collection_setting/index.ts +0 -16
@@ -365,35 +365,35 @@ export default class MyBalanceApp implements Billing.CustomerBalanceApplication<
365
365
  `
366
366
  },
367
367
  {
368
- path: "extensions/billing.invoice_collection_setting/index.test.ts",
368
+ path: "extensions/billing.invoice_collection_options/index.test.ts",
369
369
  content: `import { beforeEach, describe, it, expect } from 'vitest';
370
370
 
371
- import MyInvoiceCollectionSetting from './index.js';
371
+ import MyInvoiceCollectionOptions from './index.js';
372
372
 
373
- describe('MyInvoiceCollectionSetting', () => {
374
- let instance: MyInvoiceCollectionSetting;
373
+ describe('MyInvoiceCollectionOptions', () => {
374
+ let instance: MyInvoiceCollectionOptions;
375
375
 
376
376
  beforeEach(() => {
377
- instance = new MyInvoiceCollectionSetting();
377
+ instance = new MyInvoiceCollectionOptions();
378
378
  });
379
379
 
380
380
  it('should be constructable', () => {
381
- expect(instance).toBeInstanceOf(MyInvoiceCollectionSetting);
381
+ expect(instance).toBeInstanceOf(MyInvoiceCollectionOptions);
382
382
  });
383
383
  });
384
384
  `
385
385
  },
386
386
  {
387
- path: "extensions/billing.invoice_collection_setting/index.ts",
387
+ path: "extensions/billing.invoice_collection_options/index.ts",
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 {}
391
+ interface MyInvoiceCollectionOptionsConfig {}
392
392
 
393
- export default class MyInvoiceCollectionSetting implements Billing.InvoiceCollectionSetting<MyInvoiceCollectionSettingConfig> {
394
- collectionOverride(
395
- _request: Billing.InvoiceCollectionSetting.InvoiceCollectionRequest,
396
- _config: MyInvoiceCollectionSettingConfig,
393
+ export default class MyInvoiceCollectionOptions implements Billing.InvoiceCollectionOptions<MyInvoiceCollectionOptionsConfig> {
394
+ overrideOptions(
395
+ _request: Billing.InvoiceCollectionOptions.InvoiceCollectionOptionsInput,
396
+ _config: MyInvoiceCollectionOptionsConfig,
397
397
  _context: Context
398
398
  ) {
399
399
  // TODO: implement your collection setting logic here
@@ -865,6 +865,99 @@ install-deps.log
865
865
 
866
866
  # generated schemas
867
867
  generated
868
+ `
869
+ },
870
+ {
871
+ path: "root/custom-objects/eslint.config.mts",
872
+ content: `import eslint from '@eslint/js';
873
+ import { defineConfig } from 'eslint/config';
874
+ import tseslint from 'typescript-eslint';
875
+ import eslintConfigPrettier from 'eslint-config-prettier/flat';
876
+
877
+ import globals from 'globals';
878
+
879
+ import stripeAppsConfig from '@stripe/extensibility-eslint-plugin';
880
+ import customObjectsConfig from '@stripe/extensibility-eslint-plugin/custom-objects';
881
+
882
+ export default defineConfig([
883
+ eslint.configs.recommended,
884
+ ...tseslint.configs.recommended,
885
+ ...stripeAppsConfig,
886
+ ...customObjectsConfig,
887
+
888
+ // Global ignores
889
+ {
890
+ ignores: ['dist', 'generated', 'node_modules'],
891
+ },
892
+
893
+ // TypeScript source files (with type-checking)
894
+ {
895
+ name: 'sources',
896
+ files: ['src/**/*.ts'],
897
+ ignores: ['**/*.test.ts', '**/__tests__/**'],
898
+ languageOptions: {
899
+ globals: {
900
+ ...globals.node,
901
+ },
902
+ parserOptions: {
903
+ projectService: true,
904
+ tsconfigRootDir: import.meta.dirname,
905
+ },
906
+ },
907
+ },
908
+
909
+ // Test files
910
+ {
911
+ name: 'tests',
912
+ files: ['src/**/*.test.ts', 'src/**/__tests__/**/*.ts'],
913
+ languageOptions: {
914
+ globals: {
915
+ ...globals.node,
916
+ },
917
+ parserOptions: {
918
+ projectService: true,
919
+ tsconfigRootDir: import.meta.dirname,
920
+ },
921
+ },
922
+ },
923
+
924
+ // Config files
925
+ {
926
+ name: 'ts-configs',
927
+ files: ['*.config.m?ts', 'eslint.config.mts'],
928
+ languageOptions: {
929
+ globals: {
930
+ ...globals.node,
931
+ },
932
+ parserOptions: {
933
+ projectService: false,
934
+ },
935
+ },
936
+ rules: {
937
+ '@typescript-eslint/no-unused-vars': 'off',
938
+ },
939
+ },
940
+
941
+ // JavaScript/MJS files (scripts, configs) \u2014 no TS project, so only
942
+ // disable the TS-parser-specific rule that doesn't apply without it.
943
+ {
944
+ name: 'js-configs',
945
+ files: ['**/*.js', '**/*.mjs'],
946
+ languageOptions: {
947
+ globals: {
948
+ ...globals.node,
949
+ },
950
+ parserOptions: {
951
+ projectService: false,
952
+ },
953
+ },
954
+ rules: {
955
+ '@typescript-eslint/no-require-imports': 'off',
956
+ },
957
+ },
958
+
959
+ eslintConfigPrettier,
960
+ ]);
868
961
  `
869
962
  },
870
963
  {
@@ -877,7 +970,9 @@ generated
877
970
  "private": true,
878
971
  "scripts": {
879
972
  "build": "test -d src && custom-objects-build --input src --output dist || true",
973
+ "lint": "pnpm lint:types && pnpm lint:eslint",
880
974
  "lint:types": "test ! -d src || tsc --noEmit",
975
+ "lint:eslint": "eslint .",
881
976
  "test": "vitest run"
882
977
  },
883
978
  "dependencies": {
@@ -900,8 +995,20 @@ generated
900
995
  "moduleResolution": "bundler",
901
996
  "types": ["vitest/globals"]
902
997
  },
998
+ "include": ["src/**/*.ts"],
903
999
  "exclude": ["dist"]
904
1000
  }
1001
+ `
1002
+ },
1003
+ {
1004
+ path: "root/custom-objects/vitest.config.mts",
1005
+ content: `import { defineConfig } from 'vitest/config';
1006
+
1007
+ export default defineConfig({
1008
+ test: {
1009
+ globals: true,
1010
+ },
1011
+ });
905
1012
  `
906
1013
  },
907
1014
  {
@@ -1019,7 +1126,7 @@ export default defineConfig([
1019
1126
  "build": "pnpm -r --if-present build",
1020
1127
  "lint": "pnpm lint:types && pnpm lint:eslint && pnpm lint:format",
1021
1128
  "lint:types": "pnpm -r --if-present lint:types",
1022
- "lint:eslint": "eslint . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present lint:eslint",
1129
+ "lint:eslint": "eslint . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present lint:eslint && pnpm -r --filter './custom-objects' --if-present lint:eslint",
1023
1130
  "lint:format": "prettier --check .",
1024
1131
  "fix:lint": "eslint --fix . --ignore-pattern 'extensions/**' && pnpm -r --filter './extensions/*' --if-present fix:lint",
1025
1132
  "fix:format": "prettier --write .",
@@ -1065,7 +1172,7 @@ declarations:
1065
1172
  content: `#!/usr/bin/env tsx
1066
1173
  /**
1067
1174
  * Runs tests across the workspace:
1068
- * - vitest for script extensions and custom objects (extensions/*)
1175
+ * - vitest for script extensions (extensions/*) and custom objects (custom-objects/)
1069
1176
  * - jest for UI extensions (ui/)
1070
1177
  */
1071
1178
  import { existsSync, readdirSync } from 'node:fs';
@@ -1075,6 +1182,8 @@ const hasExtensions =
1075
1182
  existsSync('extensions') &&
1076
1183
  readdirSync('extensions').some((name) => existsSync(\`extensions/\${name}/package.json\`));
1077
1184
 
1185
+ const hasCustomObjects = existsSync('custom-objects/package.json');
1186
+
1078
1187
  const hasUI = existsSync('ui/package.json');
1079
1188
 
1080
1189
  let exitCode = 0;
@@ -1087,7 +1196,7 @@ function run(cmd: string): void {
1087
1196
  }
1088
1197
  }
1089
1198
 
1090
- if (hasExtensions) {
1199
+ if (hasExtensions || hasCustomObjects) {
1091
1200
  run('vitest run');
1092
1201
  }
1093
1202
 
@@ -1239,8 +1348,30 @@ function _devNpmDep(name, version) {
1239
1348
  return { type: "dev-npm", name, version };
1240
1349
  }
1241
1350
 
1351
+ // src/workspace-versions.json
1352
+ var workspace_versions_default = {
1353
+ "@stripe/extensibility-custom-objects": "0.8.0",
1354
+ "@stripe/extensibility-custom-objects-tools": "0.42.1",
1355
+ "@stripe/extensibility-dev-tools": "0.25.1",
1356
+ "@stripe/extensibility-eslint-plugin": "0.17.1",
1357
+ "@stripe/extensibility-language-server": "0.3.4",
1358
+ "@stripe/extensibility-sdk": "0.27.1",
1359
+ "@stripe/extensibility-test-helpers": "0.2.7"
1360
+ };
1361
+
1362
+ // src/workspace-versions.ts
1363
+ var _workspaceVersions = workspace_versions_default;
1364
+ function _workspaceVersion(packageName) {
1365
+ const v = _workspaceVersions[packageName];
1366
+ if (v === void 0) {
1367
+ throw new Error(
1368
+ `Unknown workspace package "${packageName}". Check workspace-versions.json or run: tsx scripts/src/sync-workspace-versions.ts`
1369
+ );
1370
+ }
1371
+ return v;
1372
+ }
1373
+
1242
1374
  // src/templates/extensions/base.ts
1243
- import { _workspaceVersion } from "@stripe/extensibility-tool-utils";
1244
1375
  var SDK_PACKAGE_NAME = "@stripe/extensibility-sdk";
1245
1376
  var LANGUAGE_SERVER_PACKAGE_NAME = "@stripe/extensibility-language-server";
1246
1377
  var LANGUAGE_SERVER_PACKAGE_VERSION = `^${_workspaceVersion(LANGUAGE_SERVER_PACKAGE_NAME)}`;
@@ -1545,14 +1676,14 @@ var billing_bill_discount_calculation_default = {
1545
1676
  [EXTENSION_INTERFACE_ID5]: discountCalculationTemplate
1546
1677
  };
1547
1678
 
1548
- // src/templates/extensions/billing.invoice_collection_setting.ts
1549
- var EXTENSION_INTERFACE_ID6 = "billing.invoice_collection_setting";
1550
- var invoiceCollectionSettingTemplate = {
1679
+ // src/templates/extensions/billing.invoice_collection_options.ts
1680
+ var EXTENSION_INTERFACE_ID6 = "billing.invoice_collection_options";
1681
+ var invoiceCollectionOptionsTemplate = {
1551
1682
  hidden: true,
1552
1683
  methods: {
1553
- collection_override: { implementation_types: ["script"] }
1684
+ override_options: { implementation_types: ["script"] }
1554
1685
  },
1555
- description: "Use Stripe Scripts to create custom invoice collection logic that controls how your integration handles invoices generated from subscriptions.",
1686
+ description: "Use Stripe Scripts to create custom invoice collection options that controls how your integration handles invoices generated from subscriptions.",
1556
1687
  generate: (params, context) => {
1557
1688
  const { id } = params;
1558
1689
  const { fs: fs3 } = context;
@@ -1580,15 +1711,15 @@ var invoiceCollectionSettingTemplate = {
1580
1711
  ...base.files
1581
1712
  ],
1582
1713
  methods: {
1583
- collection_override: {
1714
+ override_options: {
1584
1715
  implementation_type: "script"
1585
1716
  }
1586
1717
  }
1587
1718
  };
1588
1719
  }
1589
1720
  };
1590
- var billing_invoice_collection_setting_default = {
1591
- [EXTENSION_INTERFACE_ID6]: invoiceCollectionSettingTemplate
1721
+ var billing_invoice_collection_options_default = {
1722
+ [EXTENSION_INTERFACE_ID6]: invoiceCollectionOptionsTemplate
1592
1723
  };
1593
1724
 
1594
1725
  // src/templates/extensions/billing.prorations.ts
@@ -1696,7 +1827,7 @@ var DEFAULT_TEMPLATES = {
1696
1827
  ...extend_workflows_custom_action_default,
1697
1828
  ...billing_customer_balance_application_default,
1698
1829
  ...billing_bill_discount_calculation_default,
1699
- ...billing_invoice_collection_setting_default,
1830
+ ...billing_invoice_collection_options_default,
1700
1831
  ...billing_prorations_default,
1701
1832
  ...billing_recurring_billing_item_handling_default
1702
1833
  };
@@ -1762,10 +1893,11 @@ function mapActions(actions) {
1762
1893
  }
1763
1894
  function mapProperties(schema) {
1764
1895
  const result = {};
1765
- const requiredSet = new Set(schema?.required ?? []);
1766
- if (!schema?.properties) return result;
1767
- const defs = schema.$defs ?? {};
1768
- for (const [key, propSchema] of Object.entries(schema.properties)) {
1896
+ const resolvedSchema = schema === null || schema === void 0 ? schema : resolveRef(schema, schema.$defs ?? {});
1897
+ const requiredSet = new Set(resolvedSchema?.required ?? []);
1898
+ if (!resolvedSchema?.properties) return result;
1899
+ const defs = resolvedSchema.$defs ?? {};
1900
+ for (const [key, propSchema] of Object.entries(resolvedSchema.properties)) {
1769
1901
  result[key] = toFieldSchema(resolveRef(propSchema, defs), requiredSet.has(key));
1770
1902
  }
1771
1903
  return result;
@@ -1809,10 +1941,11 @@ function toFieldSchema(schema, required) {
1809
1941
  fieldSchema.valuesPresence = FieldPresence.PRESENT;
1810
1942
  }
1811
1943
  if (schema.default !== void 0) {
1812
- if (dataType === DataType.ENUM_TYPE && enumValues && (typeof schema.default !== "string" || !enumValues.includes(schema.default))) {
1813
- throw new Error(
1814
- `Default value ${JSON.stringify(schema.default)} is not a valid enum value. Expected one of: ${enumValues.join(", ")}`
1815
- );
1944
+ if (dataType === DataType.ENUM_TYPE && enumValues) {
1945
+ validateEnumDefault(schema.default, enumValues);
1946
+ }
1947
+ if (dataType === DataType.DATETIME_TYPE) {
1948
+ validateDatetimeDefault(schema.default);
1816
1949
  }
1817
1950
  fieldSchema.default = toDefaultValue(schema.default, dataType);
1818
1951
  }
@@ -1826,7 +1959,6 @@ function resolveDataType(schema, enumValues, refTarget) {
1826
1959
  if (schema.format === "date-time") return DataType.DATETIME_TYPE;
1827
1960
  return DataType.STRING_TYPE;
1828
1961
  case "integer":
1829
- case "number":
1830
1962
  return DataType.INTEGER_TYPE;
1831
1963
  case "boolean":
1832
1964
  return DataType.BOOLEAN_TYPE;
@@ -1863,14 +1995,31 @@ function extractSingleLiteral(schema) {
1863
1995
  return null;
1864
1996
  }
1865
1997
  function extractEnumValues(schema) {
1866
- if (schema.enum) {
1998
+ if (Array.isArray(schema.enum) && schema.enum.every((value) => typeof value === "string")) {
1867
1999
  return schema.enum.map(String);
1868
2000
  }
1869
- if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every((item) => "const" in item)) {
2001
+ if (Array.isArray(schema.oneOf) && schema.oneOf.length > 0 && schema.oneOf.every(
2002
+ (item) => "const" in item && typeof item.const === "string"
2003
+ )) {
1870
2004
  return schema.oneOf.map((item) => String(item.const));
1871
2005
  }
1872
2006
  return null;
1873
2007
  }
2008
+ function validateEnumDefault(value, enumValues) {
2009
+ if (typeof value !== "string" || !enumValues.includes(value)) {
2010
+ throw new Error(
2011
+ `Default value ${JSON.stringify(value)} is not a valid enum value. Expected one of: ${enumValues.join(", ")}`
2012
+ );
2013
+ }
2014
+ }
2015
+ var DATETIME_UTC_MS_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}(Z|\+00:00)$/;
2016
+ function validateDatetimeDefault(value) {
2017
+ if (typeof value !== "string" || !DATETIME_UTC_MS_RE.test(value)) {
2018
+ throw new Error(
2019
+ `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`
2020
+ );
2021
+ }
2022
+ }
1874
2023
  function toValueBoundary(value) {
1875
2024
  if (!Number.isInteger(value)) {
1876
2025
  throw new Error(
@@ -1886,7 +2035,15 @@ function toDefaultValue(value, dataType) {
1886
2035
  if (dataType === DataType.ENUM_TYPE && typeof value === "string") {
1887
2036
  return { stringDefault: value };
1888
2037
  }
2038
+ if (dataType === DataType.DATETIME_TYPE && typeof value === "string") {
2039
+ return { stringDefault: value };
2040
+ }
1889
2041
  if (dataType === DataType.INTEGER_TYPE && typeof value === "number") {
2042
+ if (!Number.isInteger(value)) {
2043
+ throw new Error(
2044
+ `Integer default values must be whole numbers, got ${JSON.stringify(value)}.`
2045
+ );
2046
+ }
1890
2047
  return { integerDefault: value };
1891
2048
  }
1892
2049
  if (dataType === DataType.BOOLEAN_TYPE && typeof value === "boolean") {
@@ -1922,7 +2079,7 @@ async function analyzeAndInjectManifest(options) {
1922
2079
  (diagnostic) => diagnostic.severity === "error"
1923
2080
  );
1924
2081
  if (errorDiagnostics.length > 0) {
1925
- const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("; ");
2082
+ const details = errorDiagnostics.map((diagnostic) => diagnostic.message).join("\n");
1926
2083
  throw new Error(details);
1927
2084
  }
1928
2085
  const coPackageJsonPath = path2.join(projectRoot, "custom-objects", "package.json");